blob: d7e49cdcb9350b6f17c28882fc6c0aa6f57d12b4 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/elements.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/arguments.h"
8#include "src/conversions.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/factory.h"
Ben Murdochda12d292016-06-02 14:46:10 +010010#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/messages.h"
12#include "src/objects-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/utils.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014
15// Each concrete ElementsAccessor can handle exactly one ElementsKind,
16// several abstract ElementsAccessor classes are used to allow sharing
17// common code.
18//
19// Inheritance hierarchy:
20// - ElementsAccessorBase (abstract)
21// - FastElementsAccessor (abstract)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022// - FastSmiOrObjectElementsAccessor
23// - FastPackedSmiElementsAccessor
24// - FastHoleySmiElementsAccessor
25// - FastPackedObjectElementsAccessor
26// - FastHoleyObjectElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010027// - FastDoubleElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028// - FastPackedDoubleElementsAccessor
29// - FastHoleyDoubleElementsAccessor
30// - TypedElementsAccessor: template, with instantiations:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031// - FixedUint8ElementsAccessor
32// - FixedInt8ElementsAccessor
33// - FixedUint16ElementsAccessor
34// - FixedInt16ElementsAccessor
35// - FixedUint32ElementsAccessor
36// - FixedInt32ElementsAccessor
37// - FixedFloat32ElementsAccessor
38// - FixedFloat64ElementsAccessor
39// - FixedUint8ClampedElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010040// - DictionaryElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041// - SloppyArgumentsElementsAccessor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042// - FastSloppyArgumentsElementsAccessor
43// - SlowSloppyArgumentsElementsAccessor
Ben Murdoch097c5b22016-05-18 11:27:45 +010044// - StringWrapperElementsAccessor
45// - FastStringWrapperElementsAccessor
46// - SlowStringWrapperElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010047
Ben Murdoch69a99ed2011-11-30 16:03:39 +000048namespace v8 {
49namespace internal {
50
51
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052namespace {
53
54
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055static const int kPackedSizeNotKnown = -1;
56
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057enum Where { AT_START, AT_END };
58
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060// First argument in list is the accessor class, the second argument is the
61// accessor ElementsKind, and the third is the backing store class. Use the
62// fast element handler for smi-only arrays. The implementation is currently
63// identical. Note that the order must match that of the ElementsKind enum for
64// the |accessor_array[]| below to work.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065#define ELEMENTS_LIST(V) \
66 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
67 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
68 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
69 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
70 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
71 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
72 FixedDoubleArray) \
73 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
74 V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
75 FixedArray) \
76 V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
77 FixedArray) \
Ben Murdoch097c5b22016-05-18 11:27:45 +010078 V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS, \
79 FixedArray) \
80 V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS, \
81 FixedArray) \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
83 V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
84 V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
85 V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
86 V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
87 V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
88 V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
89 V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
90 V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 FixedUint8ClampedArray)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010092
Ben Murdoch3ef787d2012-04-12 10:51:47 +010093template<ElementsKind Kind> class ElementsKindTraits {
94 public:
95 typedef FixedArrayBase BackingStore;
96};
97
98#define ELEMENTS_TRAITS(Class, KindParam, Store) \
99template<> class ElementsKindTraits<KindParam> { \
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 public: /* NOLINT */ \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100101 static const ElementsKind Kind = KindParam; \
102 typedef Store BackingStore; \
103};
104ELEMENTS_LIST(ELEMENTS_TRAITS)
105#undef ELEMENTS_TRAITS
106
107
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108MUST_USE_RESULT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
110 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100112}
113
114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115void CopyObjectToObjectElements(FixedArrayBase* from_base,
116 ElementsKind from_kind, uint32_t from_start,
117 FixedArrayBase* to_base, ElementsKind to_kind,
118 uint32_t to_start, int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 DCHECK(to_base->map() !=
120 from_base->GetIsolate()->heap()->fixed_cow_array_map());
121 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100122 int copy_size = raw_copy_size;
123 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100125 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 copy_size = Min(from_base->length() - from_start,
127 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100128 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 int start = to_start + copy_size;
130 int length = to_base->length() - start;
131 if (length > 0) {
132 Heap* heap = from_base->GetHeap();
133 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
134 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100135 }
136 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
139 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 FixedArray* from = FixedArray::cast(from_base);
142 FixedArray* to = FixedArray::cast(to_base);
Ben Murdochc5610432016-08-08 18:44:38 +0100143 DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145
146 WriteBarrierMode write_barrier_mode =
Ben Murdochc5610432016-08-08 18:44:38 +0100147 (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 ? UPDATE_WRITE_BARRIER
149 : SKIP_WRITE_BARRIER;
150 for (int i = 0; i < copy_size; i++) {
151 Object* value = from->get(from_start + i);
152 to->set(to_start + i, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100153 }
154}
155
156
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157static void CopyDictionaryToObjectElements(
158 FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
159 ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
160 DisallowHeapAllocation no_allocation;
161 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100162 int copy_size = raw_copy_size;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100163 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100165 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
166 copy_size = from->max_number_key() + 1 - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100167 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 int start = to_start + copy_size;
169 int length = to_base->length() - start;
170 if (length > 0) {
171 Heap* heap = from->GetHeap();
172 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
173 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100174 }
175 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 DCHECK(to_base != from_base);
178 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100179 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 FixedArray* to = FixedArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 uint32_t to_length = to->length();
182 if (to_start + copy_size > to_length) {
183 copy_size = to_length - to_start;
184 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185 WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
186 ? UPDATE_WRITE_BARRIER
187 : SKIP_WRITE_BARRIER;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100188 for (int i = 0; i < copy_size; i++) {
189 int entry = from->FindEntry(i + from_start);
190 if (entry != SeededNumberDictionary::kNotFound) {
191 Object* value = from->ValueAt(entry);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100192 DCHECK(!value->IsTheHole(from->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 to->set(i + to_start, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100194 } else {
195 to->set_the_hole(i + to_start);
196 }
197 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100198}
199
200
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400201// NOTE: this method violates the handlified function signature convention:
202// raw pointer parameters in the function that allocates.
203// See ElementsAccessorBase::CopyElements() for details.
204static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 uint32_t from_start,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206 FixedArrayBase* to_base,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 uint32_t to_start, int raw_copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100208 int copy_size = raw_copy_size;
209 if (raw_copy_size < 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100212 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 copy_size = Min(from_base->length() - from_start,
214 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 // Also initialize the area that will be copied over since HeapNumber
217 // allocation below can cause an incremental marking step, requiring all
218 // existing heap objects to be propertly initialized.
219 int start = to_start;
220 int length = to_base->length() - start;
221 if (length > 0) {
222 Heap* heap = from_base->GetHeap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100225 }
226 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100227 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
230 (copy_size + static_cast<int>(from_start)) <= from_base->length());
231 if (copy_size == 0) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400232
233 // From here on, the code below could actually allocate. Therefore the raw
234 // values are wrapped into handles.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 Isolate* isolate = from_base->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
237 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238
Ben Murdoch097c5b22016-05-18 11:27:45 +0100239 // Use an outer loop to not waste too much time on creating HandleScopes.
240 // On the other hand we might overflow a single handle scope depending on
241 // the copy_size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 int offset = 0;
243 while (offset < copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 offset += 100;
246 for (int i = offset - 100; i < offset && i < copy_size; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 Handle<Object> value =
248 FixedDoubleArray::get(*from, i + from_start, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100250 }
251 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252}
253
254
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100256 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 FixedArrayBase* to_base,
258 uint32_t to_start, int raw_copy_size) {
259 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260 int copy_size = raw_copy_size;
261 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100263 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 copy_size = Min(from_base->length() - from_start,
265 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
268 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269 }
270 }
271 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
273 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
276 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100277 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
278 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
279 to_address += kDoubleSize * to_start;
280 from_address += kDoubleSize * from_start;
281 int words_per_double = (kDoubleSize / kPointerSize);
282 CopyWords(reinterpret_cast<Object**>(to_address),
283 reinterpret_cast<Object**>(from_address),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 static_cast<size_t>(words_per_double * copy_size));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100285}
286
287
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288static void CopySmiToDoubleElements(FixedArrayBase* from_base,
289 uint32_t from_start,
290 FixedArrayBase* to_base, uint32_t to_start,
291 int raw_copy_size) {
292 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100293 int copy_size = raw_copy_size;
294 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100296 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 copy_size = from_base->length() - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100298 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
300 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100301 }
302 }
303 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
305 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100306 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 FixedArray* from = FixedArray::cast(from_base);
308 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
309 Object* the_hole = from->GetHeap()->the_hole_value();
310 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
311 from_start < from_end; from_start++, to_start++) {
312 Object* hole_or_smi = from->get(from_start);
313 if (hole_or_smi == the_hole) {
314 to->set_the_hole(to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100315 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 to->set(to_start, Smi::cast(hole_or_smi)->value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100317 }
318 }
319}
320
321
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
323 uint32_t from_start,
324 FixedArrayBase* to_base,
325 uint32_t to_start, int packed_size,
326 int raw_copy_size) {
327 DisallowHeapAllocation no_allocation;
328 int copy_size = raw_copy_size;
329 uint32_t to_end;
330 if (raw_copy_size < 0) {
331 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
332 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
333 copy_size = packed_size - from_start;
334 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
335 to_end = to_base->length();
336 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
337 FixedDoubleArray::cast(to_base)->set_the_hole(i);
338 }
339 } else {
340 to_end = to_start + static_cast<uint32_t>(copy_size);
341 }
342 } else {
343 to_end = to_start + static_cast<uint32_t>(copy_size);
344 }
345 DCHECK(static_cast<int>(to_end) <= to_base->length());
346 DCHECK(packed_size >= 0 && packed_size <= copy_size);
347 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
348 (copy_size + static_cast<int>(from_start)) <= from_base->length());
349 if (copy_size == 0) return;
350 FixedArray* from = FixedArray::cast(from_base);
351 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
352 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
353 from_start < from_end; from_start++, to_start++) {
354 Object* smi = from->get(from_start);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100355 DCHECK(!smi->IsTheHole(from->GetIsolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 to->set(to_start, Smi::cast(smi)->value());
357 }
358}
359
360
361static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
362 uint32_t from_start,
363 FixedArrayBase* to_base,
364 uint32_t to_start, int raw_copy_size) {
365 DisallowHeapAllocation no_allocation;
366 int copy_size = raw_copy_size;
367 if (raw_copy_size < 0) {
368 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
369 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
370 copy_size = from_base->length() - from_start;
371 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
372 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
373 FixedDoubleArray::cast(to_base)->set_the_hole(i);
374 }
375 }
376 }
377 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
378 (copy_size + static_cast<int>(from_start)) <= from_base->length());
379 if (copy_size == 0) return;
380 FixedArray* from = FixedArray::cast(from_base);
381 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
382 Object* the_hole = from->GetHeap()->the_hole_value();
383 for (uint32_t from_end = from_start + copy_size;
384 from_start < from_end; from_start++, to_start++) {
385 Object* hole_or_object = from->get(from_start);
386 if (hole_or_object == the_hole) {
387 to->set_the_hole(to_start);
388 } else {
389 to->set(to_start, hole_or_object->Number());
390 }
391 }
392}
393
394
395static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 FixedArrayBase* to_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398 uint32_t to_start,
399 int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000400 DisallowHeapAllocation no_allocation;
401 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100402 int copy_size = raw_copy_size;
403 if (copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100405 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
406 copy_size = from->max_number_key() + 1 - from_start;
407 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000408 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
409 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100410 }
411 }
412 }
413 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100415 uint32_t to_length = to->length();
416 if (to_start + copy_size > to_length) {
417 copy_size = to_length - to_start;
418 }
419 for (int i = 0; i < copy_size; i++) {
420 int entry = from->FindEntry(i + from_start);
421 if (entry != SeededNumberDictionary::kNotFound) {
422 to->set(i + to_start, from->ValueAt(entry)->Number());
423 } else {
424 to->set_the_hole(i + to_start);
425 }
426 }
427}
428
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429static void TraceTopFrame(Isolate* isolate) {
430 StackFrameIterator it(isolate);
431 if (it.done()) {
432 PrintF("unknown location (no JavaScript frames present)");
433 return;
434 }
435 StackFrame* raw_frame = it.frame();
436 if (raw_frame->is_internal()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 Code* apply_builtin =
438 isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 if (raw_frame->unchecked_code() == apply_builtin) {
440 PrintF("apply from ");
441 it.Advance();
442 raw_frame = it.frame();
443 }
444 }
445 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
446}
447
Ben Murdoch61f157c2016-09-16 13:49:30 +0100448static void SortIndices(
449 Handle<FixedArray> indices, uint32_t sort_size,
450 WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER) {
451 struct {
452 bool operator()(Object* a, Object* b) {
453 if (a->IsSmi() || !a->IsUndefined(HeapObject::cast(a)->GetIsolate())) {
454 if (!b->IsSmi() && b->IsUndefined(HeapObject::cast(b)->GetIsolate())) {
455 return true;
456 }
457 return a->Number() < b->Number();
458 }
459 return !b->IsSmi() && b->IsUndefined(HeapObject::cast(b)->GetIsolate());
460 }
461 } cmp;
462 Object** start =
463 reinterpret_cast<Object**>(indices->GetFirstElementAddress());
464 std::sort(start, start + sort_size, cmp);
465 if (write_barrier_mode != SKIP_WRITE_BARRIER) {
466 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(indices->GetIsolate()->heap(), *indices,
467 0, sort_size);
468 }
469}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000471// Base class for element handler implementations. Contains the
472// the common logic for objects with different ElementsKinds.
473// Subclasses must specialize method for which the element
474// implementation differs from the base class implementation.
475//
476// This class is intended to be used in the following way:
477//
478// class SomeElementsAccessor :
479// public ElementsAccessorBase<SomeElementsAccessor,
480// BackingStoreClass> {
481// ...
482// }
483//
484// This is an example of the Curiously Recurring Template Pattern (see
485// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
486// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
487// specialization of SomeElementsAccessor methods).
Ben Murdochc5610432016-08-08 18:44:38 +0100488template <typename Subclass, typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000489class ElementsAccessorBase : public ElementsAccessor {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100491 explicit ElementsAccessorBase(const char* name)
492 : ElementsAccessor(name) { }
493
494 typedef ElementsTraitsParam ElementsTraits;
495 typedef typename ElementsTraitsParam::BackingStore BackingStore;
496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 static ElementsKind kind() { return ElementsTraits::Kind; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100498
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499 static void ValidateContents(Handle<JSObject> holder, int length) {
500 }
501
502 static void ValidateImpl(Handle<JSObject> holder) {
503 Handle<FixedArrayBase> fixed_array_base(holder->elements());
504 if (!fixed_array_base->IsHeapObject()) return;
505 // Arrays that have been shifted in place can't be verified.
506 if (fixed_array_base->IsFiller()) return;
507 int length = 0;
508 if (holder->IsJSArray()) {
509 Object* length_obj = Handle<JSArray>::cast(holder)->length();
510 if (length_obj->IsSmi()) {
511 length = Smi::cast(length_obj)->value();
512 }
513 } else {
514 length = fixed_array_base->length();
515 }
Ben Murdochc5610432016-08-08 18:44:38 +0100516 Subclass::ValidateContents(holder, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000517 }
518
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519 void Validate(Handle<JSObject> holder) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +0100521 Subclass::ValidateImpl(holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522 }
523
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 static bool IsPackedImpl(Handle<JSObject> holder,
525 Handle<FixedArrayBase> backing_store, uint32_t start,
526 uint32_t end) {
527 if (IsFastPackedElementsKind(kind())) return true;
528 for (uint32_t i = start; i < end; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100529 if (!Subclass::HasElementImpl(holder, i, backing_store, ALL_PROPERTIES)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 return false;
531 }
532 }
533 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100534 }
535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
537 if (!IsHoleyElementsKind(kind())) return;
538 int length = Smi::cast(array->length())->value();
539 Handle<FixedArrayBase> backing_store(array->elements());
Ben Murdochc5610432016-08-08 18:44:38 +0100540 if (!Subclass::IsPackedImpl(array, backing_store, 0, length)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 return;
542 }
543 ElementsKind packed_kind = GetPackedElementsKind(kind());
544 Handle<Map> new_map =
545 JSObject::GetElementsTransitionMap(array, packed_kind);
546 JSObject::MigrateToMap(array, new_map);
547 if (FLAG_trace_elements_transitions) {
548 JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
549 packed_kind, backing_store);
550 }
551 }
552
553 bool HasElement(Handle<JSObject> holder, uint32_t index,
554 Handle<FixedArrayBase> backing_store,
555 PropertyFilter filter) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100556 return Subclass::HasElementImpl(holder, index, backing_store, filter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 }
558
559 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
560 Handle<FixedArrayBase> backing_store,
561 PropertyFilter filter) {
Ben Murdochc5610432016-08-08 18:44:38 +0100562 return Subclass::GetEntryForIndexImpl(*holder, *backing_store, index,
563 filter) != kMaxUInt32;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 }
565
Ben Murdoch097c5b22016-05-18 11:27:45 +0100566 bool HasAccessors(JSObject* holder) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100567 return Subclass::HasAccessorsImpl(holder, holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568 }
569
Ben Murdoch097c5b22016-05-18 11:27:45 +0100570 static bool HasAccessorsImpl(JSObject* holder,
571 FixedArrayBase* backing_store) {
572 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 }
574
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100576 return Subclass::GetImpl(holder, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 }
578
Ben Murdoch097c5b22016-05-18 11:27:45 +0100579 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +0100580 return Subclass::GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 }
582
Ben Murdoch097c5b22016-05-18 11:27:45 +0100583 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
584 Isolate* isolate = backing_store->GetIsolate();
585 uint32_t index = GetIndexForEntryImpl(backing_store, entry);
586 return handle(BackingStore::cast(backing_store)->get(index), isolate);
587 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588
Ben Murdoch097c5b22016-05-18 11:27:45 +0100589 void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100590 Subclass::SetImpl(holder, entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000591 }
592
593 void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
594 uint32_t entry, Handle<Object> value,
595 PropertyAttributes attributes) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100596 Subclass::ReconfigureImpl(object, store, entry, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 }
598
599 static void ReconfigureImpl(Handle<JSObject> object,
600 Handle<FixedArrayBase> store, uint32_t entry,
601 Handle<Object> value,
602 PropertyAttributes attributes) {
603 UNREACHABLE();
604 }
605
606 void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
607 PropertyAttributes attributes, uint32_t new_capacity) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100608 Subclass::AddImpl(object, index, value, attributes, new_capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 }
610
611 static void AddImpl(Handle<JSObject> object, uint32_t index,
612 Handle<Object> value, PropertyAttributes attributes,
613 uint32_t new_capacity) {
614 UNREACHABLE();
615 }
616
Ben Murdochda12d292016-06-02 14:46:10 +0100617 uint32_t Push(Handle<JSArray> receiver, Arguments* args,
618 uint32_t push_size) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100619 return Subclass::PushImpl(receiver, args, push_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 }
621
Ben Murdochda12d292016-06-02 14:46:10 +0100622 static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 uint32_t push_sized) {
624 UNREACHABLE();
625 return 0;
626 }
627
Ben Murdochda12d292016-06-02 14:46:10 +0100628 uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 uint32_t unshift_size) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100630 return Subclass::UnshiftImpl(receiver, args, unshift_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 }
632
Ben Murdochda12d292016-06-02 14:46:10 +0100633 static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 uint32_t unshift_size) {
635 UNREACHABLE();
636 return 0;
637 }
638
Ben Murdochda12d292016-06-02 14:46:10 +0100639 Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000640 uint32_t end) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100641 return Subclass::SliceImpl(receiver, start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 }
643
644 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 uint32_t start, uint32_t end) {
646 UNREACHABLE();
647 return Handle<JSArray>();
648 }
649
Ben Murdochda12d292016-06-02 14:46:10 +0100650 Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000651 uint32_t delete_count, Arguments* args,
652 uint32_t add_count) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100653 return Subclass::SpliceImpl(receiver, start, delete_count, args, add_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 }
655
656 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 uint32_t start, uint32_t delete_count,
658 Arguments* args, uint32_t add_count) {
659 UNREACHABLE();
660 return Handle<JSArray>();
661 }
662
Ben Murdochda12d292016-06-02 14:46:10 +0100663 Handle<Object> Pop(Handle<JSArray> receiver) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100664 return Subclass::PopImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665 }
666
Ben Murdochda12d292016-06-02 14:46:10 +0100667 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 UNREACHABLE();
669 return Handle<Object>();
670 }
671
Ben Murdochda12d292016-06-02 14:46:10 +0100672 Handle<Object> Shift(Handle<JSArray> receiver) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100673 return Subclass::ShiftImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000674 }
675
Ben Murdochda12d292016-06-02 14:46:10 +0100676 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 UNREACHABLE();
678 return Handle<Object>();
679 }
680
681 void SetLength(Handle<JSArray> array, uint32_t length) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100682 Subclass::SetLengthImpl(array->GetIsolate(), array, length,
683 handle(array->elements()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000684 }
685
686 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
687 uint32_t length,
688 Handle<FixedArrayBase> backing_store) {
689 DCHECK(!array->SetLengthWouldNormalize(length));
690 DCHECK(IsFastElementsKind(array->GetElementsKind()));
691 uint32_t old_length = 0;
692 CHECK(array->length()->ToArrayIndex(&old_length));
693
694 if (old_length < length) {
695 ElementsKind kind = array->GetElementsKind();
696 if (!IsFastHoleyElementsKind(kind)) {
697 kind = GetHoleyElementsKind(kind);
698 JSObject::TransitionElementsKind(array, kind);
699 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100700 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702 // Check whether the backing store should be shrunk.
703 uint32_t capacity = backing_store->length();
704 old_length = Min(old_length, capacity);
705 if (length == 0) {
706 array->initialize_elements();
707 } else if (length <= capacity) {
Ben Murdochda12d292016-06-02 14:46:10 +0100708 if (IsFastSmiOrObjectElementsKind(kind())) {
709 JSObject::EnsureWritableFastElements(array);
710 if (array->elements() != *backing_store) {
711 backing_store = handle(array->elements(), isolate);
712 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 }
714 if (2 * length <= capacity) {
715 // If more than half the elements won't be used, trim the array.
716 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
717 *backing_store, capacity - length);
718 } else {
719 // Otherwise, fill the unused tail with holes.
720 for (uint32_t i = length; i < old_length; i++) {
721 BackingStore::cast(*backing_store)->set_the_hole(i);
722 }
723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 // Check whether the backing store should be expanded.
726 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
Ben Murdochc5610432016-08-08 18:44:38 +0100727 Subclass::GrowCapacityAndConvertImpl(array, capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 }
729
730 array->set_length(Smi::FromInt(length));
731 JSObject::ValidateElements(array);
732 }
733
Ben Murdoch61f157c2016-09-16 13:49:30 +0100734 static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
Ben Murdochda12d292016-06-02 14:46:10 +0100735 if (receiver->IsJSArray()) {
736 DCHECK(JSArray::cast(receiver)->length()->IsSmi());
737 return static_cast<uint32_t>(
738 Smi::cast(JSArray::cast(receiver)->length())->value());
739 }
Ben Murdochc5610432016-08-08 18:44:38 +0100740 return Subclass::GetCapacityImpl(receiver, elements);
Ben Murdochda12d292016-06-02 14:46:10 +0100741 }
742
Ben Murdoch61f157c2016-09-16 13:49:30 +0100743 static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
744 FixedArrayBase* elements) {
745 return Subclass::GetMaxIndex(receiver, elements);
746 }
747
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
749 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
750 ElementsKind from_kind, uint32_t capacity) {
751 return ConvertElementsWithCapacity(
752 object, old_elements, from_kind, capacity, 0, 0,
753 ElementsAccessor::kCopyToEndAndInitializeToHole);
754 }
755
756 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
757 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
758 ElementsKind from_kind, uint32_t capacity, int copy_size) {
759 return ConvertElementsWithCapacity(object, old_elements, from_kind,
760 capacity, 0, 0, copy_size);
761 }
762
763 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
764 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
765 ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
766 uint32_t dst_index, int copy_size) {
767 Isolate* isolate = object->GetIsolate();
768 Handle<FixedArrayBase> new_elements;
769 if (IsFastDoubleElementsKind(kind())) {
770 new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
771 } else {
772 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
773 }
774
775 int packed_size = kPackedSizeNotKnown;
776 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
777 packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
778 }
779
Ben Murdochc5610432016-08-08 18:44:38 +0100780 Subclass::CopyElementsImpl(*old_elements, src_index, *new_elements,
781 from_kind, dst_index, packed_size, copy_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782
783 return new_elements;
784 }
785
786 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
787 uint32_t capacity) {
788 ElementsKind from_kind = object->GetElementsKind();
789 if (IsFastSmiOrObjectElementsKind(from_kind)) {
790 // Array optimizations rely on the prototype lookups of Array objects
791 // always returning undefined. If there is a store to the initial
792 // prototype object, make sure all of these optimizations are invalidated.
793 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
794 }
795 Handle<FixedArrayBase> old_elements(object->elements());
796 // This method should only be called if there's a reason to update the
797 // elements.
798 DCHECK(IsFastDoubleElementsKind(from_kind) !=
799 IsFastDoubleElementsKind(kind()) ||
800 IsDictionaryElementsKind(from_kind) ||
801 static_cast<uint32_t>(old_elements->length()) < capacity);
Ben Murdochc5610432016-08-08 18:44:38 +0100802 Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
803 kind(), capacity);
804 }
805
806 static void BasicGrowCapacityAndConvertImpl(
807 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
808 ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 Handle<FixedArrayBase> elements =
810 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
811
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000812 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
813 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
814 JSObject::SetMapAndElements(object, new_map, elements);
815
816 // Transition through the allocation site as well if present.
817 JSObject::UpdateAllocationSite(object, to_kind);
818
819 if (FLAG_trace_elements_transitions) {
820 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
821 to_kind, elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100823 }
824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 void GrowCapacityAndConvert(Handle<JSObject> object,
826 uint32_t capacity) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100827 Subclass::GrowCapacityAndConvertImpl(object, capacity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000828 }
829
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830 void Delete(Handle<JSObject> obj, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100831 Subclass::DeleteImpl(obj, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 }
833
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400834 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
835 FixedArrayBase* to, ElementsKind from_kind,
836 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 int copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100838 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100839 }
840
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000841 void CopyElements(JSObject* from_holder, uint32_t from_start,
842 ElementsKind from_kind, Handle<FixedArrayBase> to,
843 uint32_t to_start, int copy_size) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000844 int packed_size = kPackedSizeNotKnown;
845 bool is_packed = IsFastPackedElementsKind(from_kind) &&
846 from_holder->IsJSArray();
847 if (is_packed) {
848 packed_size =
849 Smi::cast(JSArray::cast(from_holder)->length())->value();
850 if (copy_size >= 0 && packed_size > copy_size) {
851 packed_size = copy_size;
852 }
853 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400854 FixedArrayBase* from = from_holder->elements();
Ben Murdochc5610432016-08-08 18:44:38 +0100855 // NOTE: the Subclass::CopyElementsImpl() methods
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400856 // violate the handlified function signature convention:
857 // raw pointer parameters in the function that allocates. This is done
858 // intentionally to avoid ArrayConcat() builtin performance degradation.
859 //
860 // Details: The idea is that allocations actually happen only in case of
861 // copying from object with fast double elements to object with object
862 // elements. In all the other cases there are no allocations performed and
863 // handle creation causes noticeable performance degradation of the builtin.
Ben Murdochc5610432016-08-08 18:44:38 +0100864 Subclass::CopyElementsImpl(from, from_start, *to, from_kind, to_start,
865 packed_size, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000866 }
867
Ben Murdochda12d292016-06-02 14:46:10 +0100868 Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100869 return Subclass::NormalizeImpl(object, handle(object->elements()));
Ben Murdochda12d292016-06-02 14:46:10 +0100870 }
871
872 static Handle<SeededNumberDictionary> NormalizeImpl(
873 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
874 UNREACHABLE();
875 return Handle<SeededNumberDictionary>();
876 }
877
878 Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
879 Handle<FixedArray> values_or_entries,
880 bool get_entries, int* nof_items,
881 PropertyFilter filter) {
Ben Murdochc5610432016-08-08 18:44:38 +0100882 return Subclass::CollectValuesOrEntriesImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100883 isolate, object, values_or_entries, get_entries, nof_items, filter);
884 }
885
886 static Maybe<bool> CollectValuesOrEntriesImpl(
887 Isolate* isolate, Handle<JSObject> object,
888 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
889 PropertyFilter filter) {
890 int count = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100891 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
892 ALL_PROPERTIES);
Ben Murdochc5610432016-08-08 18:44:38 +0100893 Subclass::CollectElementIndicesImpl(
894 object, handle(object->elements(), isolate), &accumulator);
Ben Murdochda12d292016-06-02 14:46:10 +0100895 Handle<FixedArray> keys = accumulator.GetKeys();
896
897 for (int i = 0; i < keys->length(); ++i) {
898 Handle<Object> key(keys->get(i), isolate);
899 Handle<Object> value;
900 uint32_t index;
901 if (!key->ToUint32(&index)) continue;
902
Ben Murdochc5610432016-08-08 18:44:38 +0100903 uint32_t entry = Subclass::GetEntryForIndexImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100904 *object, object->elements(), index, filter);
905 if (entry == kMaxUInt32) continue;
906
Ben Murdochc5610432016-08-08 18:44:38 +0100907 PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
Ben Murdochda12d292016-06-02 14:46:10 +0100908
909 if (details.kind() == kData) {
Ben Murdochc5610432016-08-08 18:44:38 +0100910 value = Subclass::GetImpl(object, entry);
Ben Murdochda12d292016-06-02 14:46:10 +0100911 } else {
912 LookupIterator it(isolate, object, index, LookupIterator::OWN);
913 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
914 isolate, value, Object::GetProperty(&it), Nothing<bool>());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100915 }
Ben Murdochda12d292016-06-02 14:46:10 +0100916 if (get_entries) {
917 value = MakeEntryPair(isolate, index, value);
918 }
919 values_or_entries->set(count++, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000920 }
Ben Murdochda12d292016-06-02 14:46:10 +0100921
922 *nof_items = count;
923 return Just(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000924 }
925
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000926 void CollectElementIndices(Handle<JSObject> object,
927 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +0100928 KeyAccumulator* keys) final {
929 if (keys->filter() & ONLY_ALL_CAN_READ) return;
930 Subclass::CollectElementIndicesImpl(object, backing_store, keys);
Ben Murdochda12d292016-06-02 14:46:10 +0100931 }
932
933 static void CollectElementIndicesImpl(Handle<JSObject> object,
934 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +0100935 KeyAccumulator* keys) {
Ben Murdochda12d292016-06-02 14:46:10 +0100936 DCHECK_NE(DICTIONARY_ELEMENTS, kind());
937 // Non-dictionary elements can't have all-can-read accessors.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100938 uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
Ben Murdochc5610432016-08-08 18:44:38 +0100939 PropertyFilter filter = keys->filter();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100940 Factory* factory = keys->isolate()->factory();
Ben Murdochc5610432016-08-08 18:44:38 +0100941 for (uint32_t i = 0; i < length; i++) {
942 if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100943 keys->AddKey(factory->NewNumberFromUint(i));
Ben Murdochda12d292016-06-02 14:46:10 +0100944 }
945 }
946 }
947
948 static Handle<FixedArray> DirectCollectElementIndicesImpl(
949 Isolate* isolate, Handle<JSObject> object,
950 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
951 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
952 uint32_t insertion_index = 0) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100953 uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
Ben Murdochda12d292016-06-02 14:46:10 +0100954 for (uint32_t i = 0; i < length; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100955 if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100956 if (convert == GetKeysConversion::kConvertToString) {
Ben Murdochda12d292016-06-02 14:46:10 +0100957 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
958 list->set(insertion_index, *index_string);
959 } else {
960 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
961 }
962 insertion_index++;
963 }
964 }
965 *nof_indices = insertion_index;
966 return list;
967 }
968
969 Handle<FixedArray> PrependElementIndices(Handle<JSObject> object,
970 Handle<FixedArrayBase> backing_store,
971 Handle<FixedArray> keys,
972 GetKeysConversion convert,
973 PropertyFilter filter) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100974 return Subclass::PrependElementIndicesImpl(object, backing_store, keys,
975 convert, filter);
Ben Murdochda12d292016-06-02 14:46:10 +0100976 }
977
978 static Handle<FixedArray> PrependElementIndicesImpl(
979 Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
980 Handle<FixedArray> keys, GetKeysConversion convert,
981 PropertyFilter filter) {
982 Isolate* isolate = object->GetIsolate();
983 uint32_t nof_property_keys = keys->length();
984 uint32_t initial_list_length =
Ben Murdochc5610432016-08-08 18:44:38 +0100985 Subclass::GetCapacityImpl(*object, *backing_store);
Ben Murdochda12d292016-06-02 14:46:10 +0100986 initial_list_length += nof_property_keys;
987
988 // Collect the element indices into a new list.
989 uint32_t nof_indices = 0;
990 Handle<FixedArray> combined_keys =
991 isolate->factory()->NewFixedArray(initial_list_length);
Ben Murdochc5610432016-08-08 18:44:38 +0100992 combined_keys = Subclass::DirectCollectElementIndicesImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100993 isolate, object, backing_store, convert, filter, combined_keys,
994 &nof_indices);
995
996 // Sort the indices list if necessary.
997 if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100998 SortIndices(combined_keys, nof_indices, SKIP_WRITE_BARRIER);
Ben Murdochda12d292016-06-02 14:46:10 +0100999 uint32_t array_length = 0;
1000 // Indices from dictionary elements should only be converted after
1001 // sorting.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001002 if (convert == GetKeysConversion::kConvertToString) {
Ben Murdochda12d292016-06-02 14:46:10 +01001003 for (uint32_t i = 0; i < nof_indices; i++) {
1004 Handle<Object> index_string = isolate->factory()->Uint32ToString(
1005 combined_keys->get(i)->Number());
1006 combined_keys->set(i, *index_string);
1007 }
1008 } else if (!(object->IsJSArray() &&
1009 JSArray::cast(*object)->length()->ToArrayLength(
1010 &array_length) &&
1011 array_length <= Smi::kMaxValue)) {
1012 // Since we use std::sort above, the GC will no longer know where the
Ben Murdochc5610432016-08-08 18:44:38 +01001013 // HeapNumbers are. For Arrays with valid Smi length, we are sure to
1014 // have no HeapNumber indices and thus we can skip this step.
1015 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(isolate->heap(), *combined_keys, 0,
1016 nof_indices);
Ben Murdochda12d292016-06-02 14:46:10 +01001017 }
1018 }
1019
1020 // Copy over the passed-in property keys.
1021 CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
1022 FAST_ELEMENTS, nof_indices, nof_property_keys);
1023
1024 if (IsHoleyElementsKind(kind())) {
1025 // Shrink combined_keys to the final size.
1026 int final_size = nof_indices + nof_property_keys;
1027 DCHECK_LE(final_size, combined_keys->length());
1028 combined_keys->Shrink(final_size);
1029 }
1030
1031 return combined_keys;
1032 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001033
1034 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
1035 KeyAccumulator* accumulator,
1036 AddKeyConversion convert) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001037 Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001038 }
1039
1040 static uint32_t GetCapacityImpl(JSObject* holder,
1041 FixedArrayBase* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001042 return backing_store->length();
1043 }
1044
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001045 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001046 return Subclass::GetCapacityImpl(holder, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001047 }
1048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001049 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1050 uint32_t entry) {
1051 return entry;
1052 }
1053
1054 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1055 FixedArrayBase* backing_store,
1056 uint32_t index, PropertyFilter filter) {
1057 if (IsHoleyElementsKind(kind())) {
Ben Murdochc5610432016-08-08 18:44:38 +01001058 return index < Subclass::GetCapacityImpl(holder, backing_store) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001059 !BackingStore::cast(backing_store)->is_the_hole(index)
1060 ? index
1061 : kMaxUInt32;
1062 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001063 uint32_t length = Subclass::GetMaxIndex(holder, backing_store);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001064 return index < length ? index : kMaxUInt32;
1065 }
1066 }
1067
1068 uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
1069 uint32_t index) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001070 return Subclass::GetEntryForIndexImpl(holder, backing_store, index,
1071 ALL_PROPERTIES);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 }
1073
1074 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1075 uint32_t entry) {
1076 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1077 }
1078
Ben Murdoch097c5b22016-05-18 11:27:45 +01001079 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1080 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1081 }
1082
1083 PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001084 return Subclass::GetDetailsImpl(holder, entry);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001085 }
1086
1087 private:
1088 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1089};
1090
1091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001092class DictionaryElementsAccessor
1093 : public ElementsAccessorBase<DictionaryElementsAccessor,
1094 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1095 public:
1096 explicit DictionaryElementsAccessor(const char* name)
1097 : ElementsAccessorBase<DictionaryElementsAccessor,
1098 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1099
Ben Murdoch61f157c2016-09-16 13:49:30 +01001100 static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
1101 // We cannot properly estimate this for dictionaries.
1102 UNREACHABLE();
1103 }
1104
1105 static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
1106 FixedArrayBase* backing_store) {
1107 SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1108 return dict->NumberOfElements();
Ben Murdochda12d292016-06-02 14:46:10 +01001109 }
1110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1112 uint32_t length,
1113 Handle<FixedArrayBase> backing_store) {
1114 Handle<SeededNumberDictionary> dict =
1115 Handle<SeededNumberDictionary>::cast(backing_store);
1116 int capacity = dict->Capacity();
1117 uint32_t old_length = 0;
1118 CHECK(array->length()->ToArrayLength(&old_length));
1119 if (length < old_length) {
1120 if (dict->requires_slow_elements()) {
1121 // Find last non-deletable element in range of elements to be
1122 // deleted and adjust range accordingly.
1123 for (int entry = 0; entry < capacity; entry++) {
1124 DisallowHeapAllocation no_gc;
1125 Object* index = dict->KeyAt(entry);
1126 if (index->IsNumber()) {
1127 uint32_t number = static_cast<uint32_t>(index->Number());
1128 if (length <= number && number < old_length) {
1129 PropertyDetails details = dict->DetailsAt(entry);
1130 if (!details.IsConfigurable()) length = number + 1;
1131 }
1132 }
1133 }
1134 }
1135
1136 if (length == 0) {
1137 // Flush the backing store.
1138 JSObject::ResetElements(array);
1139 } else {
1140 DisallowHeapAllocation no_gc;
1141 // Remove elements that should be deleted.
1142 int removed_entries = 0;
1143 Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1144 for (int entry = 0; entry < capacity; entry++) {
1145 Object* index = dict->KeyAt(entry);
1146 if (index->IsNumber()) {
1147 uint32_t number = static_cast<uint32_t>(index->Number());
1148 if (length <= number && number < old_length) {
1149 dict->SetEntry(entry, the_hole_value, the_hole_value);
1150 removed_entries++;
1151 }
1152 }
1153 }
1154
1155 // Update the number of elements.
1156 dict->ElementsRemoved(removed_entries);
1157 }
1158 }
1159
1160 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1161 array->set_length(*length_obj);
1162 }
1163
1164 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1165 FixedArrayBase* to, ElementsKind from_kind,
1166 uint32_t to_start, int packed_size,
1167 int copy_size) {
1168 UNREACHABLE();
1169 }
1170
1171
1172 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1173 // TODO(verwaest): Remove reliance on index in Shrink.
1174 Handle<SeededNumberDictionary> dict(
1175 SeededNumberDictionary::cast(obj->elements()));
1176 uint32_t index = GetIndexForEntryImpl(*dict, entry);
1177 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1178 USE(result);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001179 DCHECK(result->IsTrue(dict->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 Handle<FixedArray> new_elements =
1181 SeededNumberDictionary::Shrink(dict, index);
1182 obj->set_elements(*new_elements);
1183 }
1184
Ben Murdoch097c5b22016-05-18 11:27:45 +01001185 static bool HasAccessorsImpl(JSObject* holder,
1186 FixedArrayBase* backing_store) {
Ben Murdochda12d292016-06-02 14:46:10 +01001187 DisallowHeapAllocation no_gc;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001188 SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1189 if (!dict->requires_slow_elements()) return false;
1190 int capacity = dict->Capacity();
Ben Murdoch61f157c2016-09-16 13:49:30 +01001191 Isolate* isolate = dict->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001192 for (int i = 0; i < capacity; i++) {
1193 Object* key = dict->KeyAt(i);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001194 if (!dict->IsKey(isolate, key)) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001195 DCHECK(!dict->IsDeleted(i));
1196 PropertyDetails details = dict->DetailsAt(i);
1197 if (details.type() == ACCESSOR_CONSTANT) return true;
1198 }
1199 return false;
1200 }
1201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1203 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1204 return backing_store->ValueAt(entry);
1205 }
1206
Ben Murdoch097c5b22016-05-18 11:27:45 +01001207 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1208 return GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209 }
1210
Ben Murdoch097c5b22016-05-18 11:27:45 +01001211 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1212 return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
1213 }
1214
1215 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216 Object* value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001217 SetImpl(holder->elements(), entry, value);
1218 }
1219
1220 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1221 Object* value) {
1222 SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 }
1224
1225 static void ReconfigureImpl(Handle<JSObject> object,
1226 Handle<FixedArrayBase> store, uint32_t entry,
1227 Handle<Object> value,
1228 PropertyAttributes attributes) {
1229 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1230 if (attributes != NONE) object->RequireSlowElements(dictionary);
1231 dictionary->ValueAtPut(entry, *value);
1232 PropertyDetails details = dictionary->DetailsAt(entry);
1233 details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1234 PropertyCellType::kNoCell);
1235 dictionary->DetailsAtPut(entry, details);
1236 }
1237
1238 static void AddImpl(Handle<JSObject> object, uint32_t index,
1239 Handle<Object> value, PropertyAttributes attributes,
1240 uint32_t new_capacity) {
1241 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1242 Handle<SeededNumberDictionary> dictionary =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001243 object->HasFastElements() || object->HasFastStringWrapperElements()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001244 ? JSObject::NormalizeElements(object)
1245 : handle(SeededNumberDictionary::cast(object->elements()));
1246 Handle<SeededNumberDictionary> new_dictionary =
1247 SeededNumberDictionary::AddNumberEntry(
1248 dictionary, index, value, details,
1249 object->map()->is_prototype_map());
1250 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1251 if (dictionary.is_identical_to(new_dictionary)) return;
1252 object->set_elements(*new_dictionary);
1253 }
1254
1255 static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1256 DisallowHeapAllocation no_gc;
1257 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1258 Object* index = dict->KeyAt(entry);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001259 return !index->IsTheHole(dict->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 }
1261
1262 static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1263 DisallowHeapAllocation no_gc;
1264 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1265 uint32_t result = 0;
1266 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1267 return result;
1268 }
1269
1270 static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1271 uint32_t index, PropertyFilter filter) {
1272 DisallowHeapAllocation no_gc;
1273 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1274 int entry = dictionary->FindEntry(index);
1275 if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1276 if (filter != ALL_PROPERTIES) {
1277 PropertyDetails details = dictionary->DetailsAt(entry);
1278 PropertyAttributes attr = details.attributes();
1279 if ((attr & filter) != 0) return kMaxUInt32;
1280 }
1281 return static_cast<uint32_t>(entry);
1282 }
1283
Ben Murdoch097c5b22016-05-18 11:27:45 +01001284 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1285 return GetDetailsImpl(holder->elements(), entry);
1286 }
1287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1289 uint32_t entry) {
1290 return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1291 }
1292
Ben Murdochda12d292016-06-02 14:46:10 +01001293 static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
1294 int entry, Object* raw_key, PropertyFilter filter) {
1295 DCHECK(!dictionary->IsDeleted(entry));
1296 DCHECK(raw_key->IsNumber());
1297 DCHECK_LE(raw_key->Number(), kMaxUInt32);
1298 PropertyDetails details = dictionary->DetailsAt(entry);
1299 PropertyAttributes attr = details.attributes();
1300 if ((attr & filter) != 0) return kMaxUInt32;
1301 return static_cast<uint32_t>(raw_key->Number());
1302 }
1303
Ben Murdoch61f157c2016-09-16 13:49:30 +01001304 static uint32_t GetKeyForEntryImpl(Isolate* isolate,
1305 Handle<SeededNumberDictionary> dictionary,
Ben Murdochda12d292016-06-02 14:46:10 +01001306 int entry, PropertyFilter filter) {
1307 DisallowHeapAllocation no_gc;
1308 Object* raw_key = dictionary->KeyAt(entry);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001309 if (!dictionary->IsKey(isolate, raw_key)) return kMaxUInt32;
Ben Murdochda12d292016-06-02 14:46:10 +01001310 return FilterKey(dictionary, entry, raw_key, filter);
1311 }
1312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 static void CollectElementIndicesImpl(Handle<JSObject> object,
1314 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01001315 KeyAccumulator* keys) {
1316 if (keys->filter() & SKIP_STRINGS) return;
Ben Murdochda12d292016-06-02 14:46:10 +01001317 Isolate* isolate = keys->isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001318 Handle<SeededNumberDictionary> dictionary =
1319 Handle<SeededNumberDictionary>::cast(backing_store);
1320 int capacity = dictionary->Capacity();
Ben Murdoch61f157c2016-09-16 13:49:30 +01001321 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
1322 GetMaxNumberOfEntries(*object, *backing_store));
1323 int insertion_index = 0;
Ben Murdochc5610432016-08-08 18:44:38 +01001324 PropertyFilter filter = keys->filter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325 for (int i = 0; i < capacity; i++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001326 uint32_t key = GetKeyForEntryImpl(isolate, dictionary, i, filter);
Ben Murdochda12d292016-06-02 14:46:10 +01001327 if (key == kMaxUInt32) continue;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001328 Handle<Object> key_handle = isolate->factory()->NewNumberFromUint(key);
1329 elements->set(insertion_index, *key_handle);
1330 insertion_index++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001331 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001332 SortIndices(elements, insertion_index);
1333 for (int i = 0; i < insertion_index; i++) {
1334 keys->AddKey(elements->get(i));
1335 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001337
Ben Murdochda12d292016-06-02 14:46:10 +01001338 static Handle<FixedArray> DirectCollectElementIndicesImpl(
1339 Isolate* isolate, Handle<JSObject> object,
1340 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1341 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1342 uint32_t insertion_index = 0) {
1343 if (filter & SKIP_STRINGS) return list;
1344 if (filter & ONLY_ALL_CAN_READ) return list;
1345
Ben Murdochda12d292016-06-02 14:46:10 +01001346 Handle<SeededNumberDictionary> dictionary =
1347 Handle<SeededNumberDictionary>::cast(backing_store);
1348 uint32_t capacity = dictionary->Capacity();
1349 for (uint32_t i = 0; i < capacity; i++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001350 uint32_t key = GetKeyForEntryImpl(isolate, dictionary, i, filter);
Ben Murdochda12d292016-06-02 14:46:10 +01001351 if (key == kMaxUInt32) continue;
1352 Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
1353 list->set(insertion_index, *index);
1354 insertion_index++;
1355 }
1356 *nof_indices = insertion_index;
1357 return list;
1358 }
1359
Ben Murdoch097c5b22016-05-18 11:27:45 +01001360 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1361 KeyAccumulator* accumulator,
1362 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01001363 Isolate* isolate = accumulator->isolate();
1364 Handle<Object> undefined = isolate->factory()->undefined_value();
1365 Handle<Object> the_hole = isolate->factory()->the_hole_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001366 SeededNumberDictionary* dictionary =
1367 SeededNumberDictionary::cast(receiver->elements());
1368 int capacity = dictionary->Capacity();
1369 for (int i = 0; i < capacity; i++) {
1370 Object* k = dictionary->KeyAt(i);
Ben Murdochda12d292016-06-02 14:46:10 +01001371 if (k == *undefined) continue;
1372 if (k == *the_hole) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001373 if (dictionary->IsDeleted(i)) continue;
1374 Object* value = dictionary->ValueAt(i);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001375 DCHECK(!value->IsTheHole(isolate));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001376 DCHECK(!value->IsAccessorPair());
1377 DCHECK(!value->IsAccessorInfo());
1378 accumulator->AddKey(value, convert);
1379 }
1380 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381};
1382
1383
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001384// Super class for all fast element arrays.
Ben Murdochc5610432016-08-08 18:44:38 +01001385template <typename Subclass, typename KindTraits>
1386class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001387 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388 explicit FastElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001389 : ElementsAccessorBase<Subclass, KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001390
1391 typedef typename KindTraits::BackingStore BackingStore;
1392
Ben Murdochda12d292016-06-02 14:46:10 +01001393 static Handle<SeededNumberDictionary> NormalizeImpl(
1394 Handle<JSObject> object, Handle<FixedArrayBase> store) {
1395 Isolate* isolate = store->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001396 ElementsKind kind = Subclass::kind();
Ben Murdochda12d292016-06-02 14:46:10 +01001397
1398 // Ensure that notifications fire if the array or object prototypes are
1399 // normalizing.
1400 if (IsFastSmiOrObjectElementsKind(kind)) {
1401 isolate->UpdateArrayProtectorOnNormalizeElements(object);
1402 }
1403
1404 int capacity = object->GetFastElementsUsage();
1405 Handle<SeededNumberDictionary> dictionary =
1406 SeededNumberDictionary::New(isolate, capacity);
1407
1408 PropertyDetails details = PropertyDetails::Empty();
1409 bool used_as_prototype = object->map()->is_prototype_map();
1410 int j = 0;
1411 for (int i = 0; j < capacity; i++) {
1412 if (IsHoleyElementsKind(kind)) {
1413 if (BackingStore::cast(*store)->is_the_hole(i)) continue;
1414 }
Ben Murdochc5610432016-08-08 18:44:38 +01001415 Handle<Object> value = Subclass::GetImpl(*store, i);
Ben Murdochda12d292016-06-02 14:46:10 +01001416 dictionary = SeededNumberDictionary::AddNumberEntry(
1417 dictionary, i, value, details, used_as_prototype);
1418 j++;
1419 }
1420 return dictionary;
1421 }
1422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 static void DeleteAtEnd(Handle<JSObject> obj,
1424 Handle<BackingStore> backing_store, uint32_t entry) {
1425 uint32_t length = static_cast<uint32_t>(backing_store->length());
1426 Heap* heap = obj->GetHeap();
1427 for (; entry > 0; entry--) {
1428 if (!backing_store->is_the_hole(entry - 1)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001429 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001430 if (entry == 0) {
1431 FixedArray* empty = heap->empty_fixed_array();
Ben Murdochc5610432016-08-08 18:44:38 +01001432 // Dynamically ask for the elements kind here since we manually redirect
1433 // the operations for argument backing stores.
1434 if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 FixedArray::cast(obj->elements())->set(1, empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001437 obj->set_elements(empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001438 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001440 }
1441
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001442 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1443 length - entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001444 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1447 Handle<FixedArrayBase> store) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001448 DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
1449 obj->HasFastArgumentsElements() ||
1450 obj->HasFastStringWrapperElements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001451 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1452 if (!obj->IsJSArray() &&
1453 entry == static_cast<uint32_t>(store->length()) - 1) {
1454 DeleteAtEnd(obj, backing_store, entry);
1455 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457
1458 backing_store->set_the_hole(entry);
1459
1460 // TODO(verwaest): Move this out of elements.cc.
1461 // If an old space backing store is larger than a certain size and
1462 // has too few used values, normalize it.
1463 // To avoid doing the check on every delete we require at least
1464 // one adjacent hole to the value being deleted.
1465 const int kMinLengthForSparsenessCheck = 64;
1466 if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1467 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1468 uint32_t length = 0;
1469 if (obj->IsJSArray()) {
1470 JSArray::cast(*obj)->length()->ToArrayLength(&length);
1471 } else {
1472 length = static_cast<uint32_t>(store->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1475 (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1476 if (!obj->IsJSArray()) {
1477 uint32_t i;
1478 for (i = entry + 1; i < length; i++) {
1479 if (!backing_store->is_the_hole(i)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 if (i == length) {
1482 DeleteAtEnd(obj, backing_store, entry);
1483 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 }
1485 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 int num_used = 0;
1487 for (int i = 0; i < backing_store->length(); ++i) {
1488 if (!backing_store->is_the_hole(i)) {
1489 ++num_used;
1490 // Bail out if a number dictionary wouldn't be able to save at least
1491 // 75% space.
1492 if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1493 SeededNumberDictionary::kEntrySize >
1494 backing_store->length()) {
1495 return;
1496 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001497 }
1498 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 JSObject::NormalizeElements(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001500 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001501 }
1502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503 static void ReconfigureImpl(Handle<JSObject> object,
1504 Handle<FixedArrayBase> store, uint32_t entry,
1505 Handle<Object> value,
1506 PropertyAttributes attributes) {
1507 Handle<SeededNumberDictionary> dictionary =
1508 JSObject::NormalizeElements(object);
1509 entry = dictionary->FindEntry(entry);
1510 DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1511 value, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 }
1513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 static void AddImpl(Handle<JSObject> object, uint32_t index,
1515 Handle<Object> value, PropertyAttributes attributes,
1516 uint32_t new_capacity) {
1517 DCHECK_EQ(NONE, attributes);
1518 ElementsKind from_kind = object->GetElementsKind();
Ben Murdochc5610432016-08-08 18:44:38 +01001519 ElementsKind to_kind = Subclass::kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520 if (IsDictionaryElementsKind(from_kind) ||
1521 IsFastDoubleElementsKind(from_kind) !=
1522 IsFastDoubleElementsKind(to_kind) ||
Ben Murdochc5610432016-08-08 18:44:38 +01001523 Subclass::GetCapacityImpl(*object, object->elements()) !=
1524 new_capacity) {
1525 Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001527 if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001528 JSObject::TransitionElementsKind(object, to_kind);
1529 }
1530 if (IsFastSmiOrObjectElementsKind(from_kind)) {
1531 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1532 JSObject::EnsureWritableFastElements(object);
1533 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001534 }
Ben Murdochc5610432016-08-08 18:44:38 +01001535 Subclass::SetImpl(object, index, *value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 }
1537
1538 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1539 ElementsKind kind = KindTraits::Kind;
1540 if (IsFastPackedElementsKind(kind)) {
1541 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1542 }
1543 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1544 JSObject::EnsureWritableFastElements(obj);
1545 }
1546 DeleteCommon(obj, entry, handle(obj->elements()));
1547 }
1548
1549 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1550 return !BackingStore::cast(backing_store)->is_the_hole(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001551 }
1552
Ben Murdoch097c5b22016-05-18 11:27:45 +01001553 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1554 KeyAccumulator* accumulator,
1555 AddKeyConversion convert) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001556 Handle<FixedArrayBase> elements(receiver->elements(),
Ben Murdoch61f157c2016-09-16 13:49:30 +01001557 accumulator->isolate());
1558 uint32_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001559 for (uint32_t i = 0; i < length; i++) {
1560 if (IsFastPackedElementsKind(KindTraits::Kind) ||
1561 HasEntryImpl(*elements, i)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001562 accumulator->AddKey(Subclass::GetImpl(*elements, i), convert);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001563 }
1564 }
1565 }
1566
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 static void ValidateContents(Handle<JSObject> holder, int length) {
1568#if DEBUG
1569 Isolate* isolate = holder->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001570 Heap* heap = isolate->heap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 HandleScope scope(isolate);
1572 Handle<FixedArrayBase> elements(holder->elements(), isolate);
1573 Map* map = elements->map();
Ben Murdochc5610432016-08-08 18:44:38 +01001574 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1575 DCHECK_NE(map, heap->fixed_double_array_map());
1576 } else if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1577 DCHECK_NE(map, heap->fixed_cow_array_map());
1578 if (map == heap->fixed_array_map()) DCHECK_EQ(0, length);
1579 } else {
1580 UNREACHABLE();
1581 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001582 if (length == 0) return; // nothing to do!
Ben Murdochc5610432016-08-08 18:44:38 +01001583#if ENABLE_SLOW_DCHECKS
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001585 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1586 if (IsFastSmiElementsKind(KindTraits::Kind)) {
1587 for (int i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001588 DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001589 (IsFastHoleyElementsKind(KindTraits::Kind) &&
1590 backing_store->is_the_hole(i)));
1591 }
Ben Murdochc5610432016-08-08 18:44:38 +01001592 } else if (KindTraits::Kind == FAST_ELEMENTS ||
1593 KindTraits::Kind == FAST_DOUBLE_ELEMENTS) {
1594 for (int i = 0; i < length; i++) {
1595 DCHECK(!backing_store->is_the_hole(i));
1596 }
1597 } else {
1598 DCHECK(IsFastHoleyElementsKind(KindTraits::Kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001599 }
1600#endif
Ben Murdochc5610432016-08-08 18:44:38 +01001601#endif
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001602 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001603
Ben Murdochda12d292016-06-02 14:46:10 +01001604 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
Ben Murdochc5610432016-08-08 18:44:38 +01001605 return Subclass::RemoveElement(receiver, AT_END);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607
Ben Murdochda12d292016-06-02 14:46:10 +01001608 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
Ben Murdochc5610432016-08-08 18:44:38 +01001609 return Subclass::RemoveElement(receiver, AT_START);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610 }
1611
1612 static uint32_t PushImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001613 Arguments* args, uint32_t push_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001614 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdochc5610432016-08-08 18:44:38 +01001615 return Subclass::AddArguments(receiver, backing_store, args, push_size,
1616 AT_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001617 }
1618
1619 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001620 Arguments* args, uint32_t unshift_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001621 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdochc5610432016-08-08 18:44:38 +01001622 return Subclass::AddArguments(receiver, backing_store, args, unshift_size,
1623 AT_START);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001624 }
1625
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001627 uint32_t start, uint32_t end) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001629 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1630 int result_len = end < start ? 0u : end - start;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001631 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1632 KindTraits::Kind, result_len, result_len);
1633 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +01001634 Subclass::CopyElementsImpl(*backing_store, start, result_array->elements(),
1635 KindTraits::Kind, 0, kPackedSizeNotKnown,
1636 result_len);
1637 Subclass::TryTransitionResultArrayToPacked(result_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001638 return result_array;
1639 }
1640
1641 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001642 uint32_t start, uint32_t delete_count,
1643 Arguments* args, uint32_t add_count) {
1644 Isolate* isolate = receiver->GetIsolate();
1645 Heap* heap = isolate->heap();
1646 uint32_t length = Smi::cast(receiver->length())->value();
1647 uint32_t new_length = length - delete_count + add_count;
1648
Ben Murdochda12d292016-06-02 14:46:10 +01001649 ElementsKind kind = KindTraits::Kind;
1650 if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
1651 IsFastSmiOrObjectElementsKind(kind)) {
1652 HandleScope scope(isolate);
1653 JSObject::EnsureWritableFastElements(receiver);
1654 }
1655
1656 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1657
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001658 if (new_length == 0) {
1659 receiver->set_elements(heap->empty_fixed_array());
1660 receiver->set_length(Smi::FromInt(0));
1661 return isolate->factory()->NewJSArrayWithElements(
1662 backing_store, KindTraits::Kind, delete_count);
1663 }
1664
1665 // Construct the result array which holds the deleted elements.
1666 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1667 KindTraits::Kind, delete_count, delete_count);
1668 if (delete_count > 0) {
1669 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +01001670 Subclass::CopyElementsImpl(*backing_store, start,
1671 deleted_elements->elements(), KindTraits::Kind,
1672 0, kPackedSizeNotKnown, delete_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001673 }
1674
1675 // Delete and move elements to make space for add_count new elements.
1676 if (add_count < delete_count) {
Ben Murdochc5610432016-08-08 18:44:38 +01001677 Subclass::SpliceShrinkStep(isolate, receiver, backing_store, start,
1678 delete_count, add_count, length, new_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001679 } else if (add_count > delete_count) {
Ben Murdochc5610432016-08-08 18:44:38 +01001680 backing_store =
1681 Subclass::SpliceGrowStep(isolate, receiver, backing_store, start,
1682 delete_count, add_count, length, new_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001683 }
1684
1685 // Copy over the arguments.
Ben Murdochc5610432016-08-08 18:44:38 +01001686 Subclass::CopyArguments(args, backing_store, add_count, 3, start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001687
1688 receiver->set_length(Smi::FromInt(new_length));
Ben Murdochc5610432016-08-08 18:44:38 +01001689 Subclass::TryTransitionResultArrayToPacked(deleted_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001690 return deleted_elements;
1691 }
1692
Ben Murdochda12d292016-06-02 14:46:10 +01001693 static Maybe<bool> CollectValuesOrEntriesImpl(
1694 Isolate* isolate, Handle<JSObject> object,
1695 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
1696 PropertyFilter filter) {
1697 int count = 0;
1698 uint32_t length = object->elements()->length();
1699 for (uint32_t index = 0; index < length; ++index) {
1700 if (!HasEntryImpl(object->elements(), index)) continue;
Ben Murdochc5610432016-08-08 18:44:38 +01001701 Handle<Object> value = Subclass::GetImpl(object->elements(), index);
Ben Murdochda12d292016-06-02 14:46:10 +01001702 if (get_entries) {
1703 value = MakeEntryPair(isolate, index, value);
1704 }
1705 values_or_entries->set(count++, *value);
1706 }
1707 *nof_items = count;
1708 return Just(true);
1709 }
1710
1711 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1712 Handle<FixedArrayBase> backing_store, int dst_index,
1713 int src_index, int len, int hole_start,
1714 int hole_end) {
1715 Heap* heap = isolate->heap();
1716 Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
1717 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1718 // Update all the copies of this backing_store handle.
1719 *dst_elms.location() =
1720 BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1721 receiver->set_elements(*dst_elms);
1722 // Adjust the hole offset as the array has been shrunk.
1723 hole_end -= src_index;
1724 DCHECK_LE(hole_start, backing_store->length());
1725 DCHECK_LE(hole_end, backing_store->length());
1726 } else if (len != 0) {
1727 if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1728 MemMove(dst_elms->data_start() + dst_index,
1729 dst_elms->data_start() + src_index, len * kDoubleSize);
1730 } else {
1731 DisallowHeapAllocation no_gc;
1732 heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
1733 len);
1734 }
1735 }
1736 if (hole_start != hole_end) {
1737 dst_elms->FillWithHoles(hole_start, hole_end);
1738 }
1739 }
1740
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001741 private:
1742 // SpliceShrinkStep might modify the backing_store.
1743 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1744 Handle<FixedArrayBase> backing_store,
1745 uint32_t start, uint32_t delete_count,
1746 uint32_t add_count, uint32_t len,
1747 uint32_t new_length) {
1748 const int move_left_count = len - delete_count - start;
1749 const int move_left_dst_index = start + add_count;
Ben Murdochc5610432016-08-08 18:44:38 +01001750 Subclass::MoveElements(isolate, receiver, backing_store,
1751 move_left_dst_index, start + delete_count,
1752 move_left_count, new_length, len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001753 }
1754
1755 // SpliceGrowStep might modify the backing_store.
1756 static Handle<FixedArrayBase> SpliceGrowStep(
1757 Isolate* isolate, Handle<JSArray> receiver,
1758 Handle<FixedArrayBase> backing_store, uint32_t start,
1759 uint32_t delete_count, uint32_t add_count, uint32_t length,
1760 uint32_t new_length) {
1761 // Check we do not overflow the new_length.
1762 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1763 // Check if backing_store is big enough.
1764 if (new_length <= static_cast<uint32_t>(backing_store->length())) {
Ben Murdochc5610432016-08-08 18:44:38 +01001765 Subclass::MoveElements(isolate, receiver, backing_store,
1766 start + add_count, start + delete_count,
1767 (length - delete_count - start), 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001768 // MoveElements updates the backing_store in-place.
1769 return backing_store;
1770 }
1771 // New backing storage is needed.
1772 int capacity = JSObject::NewElementsCapacity(new_length);
1773 // Partially copy all elements up to start.
Ben Murdochc5610432016-08-08 18:44:38 +01001774 Handle<FixedArrayBase> new_elms = Subclass::ConvertElementsWithCapacity(
1775 receiver, backing_store, KindTraits::Kind, capacity, start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001776 // Copy the trailing elements after start + delete_count
Ben Murdochc5610432016-08-08 18:44:38 +01001777 Subclass::CopyElementsImpl(*backing_store, start + delete_count, *new_elms,
1778 KindTraits::Kind, start + add_count,
1779 kPackedSizeNotKnown,
1780 ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001781 receiver->set_elements(*new_elms);
1782 return new_elms;
1783 }
1784
1785 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001786 Where remove_position) {
1787 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001788 ElementsKind kind = KindTraits::Kind;
1789 if (IsFastSmiOrObjectElementsKind(kind)) {
1790 HandleScope scope(isolate);
1791 JSObject::EnsureWritableFastElements(receiver);
1792 }
1793 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001794 uint32_t length =
1795 static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1796 DCHECK(length > 0);
1797 int new_length = length - 1;
1798 int remove_index = remove_position == AT_START ? 0 : new_length;
Ben Murdochc5610432016-08-08 18:44:38 +01001799 Handle<Object> result = Subclass::GetImpl(*backing_store, remove_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001800 if (remove_position == AT_START) {
Ben Murdochc5610432016-08-08 18:44:38 +01001801 Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
1802 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001803 }
Ben Murdochc5610432016-08-08 18:44:38 +01001804 Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001805
Ben Murdoch61f157c2016-09-16 13:49:30 +01001806 if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001807 return isolate->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001808 }
1809 return result;
1810 }
1811
1812 static uint32_t AddArguments(Handle<JSArray> receiver,
1813 Handle<FixedArrayBase> backing_store,
1814 Arguments* args, uint32_t add_size,
Ben Murdochc5610432016-08-08 18:44:38 +01001815 Where add_position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001816 uint32_t length = Smi::cast(receiver->length())->value();
Ben Murdochda12d292016-06-02 14:46:10 +01001817 DCHECK(0 < add_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 uint32_t elms_len = backing_store->length();
1819 // Check we do not overflow the new_length.
1820 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1821 uint32_t new_length = length + add_size;
1822
1823 if (new_length > elms_len) {
1824 // New backing storage is needed.
1825 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1826 // If we add arguments to the start we have to shift the existing objects.
Ben Murdochc5610432016-08-08 18:44:38 +01001827 int copy_dst_index = add_position == AT_START ? add_size : 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828 // Copy over all objects to a new backing_store.
Ben Murdochc5610432016-08-08 18:44:38 +01001829 backing_store = Subclass::ConvertElementsWithCapacity(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001830 receiver, backing_store, KindTraits::Kind, capacity, 0,
1831 copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1832 receiver->set_elements(*backing_store);
Ben Murdochc5610432016-08-08 18:44:38 +01001833 } else if (add_position == AT_START) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001834 // If the backing store has enough capacity and we add elements to the
1835 // start we have to shift the existing objects.
1836 Isolate* isolate = receiver->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001837 Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
1838 length, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 }
1840
Ben Murdochc5610432016-08-08 18:44:38 +01001841 int insertion_index = add_position == AT_START ? 0 : length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001842 // Copy the arguments to the start.
Ben Murdochc5610432016-08-08 18:44:38 +01001843 Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 // Set the length.
1845 receiver->set_length(Smi::FromInt(new_length));
1846 return new_length;
1847 }
1848
1849 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1850 uint32_t copy_size, uint32_t src_index,
1851 uint32_t dst_index) {
1852 // Add the provided values.
1853 DisallowHeapAllocation no_gc;
1854 FixedArrayBase* raw_backing_store = *dst_store;
1855 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1856 for (uint32_t i = 0; i < copy_size; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01001857 Object* argument = (*args)[src_index + i];
Ben Murdoch61f157c2016-09-16 13:49:30 +01001858 DCHECK(!argument->IsTheHole(raw_backing_store->GetIsolate()));
Ben Murdochc5610432016-08-08 18:44:38 +01001859 Subclass::SetImpl(raw_backing_store, dst_index + i, argument, mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001860 }
1861 }
1862};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863
Ben Murdochc5610432016-08-08 18:44:38 +01001864template <typename Subclass, typename KindTraits>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001865class FastSmiOrObjectElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01001866 : public FastElementsAccessor<Subclass, KindTraits> {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 public:
1868 explicit FastSmiOrObjectElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001869 : FastElementsAccessor<Subclass, KindTraits>(name) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001870
Ben Murdoch097c5b22016-05-18 11:27:45 +01001871 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1872 Object* value) {
1873 SetImpl(holder->elements(), entry, value);
1874 }
1875
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1877 Object* value) {
1878 FixedArray::cast(backing_store)->set(entry, value);
1879 }
1880
1881 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1882 Object* value, WriteBarrierMode mode) {
1883 FixedArray::cast(backing_store)->set(entry, value, mode);
1884 }
1885
1886 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +01001887 uint32_t index = Subclass::GetIndexForEntryImpl(backing_store, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001888 return backing_store->get(index);
1889 }
1890
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001891
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001892 // NOTE: this method violates the handlified function signature convention:
1893 // raw pointer parameters in the function that allocates.
1894 // See ElementsAccessor::CopyElements() for details.
1895 // This method could actually allocate if copying from double elements to
1896 // object elements.
1897 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1898 FixedArrayBase* to, ElementsKind from_kind,
1899 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001901 DisallowHeapAllocation no_gc;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902 ElementsKind to_kind = KindTraits::Kind;
1903 switch (from_kind) {
1904 case FAST_SMI_ELEMENTS:
1905 case FAST_HOLEY_SMI_ELEMENTS:
1906 case FAST_ELEMENTS:
1907 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001908 CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 to_start, copy_size);
1910 break;
1911 case FAST_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001912 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1913 AllowHeapAllocation allow_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001914 DCHECK(IsFastObjectElementsKind(to_kind));
1915 CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001917 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001919 CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1920 copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001922 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1923 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdochc5610432016-08-08 18:44:38 +01001924 case FAST_STRING_WRAPPER_ELEMENTS:
1925 case SLOW_STRING_WRAPPER_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001926#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001927 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1928#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01001929 // This function is currently only used for JSArrays with non-zero
1930 // length.
1931 UNREACHABLE();
1932 break;
1933 case NO_ELEMENTS:
1934 break; // Nothing to do.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935 }
1936 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937};
1938
1939
1940class FastPackedSmiElementsAccessor
1941 : public FastSmiOrObjectElementsAccessor<
1942 FastPackedSmiElementsAccessor,
1943 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1944 public:
1945 explicit FastPackedSmiElementsAccessor(const char* name)
1946 : FastSmiOrObjectElementsAccessor<
1947 FastPackedSmiElementsAccessor,
1948 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1949};
1950
1951
1952class FastHoleySmiElementsAccessor
1953 : public FastSmiOrObjectElementsAccessor<
1954 FastHoleySmiElementsAccessor,
1955 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1956 public:
1957 explicit FastHoleySmiElementsAccessor(const char* name)
1958 : FastSmiOrObjectElementsAccessor<
1959 FastHoleySmiElementsAccessor,
1960 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1961};
1962
1963
1964class FastPackedObjectElementsAccessor
1965 : public FastSmiOrObjectElementsAccessor<
1966 FastPackedObjectElementsAccessor,
1967 ElementsKindTraits<FAST_ELEMENTS> > {
1968 public:
1969 explicit FastPackedObjectElementsAccessor(const char* name)
1970 : FastSmiOrObjectElementsAccessor<
1971 FastPackedObjectElementsAccessor,
1972 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1973};
1974
1975
1976class FastHoleyObjectElementsAccessor
1977 : public FastSmiOrObjectElementsAccessor<
1978 FastHoleyObjectElementsAccessor,
1979 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1980 public:
1981 explicit FastHoleyObjectElementsAccessor(const char* name)
1982 : FastSmiOrObjectElementsAccessor<
1983 FastHoleyObjectElementsAccessor,
1984 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1985};
1986
Ben Murdochc5610432016-08-08 18:44:38 +01001987template <typename Subclass, typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001988class FastDoubleElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01001989 : public FastElementsAccessor<Subclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001990 public:
1991 explicit FastDoubleElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001992 : FastElementsAccessor<Subclass, KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001993
Ben Murdoch097c5b22016-05-18 11:27:45 +01001994 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1995 return GetImpl(holder->elements(), entry);
1996 }
1997
1998 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1999 Isolate* isolate = backing_store->GetIsolate();
2000 return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
2001 isolate);
2002 }
2003
2004 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2005 Object* value) {
2006 SetImpl(holder->elements(), entry, value);
2007 }
2008
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002009 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2010 Object* value) {
2011 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002012 }
2013
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002014 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2015 Object* value, WriteBarrierMode mode) {
2016 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2017 }
2018
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002019 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2020 FixedArrayBase* to, ElementsKind from_kind,
2021 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002022 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002023 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002024 switch (from_kind) {
2025 case FAST_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002026 CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027 packed_size, copy_size);
2028 break;
2029 case FAST_HOLEY_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002030 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002032 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002033 case FAST_HOLEY_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002034 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 break;
2036 case FAST_ELEMENTS:
2037 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002038 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002039 break;
2040 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002041 CopyDictionaryToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042 copy_size);
2043 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002044 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2045 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002046 case FAST_STRING_WRAPPER_ELEMENTS:
2047 case SLOW_STRING_WRAPPER_ELEMENTS:
2048 case NO_ELEMENTS:
2049#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002050 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2051#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01002052 // This function is currently only used for JSArrays with non-zero
2053 // length.
2054 UNREACHABLE();
2055 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002056 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002057 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002058};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002059
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060
2061class FastPackedDoubleElementsAccessor
2062 : public FastDoubleElementsAccessor<
2063 FastPackedDoubleElementsAccessor,
2064 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
2065 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002066 explicit FastPackedDoubleElementsAccessor(const char* name)
2067 : FastDoubleElementsAccessor<
2068 FastPackedDoubleElementsAccessor,
2069 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
2070};
2071
2072
2073class FastHoleyDoubleElementsAccessor
2074 : public FastDoubleElementsAccessor<
2075 FastHoleyDoubleElementsAccessor,
2076 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
2077 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002078 explicit FastHoleyDoubleElementsAccessor(const char* name)
2079 : FastDoubleElementsAccessor<
2080 FastHoleyDoubleElementsAccessor,
2081 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002082};
2083
2084
2085// Super class for all external element arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002086template<ElementsKind Kind>
2087class TypedElementsAccessor
2088 : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002089 ElementsKindTraits<Kind> > {
2090 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091 explicit TypedElementsAccessor(const char* name)
2092 : ElementsAccessorBase<AccessorClass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002093 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002094
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002095 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002096 typedef TypedElementsAccessor<Kind> AccessorClass;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002097
Ben Murdoch097c5b22016-05-18 11:27:45 +01002098 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2099 Object* value) {
2100 SetImpl(holder->elements(), entry, value);
2101 }
2102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002103 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2104 Object* value) {
2105 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002106 }
2107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002108 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2109 Object* value, WriteBarrierMode mode) {
2110 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002111 }
2112
Ben Murdoch097c5b22016-05-18 11:27:45 +01002113 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2114 return GetImpl(holder->elements(), entry);
2115 }
2116
2117 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2118 return BackingStore::get(BackingStore::cast(backing_store), entry);
2119 }
2120
2121 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2122 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123 }
2124
2125 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
2126 uint32_t entry) {
2127 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
2128 }
2129
Ben Murdoch097c5b22016-05-18 11:27:45 +01002130 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
2131 Handle<FixedArrayBase> backing_store,
2132 PropertyFilter filter) {
2133 return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
2134 }
2135
2136 static bool HasAccessorsImpl(JSObject* holder,
2137 FixedArrayBase* backing_store) {
2138 return false;
2139 }
2140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002141 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2142 uint32_t length,
2143 Handle<FixedArrayBase> backing_store) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002144 // External arrays do not support changing their length.
2145 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002146 }
2147
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002148 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2149 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002150 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002152 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
2153 uint32_t entry) {
2154 return entry;
2155 }
2156
2157 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2158 FixedArrayBase* backing_store,
2159 uint32_t index, PropertyFilter filter) {
2160 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
2161 ? index
2162 : kMaxUInt32;
2163 }
2164
2165 static uint32_t GetCapacityImpl(JSObject* holder,
2166 FixedArrayBase* backing_store) {
2167 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
2168 if (view->WasNeutered()) return 0;
2169 return backing_store->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002170 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002171
2172 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2173 KeyAccumulator* accumulator,
2174 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01002175 Handle<FixedArrayBase> elements(receiver->elements());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002176 uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
2177 for (uint32_t i = 0; i < length; i++) {
2178 Handle<Object> value = AccessorClass::GetImpl(*elements, i);
2179 accumulator->AddKey(value, convert);
2180 }
2181 }
Ben Murdochda12d292016-06-02 14:46:10 +01002182
2183 static Maybe<bool> CollectValuesOrEntriesImpl(
2184 Isolate* isolate, Handle<JSObject> object,
2185 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2186 PropertyFilter filter) {
2187 int count = 0;
2188 if ((filter & ONLY_CONFIGURABLE) == 0) {
2189 Handle<FixedArrayBase> elements(object->elements());
2190 uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements);
2191 for (uint32_t index = 0; index < length; ++index) {
2192 Handle<Object> value = AccessorClass::GetImpl(*elements, index);
2193 if (get_entries) {
2194 value = MakeEntryPair(isolate, index, value);
2195 }
2196 values_or_entries->set(count++, *value);
2197 }
2198 }
2199 *nof_items = count;
2200 return Just(true);
2201 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002202};
2203
2204
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002205
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002206#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
2207 typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
2208 Fixed##Type##ElementsAccessor;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002209
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002210TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
2211#undef FIXED_ELEMENTS_ACCESSOR
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002212
Ben Murdochc5610432016-08-08 18:44:38 +01002213template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002214class SloppyArgumentsElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01002215 : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002216 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217 explicit SloppyArgumentsElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01002218 : ElementsAccessorBase<Subclass, KindTraits>(name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002219 USE(KindTraits::Kind);
2220 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002221
Ben Murdoch097c5b22016-05-18 11:27:45 +01002222 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2223 return GetImpl(holder->elements(), entry);
2224 }
2225
2226 static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002227 Isolate* isolate = parameters->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002228 Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002229 uint32_t length = parameter_map->length() - 2;
2230 if (entry < length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002231 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002232 Object* probe = parameter_map->get(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002233 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002234 int context_entry = Smi::cast(probe)->value();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002235 DCHECK(!context->get(context_entry)->IsTheHole(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002236 return handle(context->get(context_entry), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002237 } else {
2238 // Object is not mapped, defer to the arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002239 Handle<Object> result = ArgumentsAccessor::GetImpl(
2240 FixedArray::cast(parameter_map->get(1)), entry - length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002241 // Elements of the arguments object in slow mode might be slow aliases.
2242 if (result->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002243 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002244 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002245 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002246 int context_entry = alias->aliased_context_slot();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002247 DCHECK(!context->get(context_entry)->IsTheHole(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002248 return handle(context->get(context_entry), isolate);
2249 }
2250 return result;
2251 }
2252 }
2253
2254 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2255 uint32_t capacity) {
2256 UNREACHABLE();
2257 }
2258
Ben Murdoch097c5b22016-05-18 11:27:45 +01002259 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2260 Object* value) {
2261 SetImpl(holder->elements(), entry, value);
2262 }
2263
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002264 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
2265 Object* value) {
2266 FixedArray* parameter_map = FixedArray::cast(store);
2267 uint32_t length = parameter_map->length() - 2;
2268 if (entry < length) {
2269 Object* probe = parameter_map->get(entry + 2);
2270 Context* context = Context::cast(parameter_map->get(0));
2271 int context_entry = Smi::cast(probe)->value();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002272 DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002273 context->set(context_entry, value);
2274 } else {
2275 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2276 Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
2277 if (current->IsAliasedArgumentsEntry()) {
2278 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
2279 Context* context = Context::cast(parameter_map->get(0));
2280 int context_entry = alias->aliased_context_slot();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002281 DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002282 context->set(context_entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002283 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002284 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002285 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002286 }
2287 }
2288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002289 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2290 uint32_t length,
2291 Handle<FixedArrayBase> parameter_map) {
2292 // Sloppy arguments objects are not arrays.
2293 UNREACHABLE();
2294 }
2295
2296 static uint32_t GetCapacityImpl(JSObject* holder,
2297 FixedArrayBase* backing_store) {
2298 FixedArray* parameter_map = FixedArray::cast(backing_store);
2299 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2300 return parameter_map->length() - 2 +
2301 ArgumentsAccessor::GetCapacityImpl(holder, arguments);
2302 }
2303
Ben Murdoch097c5b22016-05-18 11:27:45 +01002304 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2305 KeyAccumulator* accumulator,
2306 AddKeyConversion convert) {
2307 FixedArrayBase* elements = receiver->elements();
2308 uint32_t length = GetCapacityImpl(*receiver, elements);
2309 for (uint32_t entry = 0; entry < length; entry++) {
2310 if (!HasEntryImpl(elements, entry)) continue;
2311 Handle<Object> value = GetImpl(elements, entry);
2312 accumulator->AddKey(value, convert);
2313 }
2314 }
2315
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002316 static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
2317 FixedArray* parameter_map = FixedArray::cast(parameters);
2318 uint32_t length = parameter_map->length() - 2;
2319 if (entry < length) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002320 return !GetParameterMapArg(parameter_map, entry)
2321 ->IsTheHole(parameter_map->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002322 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002323
2324 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2325 return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002326 }
2327
Ben Murdoch097c5b22016-05-18 11:27:45 +01002328 static bool HasAccessorsImpl(JSObject* holder,
2329 FixedArrayBase* backing_store) {
2330 FixedArray* parameter_map = FixedArray::cast(backing_store);
2331 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2332 return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
2333 }
2334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002335 static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
2336 uint32_t entry) {
2337 FixedArray* parameter_map = FixedArray::cast(parameters);
2338 uint32_t length = parameter_map->length() - 2;
2339 if (entry < length) return entry;
2340
2341 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2342 return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
2343 }
2344
2345 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2346 FixedArrayBase* parameters,
2347 uint32_t index, PropertyFilter filter) {
2348 FixedArray* parameter_map = FixedArray::cast(parameters);
2349 Object* probe = GetParameterMapArg(parameter_map, index);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002350 if (!probe->IsTheHole(holder->GetIsolate())) return index;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002351
2352 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2353 uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
2354 index, filter);
Ben Murdochc5610432016-08-08 18:44:38 +01002355 if (entry == kMaxUInt32) return kMaxUInt32;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002356 return (parameter_map->length() - 2) + entry;
2357 }
2358
Ben Murdoch097c5b22016-05-18 11:27:45 +01002359 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2360 FixedArray* parameter_map = FixedArray::cast(holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002361 uint32_t length = parameter_map->length() - 2;
2362 if (entry < length) {
2363 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002364 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002365 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2366 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002367 }
2368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002369 static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2370 uint32_t length = parameter_map->length() - 2;
2371 return index < length
2372 ? parameter_map->get(index + 2)
2373 : Object::cast(parameter_map->GetHeap()->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002374 }
2375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002376 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2377 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2378 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2379 if (entry < length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002380 // TODO(kmillikin): We could check if this was the last aliased
2381 // parameter, and revert to normal elements in that case. That
2382 // would enable GC of the context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002383 parameter_map->set_the_hole(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002384 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002385 Subclass::DeleteFromArguments(obj, entry - length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002386 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387 }
Ben Murdochda12d292016-06-02 14:46:10 +01002388
2389 static void CollectElementIndicesImpl(Handle<JSObject> object,
2390 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01002391 KeyAccumulator* keys) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002392 Isolate* isolate = keys->isolate();
2393 uint32_t nof_indices = 0;
2394 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
2395 GetCapacityImpl(*object, *backing_store));
2396 DirectCollectElementIndicesImpl(isolate, object, backing_store,
2397 GetKeysConversion::kKeepNumbers,
2398 ENUMERABLE_STRINGS, indices, &nof_indices);
2399 SortIndices(indices, nof_indices);
2400 for (uint32_t i = 0; i < nof_indices; i++) {
2401 keys->AddKey(indices->get(i));
Ben Murdochda12d292016-06-02 14:46:10 +01002402 }
2403 }
2404
2405 static Handle<FixedArray> DirectCollectElementIndicesImpl(
2406 Isolate* isolate, Handle<JSObject> object,
2407 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
2408 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
2409 uint32_t insertion_index = 0) {
2410 FixedArray* parameter_map = FixedArray::cast(*backing_store);
2411 uint32_t length = parameter_map->length() - 2;
2412
2413 for (uint32_t i = 0; i < length; ++i) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002414 if (parameter_map->get(i + 2)->IsTheHole(isolate)) continue;
2415 if (convert == GetKeysConversion::kConvertToString) {
Ben Murdochda12d292016-06-02 14:46:10 +01002416 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
2417 list->set(insertion_index, *index_string);
2418 } else {
2419 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
2420 }
2421 insertion_index++;
2422 }
2423
2424 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
2425 return ArgumentsAccessor::DirectCollectElementIndicesImpl(
2426 isolate, object, store, convert, filter, list, nof_indices,
2427 insertion_index);
2428 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002429};
2430
2431
2432class SlowSloppyArgumentsElementsAccessor
2433 : public SloppyArgumentsElementsAccessor<
2434 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2435 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2436 public:
2437 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2438 : SloppyArgumentsElementsAccessor<
2439 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2440 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2441
2442 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2443 Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2444 Handle<SeededNumberDictionary> dict(
2445 SeededNumberDictionary::cast(parameter_map->get(1)));
2446 // TODO(verwaest): Remove reliance on index in Shrink.
2447 uint32_t index = GetIndexForEntryImpl(*dict, entry);
2448 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2449 USE(result);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002450 DCHECK(result->IsTrue(dict->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002451 Handle<FixedArray> new_elements =
2452 SeededNumberDictionary::Shrink(dict, index);
2453 parameter_map->set(1, *new_elements);
2454 }
2455
2456 static void AddImpl(Handle<JSObject> object, uint32_t index,
2457 Handle<Object> value, PropertyAttributes attributes,
2458 uint32_t new_capacity) {
2459 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2460 Handle<FixedArrayBase> old_elements(
2461 FixedArrayBase::cast(parameter_map->get(1)));
2462 Handle<SeededNumberDictionary> dictionary =
2463 old_elements->IsSeededNumberDictionary()
2464 ? Handle<SeededNumberDictionary>::cast(old_elements)
2465 : JSObject::NormalizeElements(object);
2466 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2467 Handle<SeededNumberDictionary> new_dictionary =
2468 SeededNumberDictionary::AddNumberEntry(
2469 dictionary, index, value, details,
2470 object->map()->is_prototype_map());
2471 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2472 if (*dictionary != *new_dictionary) {
2473 FixedArray::cast(object->elements())->set(1, *new_dictionary);
2474 }
2475 }
2476
2477 static void ReconfigureImpl(Handle<JSObject> object,
2478 Handle<FixedArrayBase> store, uint32_t entry,
2479 Handle<Object> value,
2480 PropertyAttributes attributes) {
2481 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2482 uint32_t length = parameter_map->length() - 2;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002483 Isolate* isolate = store->GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002484 if (entry < length) {
2485 Object* probe = parameter_map->get(entry + 2);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002486 DCHECK(!probe->IsTheHole(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002487 Context* context = Context::cast(parameter_map->get(0));
2488 int context_entry = Smi::cast(probe)->value();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002489 DCHECK(!context->get(context_entry)->IsTheHole(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002490 context->set(context_entry, *value);
2491
2492 // Redefining attributes of an aliased element destroys fast aliasing.
2493 parameter_map->set_the_hole(entry + 2);
2494 // For elements that are still writable we re-establish slow aliasing.
2495 if ((attributes & READ_ONLY) == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002496 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2497 }
2498
2499 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2500 Handle<SeededNumberDictionary> arguments(
Ben Murdoch61f157c2016-09-16 13:49:30 +01002501 SeededNumberDictionary::cast(parameter_map->get(1)), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002502 arguments = SeededNumberDictionary::AddNumberEntry(
2503 arguments, entry, value, details, object->map()->is_prototype_map());
2504 // If the attributes were NONE, we would have called set rather than
2505 // reconfigure.
2506 DCHECK_NE(NONE, attributes);
2507 object->RequireSlowElements(*arguments);
2508 parameter_map->set(1, *arguments);
2509 } else {
2510 Handle<FixedArrayBase> arguments(
Ben Murdoch61f157c2016-09-16 13:49:30 +01002511 FixedArrayBase::cast(parameter_map->get(1)), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002512 DictionaryElementsAccessor::ReconfigureImpl(
2513 object, arguments, entry - length, value, attributes);
2514 }
2515 }
2516};
2517
2518
2519class FastSloppyArgumentsElementsAccessor
2520 : public SloppyArgumentsElementsAccessor<
2521 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2522 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2523 public:
2524 explicit FastSloppyArgumentsElementsAccessor(const char* name)
2525 : SloppyArgumentsElementsAccessor<
2526 FastSloppyArgumentsElementsAccessor,
2527 FastHoleyObjectElementsAccessor,
2528 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2529
Ben Murdochc5610432016-08-08 18:44:38 +01002530 static Handle<FixedArray> GetArguments(Isolate* isolate,
2531 FixedArrayBase* backing_store) {
2532 FixedArray* parameter_map = FixedArray::cast(backing_store);
2533 return Handle<FixedArray>(FixedArray::cast(parameter_map->get(1)), isolate);
2534 }
2535
2536 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, uint32_t start,
2537 uint32_t end) {
2538 Isolate* isolate = receiver->GetIsolate();
2539 uint32_t result_len = end < start ? 0u : end - start;
2540 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2541 FAST_HOLEY_ELEMENTS, result_len, result_len);
2542 DisallowHeapAllocation no_gc;
2543 FixedArray* elements = FixedArray::cast(result_array->elements());
2544 FixedArray* parameters = FixedArray::cast(receiver->elements());
2545 uint32_t insertion_index = 0;
2546 for (uint32_t i = start; i < end; i++) {
2547 uint32_t entry =
2548 GetEntryForIndexImpl(*receiver, parameters, i, ALL_PROPERTIES);
2549 if (entry != kMaxUInt32 && HasEntryImpl(parameters, entry)) {
2550 elements->set(insertion_index, *GetImpl(parameters, entry));
2551 } else {
2552 elements->set_the_hole(insertion_index);
2553 }
2554 insertion_index++;
2555 }
2556 return result_array;
2557 }
2558
Ben Murdochda12d292016-06-02 14:46:10 +01002559 static Handle<SeededNumberDictionary> NormalizeImpl(
2560 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
Ben Murdochc5610432016-08-08 18:44:38 +01002561 Handle<FixedArray> arguments =
2562 GetArguments(elements->GetIsolate(), *elements);
Ben Murdochda12d292016-06-02 14:46:10 +01002563 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
2564 }
2565
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002566 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +01002567 Handle<FixedArray> arguments =
2568 GetArguments(obj->GetIsolate(), obj->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002569 FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2570 }
2571
2572 static void AddImpl(Handle<JSObject> object, uint32_t index,
2573 Handle<Object> value, PropertyAttributes attributes,
2574 uint32_t new_capacity) {
2575 DCHECK_EQ(NONE, attributes);
2576 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2577 Handle<FixedArrayBase> old_elements(
2578 FixedArrayBase::cast(parameter_map->get(1)));
2579 if (old_elements->IsSeededNumberDictionary() ||
2580 static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2581 GrowCapacityAndConvertImpl(object, new_capacity);
2582 }
2583 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2584 // For fast holey objects, the entry equals the index. The code above made
2585 // sure that there's enough space to store the value. We cannot convert
2586 // index to entry explicitly since the slot still contains the hole, so the
2587 // current EntryForIndex would indicate that it is "absent" by returning
2588 // kMaxUInt32.
2589 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2590 }
2591
2592 static void ReconfigureImpl(Handle<JSObject> object,
2593 Handle<FixedArrayBase> store, uint32_t entry,
2594 Handle<Object> value,
2595 PropertyAttributes attributes) {
2596 Handle<SeededNumberDictionary> dictionary =
2597 JSObject::NormalizeElements(object);
2598 FixedArray::cast(*store)->set(1, *dictionary);
2599 uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2600 if (entry >= length) {
2601 entry = dictionary->FindEntry(entry - length) + length;
2602 }
2603 SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2604 value, attributes);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002605 }
2606
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002607 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2608 FixedArrayBase* to, ElementsKind from_kind,
2609 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002610 int copy_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002611 DCHECK(!to->IsDictionary());
2612 if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2613 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2614 to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002615 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002616 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2617 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2618 FAST_HOLEY_ELEMENTS, to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002619 }
2620 }
2621
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002622 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2623 uint32_t capacity) {
2624 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2625 Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2626 ElementsKind from_kind = object->GetElementsKind();
2627 // This method should only be called if there's a reason to update the
2628 // elements.
2629 DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2630 static_cast<uint32_t>(old_elements->length()) < capacity);
2631 Handle<FixedArrayBase> elements =
2632 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2633 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2634 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2635 JSObject::MigrateToMap(object, new_map);
2636 parameter_map->set(1, *elements);
2637 JSObject::ValidateElements(object);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002638 }
2639};
2640
Ben Murdochc5610432016-08-08 18:44:38 +01002641template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
Ben Murdoch097c5b22016-05-18 11:27:45 +01002642class StringWrapperElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01002643 : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002644 public:
2645 explicit StringWrapperElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01002646 : ElementsAccessorBase<Subclass, KindTraits>(name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002647 USE(KindTraits::Kind);
2648 }
2649
2650 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2651 Isolate* isolate = holder->GetIsolate();
2652 Handle<String> string(GetString(*holder), isolate);
2653 uint32_t length = static_cast<uint32_t>(string->length());
2654 if (entry < length) {
2655 return isolate->factory()->LookupSingleCharacterStringFromCode(
2656 String::Flatten(string)->Get(entry));
2657 }
2658 return BackingStoreAccessor::GetImpl(holder, entry - length);
2659 }
2660
2661 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2662 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2663 if (entry < length) {
2664 PropertyAttributes attributes =
2665 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
2666 return PropertyDetails(attributes, v8::internal::DATA, 0,
2667 PropertyCellType::kNoCell);
2668 }
2669 return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
2670 }
2671
2672 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2673 FixedArrayBase* backing_store,
2674 uint32_t index, PropertyFilter filter) {
2675 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2676 if (index < length) return index;
2677 uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
2678 holder, backing_store, index, filter);
2679 if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
2680 DCHECK(backing_store_entry < kMaxUInt32 - length);
2681 return backing_store_entry + length;
2682 }
2683
2684 static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
2685 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2686 if (entry < length) {
2687 return; // String contents can't be deleted.
2688 }
2689 BackingStoreAccessor::DeleteImpl(holder, entry - length);
2690 }
2691
2692 static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
2693 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2694 if (entry < length) {
2695 return; // String contents are read-only.
2696 }
2697 BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
2698 }
2699
2700 static void AddImpl(Handle<JSObject> object, uint32_t index,
2701 Handle<Object> value, PropertyAttributes attributes,
2702 uint32_t new_capacity) {
2703 DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
2704 // Explicitly grow fast backing stores if needed. Dictionaries know how to
2705 // extend their capacity themselves.
2706 if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
2707 (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
2708 BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
2709 new_capacity)) {
Ben Murdochc5610432016-08-08 18:44:38 +01002710 GrowCapacityAndConvertImpl(object, new_capacity);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002711 }
2712 BackingStoreAccessor::AddImpl(object, index, value, attributes,
2713 new_capacity);
2714 }
2715
2716 static void ReconfigureImpl(Handle<JSObject> object,
2717 Handle<FixedArrayBase> store, uint32_t entry,
2718 Handle<Object> value,
2719 PropertyAttributes attributes) {
2720 uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
2721 if (entry < length) {
2722 return; // String contents can't be reconfigured.
2723 }
2724 BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
2725 attributes);
2726 }
2727
2728 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2729 KeyAccumulator* accumulator,
2730 AddKeyConversion convert) {
2731 Isolate* isolate = receiver->GetIsolate();
2732 Handle<String> string(GetString(*receiver), isolate);
2733 string = String::Flatten(string);
2734 uint32_t length = static_cast<uint32_t>(string->length());
2735 for (uint32_t i = 0; i < length; i++) {
2736 accumulator->AddKey(
2737 isolate->factory()->LookupSingleCharacterStringFromCode(
2738 string->Get(i)),
2739 convert);
2740 }
2741 BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
2742 convert);
2743 }
2744
2745 static void CollectElementIndicesImpl(Handle<JSObject> object,
2746 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01002747 KeyAccumulator* keys) {
Ben Murdochda12d292016-06-02 14:46:10 +01002748 uint32_t length = GetString(*object)->length();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002749 Factory* factory = keys->isolate()->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01002750 for (uint32_t i = 0; i < length; i++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002751 keys->AddKey(factory->NewNumberFromUint(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002752 }
Ben Murdochc5610432016-08-08 18:44:38 +01002753 BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
2754 keys);
2755 }
2756
2757 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2758 uint32_t capacity) {
2759 Handle<FixedArrayBase> old_elements(object->elements());
2760 ElementsKind from_kind = object->GetElementsKind();
2761 // This method should only be called if there's a reason to update the
2762 // elements.
2763 DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
2764 static_cast<uint32_t>(old_elements->length()) < capacity);
2765 Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
2766 FAST_STRING_WRAPPER_ELEMENTS,
2767 capacity);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002768 }
2769
2770 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2771 FixedArrayBase* to, ElementsKind from_kind,
2772 uint32_t to_start, int packed_size,
2773 int copy_size) {
Ben Murdochc5610432016-08-08 18:44:38 +01002774 DCHECK(!to->IsDictionary());
2775 if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
2776 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2777 to_start, copy_size);
2778 } else {
2779 DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
2780 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2781 FAST_HOLEY_ELEMENTS, to_start, copy_size);
2782 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002783 }
2784
2785 private:
2786 static String* GetString(JSObject* holder) {
2787 DCHECK(holder->IsJSValue());
2788 JSValue* js_value = JSValue::cast(holder);
2789 DCHECK(js_value->value()->IsString());
2790 return String::cast(js_value->value());
2791 }
2792};
2793
2794class FastStringWrapperElementsAccessor
2795 : public StringWrapperElementsAccessor<
2796 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2797 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
2798 public:
2799 explicit FastStringWrapperElementsAccessor(const char* name)
2800 : StringWrapperElementsAccessor<
2801 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2802 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
Ben Murdochda12d292016-06-02 14:46:10 +01002803
2804 static Handle<SeededNumberDictionary> NormalizeImpl(
2805 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
2806 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
2807 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002808};
2809
2810class SlowStringWrapperElementsAccessor
2811 : public StringWrapperElementsAccessor<
2812 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2813 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
2814 public:
2815 explicit SlowStringWrapperElementsAccessor(const char* name)
2816 : StringWrapperElementsAccessor<
2817 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2818 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
2819
2820 static bool HasAccessorsImpl(JSObject* holder,
2821 FixedArrayBase* backing_store) {
2822 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
2823 }
2824};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002825
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002826} // namespace
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002827
2828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002829void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2830 bool allow_appending) {
2831 DisallowHeapAllocation no_allocation;
2832 Object* raw_length = NULL;
2833 const char* elements_type = "array";
2834 if (obj->IsJSArray()) {
2835 JSArray* array = JSArray::cast(*obj);
2836 raw_length = array->length();
2837 } else {
2838 raw_length = Smi::FromInt(obj->elements()->length());
2839 elements_type = "object";
2840 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842 if (raw_length->IsNumber()) {
2843 double n = raw_length->Number();
2844 if (FastI2D(FastD2UI(n)) == n) {
2845 int32_t int32_length = DoubleToInt32(n);
2846 uint32_t compare_length = static_cast<uint32_t>(int32_length);
2847 if (allow_appending) compare_length++;
2848 if (index >= compare_length) {
2849 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2850 elements_type, op, elements_type, static_cast<int>(int32_length),
2851 static_cast<int>(index));
2852 TraceTopFrame(obj->GetIsolate());
2853 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002854 }
2855 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002856 PrintF("[%s elements length not integer value in ", elements_type);
2857 TraceTopFrame(obj->GetIsolate());
2858 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002859 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002860 } else {
2861 PrintF("[%s elements length not a number in ", elements_type);
2862 TraceTopFrame(obj->GetIsolate());
2863 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002864 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002865}
2866
2867
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002868MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2869 Arguments* args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002870 if (args->length() == 0) {
2871 // Optimize the case where there are no parameters passed.
2872 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2873 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002874
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002875 } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2876 uint32_t length;
2877 if (!args->at<Object>(0)->ToArrayLength(&length)) {
2878 return ThrowArrayLengthRangeError(array->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002879 }
2880
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002881 // Optimize the case where there is one argument and the argument is a small
2882 // smi.
2883 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2884 ElementsKind elements_kind = array->GetElementsKind();
2885 JSArray::Initialize(array, length, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002886
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002887 if (!IsFastHoleyElementsKind(elements_kind)) {
2888 elements_kind = GetHoleyElementsKind(elements_kind);
2889 JSObject::TransitionElementsKind(array, elements_kind);
2890 }
2891 } else if (length == 0) {
2892 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2893 } else {
2894 // Take the argument as the length.
2895 JSArray::Initialize(array, 0);
2896 JSArray::SetLength(array, length);
2897 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002898 return array;
2899 }
2900
2901 Factory* factory = array->GetIsolate()->factory();
2902
2903 // Set length and elements on the array.
2904 int number_of_elements = args->length();
2905 JSObject::EnsureCanContainElements(
2906 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2907
2908 // Allocate an appropriately typed elements array.
2909 ElementsKind elements_kind = array->GetElementsKind();
2910 Handle<FixedArrayBase> elms;
2911 if (IsFastDoubleElementsKind(elements_kind)) {
2912 elms = Handle<FixedArrayBase>::cast(
2913 factory->NewFixedDoubleArray(number_of_elements));
2914 } else {
2915 elms = Handle<FixedArrayBase>::cast(
2916 factory->NewFixedArrayWithHoles(number_of_elements));
2917 }
2918
2919 // Fill in the content
Ben Murdochc5610432016-08-08 18:44:38 +01002920 switch (elements_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002921 case FAST_HOLEY_SMI_ELEMENTS:
2922 case FAST_SMI_ELEMENTS: {
2923 Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002924 for (int entry = 0; entry < number_of_elements; entry++) {
2925 smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002926 }
2927 break;
2928 }
2929 case FAST_HOLEY_ELEMENTS:
2930 case FAST_ELEMENTS: {
2931 DisallowHeapAllocation no_gc;
2932 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2933 Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002934 for (int entry = 0; entry < number_of_elements; entry++) {
2935 object_elms->set(entry, (*args)[entry], mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002936 }
2937 break;
2938 }
2939 case FAST_HOLEY_DOUBLE_ELEMENTS:
2940 case FAST_DOUBLE_ELEMENTS: {
2941 Handle<FixedDoubleArray> double_elms =
2942 Handle<FixedDoubleArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002943 for (int entry = 0; entry < number_of_elements; entry++) {
2944 double_elms->set(entry, (*args)[entry]->Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002945 }
2946 break;
2947 }
2948 default:
2949 UNREACHABLE();
2950 break;
2951 }
2952
2953 array->set_elements(*elms);
2954 array->set_length(Smi::FromInt(number_of_elements));
2955 return array;
2956}
2957
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002958
2959void ElementsAccessor::InitializeOncePerProcess() {
2960 static ElementsAccessor* accessor_array[] = {
2961#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2962 ELEMENTS_LIST(ACCESSOR_ARRAY)
2963#undef ACCESSOR_ARRAY
2964 };
2965
2966 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2967 kElementsKindCount);
2968
2969 elements_accessors_ = accessor_array;
2970}
2971
2972
2973void ElementsAccessor::TearDown() {
2974 if (elements_accessors_ == NULL) return;
2975#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2976 ELEMENTS_LIST(ACCESSOR_DELETE)
2977#undef ACCESSOR_DELETE
2978 elements_accessors_ = NULL;
2979}
2980
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002981Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
Ben Murdochc5610432016-08-08 18:44:38 +01002982 uint32_t concat_size,
2983 uint32_t result_len) {
Ben Murdochda12d292016-06-02 14:46:10 +01002984 ElementsKind result_elements_kind = GetInitialFastElementsKind();
Ben Murdochc5610432016-08-08 18:44:38 +01002985 bool has_raw_doubles = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002986 {
2987 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +01002988 bool is_holey = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002989 for (uint32_t i = 0; i < concat_size; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01002990 Object* arg = (*args)[i];
2991 ElementsKind arg_kind = JSArray::cast(arg)->GetElementsKind();
Ben Murdochda12d292016-06-02 14:46:10 +01002992 has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002993 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
Ben Murdochda12d292016-06-02 14:46:10 +01002994 result_elements_kind =
2995 GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002996 }
2997 if (is_holey) {
Ben Murdochda12d292016-06-02 14:46:10 +01002998 result_elements_kind = GetHoleyElementsKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002999 }
3000 }
3001
3002 // If a double array is concatted into a fast elements array, the fast
3003 // elements array needs to be initialized to contain proper holes, since
3004 // boxing doubles may cause incremental marking.
Ben Murdochda12d292016-06-02 14:46:10 +01003005 bool requires_double_boxing =
3006 has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
3007 ArrayStorageAllocationMode mode = requires_double_boxing
3008 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
3009 : DONT_INITIALIZE_ARRAY_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003010 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
Ben Murdochda12d292016-06-02 14:46:10 +01003011 result_elements_kind, result_len, result_len, mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003012 if (result_len == 0) return result_array;
Ben Murdochda12d292016-06-02 14:46:10 +01003013
3014 uint32_t insertion_index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003015 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
Ben Murdochda12d292016-06-02 14:46:10 +01003016 ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003017 for (uint32_t i = 0; i < concat_size; i++) {
3018 // It is crucial to keep |array| in a raw pointer form to avoid
3019 // performance degradation.
3020 JSArray* array = JSArray::cast((*args)[i]);
Ben Murdochda12d292016-06-02 14:46:10 +01003021 uint32_t len = 0;
3022 array->length()->ToArrayLength(&len);
3023 if (len == 0) continue;
3024 ElementsKind from_kind = array->GetElementsKind();
3025 accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
3026 insertion_index += len;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003027 }
3028
Ben Murdochda12d292016-06-02 14:46:10 +01003029 DCHECK_EQ(insertion_index, result_len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003030 return result_array;
3031}
3032
3033ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3034} // namespace internal
3035} // namespace v8