blob: 288c60e30515a5874042824c406406d9ba598ffc [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 Murdoch097c5b22016-05-18 11:27:45 +0100143 DCHECK(IsFastSmiOrObjectElementsKind(from_kind) ||
144 from_kind == FAST_STRING_WRAPPER_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146
147 WriteBarrierMode write_barrier_mode =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 ((IsFastObjectElementsKind(from_kind) &&
149 IsFastObjectElementsKind(to_kind)) ||
150 from_kind == FAST_STRING_WRAPPER_ELEMENTS)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 ? UPDATE_WRITE_BARRIER
152 : SKIP_WRITE_BARRIER;
153 for (int i = 0; i < copy_size; i++) {
154 Object* value = from->get(from_start + i);
155 to->set(to_start + i, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100156 }
157}
158
159
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160static void CopyDictionaryToObjectElements(
161 FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
162 ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
163 DisallowHeapAllocation no_allocation;
164 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100165 int copy_size = raw_copy_size;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100166 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100168 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
169 copy_size = from->max_number_key() + 1 - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100170 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 int start = to_start + copy_size;
172 int length = to_base->length() - start;
173 if (length > 0) {
174 Heap* heap = from->GetHeap();
175 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
176 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 }
178 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100179 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 DCHECK(to_base != from_base);
181 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 FixedArray* to = FixedArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100184 uint32_t to_length = to->length();
185 if (to_start + copy_size > to_length) {
186 copy_size = to_length - to_start;
187 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
189 ? UPDATE_WRITE_BARRIER
190 : SKIP_WRITE_BARRIER;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100191 for (int i = 0; i < copy_size; i++) {
192 int entry = from->FindEntry(i + from_start);
193 if (entry != SeededNumberDictionary::kNotFound) {
194 Object* value = from->ValueAt(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 DCHECK(!value->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 to->set(i + to_start, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100197 } else {
198 to->set_the_hole(i + to_start);
199 }
200 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100201}
202
203
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400204// NOTE: this method violates the handlified function signature convention:
205// raw pointer parameters in the function that allocates.
206// See ElementsAccessorBase::CopyElements() for details.
207static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 uint32_t from_start,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400209 FixedArrayBase* to_base,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 uint32_t to_start, int raw_copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100211 int copy_size = raw_copy_size;
212 if (raw_copy_size < 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 copy_size = Min(from_base->length() - from_start,
217 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100218 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 // Also initialize the area that will be copied over since HeapNumber
220 // allocation below can cause an incremental marking step, requiring all
221 // existing heap objects to be propertly initialized.
222 int start = to_start;
223 int length = to_base->length() - start;
224 if (length > 0) {
225 Heap* heap = from_base->GetHeap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400226 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100228 }
229 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
233 (copy_size + static_cast<int>(from_start)) <= from_base->length());
234 if (copy_size == 0) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235
236 // From here on, the code below could actually allocate. Therefore the raw
237 // values are wrapped into handles.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 Isolate* isolate = from_base->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
240 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241
Ben Murdoch097c5b22016-05-18 11:27:45 +0100242 // Use an outer loop to not waste too much time on creating HandleScopes.
243 // On the other hand we might overflow a single handle scope depending on
244 // the copy_size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 int offset = 0;
246 while (offset < copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 offset += 100;
249 for (int i = offset - 100; i < offset && i < copy_size; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100250 Handle<Object> value =
251 FixedDoubleArray::get(*from, i + from_start, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100253 }
254 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100255}
256
257
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100259 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 FixedArrayBase* to_base,
261 uint32_t to_start, int raw_copy_size) {
262 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100263 int copy_size = raw_copy_size;
264 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 copy_size = Min(from_base->length() - from_start,
268 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000270 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
271 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100272 }
273 }
274 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
276 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100277 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
279 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100280 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
281 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
282 to_address += kDoubleSize * to_start;
283 from_address += kDoubleSize * from_start;
284 int words_per_double = (kDoubleSize / kPointerSize);
285 CopyWords(reinterpret_cast<Object**>(to_address),
286 reinterpret_cast<Object**>(from_address),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 static_cast<size_t>(words_per_double * copy_size));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100288}
289
290
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291static void CopySmiToDoubleElements(FixedArrayBase* from_base,
292 uint32_t from_start,
293 FixedArrayBase* to_base, uint32_t to_start,
294 int raw_copy_size) {
295 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100296 int copy_size = raw_copy_size;
297 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100299 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000300 copy_size = from_base->length() - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100301 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
303 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100304 }
305 }
306 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
308 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100309 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 FixedArray* from = FixedArray::cast(from_base);
311 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
312 Object* the_hole = from->GetHeap()->the_hole_value();
313 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
314 from_start < from_end; from_start++, to_start++) {
315 Object* hole_or_smi = from->get(from_start);
316 if (hole_or_smi == the_hole) {
317 to->set_the_hole(to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100318 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 to->set(to_start, Smi::cast(hole_or_smi)->value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100320 }
321 }
322}
323
324
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
326 uint32_t from_start,
327 FixedArrayBase* to_base,
328 uint32_t to_start, int packed_size,
329 int raw_copy_size) {
330 DisallowHeapAllocation no_allocation;
331 int copy_size = raw_copy_size;
332 uint32_t to_end;
333 if (raw_copy_size < 0) {
334 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
335 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
336 copy_size = packed_size - from_start;
337 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
338 to_end = to_base->length();
339 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
340 FixedDoubleArray::cast(to_base)->set_the_hole(i);
341 }
342 } else {
343 to_end = to_start + static_cast<uint32_t>(copy_size);
344 }
345 } else {
346 to_end = to_start + static_cast<uint32_t>(copy_size);
347 }
348 DCHECK(static_cast<int>(to_end) <= to_base->length());
349 DCHECK(packed_size >= 0 && packed_size <= copy_size);
350 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
351 (copy_size + static_cast<int>(from_start)) <= from_base->length());
352 if (copy_size == 0) return;
353 FixedArray* from = FixedArray::cast(from_base);
354 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
355 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
356 from_start < from_end; from_start++, to_start++) {
357 Object* smi = from->get(from_start);
358 DCHECK(!smi->IsTheHole());
359 to->set(to_start, Smi::cast(smi)->value());
360 }
361}
362
363
364static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
365 uint32_t from_start,
366 FixedArrayBase* to_base,
367 uint32_t to_start, int raw_copy_size) {
368 DisallowHeapAllocation no_allocation;
369 int copy_size = raw_copy_size;
370 if (raw_copy_size < 0) {
371 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
372 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
373 copy_size = from_base->length() - from_start;
374 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
375 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
376 FixedDoubleArray::cast(to_base)->set_the_hole(i);
377 }
378 }
379 }
380 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
381 (copy_size + static_cast<int>(from_start)) <= from_base->length());
382 if (copy_size == 0) return;
383 FixedArray* from = FixedArray::cast(from_base);
384 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
385 Object* the_hole = from->GetHeap()->the_hole_value();
386 for (uint32_t from_end = from_start + copy_size;
387 from_start < from_end; from_start++, to_start++) {
388 Object* hole_or_object = from->get(from_start);
389 if (hole_or_object == the_hole) {
390 to->set_the_hole(to_start);
391 } else {
392 to->set(to_start, hole_or_object->Number());
393 }
394 }
395}
396
397
398static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000400 FixedArrayBase* to_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100401 uint32_t to_start,
402 int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000403 DisallowHeapAllocation no_allocation;
404 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100405 int copy_size = raw_copy_size;
406 if (copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000407 DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100408 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
409 copy_size = from->max_number_key() + 1 - from_start;
410 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000411 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
412 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100413 }
414 }
415 }
416 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000417 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100418 uint32_t to_length = to->length();
419 if (to_start + copy_size > to_length) {
420 copy_size = to_length - to_start;
421 }
422 for (int i = 0; i < copy_size; i++) {
423 int entry = from->FindEntry(i + from_start);
424 if (entry != SeededNumberDictionary::kNotFound) {
425 to->set(i + to_start, from->ValueAt(entry)->Number());
426 } else {
427 to->set_the_hole(i + to_start);
428 }
429 }
430}
431
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432static void TraceTopFrame(Isolate* isolate) {
433 StackFrameIterator it(isolate);
434 if (it.done()) {
435 PrintF("unknown location (no JavaScript frames present)");
436 return;
437 }
438 StackFrame* raw_frame = it.frame();
439 if (raw_frame->is_internal()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 Code* apply_builtin =
441 isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 if (raw_frame->unchecked_code() == apply_builtin) {
443 PrintF("apply from ");
444 it.Advance();
445 raw_frame = it.frame();
446 }
447 }
448 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
449}
450
451
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000452// Base class for element handler implementations. Contains the
453// the common logic for objects with different ElementsKinds.
454// Subclasses must specialize method for which the element
455// implementation differs from the base class implementation.
456//
457// This class is intended to be used in the following way:
458//
459// class SomeElementsAccessor :
460// public ElementsAccessorBase<SomeElementsAccessor,
461// BackingStoreClass> {
462// ...
463// }
464//
465// This is an example of the Curiously Recurring Template Pattern (see
466// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
467// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
468// specialization of SomeElementsAccessor methods).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100469template <typename ElementsAccessorSubclass,
470 typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000471class ElementsAccessorBase : public ElementsAccessor {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100473 explicit ElementsAccessorBase(const char* name)
474 : ElementsAccessor(name) { }
475
476 typedef ElementsTraitsParam ElementsTraits;
477 typedef typename ElementsTraitsParam::BackingStore BackingStore;
478
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 static ElementsKind kind() { return ElementsTraits::Kind; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100480
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 static void ValidateContents(Handle<JSObject> holder, int length) {
482 }
483
484 static void ValidateImpl(Handle<JSObject> holder) {
485 Handle<FixedArrayBase> fixed_array_base(holder->elements());
486 if (!fixed_array_base->IsHeapObject()) return;
487 // Arrays that have been shifted in place can't be verified.
488 if (fixed_array_base->IsFiller()) return;
489 int length = 0;
490 if (holder->IsJSArray()) {
491 Object* length_obj = Handle<JSArray>::cast(holder)->length();
492 if (length_obj->IsSmi()) {
493 length = Smi::cast(length_obj)->value();
494 }
495 } else {
496 length = fixed_array_base->length();
497 }
498 ElementsAccessorSubclass::ValidateContents(holder, length);
499 }
500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 void Validate(Handle<JSObject> holder) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 DisallowHeapAllocation no_gc;
503 ElementsAccessorSubclass::ValidateImpl(holder);
504 }
505
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 static bool IsPackedImpl(Handle<JSObject> holder,
507 Handle<FixedArrayBase> backing_store, uint32_t start,
508 uint32_t end) {
509 if (IsFastPackedElementsKind(kind())) return true;
510 for (uint32_t i = start; i < end; i++) {
511 if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
512 ALL_PROPERTIES)) {
513 return false;
514 }
515 }
516 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100517 }
518
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519 static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
520 if (!IsHoleyElementsKind(kind())) return;
521 int length = Smi::cast(array->length())->value();
522 Handle<FixedArrayBase> backing_store(array->elements());
523 if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
524 length)) {
525 return;
526 }
527 ElementsKind packed_kind = GetPackedElementsKind(kind());
528 Handle<Map> new_map =
529 JSObject::GetElementsTransitionMap(array, packed_kind);
530 JSObject::MigrateToMap(array, new_map);
531 if (FLAG_trace_elements_transitions) {
532 JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
533 packed_kind, backing_store);
534 }
535 }
536
537 bool HasElement(Handle<JSObject> holder, uint32_t index,
538 Handle<FixedArrayBase> backing_store,
539 PropertyFilter filter) final {
540 return ElementsAccessorSubclass::HasElementImpl(holder, index,
541 backing_store, filter);
542 }
543
544 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
545 Handle<FixedArrayBase> backing_store,
546 PropertyFilter filter) {
547 return ElementsAccessorSubclass::GetEntryForIndexImpl(
548 *holder, *backing_store, index, filter) != kMaxUInt32;
549 }
550
Ben Murdoch097c5b22016-05-18 11:27:45 +0100551 bool HasAccessors(JSObject* holder) final {
552 return ElementsAccessorSubclass::HasAccessorsImpl(holder,
553 holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 }
555
Ben Murdoch097c5b22016-05-18 11:27:45 +0100556 static bool HasAccessorsImpl(JSObject* holder,
557 FixedArrayBase* backing_store) {
558 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000559 }
560
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
562 return ElementsAccessorSubclass::GetImpl(holder, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563 }
564
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
566 return ElementsAccessorSubclass::GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 }
568
Ben Murdoch097c5b22016-05-18 11:27:45 +0100569 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
570 Isolate* isolate = backing_store->GetIsolate();
571 uint32_t index = GetIndexForEntryImpl(backing_store, entry);
572 return handle(BackingStore::cast(backing_store)->get(index), isolate);
573 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
576 ElementsAccessorSubclass::SetImpl(holder, entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 }
578
579 void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
580 uint32_t entry, Handle<Object> value,
581 PropertyAttributes attributes) final {
582 ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
583 attributes);
584 }
585
586 static void ReconfigureImpl(Handle<JSObject> object,
587 Handle<FixedArrayBase> store, uint32_t entry,
588 Handle<Object> value,
589 PropertyAttributes attributes) {
590 UNREACHABLE();
591 }
592
593 void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
594 PropertyAttributes attributes, uint32_t new_capacity) final {
595 ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
596 new_capacity);
597 }
598
599 static void AddImpl(Handle<JSObject> object, uint32_t index,
600 Handle<Object> value, PropertyAttributes attributes,
601 uint32_t new_capacity) {
602 UNREACHABLE();
603 }
604
Ben Murdochda12d292016-06-02 14:46:10 +0100605 uint32_t Push(Handle<JSArray> receiver, Arguments* args,
606 uint32_t push_size) final {
607 return ElementsAccessorSubclass::PushImpl(receiver, args, push_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 }
609
Ben Murdochda12d292016-06-02 14:46:10 +0100610 static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 uint32_t push_sized) {
612 UNREACHABLE();
613 return 0;
614 }
615
Ben Murdochda12d292016-06-02 14:46:10 +0100616 uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 uint32_t unshift_size) final {
Ben Murdochda12d292016-06-02 14:46:10 +0100618 return ElementsAccessorSubclass::UnshiftImpl(receiver, args, unshift_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 }
620
Ben Murdochda12d292016-06-02 14:46:10 +0100621 static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 uint32_t unshift_size) {
623 UNREACHABLE();
624 return 0;
625 }
626
Ben Murdochda12d292016-06-02 14:46:10 +0100627 Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628 uint32_t end) final {
Ben Murdochda12d292016-06-02 14:46:10 +0100629 return ElementsAccessorSubclass::SliceImpl(receiver, start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 }
631
632 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000633 uint32_t start, uint32_t end) {
634 UNREACHABLE();
635 return Handle<JSArray>();
636 }
637
Ben Murdochda12d292016-06-02 14:46:10 +0100638 Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 uint32_t delete_count, Arguments* args,
640 uint32_t add_count) final {
Ben Murdochda12d292016-06-02 14:46:10 +0100641 return ElementsAccessorSubclass::SpliceImpl(receiver, start, delete_count,
642 args, add_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 }
644
645 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 uint32_t start, uint32_t delete_count,
647 Arguments* args, uint32_t add_count) {
648 UNREACHABLE();
649 return Handle<JSArray>();
650 }
651
Ben Murdochda12d292016-06-02 14:46:10 +0100652 Handle<Object> Pop(Handle<JSArray> receiver) final {
653 return ElementsAccessorSubclass::PopImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 }
655
Ben Murdochda12d292016-06-02 14:46:10 +0100656 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 UNREACHABLE();
658 return Handle<Object>();
659 }
660
Ben Murdochda12d292016-06-02 14:46:10 +0100661 Handle<Object> Shift(Handle<JSArray> receiver) final {
662 return ElementsAccessorSubclass::ShiftImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 }
664
Ben Murdochda12d292016-06-02 14:46:10 +0100665 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 UNREACHABLE();
667 return Handle<Object>();
668 }
669
670 void SetLength(Handle<JSArray> array, uint32_t length) final {
671 ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
672 handle(array->elements()));
673 }
674
675 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
676 uint32_t length,
677 Handle<FixedArrayBase> backing_store) {
678 DCHECK(!array->SetLengthWouldNormalize(length));
679 DCHECK(IsFastElementsKind(array->GetElementsKind()));
680 uint32_t old_length = 0;
681 CHECK(array->length()->ToArrayIndex(&old_length));
682
683 if (old_length < length) {
684 ElementsKind kind = array->GetElementsKind();
685 if (!IsFastHoleyElementsKind(kind)) {
686 kind = GetHoleyElementsKind(kind);
687 JSObject::TransitionElementsKind(array, kind);
688 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 // Check whether the backing store should be shrunk.
692 uint32_t capacity = backing_store->length();
693 old_length = Min(old_length, capacity);
694 if (length == 0) {
695 array->initialize_elements();
696 } else if (length <= capacity) {
Ben Murdochda12d292016-06-02 14:46:10 +0100697 if (IsFastSmiOrObjectElementsKind(kind())) {
698 JSObject::EnsureWritableFastElements(array);
699 if (array->elements() != *backing_store) {
700 backing_store = handle(array->elements(), isolate);
701 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702 }
703 if (2 * length <= capacity) {
704 // If more than half the elements won't be used, trim the array.
705 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
706 *backing_store, capacity - length);
707 } else {
708 // Otherwise, fill the unused tail with holes.
709 for (uint32_t i = length; i < old_length; i++) {
710 BackingStore::cast(*backing_store)->set_the_hole(i);
711 }
712 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 // Check whether the backing store should be expanded.
715 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
716 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
717 }
718
719 array->set_length(Smi::FromInt(length));
720 JSObject::ValidateElements(array);
721 }
722
Ben Murdochda12d292016-06-02 14:46:10 +0100723 static uint32_t GetIterationLength(JSObject* receiver,
724 FixedArrayBase* elements) {
725 if (receiver->IsJSArray()) {
726 DCHECK(JSArray::cast(receiver)->length()->IsSmi());
727 return static_cast<uint32_t>(
728 Smi::cast(JSArray::cast(receiver)->length())->value());
729 }
730 return ElementsAccessorSubclass::GetCapacityImpl(receiver, elements);
731 }
732
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
734 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
735 ElementsKind from_kind, uint32_t capacity) {
736 return ConvertElementsWithCapacity(
737 object, old_elements, from_kind, capacity, 0, 0,
738 ElementsAccessor::kCopyToEndAndInitializeToHole);
739 }
740
741 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
742 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
743 ElementsKind from_kind, uint32_t capacity, int copy_size) {
744 return ConvertElementsWithCapacity(object, old_elements, from_kind,
745 capacity, 0, 0, copy_size);
746 }
747
748 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
749 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
750 ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
751 uint32_t dst_index, int copy_size) {
752 Isolate* isolate = object->GetIsolate();
753 Handle<FixedArrayBase> new_elements;
754 if (IsFastDoubleElementsKind(kind())) {
755 new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
756 } else {
757 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
758 }
759
760 int packed_size = kPackedSizeNotKnown;
761 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
762 packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
763 }
764
765 ElementsAccessorSubclass::CopyElementsImpl(
766 *old_elements, src_index, *new_elements, from_kind, dst_index,
767 packed_size, copy_size);
768
769 return new_elements;
770 }
771
772 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
773 uint32_t capacity) {
774 ElementsKind from_kind = object->GetElementsKind();
775 if (IsFastSmiOrObjectElementsKind(from_kind)) {
776 // Array optimizations rely on the prototype lookups of Array objects
777 // always returning undefined. If there is a store to the initial
778 // prototype object, make sure all of these optimizations are invalidated.
779 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
780 }
781 Handle<FixedArrayBase> old_elements(object->elements());
782 // This method should only be called if there's a reason to update the
783 // elements.
784 DCHECK(IsFastDoubleElementsKind(from_kind) !=
785 IsFastDoubleElementsKind(kind()) ||
786 IsDictionaryElementsKind(from_kind) ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100787 from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 static_cast<uint32_t>(old_elements->length()) < capacity);
789 Handle<FixedArrayBase> elements =
790 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
791
792 ElementsKind to_kind = kind();
793 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
794 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
795 JSObject::SetMapAndElements(object, new_map, elements);
796
797 // Transition through the allocation site as well if present.
798 JSObject::UpdateAllocationSite(object, to_kind);
799
800 if (FLAG_trace_elements_transitions) {
801 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
802 to_kind, elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100804 }
805
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 void GrowCapacityAndConvert(Handle<JSObject> object,
807 uint32_t capacity) final {
808 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000809 }
810
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 void Delete(Handle<JSObject> obj, uint32_t entry) final {
812 ElementsAccessorSubclass::DeleteImpl(obj, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813 }
814
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400815 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
816 FixedArrayBase* to, ElementsKind from_kind,
817 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818 int copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100819 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100820 }
821
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 void CopyElements(JSObject* from_holder, uint32_t from_start,
823 ElementsKind from_kind, Handle<FixedArrayBase> to,
824 uint32_t to_start, int copy_size) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 int packed_size = kPackedSizeNotKnown;
826 bool is_packed = IsFastPackedElementsKind(from_kind) &&
827 from_holder->IsJSArray();
828 if (is_packed) {
829 packed_size =
830 Smi::cast(JSArray::cast(from_holder)->length())->value();
831 if (copy_size >= 0 && packed_size > copy_size) {
832 packed_size = copy_size;
833 }
834 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400835 FixedArrayBase* from = from_holder->elements();
836 // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
837 // violate the handlified function signature convention:
838 // raw pointer parameters in the function that allocates. This is done
839 // intentionally to avoid ArrayConcat() builtin performance degradation.
840 //
841 // Details: The idea is that allocations actually happen only in case of
842 // copying from object with fast double elements to object with object
843 // elements. In all the other cases there are no allocations performed and
844 // handle creation causes noticeable performance degradation of the builtin.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000845 ElementsAccessorSubclass::CopyElementsImpl(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400846 from, from_start, *to, from_kind, to_start, packed_size, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000847 }
848
Ben Murdochda12d292016-06-02 14:46:10 +0100849 Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
850 return ElementsAccessorSubclass::NormalizeImpl(object,
851 handle(object->elements()));
852 }
853
854 static Handle<SeededNumberDictionary> NormalizeImpl(
855 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
856 UNREACHABLE();
857 return Handle<SeededNumberDictionary>();
858 }
859
860 Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
861 Handle<FixedArray> values_or_entries,
862 bool get_entries, int* nof_items,
863 PropertyFilter filter) {
864 return ElementsAccessorSubclass::CollectValuesOrEntriesImpl(
865 isolate, object, values_or_entries, get_entries, nof_items, filter);
866 }
867
868 static Maybe<bool> CollectValuesOrEntriesImpl(
869 Isolate* isolate, Handle<JSObject> object,
870 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
871 PropertyFilter filter) {
872 int count = 0;
873 KeyAccumulator accumulator(isolate, OWN_ONLY, ALL_PROPERTIES);
874 accumulator.NextPrototype();
875 ElementsAccessorSubclass::CollectElementIndicesImpl(
876 object, handle(object->elements(), isolate), &accumulator, kMaxUInt32,
877 ALL_PROPERTIES, 0);
878 Handle<FixedArray> keys = accumulator.GetKeys();
879
880 for (int i = 0; i < keys->length(); ++i) {
881 Handle<Object> key(keys->get(i), isolate);
882 Handle<Object> value;
883 uint32_t index;
884 if (!key->ToUint32(&index)) continue;
885
886 uint32_t entry = ElementsAccessorSubclass::GetEntryForIndexImpl(
887 *object, object->elements(), index, filter);
888 if (entry == kMaxUInt32) continue;
889
890 PropertyDetails details =
891 ElementsAccessorSubclass::GetDetailsImpl(*object, entry);
892
893 if (details.kind() == kData) {
894 value = ElementsAccessorSubclass::GetImpl(object, entry);
895 } else {
896 LookupIterator it(isolate, object, index, LookupIterator::OWN);
897 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
898 isolate, value, Object::GetProperty(&it), Nothing<bool>());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100899 }
Ben Murdochda12d292016-06-02 14:46:10 +0100900 if (get_entries) {
901 value = MakeEntryPair(isolate, index, value);
902 }
903 values_or_entries->set(count++, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000904 }
Ben Murdochda12d292016-06-02 14:46:10 +0100905
906 *nof_items = count;
907 return Just(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000908 }
909
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 void CollectElementIndices(Handle<JSObject> object,
911 Handle<FixedArrayBase> backing_store,
912 KeyAccumulator* keys, uint32_t range,
913 PropertyFilter filter, uint32_t offset) final {
Ben Murdochda12d292016-06-02 14:46:10 +0100914 if (filter & ONLY_ALL_CAN_READ) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 ElementsAccessorSubclass::CollectElementIndicesImpl(
916 object, backing_store, keys, range, filter, offset);
Ben Murdochda12d292016-06-02 14:46:10 +0100917 }
918
919 static void CollectElementIndicesImpl(Handle<JSObject> object,
920 Handle<FixedArrayBase> backing_store,
921 KeyAccumulator* keys, uint32_t range,
922 PropertyFilter filter,
923 uint32_t offset) {
924 DCHECK_NE(DICTIONARY_ELEMENTS, kind());
925 // Non-dictionary elements can't have all-can-read accessors.
926 uint32_t length = GetIterationLength(*object, *backing_store);
927 if (range < length) length = range;
928 for (uint32_t i = offset; i < length; i++) {
929 if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
930 filter)) {
931 keys->AddKey(i);
932 }
933 }
934 }
935
936 static Handle<FixedArray> DirectCollectElementIndicesImpl(
937 Isolate* isolate, Handle<JSObject> object,
938 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
939 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
940 uint32_t insertion_index = 0) {
941 uint32_t length =
942 ElementsAccessorSubclass::GetIterationLength(*object, *backing_store);
943 for (uint32_t i = 0; i < length; i++) {
944 if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
945 filter)) {
946 if (convert == CONVERT_TO_STRING) {
947 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
948 list->set(insertion_index, *index_string);
949 } else {
950 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
951 }
952 insertion_index++;
953 }
954 }
955 *nof_indices = insertion_index;
956 return list;
957 }
958
959 Handle<FixedArray> PrependElementIndices(Handle<JSObject> object,
960 Handle<FixedArrayBase> backing_store,
961 Handle<FixedArray> keys,
962 GetKeysConversion convert,
963 PropertyFilter filter) final {
964 return ElementsAccessorSubclass::PrependElementIndicesImpl(
965 object, backing_store, keys, convert, filter);
966 }
967
968 static Handle<FixedArray> PrependElementIndicesImpl(
969 Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
970 Handle<FixedArray> keys, GetKeysConversion convert,
971 PropertyFilter filter) {
972 Isolate* isolate = object->GetIsolate();
973 uint32_t nof_property_keys = keys->length();
974 uint32_t initial_list_length =
975 ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
976 initial_list_length += nof_property_keys;
977
978 // Collect the element indices into a new list.
979 uint32_t nof_indices = 0;
980 Handle<FixedArray> combined_keys =
981 isolate->factory()->NewFixedArray(initial_list_length);
982 combined_keys = ElementsAccessorSubclass::DirectCollectElementIndicesImpl(
983 isolate, object, backing_store, convert, filter, combined_keys,
984 &nof_indices);
985
986 // Sort the indices list if necessary.
987 if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
988 struct {
989 bool operator()(Object* a, Object* b) {
990 if (!a->IsUndefined()) {
991 if (b->IsUndefined()) return true;
992 return a->Number() < b->Number();
993 }
994 return !b->IsUndefined();
995 }
996 } cmp;
997 Object** start =
998 reinterpret_cast<Object**>(combined_keys->GetFirstElementAddress());
999 std::sort(start, start + nof_indices, cmp);
1000 uint32_t array_length = 0;
1001 // Indices from dictionary elements should only be converted after
1002 // sorting.
1003 if (convert == CONVERT_TO_STRING) {
1004 for (uint32_t i = 0; i < nof_indices; i++) {
1005 Handle<Object> index_string = isolate->factory()->Uint32ToString(
1006 combined_keys->get(i)->Number());
1007 combined_keys->set(i, *index_string);
1008 }
1009 } else if (!(object->IsJSArray() &&
1010 JSArray::cast(*object)->length()->ToArrayLength(
1011 &array_length) &&
1012 array_length <= Smi::kMaxValue)) {
1013 // Since we use std::sort above, the GC will no longer know where the
1014 // HeapNumbers are, hence we have to write them again.
1015 // For Arrays with valid Smi length, we are sure to have no HeapNumber
1016 // indices and thus we can skip this step.
1017 for (uint32_t i = 0; i < nof_indices; i++) {
1018 Object* index = combined_keys->get(i);
1019 combined_keys->set(i, index);
1020 }
1021 }
1022 }
1023
1024 // Copy over the passed-in property keys.
1025 CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
1026 FAST_ELEMENTS, nof_indices, nof_property_keys);
1027
1028 if (IsHoleyElementsKind(kind())) {
1029 // Shrink combined_keys to the final size.
1030 int final_size = nof_indices + nof_property_keys;
1031 DCHECK_LE(final_size, combined_keys->length());
1032 combined_keys->Shrink(final_size);
1033 }
1034
1035 return combined_keys;
1036 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001037
1038 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
1039 KeyAccumulator* accumulator,
1040 AddKeyConversion convert) final {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001041 ElementsAccessorSubclass::AddElementsToKeyAccumulatorImpl(
1042 receiver, accumulator, convert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 }
1044
1045 static uint32_t GetCapacityImpl(JSObject* holder,
1046 FixedArrayBase* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001047 return backing_store->length();
1048 }
1049
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
1051 return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001052 }
1053
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001054 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1055 uint32_t entry) {
1056 return entry;
1057 }
1058
1059 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1060 FixedArrayBase* backing_store,
1061 uint32_t index, PropertyFilter filter) {
1062 if (IsHoleyElementsKind(kind())) {
1063 return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
1064 backing_store) &&
1065 !BackingStore::cast(backing_store)->is_the_hole(index)
1066 ? index
1067 : kMaxUInt32;
1068 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001069 uint32_t length = GetIterationLength(holder, backing_store);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070 return index < length ? index : kMaxUInt32;
1071 }
1072 }
1073
1074 uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
1075 uint32_t index) final {
1076 return ElementsAccessorSubclass::GetEntryForIndexImpl(
1077 holder, backing_store, index, ALL_PROPERTIES);
1078 }
1079
1080 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1081 uint32_t entry) {
1082 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1083 }
1084
Ben Murdoch097c5b22016-05-18 11:27:45 +01001085 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1086 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1087 }
1088
1089 PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
1090 return ElementsAccessorSubclass::GetDetailsImpl(holder, entry);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001091 }
1092
1093 private:
1094 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1095};
1096
1097
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098class DictionaryElementsAccessor
1099 : public ElementsAccessorBase<DictionaryElementsAccessor,
1100 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1101 public:
1102 explicit DictionaryElementsAccessor(const char* name)
1103 : ElementsAccessorBase<DictionaryElementsAccessor,
1104 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1105
Ben Murdochda12d292016-06-02 14:46:10 +01001106 static uint32_t GetIterationLength(JSObject* receiver,
1107 FixedArrayBase* elements) {
1108 uint32_t length;
1109 if (receiver->IsJSArray()) {
1110 // Special-case GetIterationLength for dictionary elements since the
1111 // length of the array might be a HeapNumber.
1112 JSArray::cast(receiver)->length()->ToArrayLength(&length);
1113 } else {
1114 length = GetCapacityImpl(receiver, elements);
1115 }
1116 return length;
1117 }
1118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001119 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1120 uint32_t length,
1121 Handle<FixedArrayBase> backing_store) {
1122 Handle<SeededNumberDictionary> dict =
1123 Handle<SeededNumberDictionary>::cast(backing_store);
1124 int capacity = dict->Capacity();
1125 uint32_t old_length = 0;
1126 CHECK(array->length()->ToArrayLength(&old_length));
1127 if (length < old_length) {
1128 if (dict->requires_slow_elements()) {
1129 // Find last non-deletable element in range of elements to be
1130 // deleted and adjust range accordingly.
1131 for (int entry = 0; entry < capacity; entry++) {
1132 DisallowHeapAllocation no_gc;
1133 Object* index = dict->KeyAt(entry);
1134 if (index->IsNumber()) {
1135 uint32_t number = static_cast<uint32_t>(index->Number());
1136 if (length <= number && number < old_length) {
1137 PropertyDetails details = dict->DetailsAt(entry);
1138 if (!details.IsConfigurable()) length = number + 1;
1139 }
1140 }
1141 }
1142 }
1143
1144 if (length == 0) {
1145 // Flush the backing store.
1146 JSObject::ResetElements(array);
1147 } else {
1148 DisallowHeapAllocation no_gc;
1149 // Remove elements that should be deleted.
1150 int removed_entries = 0;
1151 Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1152 for (int entry = 0; entry < capacity; entry++) {
1153 Object* index = dict->KeyAt(entry);
1154 if (index->IsNumber()) {
1155 uint32_t number = static_cast<uint32_t>(index->Number());
1156 if (length <= number && number < old_length) {
1157 dict->SetEntry(entry, the_hole_value, the_hole_value);
1158 removed_entries++;
1159 }
1160 }
1161 }
1162
1163 // Update the number of elements.
1164 dict->ElementsRemoved(removed_entries);
1165 }
1166 }
1167
1168 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1169 array->set_length(*length_obj);
1170 }
1171
1172 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1173 FixedArrayBase* to, ElementsKind from_kind,
1174 uint32_t to_start, int packed_size,
1175 int copy_size) {
1176 UNREACHABLE();
1177 }
1178
1179
1180 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1181 // TODO(verwaest): Remove reliance on index in Shrink.
1182 Handle<SeededNumberDictionary> dict(
1183 SeededNumberDictionary::cast(obj->elements()));
1184 uint32_t index = GetIndexForEntryImpl(*dict, entry);
1185 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1186 USE(result);
1187 DCHECK(result->IsTrue());
1188 Handle<FixedArray> new_elements =
1189 SeededNumberDictionary::Shrink(dict, index);
1190 obj->set_elements(*new_elements);
1191 }
1192
Ben Murdoch097c5b22016-05-18 11:27:45 +01001193 static bool HasAccessorsImpl(JSObject* holder,
1194 FixedArrayBase* backing_store) {
Ben Murdochda12d292016-06-02 14:46:10 +01001195 DisallowHeapAllocation no_gc;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001196 SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1197 if (!dict->requires_slow_elements()) return false;
1198 int capacity = dict->Capacity();
Ben Murdochda12d292016-06-02 14:46:10 +01001199 Heap* heap = holder->GetHeap();
1200 Object* undefined = heap->undefined_value();
1201 Object* the_hole = heap->the_hole_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001202 for (int i = 0; i < capacity; i++) {
1203 Object* key = dict->KeyAt(i);
Ben Murdochda12d292016-06-02 14:46:10 +01001204 if (key == the_hole || key == undefined) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001205 DCHECK(!dict->IsDeleted(i));
1206 PropertyDetails details = dict->DetailsAt(i);
1207 if (details.type() == ACCESSOR_CONSTANT) return true;
1208 }
1209 return false;
1210 }
1211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1213 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1214 return backing_store->ValueAt(entry);
1215 }
1216
Ben Murdoch097c5b22016-05-18 11:27:45 +01001217 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1218 return GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219 }
1220
Ben Murdoch097c5b22016-05-18 11:27:45 +01001221 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1222 return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
1223 }
1224
1225 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001226 Object* value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001227 SetImpl(holder->elements(), entry, value);
1228 }
1229
1230 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1231 Object* value) {
1232 SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001233 }
1234
1235 static void ReconfigureImpl(Handle<JSObject> object,
1236 Handle<FixedArrayBase> store, uint32_t entry,
1237 Handle<Object> value,
1238 PropertyAttributes attributes) {
1239 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1240 if (attributes != NONE) object->RequireSlowElements(dictionary);
1241 dictionary->ValueAtPut(entry, *value);
1242 PropertyDetails details = dictionary->DetailsAt(entry);
1243 details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1244 PropertyCellType::kNoCell);
1245 dictionary->DetailsAtPut(entry, details);
1246 }
1247
1248 static void AddImpl(Handle<JSObject> object, uint32_t index,
1249 Handle<Object> value, PropertyAttributes attributes,
1250 uint32_t new_capacity) {
1251 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1252 Handle<SeededNumberDictionary> dictionary =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001253 object->HasFastElements() || object->HasFastStringWrapperElements()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254 ? JSObject::NormalizeElements(object)
1255 : handle(SeededNumberDictionary::cast(object->elements()));
1256 Handle<SeededNumberDictionary> new_dictionary =
1257 SeededNumberDictionary::AddNumberEntry(
1258 dictionary, index, value, details,
1259 object->map()->is_prototype_map());
1260 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1261 if (dictionary.is_identical_to(new_dictionary)) return;
1262 object->set_elements(*new_dictionary);
1263 }
1264
1265 static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1266 DisallowHeapAllocation no_gc;
1267 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1268 Object* index = dict->KeyAt(entry);
1269 return !index->IsTheHole();
1270 }
1271
1272 static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1273 DisallowHeapAllocation no_gc;
1274 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1275 uint32_t result = 0;
1276 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1277 return result;
1278 }
1279
1280 static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1281 uint32_t index, PropertyFilter filter) {
1282 DisallowHeapAllocation no_gc;
1283 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1284 int entry = dictionary->FindEntry(index);
1285 if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1286 if (filter != ALL_PROPERTIES) {
1287 PropertyDetails details = dictionary->DetailsAt(entry);
1288 PropertyAttributes attr = details.attributes();
1289 if ((attr & filter) != 0) return kMaxUInt32;
1290 }
1291 return static_cast<uint32_t>(entry);
1292 }
1293
Ben Murdoch097c5b22016-05-18 11:27:45 +01001294 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1295 return GetDetailsImpl(holder->elements(), entry);
1296 }
1297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001298 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1299 uint32_t entry) {
1300 return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1301 }
1302
Ben Murdochda12d292016-06-02 14:46:10 +01001303 static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
1304 int entry, Object* raw_key, PropertyFilter filter) {
1305 DCHECK(!dictionary->IsDeleted(entry));
1306 DCHECK(raw_key->IsNumber());
1307 DCHECK_LE(raw_key->Number(), kMaxUInt32);
1308 PropertyDetails details = dictionary->DetailsAt(entry);
1309 PropertyAttributes attr = details.attributes();
1310 if ((attr & filter) != 0) return kMaxUInt32;
1311 return static_cast<uint32_t>(raw_key->Number());
1312 }
1313
1314 static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
1315 int entry, PropertyFilter filter) {
1316 DisallowHeapAllocation no_gc;
1317 Object* raw_key = dictionary->KeyAt(entry);
1318 if (!dictionary->IsKey(raw_key)) return kMaxUInt32;
1319 return FilterKey(dictionary, entry, raw_key, filter);
1320 }
1321
1322 static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
1323 int entry, PropertyFilter filter,
1324 Object* undefined, Object* the_hole) {
1325 DisallowHeapAllocation no_gc;
1326 Object* raw_key = dictionary->KeyAt(entry);
1327 // Replace the IsKey check with a direct comparison which is much faster.
1328 if (raw_key == undefined || raw_key == the_hole) {
1329 return kMaxUInt32;
1330 }
1331 return FilterKey(dictionary, entry, raw_key, filter);
1332 }
1333
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334 static void CollectElementIndicesImpl(Handle<JSObject> object,
1335 Handle<FixedArrayBase> backing_store,
1336 KeyAccumulator* keys, uint32_t range,
1337 PropertyFilter filter,
1338 uint32_t offset) {
Ben Murdochda12d292016-06-02 14:46:10 +01001339 if (filter & SKIP_STRINGS) return;
1340 Isolate* isolate = keys->isolate();
1341 Handle<Object> undefined = isolate->factory()->undefined_value();
1342 Handle<Object> the_hole = isolate->factory()->the_hole_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 Handle<SeededNumberDictionary> dictionary =
1344 Handle<SeededNumberDictionary>::cast(backing_store);
1345 int capacity = dictionary->Capacity();
1346 for (int i = 0; i < capacity; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +01001347 uint32_t key =
1348 GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
1349 if (key == kMaxUInt32) continue;
1350 keys->AddKey(key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 }
1352
1353 keys->SortCurrentElementsList();
1354 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001355
Ben Murdochda12d292016-06-02 14:46:10 +01001356 static Handle<FixedArray> DirectCollectElementIndicesImpl(
1357 Isolate* isolate, Handle<JSObject> object,
1358 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1359 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1360 uint32_t insertion_index = 0) {
1361 if (filter & SKIP_STRINGS) return list;
1362 if (filter & ONLY_ALL_CAN_READ) return list;
1363
1364 Handle<Object> undefined = isolate->factory()->undefined_value();
1365 Handle<Object> the_hole = isolate->factory()->the_hole_value();
1366 Handle<SeededNumberDictionary> dictionary =
1367 Handle<SeededNumberDictionary>::cast(backing_store);
1368 uint32_t capacity = dictionary->Capacity();
1369 for (uint32_t i = 0; i < capacity; i++) {
1370 uint32_t key =
1371 GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
1372 if (key == kMaxUInt32) continue;
1373 Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
1374 list->set(insertion_index, *index);
1375 insertion_index++;
1376 }
1377 *nof_indices = insertion_index;
1378 return list;
1379 }
1380
Ben Murdoch097c5b22016-05-18 11:27:45 +01001381 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1382 KeyAccumulator* accumulator,
1383 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01001384 Isolate* isolate = accumulator->isolate();
1385 Handle<Object> undefined = isolate->factory()->undefined_value();
1386 Handle<Object> the_hole = isolate->factory()->the_hole_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001387 SeededNumberDictionary* dictionary =
1388 SeededNumberDictionary::cast(receiver->elements());
1389 int capacity = dictionary->Capacity();
1390 for (int i = 0; i < capacity; i++) {
1391 Object* k = dictionary->KeyAt(i);
Ben Murdochda12d292016-06-02 14:46:10 +01001392 if (k == *undefined) continue;
1393 if (k == *the_hole) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001394 if (dictionary->IsDeleted(i)) continue;
1395 Object* value = dictionary->ValueAt(i);
1396 DCHECK(!value->IsTheHole());
1397 DCHECK(!value->IsAccessorPair());
1398 DCHECK(!value->IsAccessorInfo());
1399 accumulator->AddKey(value, convert);
1400 }
1401 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001402};
1403
1404
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001405// Super class for all fast element arrays.
1406template<typename FastElementsAccessorSubclass,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001407 typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001408class FastElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001409 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001410 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001411 explicit FastElementsAccessor(const char* name)
1412 : ElementsAccessorBase<FastElementsAccessorSubclass,
1413 KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001414
1415 typedef typename KindTraits::BackingStore BackingStore;
1416
Ben Murdochda12d292016-06-02 14:46:10 +01001417 static Handle<SeededNumberDictionary> NormalizeImpl(
1418 Handle<JSObject> object, Handle<FixedArrayBase> store) {
1419 Isolate* isolate = store->GetIsolate();
1420 ElementsKind kind = FastElementsAccessorSubclass::kind();
1421
1422 // Ensure that notifications fire if the array or object prototypes are
1423 // normalizing.
1424 if (IsFastSmiOrObjectElementsKind(kind)) {
1425 isolate->UpdateArrayProtectorOnNormalizeElements(object);
1426 }
1427
1428 int capacity = object->GetFastElementsUsage();
1429 Handle<SeededNumberDictionary> dictionary =
1430 SeededNumberDictionary::New(isolate, capacity);
1431
1432 PropertyDetails details = PropertyDetails::Empty();
1433 bool used_as_prototype = object->map()->is_prototype_map();
1434 int j = 0;
1435 for (int i = 0; j < capacity; i++) {
1436 if (IsHoleyElementsKind(kind)) {
1437 if (BackingStore::cast(*store)->is_the_hole(i)) continue;
1438 }
1439 Handle<Object> value = FastElementsAccessorSubclass::GetImpl(*store, i);
1440 dictionary = SeededNumberDictionary::AddNumberEntry(
1441 dictionary, i, value, details, used_as_prototype);
1442 j++;
1443 }
1444 return dictionary;
1445 }
1446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 static void DeleteAtEnd(Handle<JSObject> obj,
1448 Handle<BackingStore> backing_store, uint32_t entry) {
1449 uint32_t length = static_cast<uint32_t>(backing_store->length());
1450 Heap* heap = obj->GetHeap();
1451 for (; entry > 0; entry--) {
1452 if (!backing_store->is_the_hole(entry - 1)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001453 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454 if (entry == 0) {
1455 FixedArray* empty = heap->empty_fixed_array();
1456 if (obj->HasFastArgumentsElements()) {
1457 FixedArray::cast(obj->elements())->set(1, empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001458 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459 obj->set_elements(empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001460 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001462 }
1463
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001464 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1465 length - entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001466 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1469 Handle<FixedArrayBase> store) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001470 DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
1471 obj->HasFastArgumentsElements() ||
1472 obj->HasFastStringWrapperElements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001473 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1474 if (!obj->IsJSArray() &&
1475 entry == static_cast<uint32_t>(store->length()) - 1) {
1476 DeleteAtEnd(obj, backing_store, entry);
1477 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479
1480 backing_store->set_the_hole(entry);
1481
1482 // TODO(verwaest): Move this out of elements.cc.
1483 // If an old space backing store is larger than a certain size and
1484 // has too few used values, normalize it.
1485 // To avoid doing the check on every delete we require at least
1486 // one adjacent hole to the value being deleted.
1487 const int kMinLengthForSparsenessCheck = 64;
1488 if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1489 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1490 uint32_t length = 0;
1491 if (obj->IsJSArray()) {
1492 JSArray::cast(*obj)->length()->ToArrayLength(&length);
1493 } else {
1494 length = static_cast<uint32_t>(store->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001495 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001496 if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1497 (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1498 if (!obj->IsJSArray()) {
1499 uint32_t i;
1500 for (i = entry + 1; i < length; i++) {
1501 if (!backing_store->is_the_hole(i)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503 if (i == length) {
1504 DeleteAtEnd(obj, backing_store, entry);
1505 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001506 }
1507 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 int num_used = 0;
1509 for (int i = 0; i < backing_store->length(); ++i) {
1510 if (!backing_store->is_the_hole(i)) {
1511 ++num_used;
1512 // Bail out if a number dictionary wouldn't be able to save at least
1513 // 75% space.
1514 if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1515 SeededNumberDictionary::kEntrySize >
1516 backing_store->length()) {
1517 return;
1518 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001519 }
1520 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 JSObject::NormalizeElements(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001522 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001523 }
1524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001525 static void ReconfigureImpl(Handle<JSObject> object,
1526 Handle<FixedArrayBase> store, uint32_t entry,
1527 Handle<Object> value,
1528 PropertyAttributes attributes) {
1529 Handle<SeededNumberDictionary> dictionary =
1530 JSObject::NormalizeElements(object);
1531 entry = dictionary->FindEntry(entry);
1532 DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1533 value, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 }
1535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 static void AddImpl(Handle<JSObject> object, uint32_t index,
1537 Handle<Object> value, PropertyAttributes attributes,
1538 uint32_t new_capacity) {
1539 DCHECK_EQ(NONE, attributes);
1540 ElementsKind from_kind = object->GetElementsKind();
1541 ElementsKind to_kind = FastElementsAccessorSubclass::kind();
1542 if (IsDictionaryElementsKind(from_kind) ||
1543 IsFastDoubleElementsKind(from_kind) !=
1544 IsFastDoubleElementsKind(to_kind) ||
1545 FastElementsAccessorSubclass::GetCapacityImpl(
1546 *object, object->elements()) != new_capacity) {
1547 FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
1548 new_capacity);
1549 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001550 if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 JSObject::TransitionElementsKind(object, to_kind);
1552 }
1553 if (IsFastSmiOrObjectElementsKind(from_kind)) {
1554 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1555 JSObject::EnsureWritableFastElements(object);
1556 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001557 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001558 FastElementsAccessorSubclass::SetImpl(object, index, *value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 }
1560
1561 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1562 ElementsKind kind = KindTraits::Kind;
1563 if (IsFastPackedElementsKind(kind)) {
1564 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1565 }
1566 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1567 JSObject::EnsureWritableFastElements(obj);
1568 }
1569 DeleteCommon(obj, entry, handle(obj->elements()));
1570 }
1571
1572 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1573 return !BackingStore::cast(backing_store)->is_the_hole(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001574 }
1575
Ben Murdoch097c5b22016-05-18 11:27:45 +01001576 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1577 KeyAccumulator* accumulator,
1578 AddKeyConversion convert) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001579 Handle<FixedArrayBase> elements(receiver->elements(),
1580 receiver->GetIsolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001581 uint32_t length =
1582 FastElementsAccessorSubclass::GetIterationLength(*receiver, *elements);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001583 for (uint32_t i = 0; i < length; i++) {
1584 if (IsFastPackedElementsKind(KindTraits::Kind) ||
1585 HasEntryImpl(*elements, i)) {
1586 accumulator->AddKey(FastElementsAccessorSubclass::GetImpl(*elements, i),
1587 convert);
1588 }
1589 }
1590 }
1591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592 static void ValidateContents(Handle<JSObject> holder, int length) {
1593#if DEBUG
1594 Isolate* isolate = holder->GetIsolate();
1595 HandleScope scope(isolate);
1596 Handle<FixedArrayBase> elements(holder->elements(), isolate);
1597 Map* map = elements->map();
1598 DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
1599 (map == isolate->heap()->fixed_array_map() ||
1600 map == isolate->heap()->fixed_cow_array_map())) ||
1601 (IsFastDoubleElementsKind(KindTraits::Kind) ==
1602 ((map == isolate->heap()->fixed_array_map() && length == 0) ||
1603 map == isolate->heap()->fixed_double_array_map())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001604 if (length == 0) return; // nothing to do!
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001605 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001606 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1607 if (IsFastSmiElementsKind(KindTraits::Kind)) {
1608 for (int i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001609 DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610 (IsFastHoleyElementsKind(KindTraits::Kind) &&
1611 backing_store->is_the_hole(i)));
1612 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 }
1614#endif
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001615 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001616
Ben Murdochda12d292016-06-02 14:46:10 +01001617 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
1618 return FastElementsAccessorSubclass::RemoveElement(receiver, AT_END);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001619 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001620
Ben Murdochda12d292016-06-02 14:46:10 +01001621 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
1622 return FastElementsAccessorSubclass::RemoveElement(receiver, AT_START);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001623 }
1624
1625 static uint32_t PushImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626 Arguments* args, uint32_t push_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001627 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
1629 args, push_size, AT_END);
1630 }
1631
1632 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001633 Arguments* args, uint32_t unshift_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001634 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001635 return FastElementsAccessorSubclass::AddArguments(
1636 receiver, backing_store, args, unshift_size, AT_START);
1637 }
1638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001639 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 uint32_t start, uint32_t end) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001642 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1643 int result_len = end < start ? 0u : end - start;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001644 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1645 KindTraits::Kind, result_len, result_len);
1646 DisallowHeapAllocation no_gc;
1647 FastElementsAccessorSubclass::CopyElementsImpl(
1648 *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
1649 kPackedSizeNotKnown, result_len);
1650 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1651 result_array);
1652 return result_array;
1653 }
1654
1655 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 uint32_t start, uint32_t delete_count,
1657 Arguments* args, uint32_t add_count) {
1658 Isolate* isolate = receiver->GetIsolate();
1659 Heap* heap = isolate->heap();
1660 uint32_t length = Smi::cast(receiver->length())->value();
1661 uint32_t new_length = length - delete_count + add_count;
1662
Ben Murdochda12d292016-06-02 14:46:10 +01001663 ElementsKind kind = KindTraits::Kind;
1664 if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
1665 IsFastSmiOrObjectElementsKind(kind)) {
1666 HandleScope scope(isolate);
1667 JSObject::EnsureWritableFastElements(receiver);
1668 }
1669
1670 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 if (new_length == 0) {
1673 receiver->set_elements(heap->empty_fixed_array());
1674 receiver->set_length(Smi::FromInt(0));
1675 return isolate->factory()->NewJSArrayWithElements(
1676 backing_store, KindTraits::Kind, delete_count);
1677 }
1678
1679 // Construct the result array which holds the deleted elements.
1680 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1681 KindTraits::Kind, delete_count, delete_count);
1682 if (delete_count > 0) {
1683 DisallowHeapAllocation no_gc;
1684 FastElementsAccessorSubclass::CopyElementsImpl(
1685 *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
1686 0, kPackedSizeNotKnown, delete_count);
1687 }
1688
1689 // Delete and move elements to make space for add_count new elements.
1690 if (add_count < delete_count) {
1691 FastElementsAccessorSubclass::SpliceShrinkStep(
1692 isolate, receiver, backing_store, start, delete_count, add_count,
1693 length, new_length);
1694 } else if (add_count > delete_count) {
1695 backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
1696 isolate, receiver, backing_store, start, delete_count, add_count,
1697 length, new_length);
1698 }
1699
1700 // Copy over the arguments.
1701 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
1702 3, start);
1703
1704 receiver->set_length(Smi::FromInt(new_length));
1705 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1706 deleted_elements);
1707 return deleted_elements;
1708 }
1709
Ben Murdochda12d292016-06-02 14:46:10 +01001710 static Maybe<bool> CollectValuesOrEntriesImpl(
1711 Isolate* isolate, Handle<JSObject> object,
1712 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
1713 PropertyFilter filter) {
1714 int count = 0;
1715 uint32_t length = object->elements()->length();
1716 for (uint32_t index = 0; index < length; ++index) {
1717 if (!HasEntryImpl(object->elements(), index)) continue;
1718 Handle<Object> value =
1719 FastElementsAccessorSubclass::GetImpl(object->elements(), index);
1720 if (get_entries) {
1721 value = MakeEntryPair(isolate, index, value);
1722 }
1723 values_or_entries->set(count++, *value);
1724 }
1725 *nof_items = count;
1726 return Just(true);
1727 }
1728
1729 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1730 Handle<FixedArrayBase> backing_store, int dst_index,
1731 int src_index, int len, int hole_start,
1732 int hole_end) {
1733 Heap* heap = isolate->heap();
1734 Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
1735 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1736 // Update all the copies of this backing_store handle.
1737 *dst_elms.location() =
1738 BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1739 receiver->set_elements(*dst_elms);
1740 // Adjust the hole offset as the array has been shrunk.
1741 hole_end -= src_index;
1742 DCHECK_LE(hole_start, backing_store->length());
1743 DCHECK_LE(hole_end, backing_store->length());
1744 } else if (len != 0) {
1745 if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1746 MemMove(dst_elms->data_start() + dst_index,
1747 dst_elms->data_start() + src_index, len * kDoubleSize);
1748 } else {
1749 DisallowHeapAllocation no_gc;
1750 heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
1751 len);
1752 }
1753 }
1754 if (hole_start != hole_end) {
1755 dst_elms->FillWithHoles(hole_start, hole_end);
1756 }
1757 }
1758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001759 private:
1760 // SpliceShrinkStep might modify the backing_store.
1761 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1762 Handle<FixedArrayBase> backing_store,
1763 uint32_t start, uint32_t delete_count,
1764 uint32_t add_count, uint32_t len,
1765 uint32_t new_length) {
1766 const int move_left_count = len - delete_count - start;
1767 const int move_left_dst_index = start + add_count;
1768 FastElementsAccessorSubclass::MoveElements(
1769 isolate, receiver, backing_store, move_left_dst_index,
1770 start + delete_count, move_left_count, new_length, len);
1771 }
1772
1773 // SpliceGrowStep might modify the backing_store.
1774 static Handle<FixedArrayBase> SpliceGrowStep(
1775 Isolate* isolate, Handle<JSArray> receiver,
1776 Handle<FixedArrayBase> backing_store, uint32_t start,
1777 uint32_t delete_count, uint32_t add_count, uint32_t length,
1778 uint32_t new_length) {
1779 // Check we do not overflow the new_length.
1780 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1781 // Check if backing_store is big enough.
1782 if (new_length <= static_cast<uint32_t>(backing_store->length())) {
1783 FastElementsAccessorSubclass::MoveElements(
1784 isolate, receiver, backing_store, start + add_count,
1785 start + delete_count, (length - delete_count - start), 0, 0);
1786 // MoveElements updates the backing_store in-place.
1787 return backing_store;
1788 }
1789 // New backing storage is needed.
1790 int capacity = JSObject::NewElementsCapacity(new_length);
1791 // Partially copy all elements up to start.
1792 Handle<FixedArrayBase> new_elms =
1793 FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1794 receiver, backing_store, KindTraits::Kind, capacity, start);
1795 // Copy the trailing elements after start + delete_count
1796 FastElementsAccessorSubclass::CopyElementsImpl(
1797 *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
1798 start + add_count, kPackedSizeNotKnown,
1799 ElementsAccessor::kCopyToEndAndInitializeToHole);
1800 receiver->set_elements(*new_elms);
1801 return new_elms;
1802 }
1803
1804 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001805 Where remove_position) {
1806 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001807 ElementsKind kind = KindTraits::Kind;
1808 if (IsFastSmiOrObjectElementsKind(kind)) {
1809 HandleScope scope(isolate);
1810 JSObject::EnsureWritableFastElements(receiver);
1811 }
1812 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001813 uint32_t length =
1814 static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1815 DCHECK(length > 0);
1816 int new_length = length - 1;
1817 int remove_index = remove_position == AT_START ? 0 : new_length;
1818 Handle<Object> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001819 FastElementsAccessorSubclass::GetImpl(*backing_store, remove_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820 if (remove_position == AT_START) {
1821 FastElementsAccessorSubclass::MoveElements(
1822 isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
1823 }
1824 FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
1825 backing_store);
1826
Ben Murdochda12d292016-06-02 14:46:10 +01001827 if (IsHoleyElementsKind(kind) && result->IsTheHole()) {
1828 return isolate->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001829 }
1830 return result;
1831 }
1832
1833 static uint32_t AddArguments(Handle<JSArray> receiver,
1834 Handle<FixedArrayBase> backing_store,
1835 Arguments* args, uint32_t add_size,
1836 Where remove_position) {
1837 uint32_t length = Smi::cast(receiver->length())->value();
Ben Murdochda12d292016-06-02 14:46:10 +01001838 DCHECK(0 < add_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 uint32_t elms_len = backing_store->length();
1840 // Check we do not overflow the new_length.
1841 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1842 uint32_t new_length = length + add_size;
1843
1844 if (new_length > elms_len) {
1845 // New backing storage is needed.
1846 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1847 // If we add arguments to the start we have to shift the existing objects.
1848 int copy_dst_index = remove_position == AT_START ? add_size : 0;
1849 // Copy over all objects to a new backing_store.
1850 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1851 receiver, backing_store, KindTraits::Kind, capacity, 0,
1852 copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1853 receiver->set_elements(*backing_store);
1854 } else if (remove_position == AT_START) {
1855 // If the backing store has enough capacity and we add elements to the
1856 // start we have to shift the existing objects.
1857 Isolate* isolate = receiver->GetIsolate();
1858 FastElementsAccessorSubclass::MoveElements(
1859 isolate, receiver, backing_store, add_size, 0, length, 0, 0);
1860 }
1861
1862 int insertion_index = remove_position == AT_START ? 0 : length;
1863 // Copy the arguments to the start.
1864 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
1865 1, insertion_index);
1866 // Set the length.
1867 receiver->set_length(Smi::FromInt(new_length));
1868 return new_length;
1869 }
1870
1871 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1872 uint32_t copy_size, uint32_t src_index,
1873 uint32_t dst_index) {
1874 // Add the provided values.
1875 DisallowHeapAllocation no_gc;
1876 FixedArrayBase* raw_backing_store = *dst_store;
1877 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1878 for (uint32_t i = 0; i < copy_size; i++) {
1879 Object* argument = (*args)[i + src_index];
1880 FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
1881 argument, mode);
1882 }
1883 }
1884};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001885
1886
1887template<typename FastElementsAccessorSubclass,
1888 typename KindTraits>
1889class FastSmiOrObjectElementsAccessor
1890 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1891 public:
1892 explicit FastSmiOrObjectElementsAccessor(const char* name)
1893 : FastElementsAccessor<FastElementsAccessorSubclass,
1894 KindTraits>(name) {}
1895
Ben Murdoch097c5b22016-05-18 11:27:45 +01001896 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1897 Object* value) {
1898 SetImpl(holder->elements(), entry, value);
1899 }
1900
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1902 Object* value) {
1903 FixedArray::cast(backing_store)->set(entry, value);
1904 }
1905
1906 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1907 Object* value, WriteBarrierMode mode) {
1908 FixedArray::cast(backing_store)->set(entry, value, mode);
1909 }
1910
1911 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
1912 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
1913 backing_store, entry);
1914 return backing_store->get(index);
1915 }
1916
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001917
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001918 // NOTE: this method violates the handlified function signature convention:
1919 // raw pointer parameters in the function that allocates.
1920 // See ElementsAccessor::CopyElements() for details.
1921 // This method could actually allocate if copying from double elements to
1922 // object elements.
1923 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1924 FixedArrayBase* to, ElementsKind from_kind,
1925 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001927 DisallowHeapAllocation no_gc;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001928 ElementsKind to_kind = KindTraits::Kind;
1929 switch (from_kind) {
1930 case FAST_SMI_ELEMENTS:
1931 case FAST_HOLEY_SMI_ELEMENTS:
1932 case FAST_ELEMENTS:
1933 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001934 case FAST_STRING_WRAPPER_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001935 CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 to_start, copy_size);
1937 break;
1938 case FAST_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001939 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1940 AllowHeapAllocation allow_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001941 DCHECK(IsFastObjectElementsKind(to_kind));
1942 CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001944 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001945 case DICTIONARY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001946 case SLOW_STRING_WRAPPER_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001947 CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1948 copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001949 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001950 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1951 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001952#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001953 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1954#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01001955 // This function is currently only used for JSArrays with non-zero
1956 // length.
1957 UNREACHABLE();
1958 break;
1959 case NO_ELEMENTS:
1960 break; // Nothing to do.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 }
1962 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001963};
1964
1965
1966class FastPackedSmiElementsAccessor
1967 : public FastSmiOrObjectElementsAccessor<
1968 FastPackedSmiElementsAccessor,
1969 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1970 public:
1971 explicit FastPackedSmiElementsAccessor(const char* name)
1972 : FastSmiOrObjectElementsAccessor<
1973 FastPackedSmiElementsAccessor,
1974 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1975};
1976
1977
1978class FastHoleySmiElementsAccessor
1979 : public FastSmiOrObjectElementsAccessor<
1980 FastHoleySmiElementsAccessor,
1981 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1982 public:
1983 explicit FastHoleySmiElementsAccessor(const char* name)
1984 : FastSmiOrObjectElementsAccessor<
1985 FastHoleySmiElementsAccessor,
1986 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1987};
1988
1989
1990class FastPackedObjectElementsAccessor
1991 : public FastSmiOrObjectElementsAccessor<
1992 FastPackedObjectElementsAccessor,
1993 ElementsKindTraits<FAST_ELEMENTS> > {
1994 public:
1995 explicit FastPackedObjectElementsAccessor(const char* name)
1996 : FastSmiOrObjectElementsAccessor<
1997 FastPackedObjectElementsAccessor,
1998 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1999};
2000
2001
2002class FastHoleyObjectElementsAccessor
2003 : public FastSmiOrObjectElementsAccessor<
2004 FastHoleyObjectElementsAccessor,
2005 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
2006 public:
2007 explicit FastHoleyObjectElementsAccessor(const char* name)
2008 : FastSmiOrObjectElementsAccessor<
2009 FastHoleyObjectElementsAccessor,
2010 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
2011};
2012
2013
2014template<typename FastElementsAccessorSubclass,
2015 typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002016class FastDoubleElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002017 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002018 public:
2019 explicit FastDoubleElementsAccessor(const char* name)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002020 : FastElementsAccessor<FastElementsAccessorSubclass,
2021 KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002022
Ben Murdoch097c5b22016-05-18 11:27:45 +01002023 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2024 return GetImpl(holder->elements(), entry);
2025 }
2026
2027 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2028 Isolate* isolate = backing_store->GetIsolate();
2029 return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
2030 isolate);
2031 }
2032
2033 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2034 Object* value) {
2035 SetImpl(holder->elements(), entry, value);
2036 }
2037
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002038 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2039 Object* value) {
2040 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002041 }
2042
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002043 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2044 Object* value, WriteBarrierMode mode) {
2045 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2046 }
2047
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002048 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2049 FixedArrayBase* to, ElementsKind from_kind,
2050 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002051 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002052 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002053 switch (from_kind) {
2054 case FAST_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002055 CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056 packed_size, copy_size);
2057 break;
2058 case FAST_HOLEY_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002059 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002061 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 case FAST_HOLEY_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002063 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002064 break;
2065 case FAST_ELEMENTS:
2066 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002067 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002068 break;
2069 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002070 CopyDictionaryToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 copy_size);
2072 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002073 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2074 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002075 case FAST_STRING_WRAPPER_ELEMENTS:
2076 case SLOW_STRING_WRAPPER_ELEMENTS:
2077 case NO_ELEMENTS:
2078#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2080#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01002081 // This function is currently only used for JSArrays with non-zero
2082 // length.
2083 UNREACHABLE();
2084 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002085 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002086 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002087};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002088
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089
2090class FastPackedDoubleElementsAccessor
2091 : public FastDoubleElementsAccessor<
2092 FastPackedDoubleElementsAccessor,
2093 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
2094 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002095 explicit FastPackedDoubleElementsAccessor(const char* name)
2096 : FastDoubleElementsAccessor<
2097 FastPackedDoubleElementsAccessor,
2098 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
2099};
2100
2101
2102class FastHoleyDoubleElementsAccessor
2103 : public FastDoubleElementsAccessor<
2104 FastHoleyDoubleElementsAccessor,
2105 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
2106 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002107 explicit FastHoleyDoubleElementsAccessor(const char* name)
2108 : FastDoubleElementsAccessor<
2109 FastHoleyDoubleElementsAccessor,
2110 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002111};
2112
2113
2114// Super class for all external element arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002115template<ElementsKind Kind>
2116class TypedElementsAccessor
2117 : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002118 ElementsKindTraits<Kind> > {
2119 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002120 explicit TypedElementsAccessor(const char* name)
2121 : ElementsAccessorBase<AccessorClass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002122 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002123
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002124 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002125 typedef TypedElementsAccessor<Kind> AccessorClass;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002126
Ben Murdoch097c5b22016-05-18 11:27:45 +01002127 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2128 Object* value) {
2129 SetImpl(holder->elements(), entry, value);
2130 }
2131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002132 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2133 Object* value) {
2134 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002135 }
2136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002137 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2138 Object* value, WriteBarrierMode mode) {
2139 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002140 }
2141
Ben Murdoch097c5b22016-05-18 11:27:45 +01002142 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2143 return GetImpl(holder->elements(), entry);
2144 }
2145
2146 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2147 return BackingStore::get(BackingStore::cast(backing_store), entry);
2148 }
2149
2150 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2151 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002152 }
2153
2154 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
2155 uint32_t entry) {
2156 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
2157 }
2158
Ben Murdoch097c5b22016-05-18 11:27:45 +01002159 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
2160 Handle<FixedArrayBase> backing_store,
2161 PropertyFilter filter) {
2162 return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
2163 }
2164
2165 static bool HasAccessorsImpl(JSObject* holder,
2166 FixedArrayBase* backing_store) {
2167 return false;
2168 }
2169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002170 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2171 uint32_t length,
2172 Handle<FixedArrayBase> backing_store) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002173 // External arrays do not support changing their length.
2174 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002175 }
2176
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002177 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2178 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002179 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002180
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002181 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
2182 uint32_t entry) {
2183 return entry;
2184 }
2185
2186 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2187 FixedArrayBase* backing_store,
2188 uint32_t index, PropertyFilter filter) {
2189 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
2190 ? index
2191 : kMaxUInt32;
2192 }
2193
2194 static uint32_t GetCapacityImpl(JSObject* holder,
2195 FixedArrayBase* backing_store) {
2196 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
2197 if (view->WasNeutered()) return 0;
2198 return backing_store->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002199 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002200
2201 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2202 KeyAccumulator* accumulator,
2203 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01002204 Handle<FixedArrayBase> elements(receiver->elements());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002205 uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
2206 for (uint32_t i = 0; i < length; i++) {
2207 Handle<Object> value = AccessorClass::GetImpl(*elements, i);
2208 accumulator->AddKey(value, convert);
2209 }
2210 }
Ben Murdochda12d292016-06-02 14:46:10 +01002211
2212 static Maybe<bool> CollectValuesOrEntriesImpl(
2213 Isolate* isolate, Handle<JSObject> object,
2214 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2215 PropertyFilter filter) {
2216 int count = 0;
2217 if ((filter & ONLY_CONFIGURABLE) == 0) {
2218 Handle<FixedArrayBase> elements(object->elements());
2219 uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements);
2220 for (uint32_t index = 0; index < length; ++index) {
2221 Handle<Object> value = AccessorClass::GetImpl(*elements, index);
2222 if (get_entries) {
2223 value = MakeEntryPair(isolate, index, value);
2224 }
2225 values_or_entries->set(count++, *value);
2226 }
2227 }
2228 *nof_items = count;
2229 return Just(true);
2230 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002231};
2232
2233
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002234
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002235#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
2236 typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
2237 Fixed##Type##ElementsAccessor;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002238
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002239TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
2240#undef FIXED_ELEMENTS_ACCESSOR
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002241
2242
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002243template <typename SloppyArgumentsElementsAccessorSubclass,
2244 typename ArgumentsAccessor, typename KindTraits>
2245class SloppyArgumentsElementsAccessor
2246 : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
2247 KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002248 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002249 explicit SloppyArgumentsElementsAccessor(const char* name)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002250 : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
2251 KindTraits>(name) {
2252 USE(KindTraits::Kind);
2253 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002254
Ben Murdoch097c5b22016-05-18 11:27:45 +01002255 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2256 return GetImpl(holder->elements(), entry);
2257 }
2258
2259 static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002260 Isolate* isolate = parameters->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002261 Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002262 uint32_t length = parameter_map->length() - 2;
2263 if (entry < length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002264 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002265 Object* probe = parameter_map->get(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002266 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002267 int context_entry = Smi::cast(probe)->value();
2268 DCHECK(!context->get(context_entry)->IsTheHole());
2269 return handle(context->get(context_entry), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002270 } else {
2271 // Object is not mapped, defer to the arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002272 Handle<Object> result = ArgumentsAccessor::GetImpl(
2273 FixedArray::cast(parameter_map->get(1)), entry - length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002274 // Elements of the arguments object in slow mode might be slow aliases.
2275 if (result->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002277 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002278 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002279 int context_entry = alias->aliased_context_slot();
2280 DCHECK(!context->get(context_entry)->IsTheHole());
2281 return handle(context->get(context_entry), isolate);
2282 }
2283 return result;
2284 }
2285 }
2286
2287 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2288 uint32_t capacity) {
2289 UNREACHABLE();
2290 }
2291
Ben Murdoch097c5b22016-05-18 11:27:45 +01002292 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2293 Object* value) {
2294 SetImpl(holder->elements(), entry, value);
2295 }
2296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002297 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
2298 Object* value) {
2299 FixedArray* parameter_map = FixedArray::cast(store);
2300 uint32_t length = parameter_map->length() - 2;
2301 if (entry < length) {
2302 Object* probe = parameter_map->get(entry + 2);
2303 Context* context = Context::cast(parameter_map->get(0));
2304 int context_entry = Smi::cast(probe)->value();
2305 DCHECK(!context->get(context_entry)->IsTheHole());
2306 context->set(context_entry, value);
2307 } else {
2308 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2309 Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
2310 if (current->IsAliasedArgumentsEntry()) {
2311 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
2312 Context* context = Context::cast(parameter_map->get(0));
2313 int context_entry = alias->aliased_context_slot();
2314 DCHECK(!context->get(context_entry)->IsTheHole());
2315 context->set(context_entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002316 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002317 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002318 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002319 }
2320 }
2321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002322 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2323 uint32_t length,
2324 Handle<FixedArrayBase> parameter_map) {
2325 // Sloppy arguments objects are not arrays.
2326 UNREACHABLE();
2327 }
2328
2329 static uint32_t GetCapacityImpl(JSObject* holder,
2330 FixedArrayBase* backing_store) {
2331 FixedArray* parameter_map = FixedArray::cast(backing_store);
2332 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2333 return parameter_map->length() - 2 +
2334 ArgumentsAccessor::GetCapacityImpl(holder, arguments);
2335 }
2336
Ben Murdoch097c5b22016-05-18 11:27:45 +01002337 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2338 KeyAccumulator* accumulator,
2339 AddKeyConversion convert) {
2340 FixedArrayBase* elements = receiver->elements();
2341 uint32_t length = GetCapacityImpl(*receiver, elements);
2342 for (uint32_t entry = 0; entry < length; entry++) {
2343 if (!HasEntryImpl(elements, entry)) continue;
2344 Handle<Object> value = GetImpl(elements, entry);
2345 accumulator->AddKey(value, convert);
2346 }
2347 }
2348
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002349 static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
2350 FixedArray* parameter_map = FixedArray::cast(parameters);
2351 uint32_t length = parameter_map->length() - 2;
2352 if (entry < length) {
2353 return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002354 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002355
2356 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2357 return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002358 }
2359
Ben Murdoch097c5b22016-05-18 11:27:45 +01002360 static bool HasAccessorsImpl(JSObject* holder,
2361 FixedArrayBase* backing_store) {
2362 FixedArray* parameter_map = FixedArray::cast(backing_store);
2363 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2364 return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
2365 }
2366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002367 static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
2368 uint32_t entry) {
2369 FixedArray* parameter_map = FixedArray::cast(parameters);
2370 uint32_t length = parameter_map->length() - 2;
2371 if (entry < length) return entry;
2372
2373 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2374 return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
2375 }
2376
2377 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2378 FixedArrayBase* parameters,
2379 uint32_t index, PropertyFilter filter) {
2380 FixedArray* parameter_map = FixedArray::cast(parameters);
2381 Object* probe = GetParameterMapArg(parameter_map, index);
2382 if (!probe->IsTheHole()) return index;
2383
2384 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2385 uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
2386 index, filter);
2387 if (entry == kMaxUInt32) return entry;
2388 return (parameter_map->length() - 2) + entry;
2389 }
2390
Ben Murdoch097c5b22016-05-18 11:27:45 +01002391 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2392 FixedArray* parameter_map = FixedArray::cast(holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002393 uint32_t length = parameter_map->length() - 2;
2394 if (entry < length) {
2395 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2398 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399 }
2400
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002401 static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2402 uint32_t length = parameter_map->length() - 2;
2403 return index < length
2404 ? parameter_map->get(index + 2)
2405 : Object::cast(parameter_map->GetHeap()->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002406 }
2407
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002408 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2409 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2410 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2411 if (entry < length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002412 // TODO(kmillikin): We could check if this was the last aliased
2413 // parameter, and revert to normal elements in that case. That
2414 // would enable GC of the context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002415 parameter_map->set_the_hole(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002416 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002417 SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
2418 obj, entry - length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002419 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002420 }
Ben Murdochda12d292016-06-02 14:46:10 +01002421
2422 static void CollectElementIndicesImpl(Handle<JSObject> object,
2423 Handle<FixedArrayBase> backing_store,
2424 KeyAccumulator* keys, uint32_t range,
2425 PropertyFilter filter,
2426 uint32_t offset) {
2427 FixedArray* parameter_map = FixedArray::cast(*backing_store);
2428 uint32_t length = parameter_map->length() - 2;
2429 if (range < length) length = range;
2430
2431 for (uint32_t i = offset; i < length; ++i) {
2432 if (!parameter_map->get(i + 2)->IsTheHole()) {
2433 keys->AddKey(i);
2434 }
2435 }
2436
2437 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
2438 ArgumentsAccessor::CollectElementIndicesImpl(object, store, keys, range,
2439 filter, offset);
2440 if (SloppyArgumentsElementsAccessorSubclass::kind() ==
2441 FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
2442 keys->SortCurrentElementsList();
2443 }
2444 }
2445
2446 static Handle<FixedArray> DirectCollectElementIndicesImpl(
2447 Isolate* isolate, Handle<JSObject> object,
2448 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
2449 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
2450 uint32_t insertion_index = 0) {
2451 FixedArray* parameter_map = FixedArray::cast(*backing_store);
2452 uint32_t length = parameter_map->length() - 2;
2453
2454 for (uint32_t i = 0; i < length; ++i) {
2455 if (parameter_map->get(i + 2)->IsTheHole()) continue;
2456 if (convert == CONVERT_TO_STRING) {
2457 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
2458 list->set(insertion_index, *index_string);
2459 } else {
2460 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
2461 }
2462 insertion_index++;
2463 }
2464
2465 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
2466 return ArgumentsAccessor::DirectCollectElementIndicesImpl(
2467 isolate, object, store, convert, filter, list, nof_indices,
2468 insertion_index);
2469 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002470};
2471
2472
2473class SlowSloppyArgumentsElementsAccessor
2474 : public SloppyArgumentsElementsAccessor<
2475 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2476 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2477 public:
2478 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2479 : SloppyArgumentsElementsAccessor<
2480 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2481 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2482
2483 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2484 Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2485 Handle<SeededNumberDictionary> dict(
2486 SeededNumberDictionary::cast(parameter_map->get(1)));
2487 // TODO(verwaest): Remove reliance on index in Shrink.
2488 uint32_t index = GetIndexForEntryImpl(*dict, entry);
2489 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2490 USE(result);
2491 DCHECK(result->IsTrue());
2492 Handle<FixedArray> new_elements =
2493 SeededNumberDictionary::Shrink(dict, index);
2494 parameter_map->set(1, *new_elements);
2495 }
2496
2497 static void AddImpl(Handle<JSObject> object, uint32_t index,
2498 Handle<Object> value, PropertyAttributes attributes,
2499 uint32_t new_capacity) {
2500 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2501 Handle<FixedArrayBase> old_elements(
2502 FixedArrayBase::cast(parameter_map->get(1)));
2503 Handle<SeededNumberDictionary> dictionary =
2504 old_elements->IsSeededNumberDictionary()
2505 ? Handle<SeededNumberDictionary>::cast(old_elements)
2506 : JSObject::NormalizeElements(object);
2507 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2508 Handle<SeededNumberDictionary> new_dictionary =
2509 SeededNumberDictionary::AddNumberEntry(
2510 dictionary, index, value, details,
2511 object->map()->is_prototype_map());
2512 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2513 if (*dictionary != *new_dictionary) {
2514 FixedArray::cast(object->elements())->set(1, *new_dictionary);
2515 }
2516 }
2517
2518 static void ReconfigureImpl(Handle<JSObject> object,
2519 Handle<FixedArrayBase> store, uint32_t entry,
2520 Handle<Object> value,
2521 PropertyAttributes attributes) {
2522 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2523 uint32_t length = parameter_map->length() - 2;
2524 if (entry < length) {
2525 Object* probe = parameter_map->get(entry + 2);
2526 DCHECK(!probe->IsTheHole());
2527 Context* context = Context::cast(parameter_map->get(0));
2528 int context_entry = Smi::cast(probe)->value();
2529 DCHECK(!context->get(context_entry)->IsTheHole());
2530 context->set(context_entry, *value);
2531
2532 // Redefining attributes of an aliased element destroys fast aliasing.
2533 parameter_map->set_the_hole(entry + 2);
2534 // For elements that are still writable we re-establish slow aliasing.
2535 if ((attributes & READ_ONLY) == 0) {
2536 Isolate* isolate = store->GetIsolate();
2537 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2538 }
2539
2540 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2541 Handle<SeededNumberDictionary> arguments(
2542 SeededNumberDictionary::cast(parameter_map->get(1)));
2543 arguments = SeededNumberDictionary::AddNumberEntry(
2544 arguments, entry, value, details, object->map()->is_prototype_map());
2545 // If the attributes were NONE, we would have called set rather than
2546 // reconfigure.
2547 DCHECK_NE(NONE, attributes);
2548 object->RequireSlowElements(*arguments);
2549 parameter_map->set(1, *arguments);
2550 } else {
2551 Handle<FixedArrayBase> arguments(
2552 FixedArrayBase::cast(parameter_map->get(1)));
2553 DictionaryElementsAccessor::ReconfigureImpl(
2554 object, arguments, entry - length, value, attributes);
2555 }
2556 }
2557};
2558
2559
2560class FastSloppyArgumentsElementsAccessor
2561 : public SloppyArgumentsElementsAccessor<
2562 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2563 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2564 public:
2565 explicit FastSloppyArgumentsElementsAccessor(const char* name)
2566 : SloppyArgumentsElementsAccessor<
2567 FastSloppyArgumentsElementsAccessor,
2568 FastHoleyObjectElementsAccessor,
2569 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2570
Ben Murdochda12d292016-06-02 14:46:10 +01002571 static Handle<SeededNumberDictionary> NormalizeImpl(
2572 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
2573 FixedArray* parameter_map = FixedArray::cast(*elements);
2574 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
2575 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
2576 }
2577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002578 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2579 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2580 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
2581 FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2582 }
2583
2584 static void AddImpl(Handle<JSObject> object, uint32_t index,
2585 Handle<Object> value, PropertyAttributes attributes,
2586 uint32_t new_capacity) {
2587 DCHECK_EQ(NONE, attributes);
2588 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2589 Handle<FixedArrayBase> old_elements(
2590 FixedArrayBase::cast(parameter_map->get(1)));
2591 if (old_elements->IsSeededNumberDictionary() ||
2592 static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2593 GrowCapacityAndConvertImpl(object, new_capacity);
2594 }
2595 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2596 // For fast holey objects, the entry equals the index. The code above made
2597 // sure that there's enough space to store the value. We cannot convert
2598 // index to entry explicitly since the slot still contains the hole, so the
2599 // current EntryForIndex would indicate that it is "absent" by returning
2600 // kMaxUInt32.
2601 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2602 }
2603
2604 static void ReconfigureImpl(Handle<JSObject> object,
2605 Handle<FixedArrayBase> store, uint32_t entry,
2606 Handle<Object> value,
2607 PropertyAttributes attributes) {
2608 Handle<SeededNumberDictionary> dictionary =
2609 JSObject::NormalizeElements(object);
2610 FixedArray::cast(*store)->set(1, *dictionary);
2611 uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2612 if (entry >= length) {
2613 entry = dictionary->FindEntry(entry - length) + length;
2614 }
2615 SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2616 value, attributes);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002617 }
2618
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002619 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2620 FixedArrayBase* to, ElementsKind from_kind,
2621 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002622 int copy_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002623 DCHECK(!to->IsDictionary());
2624 if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2625 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2626 to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002627 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002628 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2629 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2630 FAST_HOLEY_ELEMENTS, to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002631 }
2632 }
2633
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002634 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2635 uint32_t capacity) {
2636 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2637 Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2638 ElementsKind from_kind = object->GetElementsKind();
2639 // This method should only be called if there's a reason to update the
2640 // elements.
2641 DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2642 static_cast<uint32_t>(old_elements->length()) < capacity);
2643 Handle<FixedArrayBase> elements =
2644 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2645 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2646 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2647 JSObject::MigrateToMap(object, new_map);
2648 parameter_map->set(1, *elements);
2649 JSObject::ValidateElements(object);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002650 }
2651};
2652
Ben Murdoch097c5b22016-05-18 11:27:45 +01002653template <typename StringWrapperElementsAccessorSubclass,
2654 typename BackingStoreAccessor, typename KindTraits>
2655class StringWrapperElementsAccessor
2656 : public ElementsAccessorBase<StringWrapperElementsAccessorSubclass,
2657 KindTraits> {
2658 public:
2659 explicit StringWrapperElementsAccessor(const char* name)
2660 : ElementsAccessorBase<StringWrapperElementsAccessorSubclass, KindTraits>(
2661 name) {
2662 USE(KindTraits::Kind);
2663 }
2664
2665 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2666 Isolate* isolate = holder->GetIsolate();
2667 Handle<String> string(GetString(*holder), isolate);
2668 uint32_t length = static_cast<uint32_t>(string->length());
2669 if (entry < length) {
2670 return isolate->factory()->LookupSingleCharacterStringFromCode(
2671 String::Flatten(string)->Get(entry));
2672 }
2673 return BackingStoreAccessor::GetImpl(holder, entry - length);
2674 }
2675
2676 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2677 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2678 if (entry < length) {
2679 PropertyAttributes attributes =
2680 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
2681 return PropertyDetails(attributes, v8::internal::DATA, 0,
2682 PropertyCellType::kNoCell);
2683 }
2684 return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
2685 }
2686
2687 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2688 FixedArrayBase* backing_store,
2689 uint32_t index, PropertyFilter filter) {
2690 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2691 if (index < length) return index;
2692 uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
2693 holder, backing_store, index, filter);
2694 if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
2695 DCHECK(backing_store_entry < kMaxUInt32 - length);
2696 return backing_store_entry + length;
2697 }
2698
2699 static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
2700 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2701 if (entry < length) {
2702 return; // String contents can't be deleted.
2703 }
2704 BackingStoreAccessor::DeleteImpl(holder, entry - length);
2705 }
2706
2707 static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
2708 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2709 if (entry < length) {
2710 return; // String contents are read-only.
2711 }
2712 BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
2713 }
2714
2715 static void AddImpl(Handle<JSObject> object, uint32_t index,
2716 Handle<Object> value, PropertyAttributes attributes,
2717 uint32_t new_capacity) {
2718 DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
2719 // Explicitly grow fast backing stores if needed. Dictionaries know how to
2720 // extend their capacity themselves.
2721 if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
2722 (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
2723 BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
2724 new_capacity)) {
2725 StringWrapperElementsAccessorSubclass::GrowCapacityAndConvertImpl(
2726 object, new_capacity);
2727 }
2728 BackingStoreAccessor::AddImpl(object, index, value, attributes,
2729 new_capacity);
2730 }
2731
2732 static void ReconfigureImpl(Handle<JSObject> object,
2733 Handle<FixedArrayBase> store, uint32_t entry,
2734 Handle<Object> value,
2735 PropertyAttributes attributes) {
2736 uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
2737 if (entry < length) {
2738 return; // String contents can't be reconfigured.
2739 }
2740 BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
2741 attributes);
2742 }
2743
2744 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2745 KeyAccumulator* accumulator,
2746 AddKeyConversion convert) {
2747 Isolate* isolate = receiver->GetIsolate();
2748 Handle<String> string(GetString(*receiver), isolate);
2749 string = String::Flatten(string);
2750 uint32_t length = static_cast<uint32_t>(string->length());
2751 for (uint32_t i = 0; i < length; i++) {
2752 accumulator->AddKey(
2753 isolate->factory()->LookupSingleCharacterStringFromCode(
2754 string->Get(i)),
2755 convert);
2756 }
2757 BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
2758 convert);
2759 }
2760
2761 static void CollectElementIndicesImpl(Handle<JSObject> object,
2762 Handle<FixedArrayBase> backing_store,
2763 KeyAccumulator* keys, uint32_t range,
2764 PropertyFilter filter,
2765 uint32_t offset) {
Ben Murdochda12d292016-06-02 14:46:10 +01002766 uint32_t length = GetString(*object)->length();
2767 for (uint32_t i = 0; i < length; i++) {
2768 keys->AddKey(i);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002769 }
2770 BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store, keys,
2771 range, filter, offset);
2772 }
2773
2774 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2775 FixedArrayBase* to, ElementsKind from_kind,
2776 uint32_t to_start, int packed_size,
2777 int copy_size) {
2778 BackingStoreAccessor::CopyElementsImpl(from, from_start, to, from_kind,
2779 to_start, packed_size, copy_size);
2780 }
2781
2782 private:
2783 static String* GetString(JSObject* holder) {
2784 DCHECK(holder->IsJSValue());
2785 JSValue* js_value = JSValue::cast(holder);
2786 DCHECK(js_value->value()->IsString());
2787 return String::cast(js_value->value());
2788 }
2789};
2790
2791class FastStringWrapperElementsAccessor
2792 : public StringWrapperElementsAccessor<
2793 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2794 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
2795 public:
2796 explicit FastStringWrapperElementsAccessor(const char* name)
2797 : StringWrapperElementsAccessor<
2798 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2799 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
Ben Murdochda12d292016-06-02 14:46:10 +01002800
2801 static Handle<SeededNumberDictionary> NormalizeImpl(
2802 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
2803 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
2804 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002805};
2806
2807class SlowStringWrapperElementsAccessor
2808 : public StringWrapperElementsAccessor<
2809 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2810 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
2811 public:
2812 explicit SlowStringWrapperElementsAccessor(const char* name)
2813 : StringWrapperElementsAccessor<
2814 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2815 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
2816
2817 static bool HasAccessorsImpl(JSObject* holder,
2818 FixedArrayBase* backing_store) {
2819 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
2820 }
2821};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002823} // namespace
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002824
2825
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002826void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2827 bool allow_appending) {
2828 DisallowHeapAllocation no_allocation;
2829 Object* raw_length = NULL;
2830 const char* elements_type = "array";
2831 if (obj->IsJSArray()) {
2832 JSArray* array = JSArray::cast(*obj);
2833 raw_length = array->length();
2834 } else {
2835 raw_length = Smi::FromInt(obj->elements()->length());
2836 elements_type = "object";
2837 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002838
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002839 if (raw_length->IsNumber()) {
2840 double n = raw_length->Number();
2841 if (FastI2D(FastD2UI(n)) == n) {
2842 int32_t int32_length = DoubleToInt32(n);
2843 uint32_t compare_length = static_cast<uint32_t>(int32_length);
2844 if (allow_appending) compare_length++;
2845 if (index >= compare_length) {
2846 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2847 elements_type, op, elements_type, static_cast<int>(int32_length),
2848 static_cast<int>(index));
2849 TraceTopFrame(obj->GetIsolate());
2850 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002851 }
2852 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002853 PrintF("[%s elements length not integer value in ", elements_type);
2854 TraceTopFrame(obj->GetIsolate());
2855 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002856 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002857 } else {
2858 PrintF("[%s elements length not a number in ", elements_type);
2859 TraceTopFrame(obj->GetIsolate());
2860 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002861 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002862}
2863
2864
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002865MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2866 Arguments* args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002867 if (args->length() == 0) {
2868 // Optimize the case where there are no parameters passed.
2869 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2870 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002871
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002872 } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2873 uint32_t length;
2874 if (!args->at<Object>(0)->ToArrayLength(&length)) {
2875 return ThrowArrayLengthRangeError(array->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002876 }
2877
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002878 // Optimize the case where there is one argument and the argument is a small
2879 // smi.
2880 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2881 ElementsKind elements_kind = array->GetElementsKind();
2882 JSArray::Initialize(array, length, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002883
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002884 if (!IsFastHoleyElementsKind(elements_kind)) {
2885 elements_kind = GetHoleyElementsKind(elements_kind);
2886 JSObject::TransitionElementsKind(array, elements_kind);
2887 }
2888 } else if (length == 0) {
2889 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2890 } else {
2891 // Take the argument as the length.
2892 JSArray::Initialize(array, 0);
2893 JSArray::SetLength(array, length);
2894 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002895 return array;
2896 }
2897
2898 Factory* factory = array->GetIsolate()->factory();
2899
2900 // Set length and elements on the array.
2901 int number_of_elements = args->length();
2902 JSObject::EnsureCanContainElements(
2903 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2904
2905 // Allocate an appropriately typed elements array.
2906 ElementsKind elements_kind = array->GetElementsKind();
2907 Handle<FixedArrayBase> elms;
2908 if (IsFastDoubleElementsKind(elements_kind)) {
2909 elms = Handle<FixedArrayBase>::cast(
2910 factory->NewFixedDoubleArray(number_of_elements));
2911 } else {
2912 elms = Handle<FixedArrayBase>::cast(
2913 factory->NewFixedArrayWithHoles(number_of_elements));
2914 }
2915
2916 // Fill in the content
2917 switch (array->GetElementsKind()) {
2918 case FAST_HOLEY_SMI_ELEMENTS:
2919 case FAST_SMI_ELEMENTS: {
2920 Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002921 for (int entry = 0; entry < number_of_elements; entry++) {
2922 smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002923 }
2924 break;
2925 }
2926 case FAST_HOLEY_ELEMENTS:
2927 case FAST_ELEMENTS: {
2928 DisallowHeapAllocation no_gc;
2929 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2930 Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002931 for (int entry = 0; entry < number_of_elements; entry++) {
2932 object_elms->set(entry, (*args)[entry], mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002933 }
2934 break;
2935 }
2936 case FAST_HOLEY_DOUBLE_ELEMENTS:
2937 case FAST_DOUBLE_ELEMENTS: {
2938 Handle<FixedDoubleArray> double_elms =
2939 Handle<FixedDoubleArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002940 for (int entry = 0; entry < number_of_elements; entry++) {
2941 double_elms->set(entry, (*args)[entry]->Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002942 }
2943 break;
2944 }
2945 default:
2946 UNREACHABLE();
2947 break;
2948 }
2949
2950 array->set_elements(*elms);
2951 array->set_length(Smi::FromInt(number_of_elements));
2952 return array;
2953}
2954
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002955
2956void ElementsAccessor::InitializeOncePerProcess() {
2957 static ElementsAccessor* accessor_array[] = {
2958#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2959 ELEMENTS_LIST(ACCESSOR_ARRAY)
2960#undef ACCESSOR_ARRAY
2961 };
2962
2963 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2964 kElementsKindCount);
2965
2966 elements_accessors_ = accessor_array;
2967}
2968
2969
2970void ElementsAccessor::TearDown() {
2971 if (elements_accessors_ == NULL) return;
2972#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2973 ELEMENTS_LIST(ACCESSOR_DELETE)
2974#undef ACCESSOR_DELETE
2975 elements_accessors_ = NULL;
2976}
2977
2978
2979Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
2980 uint32_t concat_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01002981 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
2982 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt);
2983 USE(kHalfOfMaxInt);
2984 uint32_t result_len = 0;
2985 bool has_raw_doubles = false;
2986 ElementsKind result_elements_kind = GetInitialFastElementsKind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002987 {
2988 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +01002989 bool is_holey = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002990 // Iterate through all the arguments performing checks
2991 // and calculating total length.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002992 for (uint32_t i = 0; i < concat_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +01002993 JSArray* array = JSArray::cast((*args)[i]);
2994 uint32_t len = 0;
2995 array->length()->ToArrayLength(&len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002996
2997 // We shouldn't overflow when adding another len.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002998 result_len += len;
2999 DCHECK(0 <= result_len);
3000 DCHECK(result_len <= FixedDoubleArray::kMaxLength);
3001
Ben Murdochda12d292016-06-02 14:46:10 +01003002 ElementsKind arg_kind = array->GetElementsKind();
3003 has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003004 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
Ben Murdochda12d292016-06-02 14:46:10 +01003005 result_elements_kind =
3006 GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003007 }
3008 if (is_holey) {
Ben Murdochda12d292016-06-02 14:46:10 +01003009 result_elements_kind = GetHoleyElementsKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003010 }
3011 }
3012
3013 // If a double array is concatted into a fast elements array, the fast
3014 // elements array needs to be initialized to contain proper holes, since
3015 // boxing doubles may cause incremental marking.
Ben Murdochda12d292016-06-02 14:46:10 +01003016 bool requires_double_boxing =
3017 has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
3018 ArrayStorageAllocationMode mode = requires_double_boxing
3019 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
3020 : DONT_INITIALIZE_ARRAY_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003021 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
Ben Murdochda12d292016-06-02 14:46:10 +01003022 result_elements_kind, result_len, result_len, mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003023 if (result_len == 0) return result_array;
Ben Murdochda12d292016-06-02 14:46:10 +01003024
3025 uint32_t insertion_index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003026 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
Ben Murdochda12d292016-06-02 14:46:10 +01003027 ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003028 for (uint32_t i = 0; i < concat_size; i++) {
3029 // It is crucial to keep |array| in a raw pointer form to avoid
3030 // performance degradation.
3031 JSArray* array = JSArray::cast((*args)[i]);
Ben Murdochda12d292016-06-02 14:46:10 +01003032 uint32_t len = 0;
3033 array->length()->ToArrayLength(&len);
3034 if (len == 0) continue;
3035 ElementsKind from_kind = array->GetElementsKind();
3036 accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
3037 insertion_index += len;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003038 }
3039
Ben Murdochda12d292016-06-02 14:46:10 +01003040 DCHECK_EQ(insertion_index, result_len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003041 return result_array;
3042}
3043
3044ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3045} // namespace internal
3046} // namespace v8