Home | History | Annotate | Download | only in interpreter
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/interpreter/constant-array-builder.h"
      6 
      7 #include "src/isolate.h"
      8 #include "src/objects-inl.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace interpreter {
     13 
     14 ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice(
     15     Zone* zone, size_t start_index, size_t capacity, OperandSize operand_size)
     16     : start_index_(start_index),
     17       capacity_(capacity),
     18       reserved_(0),
     19       operand_size_(operand_size),
     20       constants_(zone) {}
     21 
     22 void ConstantArrayBuilder::ConstantArraySlice::Reserve() {
     23   DCHECK_GT(available(), 0u);
     24   reserved_++;
     25   DCHECK_LE(reserved_, capacity() - constants_.size());
     26 }
     27 
     28 void ConstantArrayBuilder::ConstantArraySlice::Unreserve() {
     29   DCHECK_GT(reserved_, 0u);
     30   reserved_--;
     31 }
     32 
     33 size_t ConstantArrayBuilder::ConstantArraySlice::Allocate(
     34     Handle<Object> object) {
     35   DCHECK_GT(available(), 0u);
     36   size_t index = constants_.size();
     37   DCHECK_LT(index, capacity());
     38   constants_.push_back(object);
     39   return index + start_index();
     40 }
     41 
     42 Handle<Object> ConstantArrayBuilder::ConstantArraySlice::At(
     43     size_t index) const {
     44   DCHECK_GE(index, start_index());
     45   DCHECK_LT(index, start_index() + size());
     46   return constants_[index - start_index()];
     47 }
     48 
     49 STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::k8BitCapacity;
     50 STATIC_CONST_MEMBER_DEFINITION const size_t
     51     ConstantArrayBuilder::k16BitCapacity;
     52 STATIC_CONST_MEMBER_DEFINITION const size_t
     53     ConstantArrayBuilder::k32BitCapacity;
     54 
     55 ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone)
     56     : isolate_(isolate), constants_map_(isolate->heap(), zone) {
     57   idx_slice_[0] =
     58       new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte);
     59   idx_slice_[1] = new (zone) ConstantArraySlice(
     60       zone, k8BitCapacity, k16BitCapacity, OperandSize::kShort);
     61   idx_slice_[2] = new (zone) ConstantArraySlice(
     62       zone, k8BitCapacity + k16BitCapacity, k32BitCapacity, OperandSize::kQuad);
     63 }
     64 
     65 size_t ConstantArrayBuilder::size() const {
     66   size_t i = arraysize(idx_slice_);
     67   while (i > 0) {
     68     ConstantArraySlice* slice = idx_slice_[--i];
     69     if (slice->size() > 0) {
     70       return slice->start_index() + slice->size();
     71     }
     72   }
     73   return idx_slice_[0]->size();
     74 }
     75 
     76 const ConstantArrayBuilder::ConstantArraySlice*
     77 ConstantArrayBuilder::IndexToSlice(size_t index) const {
     78   for (const ConstantArraySlice* slice : idx_slice_) {
     79     if (index <= slice->max_index()) {
     80       return slice;
     81     }
     82   }
     83   UNREACHABLE();
     84   return nullptr;
     85 }
     86 
     87 Handle<Object> ConstantArrayBuilder::At(size_t index) const {
     88   const ConstantArraySlice* slice = IndexToSlice(index);
     89   if (index < slice->start_index() + slice->size()) {
     90     return slice->At(index);
     91   } else {
     92     DCHECK_LT(index, slice->capacity());
     93     return isolate_->factory()->the_hole_value();
     94   }
     95 }
     96 
     97 Handle<FixedArray> ConstantArrayBuilder::ToFixedArray() {
     98   Handle<FixedArray> fixed_array = isolate_->factory()->NewFixedArray(
     99       static_cast<int>(size()), PretenureFlag::TENURED);
    100   int array_index = 0;
    101   for (const ConstantArraySlice* slice : idx_slice_) {
    102     if (array_index == fixed_array->length()) {
    103       break;
    104     }
    105     DCHECK(array_index == 0 ||
    106            base::bits::IsPowerOfTwo32(static_cast<uint32_t>(array_index)));
    107     // Copy objects from slice into array.
    108     for (size_t i = 0; i < slice->size(); ++i) {
    109       fixed_array->set(array_index++, *slice->At(slice->start_index() + i));
    110     }
    111     // Insert holes where reservations led to unused slots.
    112     size_t padding =
    113         std::min(static_cast<size_t>(fixed_array->length() - array_index),
    114                  slice->capacity() - slice->size());
    115     for (size_t i = 0; i < padding; i++) {
    116       fixed_array->set(array_index++, *isolate_->factory()->the_hole_value());
    117     }
    118   }
    119   DCHECK_EQ(array_index, fixed_array->length());
    120   constants_map()->Clear();
    121   return fixed_array;
    122 }
    123 
    124 size_t ConstantArrayBuilder::Insert(Handle<Object> object) {
    125   index_t* entry = constants_map()->Find(object);
    126   return (entry == nullptr) ? AllocateEntry(object) : *entry;
    127 }
    128 
    129 ConstantArrayBuilder::index_t ConstantArrayBuilder::AllocateEntry(
    130     Handle<Object> object) {
    131   DCHECK(!object->IsOddball());
    132   index_t* entry = constants_map()->Get(object);
    133   for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
    134     if (idx_slice_[i]->available() > 0) {
    135       size_t index = idx_slice_[i]->Allocate(object);
    136       *entry = static_cast<index_t>(index);
    137       return *entry;
    138       break;
    139     }
    140   }
    141   UNREACHABLE();
    142   return kMaxUInt32;
    143 }
    144 
    145 OperandSize ConstantArrayBuilder::CreateReservedEntry() {
    146   for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
    147     if (idx_slice_[i]->available() > 0) {
    148       idx_slice_[i]->Reserve();
    149       return idx_slice_[i]->operand_size();
    150     }
    151   }
    152   UNREACHABLE();
    153   return OperandSize::kNone;
    154 }
    155 
    156 ConstantArrayBuilder::ConstantArraySlice*
    157 ConstantArrayBuilder::OperandSizeToSlice(OperandSize operand_size) const {
    158   ConstantArraySlice* slice = nullptr;
    159   switch (operand_size) {
    160     case OperandSize::kNone:
    161       UNREACHABLE();
    162       break;
    163     case OperandSize::kByte:
    164       slice = idx_slice_[0];
    165       break;
    166     case OperandSize::kShort:
    167       slice = idx_slice_[1];
    168       break;
    169     case OperandSize::kQuad:
    170       slice = idx_slice_[2];
    171       break;
    172   }
    173   DCHECK(slice->operand_size() == operand_size);
    174   return slice;
    175 }
    176 
    177 size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
    178                                                  Handle<Object> object) {
    179   DiscardReservedEntry(operand_size);
    180   size_t index;
    181   index_t* entry = constants_map()->Find(object);
    182   if (nullptr == entry) {
    183     index = AllocateEntry(object);
    184   } else {
    185     ConstantArraySlice* slice = OperandSizeToSlice(operand_size);
    186     if (*entry > slice->max_index()) {
    187       // The object is already in the constant array, but may have an
    188       // index too big for the reserved operand_size. So, duplicate
    189       // entry with the smaller operand size.
    190       *entry = static_cast<index_t>(slice->Allocate(object));
    191     }
    192     index = *entry;
    193   }
    194   return index;
    195 }
    196 
    197 void ConstantArrayBuilder::DiscardReservedEntry(OperandSize operand_size) {
    198   OperandSizeToSlice(operand_size)->Unreserve();
    199 }
    200 
    201 }  // namespace interpreter
    202 }  // namespace internal
    203 }  // namespace v8
    204