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
10namespace v8 {
11namespace internal {
12namespace interpreter {
13
14ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice(Zone* zone,
15                                                             size_t start_index,
16                                                             size_t capacity)
17    : start_index_(start_index),
18      capacity_(capacity),
19      reserved_(0),
20      constants_(zone) {}
21
22
23void ConstantArrayBuilder::ConstantArraySlice::Reserve() {
24  DCHECK_GT(available(), 0u);
25  reserved_++;
26  DCHECK_LE(reserved_, capacity() - constants_.size());
27}
28
29
30void ConstantArrayBuilder::ConstantArraySlice::Unreserve() {
31  DCHECK_GT(reserved_, 0u);
32  reserved_--;
33}
34
35
36size_t ConstantArrayBuilder::ConstantArraySlice::Allocate(
37    Handle<Object> object) {
38  DCHECK_GT(available(), 0u);
39  size_t index = constants_.size();
40  DCHECK_LT(index, capacity());
41  constants_.push_back(object);
42  return index + start_index();
43}
44
45
46Handle<Object> ConstantArrayBuilder::ConstantArraySlice::At(
47    size_t index) const {
48  return constants_[index - start_index()];
49}
50
51
52STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kMaxCapacity;
53STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kLowCapacity;
54
55
56ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone)
57    : isolate_(isolate),
58      idx8_slice_(zone, 0, kLowCapacity),
59      idx16_slice_(zone, kLowCapacity, kHighCapacity),
60      constants_map_(isolate->heap(), zone) {
61  STATIC_ASSERT(kMaxCapacity == static_cast<size_t>(kMaxUInt16 + 1));
62  DCHECK_EQ(idx8_slice_.start_index(), 0u);
63  DCHECK_EQ(idx8_slice_.capacity(), kLowCapacity);
64  DCHECK_EQ(idx16_slice_.start_index(), kLowCapacity);
65  DCHECK_EQ(idx16_slice_.capacity(), kMaxCapacity - kLowCapacity);
66}
67
68
69size_t ConstantArrayBuilder::size() const {
70  if (idx16_slice_.size() > 0) {
71    return idx16_slice_.start_index() + idx16_slice_.size();
72  } else {
73    return idx8_slice_.size();
74  }
75}
76
77
78Handle<Object> ConstantArrayBuilder::At(size_t index) const {
79  if (index >= idx16_slice_.start_index()) {
80    return idx16_slice_.At(index);
81  } else if (index < idx8_slice_.size()) {
82    return idx8_slice_.At(index);
83  } else {
84    return isolate_->factory()->the_hole_value();
85  }
86}
87
88
89Handle<FixedArray> ConstantArrayBuilder::ToFixedArray(Factory* factory) const {
90  Handle<FixedArray> fixed_array =
91      factory->NewFixedArray(static_cast<int>(size()), PretenureFlag::TENURED);
92  for (int i = 0; i < fixed_array->length(); i++) {
93    fixed_array->set(i, *At(static_cast<size_t>(i)));
94  }
95  return fixed_array;
96}
97
98
99size_t ConstantArrayBuilder::Insert(Handle<Object> object) {
100  index_t* entry = constants_map_.Find(object);
101  return (entry == nullptr) ? AllocateEntry(object) : *entry;
102}
103
104
105ConstantArrayBuilder::index_t ConstantArrayBuilder::AllocateEntry(
106    Handle<Object> object) {
107  DCHECK(!object->IsOddball());
108  size_t index;
109  index_t* entry = constants_map_.Get(object);
110  if (idx8_slice_.available() > 0) {
111    index = idx8_slice_.Allocate(object);
112  } else {
113    index = idx16_slice_.Allocate(object);
114  }
115  CHECK_LT(index, kMaxCapacity);
116  *entry = static_cast<index_t>(index);
117  return *entry;
118}
119
120
121OperandSize ConstantArrayBuilder::CreateReservedEntry() {
122  if (idx8_slice_.available() > 0) {
123    idx8_slice_.Reserve();
124    return OperandSize::kByte;
125  } else if (idx16_slice_.available() > 0) {
126    idx16_slice_.Reserve();
127    return OperandSize::kShort;
128  } else {
129    UNREACHABLE();
130    return OperandSize::kNone;
131  }
132}
133
134
135size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
136                                                 Handle<Object> object) {
137  DiscardReservedEntry(operand_size);
138  size_t index;
139  index_t* entry = constants_map_.Find(object);
140  if (nullptr == entry) {
141    index = AllocateEntry(object);
142  } else {
143    if (operand_size == OperandSize::kByte &&
144        *entry >= idx8_slice_.capacity()) {
145      // The object is already in the constant array, but has an index
146      // outside the range of an idx8 operand so we need to create a
147      // duplicate entry in the idx8 operand range to satisfy the
148      // commitment.
149      *entry = static_cast<index_t>(idx8_slice_.Allocate(object));
150    }
151    index = *entry;
152  }
153  DCHECK(operand_size == OperandSize::kShort || index < idx8_slice_.capacity());
154  DCHECK_LT(index, kMaxCapacity);
155  return index;
156}
157
158
159void ConstantArrayBuilder::DiscardReservedEntry(OperandSize operand_size) {
160  switch (operand_size) {
161    case OperandSize::kByte:
162      idx8_slice_.Unreserve();
163      return;
164    case OperandSize::kShort:
165      idx16_slice_.Unreserve();
166      return;
167    default:
168      UNREACHABLE();
169  }
170}
171
172}  // namespace interpreter
173}  // namespace internal
174}  // namespace v8
175