v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
constant-array-builder.cc
Go to the documentation of this file.
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
6
7#include <cmath>
8#include <functional>
9#include <set>
10
12#include "src/ast/scopes.h"
13#include "src/base/hashing.h"
15#include "src/handles/handles.h"
19
20namespace v8 {
21namespace internal {
22namespace interpreter {
23
25 Zone* zone, size_t start_index, size_t capacity, OperandSize operand_size)
26 : start_index_(start_index),
27 capacity_(capacity),
28 reserved_(0),
29 operand_size_(operand_size),
30 constants_(zone) {}
31
33 DCHECK_GT(available(), 0u);
34 reserved_++;
35 DCHECK_LE(reserved_, capacity() - constants_.size());
36}
37
39 DCHECK_GT(reserved_, 0u);
40 reserved_--;
41}
42
44 ConstantArrayBuilder::Entry entry, size_t count) {
45 DCHECK_GE(available(), count);
46 size_t index = constants_.size();
47 DCHECK_LT(index, capacity());
48 for (size_t i = 0; i < count; ++i) {
49 constants_.push_back(entry);
50 }
51 return index + start_index();
52}
53
55 size_t index) {
56 DCHECK_GE(index, start_index());
57 DCHECK_LT(index, start_index() + size());
58 return constants_[index - start_index()];
59}
60
62 size_t index) const {
63 DCHECK_GE(index, start_index());
64 DCHECK_LT(index, start_index() + size());
65 return constants_[index - start_index()];
66}
67
68#if DEBUG
69template <typename IsolateT>
70void ConstantArrayBuilder::ConstantArraySlice::CheckAllElementsAreUnique(
71 IsolateT* isolate) const {
72 std::set<Tagged<Smi>> smis;
73 std::set<double> heap_numbers;
74 std::set<const AstRawString*> strings;
75 std::set<const AstConsString*> cons_strings;
76 std::set<const char*> bigints;
77 std::set<const Scope*> scopes;
78 std::set<Tagged<Object>, Object::Comparer> deferred_objects;
79 for (const Entry& entry : constants_) {
80 bool duplicate = false;
81 switch (entry.tag_) {
83 duplicate = !smis.insert(entry.smi_).second;
84 break;
86 duplicate = !heap_numbers.insert(entry.heap_number_).second;
87 break;
89 duplicate = !strings.insert(entry.raw_string_).second;
90 break;
92 duplicate = !cons_strings.insert(entry.cons_string_).second;
93 break;
95 duplicate = !bigints.insert(entry.bigint_.c_str()).second;
96 break;
98 duplicate = !scopes.insert(entry.scope_).second;
99 break;
101 duplicate = !deferred_objects.insert(*entry.handle_).second;
102 break;
104 UNREACHABLE(); // Should be kHandle at this point.
107 // TODO(leszeks): Ignore jump tables because they have to be contiguous,
108 // so they can contain duplicates.
109 break;
110#define CASE_TAG(NAME, ...) case Entry::Tag::k##NAME:
112#undef CASE_TAG
113 // Singletons are non-duplicated by definition.
114 break;
115 }
116 if (duplicate) {
117 std::ostringstream os;
118 os << "Duplicate constant found: " << Brief(*entry.ToHandle(isolate))
119 << std::endl;
120 // Print all the entries in the slice to help debug duplicates.
121 size_t i = start_index();
122 for (const Entry& prev_entry : constants_) {
123 os << i++ << ": " << Brief(*prev_entry.ToHandle(isolate)) << std::endl;
124 }
125 FATAL("%s", os.str().c_str());
126 }
127 }
128}
129#endif
130
136
150
152 size_t i = arraysize(idx_slice_);
153 while (i > 0) {
154 ConstantArraySlice* slice = idx_slice_[--i];
155 if (slice->size() > 0) {
156 return slice->start_index() + slice->size();
157 }
158 }
159 return idx_slice_[0]->size();
160}
161
163 size_t index) const {
164 for (ConstantArraySlice* slice : idx_slice_) {
165 if (index <= slice->max_index()) {
166 return slice;
167 }
168 }
169 UNREACHABLE();
170}
171
172template <typename IsolateT>
174 IsolateT* isolate) const {
175 const ConstantArraySlice* slice = IndexToSlice(index);
176 DCHECK_LT(index, slice->capacity());
177 if (index < slice->start_index() + slice->size()) {
178 const Entry& entry = slice->At(index);
179 if (!entry.IsDeferred()) return entry.ToHandle(isolate);
180 }
181 return MaybeHandle<Object>();
182}
183
186 Isolate* isolate) const;
189 LocalIsolate* isolate) const;
190
191template <typename IsolateT>
193 IsolateT* isolate) {
194 Handle<TrustedFixedArray> fixed_array =
195 isolate->factory()->NewTrustedFixedArray(static_cast<int>(size()));
196 MemsetTagged(fixed_array->RawFieldOfFirstElement(),
197 *isolate->factory()->the_hole_value(), size());
198 int array_index = 0;
199 for (const ConstantArraySlice* slice : idx_slice_) {
200 DCHECK_EQ(slice->reserved(), 0);
201 DCHECK(array_index == 0 ||
202 base::bits::IsPowerOfTwo(static_cast<uint32_t>(array_index)));
203#if DEBUG
204 // Different slices might contain the same element due to reservations, but
205 // all elements within a slice should be unique.
206 slice->CheckAllElementsAreUnique(isolate);
207#endif
208 // Copy objects from slice into array.
209 for (size_t i = 0; i < slice->size(); ++i) {
211 slice->At(slice->start_index() + i).ToHandle(isolate);
212 fixed_array->set(array_index++, *value);
213 }
214 // Leave holes where reservations led to unused slots.
215 size_t padding = slice->capacity() - slice->size();
216 if (static_cast<size_t>(fixed_array->length() - array_index) <= padding) {
217 break;
218 }
219 array_index += padding;
220 }
221 DCHECK_GE(array_index, fixed_array->length());
222 return fixed_array;
223}
224
227 Isolate* isolate);
230 LocalIsolate* isolate);
231
233 auto entry = smi_map_.find(smi);
234 if (entry == smi_map_.end()) {
235 return AllocateReservedEntry(smi);
236 }
237 return entry->second;
238}
239
240size_t ConstantArrayBuilder::Insert(double number) {
241 if (std::isnan(number)) return InsertNaN();
242 auto entry = heap_number_map_.find(number);
243 if (entry == heap_number_map_.end()) {
244 index_t index = static_cast<index_t>(AllocateIndex(Entry(number)));
245 heap_number_map_[number] = index;
246 return index;
247 }
248 return entry->second;
249}
250
252 return constants_map_
253 .LookupOrInsert(reinterpret_cast<intptr_t>(raw_string),
254 raw_string->Hash(),
255 [&]() { return AllocateIndex(Entry(raw_string)); })
256 ->value;
257}
258
259size_t ConstantArrayBuilder::Insert(const AstConsString* cons_string) {
260 const AstRawString* last = cons_string->last();
261 uint32_t hash = last == nullptr ? 0 : last->Hash();
262 return constants_map_
263 .LookupOrInsert(reinterpret_cast<intptr_t>(cons_string), hash,
264 [&]() { return AllocateIndex(Entry(cons_string)); })
265 ->value;
266}
267
269 return constants_map_
270 .LookupOrInsert(reinterpret_cast<intptr_t>(bigint.c_str()),
271 static_cast<uint32_t>(base::hash_value(bigint.c_str())),
272 [&]() { return AllocateIndex(Entry(bigint)); })
273 ->value;
274}
275
277 return constants_map_
278 .LookupOrInsert(reinterpret_cast<intptr_t>(scope),
279 static_cast<uint32_t>(base::hash_value(scope)),
280 [&]() { return AllocateIndex(Entry(scope)); })
281 ->value;
282}
283
284#define INSERT_ENTRY(NAME, LOWER_NAME) \
285 size_t ConstantArrayBuilder::Insert##NAME() { \
286 if (LOWER_NAME##_ < 0) { \
287 LOWER_NAME##_ = AllocateIndex(Entry::NAME()); \
288 } \
289 return LOWER_NAME##_; \
290 }
292#undef INSERT_ENTRY
293
298
300 ConstantArrayBuilder::Entry entry, size_t count) {
301 for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
302 if (idx_slice_[i]->available() >= count) {
303 return static_cast<index_t>(idx_slice_[i]->Allocate(entry, count));
304 }
305 }
306 UNREACHABLE();
307}
308
311 ConstantArraySlice* slice = nullptr;
312 switch (operand_size) {
314 UNREACHABLE();
316 slice = idx_slice_[0];
317 break;
319 slice = idx_slice_[1];
320 break;
322 slice = idx_slice_[2];
323 break;
324 }
325 DCHECK(slice->operand_size() == operand_size);
326 return slice;
327}
328
332
336
338 ConstantArraySlice* slice = IndexToSlice(index);
339 return slice->At(index).SetDeferred(object);
340}
341
343 ConstantArraySlice* slice = IndexToSlice(index);
344 // Allow others to reuse these Smis, but insert using emplace to avoid
345 // overwriting existing values in the Smi map (which may have a smaller
346 // operand size).
347 smi_map_.emplace(smi, static_cast<index_t>(index));
348 return slice->At(index).SetJumpTableSmi(smi);
349}
350
352 OperandSize minimum_operand_size) {
353 for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
354 if (idx_slice_[i]->available() > 0 &&
355 idx_slice_[i]->operand_size() >= minimum_operand_size) {
356 idx_slice_[i]->Reserve();
357 return idx_slice_[i]->operand_size();
358 }
359 }
360 UNREACHABLE();
361}
362
369
371 Tagged<Smi> value) {
372 DiscardReservedEntry(operand_size);
373 size_t index;
374 auto entry = smi_map_.find(value);
375 if (entry == smi_map_.end()) {
376 index = AllocateReservedEntry(value);
377 } else {
378 ConstantArraySlice* slice = OperandSizeToSlice(operand_size);
379 index = entry->second;
380 if (index > slice->max_index()) {
381 // The object is already in the constant array, but may have an
382 // index too big for the reserved operand_size. So, duplicate
383 // entry with the smaller operand size.
384 index = AllocateReservedEntry(value);
385 }
386 DCHECK_LE(index, slice->max_index());
387 }
388 return index;
389}
390
394
395template <typename IsolateT>
397 switch (tag_) {
398 case Tag::kDeferred:
399 // We shouldn't have any deferred entries by now.
400 UNREACHABLE();
401 case Tag::kHandle:
402 return handle_;
403 case Tag::kSmi:
405 return handle(smi_, isolate);
407 // TODO(leszeks): There's probably a better value we could use here.
408 return isolate->factory()->the_hole_value();
409 case Tag::kRawString:
410 return raw_string_->string();
411 case Tag::kConsString:
412 return cons_string_->AllocateFlat(isolate);
413 case Tag::kHeapNumber:
414 return isolate->factory()->template NewNumber<AllocationType::kOld>(
416 case Tag::kBigInt:
417 // This should never fail: the parser will never create a BigInt
418 // literal that cannot be allocated.
419 return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked();
420 case Tag::kScope:
421 return scope_->scope_info();
422#define ENTRY_LOOKUP(Name, name) \
423 case Tag::k##Name: \
424 return isolate->factory()->name();
426#undef ENTRY_LOOKUP
427 }
428 UNREACHABLE();
429}
430
432 Isolate* isolate) const;
434 LocalIsolate* isolate) const;
435
436} // namespace interpreter
437} // namespace internal
438} // namespace v8
const char * c_str() const
const AstRawString * last() const
T * New(Args &&... args)
Definition zone.h:114
enum v8::internal::interpreter::ConstantArrayBuilder::Entry::Tag tag_
void SetJumpTableSmi(size_t index, Tagged< Smi > smi)
MaybeHandle< Object > At(size_t index, IsolateT *isolate) const
ConstantArraySlice * IndexToSlice(size_t index) const
ConstantArraySlice * OperandSizeToSlice(OperandSize operand_size) const
Handle< TrustedFixedArray > ToFixedArray(IsolateT *isolate)
void SetDeferredAt(size_t index, Handle< Object > object)
base::TemplateHashMapImpl< intptr_t, index_t, base::KeyEqualityMatcher< intptr_t >, ZoneAllocationPolicy > constants_map_
ZoneVector< std::pair< Tagged< Smi >, index_t > > smi_pairs_
index_t AllocateIndexArray(Entry constant_entry, size_t size)
size_t CommitReservedEntry(OperandSize operand_size, Tagged< Smi > value)
OperandSize CreateReservedEntry(OperandSize minimum_operand_size=OperandSize::kNone)
#define INSERT_ENTRY(NAME, LOWER_NAME)
#define ENTRY_LOOKUP(Name, name)
#define SINGLETON_CONSTANT_ENTRY_TYPES(V)
uint32_t count
#define EXPORT_TEMPLATE_DEFINE(export)
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
V8_INLINE size_t hash_value(unsigned int v)
Definition hashing.h:205
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
void MemsetTagged(Tagged_t *start, Tagged< MaybeObject > value, size_t counter)
Definition slots-inl.h:486
MaybeHandle< BigInt > BigIntLiteral(IsolateT *isolate, const char *string)
return value
Definition map-inl.h:893
Local< T > Handle
#define STATIC_CONST_MEMBER_DEFINITION
#define FATAL(...)
Definition logging.h:47
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define arraysize(array)
Definition macros.h:67
ConstantArraySlice(Zone *zone, size_t start_index, size_t capacity, OperandSize operand_size)