text: // Copyright 2018 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_PARSING_PREPARSE_DATA_IMPL_H_
  #define V8_PARSING_PREPARSE_DATA_IMPL_H_
  
  #include "src/parsing/preparse-data.h"
  
  #include "src/assert-scope.h"
  
  namespace v8 {
  namespace internal {
  
  // Classes which are internal to prepared-scope-data.cc, but are exposed in
  // a header for tests.
  
  // Wraps a ZoneVector<uint8_t> to have with functions named the same as
  // PodArray<uint8_t>.
  class ZoneVectorWrapper {
   public:
    ZoneVectorWrapper() = default;
    explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
  
    int data_length() const { return static_cast<int>(data_->size()); }
  
    uint8_t get(int index) const { return data_->at(index); }
  
   private:
    ZoneVector<uint8_t>* data_ = nullptr;
  };
  
  template <class Data>
  class BaseConsumedPreparseData : public ConsumedPreparseData {
   public:
    class ByteData : public PreparseByteDataConstants {
     public:
      ByteData() {}
  
      // Reading from the ByteData is only allowed when a ReadingScope is on the
      // stack. This ensures that we have a DisallowHeapAllocation in place
      // whenever ByteData holds a raw pointer into the heap.
      class ReadingScope {
       public:
        ReadingScope(ByteData* consumed_data, Data data)
            : consumed_data_(consumed_data) {
          consumed_data->data_ = data;
  #ifdef DEBUG
          consumed_data->has_data_ = true;
  #endif
        }
        explicit ReadingScope(BaseConsumedPreparseData<Data>* parent)
            : ReadingScope(parent->scope_data_.get(), parent->GetScopeData()) {}
        ~ReadingScope() {
  #ifdef DEBUG
          consumed_data_->has_data_ = false;
  #endif
        }
  
       private:
        ByteData* consumed_data_;
        DISALLOW_HEAP_ALLOCATION(no_gc);
      };
  
      void SetPosition(int position) {
        DCHECK_LE(position, data_.data_length());
        index_ = position;
      }
  
      size_t RemainingBytes() const {
        DCHECK(has_data_);
        DCHECK_LE(index_, data_.data_length());
        return data_.data_length() - index_;
      }
  
      bool HasRemainingBytes(size_t bytes) const {
        DCHECK(has_data_);
        return index_ <= data_.data_length() && bytes <= RemainingBytes();
      }
  
      int32_t ReadUint32() {
        DCHECK(has_data_);
        DCHECK(HasRemainingBytes(kUint32Size));
        // Check that there indeed is an integer following.
        DCHECK_EQ(data_.get(index_++), kUint32Size);
        int32_t result = data_.get(index_) + (data_.get(index_ + 1) << 8) +
                         (data_.get(index_ + 2) << 16) +
                         (data_.get(index_ + 3) << 24);
        index_ += 4;
        stored_quarters_ = 0;
        return result;
      }
  
      int32_t ReadVarint32() {
        DCHECK(HasRemainingBytes(kVarint32MinSize));
        DCHECK_EQ(data_.get(index_++), kVarint32MinSize);
        int32_t value = 0;
        bool has_another_byte;
        unsigned shift = 0;
        do {
          uint8_t byte = data_.get(index_++);
          value |= static_cast<int32_t>(byte & 0x7F) << shift;
          shift += 7;
          has_another_byte = byte & 0x80;
        } while (has_another_byte);
        DCHECK_EQ(data_.get(index_++), kVarint32EndMarker);
        stored_quarters_ = 0;
        return value;
      }
  
      uint8_t ReadUint8() {
        DCHECK(has_data_);
        DCHECK(HasRemainingBytes(kUint8Size));
        // Check that there indeed is a byte following.
        DCHECK_EQ(data_.get(index_++), kUint8Size);
        stored_quarters_ = 0;
        return data_.get(index_++);
      }
  
      uint8_t ReadQuarter() {
        DCHECK(has_data_);
        if (stored_quarters_ == 0) {
          DCHECK(HasRemainingBytes(kUint8Size));
          // Check that there indeed are quarters following.
          DCHECK_EQ(data_.get(index_++), kQuarterMarker);
          stored_byte_ = data_.get(index_++);
          stored_quarters_ = 4;
        }
        // Read the first 2 bits from stored_byte_.
        uint8_t result = (stored_byte_ >> 6) & 3;
        DCHECK_LE(result, 3);
        --stored_quarters_;
        stored_byte_ <<= 2;
        return result;
      }
  
     private:
      Data data_ = {};
      int index_ = 0;
      uint8_t stored_quarters_ = 0;
      uint8_t stored_byte_ = 0;
  #ifdef DEBUG
      bool has_data_ = false;
  #endif
    };
  
    BaseConsumedPreparseData() : scope_data_(new ByteData()), child_index_(0) {}
  
    virtual Data GetScopeData() = 0;
  
    virtual ProducedPreparseData* GetChildData(Zone* zone, int child_index) = 0;
  
    ProducedPreparseData* GetDataForSkippableFunction(
        Zone* zone, int start_position, int* end_position, int* num_parameters,
        int* num_inner_functions, bool* uses_super_property,
        LanguageMode* language_mode) final;
  
    void RestoreScopeAllocationData(DeclarationScope* scope) final;
  
  #ifdef DEBUG
    bool VerifyDataStart();
  #endif
  
   private:
    void RestoreDataForScope(Scope* scope);
    void RestoreDataForVariable(Variable* var);
    void RestoreDataForInnerScopes(Scope* scope);
  
    std::unique_ptr<ByteData> scope_data_;
    // When consuming the data, these indexes point to the data we're going to
    // consume next.
    int child_index_;
  
    DISALLOW_COPY_AND_ASSIGN(BaseConsumedPreparseData);
  };
  
  // Implementation of ConsumedPreparseData for on-heap data.
  class OnHeapConsumedPreparseData final
      : public BaseConsumedPreparseData<PreparseData> {
   public:
    OnHeapConsumedPreparseData(Isolate* isolate, Handle<PreparseData> data);
  
    PreparseData GetScopeData() final;
    ProducedPreparseData* GetChildData(Zone* zone, int child_index) final;
  
   private:
    Isolate* isolate_;
    Handle<PreparseData> data_;
  };
  
  // A serialized PreparseData in zone memory (as apposed to being on-heap).
  class ZonePreparseData : public ZoneObject {
   public:
    ZonePreparseData(Zone* zone, Vector<uint8_t>* byte_data, int child_length);
  
    Handle<PreparseData> Serialize(Isolate* isolate);
  
    int children_length() const { return static_cast<int>(children_.size()); }
  
    ZonePreparseData* get_child(int index) { return children_[index]; }
  
    void set_child(int index, ZonePreparseData* child) {
      DCHECK_NOT_NULL(child);
      children_[index] = child;
    }
  
    ZoneVector<uint8_t>* byte_data() { return &byte_data_; }
  
   private:
    ZoneVector<uint8_t> byte_data_;
    ZoneVector<ZonePreparseData*> children_;
  
    DISALLOW_COPY_AND_ASSIGN(ZonePreparseData);
  };
  
  ZonePreparseData* PreparseDataBuilder::ByteData::CopyToZone(
      Zone* zone, int children_length) {
    DCHECK(is_finalized_);
    return new (zone) ZonePreparseData(zone, &zone_byte_data_, children_length);
  }
  
  // Implementation of ConsumedPreparseData for PreparseData
  // serialized into zone memory.
  class ZoneConsumedPreparseData final
      : public BaseConsumedPreparseData<ZoneVectorWrapper> {
   public:
    ZoneConsumedPreparseData(Zone* zone, ZonePreparseData* data);
  
    ZoneVectorWrapper GetScopeData() final;
    ProducedPreparseData* GetChildData(Zone* zone, int child_index) final;
  
   private:
    ZonePreparseData* data_;
    ZoneVectorWrapper scope_data_wrapper_;
  };
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_PARSING_PREPARSE_DATA_IMPL_H_
  