blob: 6c257ac63f3424b4dd531d1c936e0ff12e38bebd [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/elements.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/arguments.h"
8#include "src/conversions.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/factory.h"
Ben Murdochda12d292016-06-02 14:46:10 +010010#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/messages.h"
12#include "src/objects-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/utils.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014
15// Each concrete ElementsAccessor can handle exactly one ElementsKind,
16// several abstract ElementsAccessor classes are used to allow sharing
17// common code.
18//
19// Inheritance hierarchy:
20// - ElementsAccessorBase (abstract)
21// - FastElementsAccessor (abstract)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022// - FastSmiOrObjectElementsAccessor
23// - FastPackedSmiElementsAccessor
24// - FastHoleySmiElementsAccessor
25// - FastPackedObjectElementsAccessor
26// - FastHoleyObjectElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010027// - FastDoubleElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028// - FastPackedDoubleElementsAccessor
29// - FastHoleyDoubleElementsAccessor
30// - TypedElementsAccessor: template, with instantiations:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031// - FixedUint8ElementsAccessor
32// - FixedInt8ElementsAccessor
33// - FixedUint16ElementsAccessor
34// - FixedInt16ElementsAccessor
35// - FixedUint32ElementsAccessor
36// - FixedInt32ElementsAccessor
37// - FixedFloat32ElementsAccessor
38// - FixedFloat64ElementsAccessor
39// - FixedUint8ClampedElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010040// - DictionaryElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041// - SloppyArgumentsElementsAccessor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042// - FastSloppyArgumentsElementsAccessor
43// - SlowSloppyArgumentsElementsAccessor
Ben Murdoch097c5b22016-05-18 11:27:45 +010044// - StringWrapperElementsAccessor
45// - FastStringWrapperElementsAccessor
46// - SlowStringWrapperElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010047
Ben Murdoch69a99ed2011-11-30 16:03:39 +000048namespace v8 {
49namespace internal {
50
51
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052namespace {
53
54
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055static const int kPackedSizeNotKnown = -1;
56
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057enum Where { AT_START, AT_END };
58
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060// First argument in list is the accessor class, the second argument is the
61// accessor ElementsKind, and the third is the backing store class. Use the
62// fast element handler for smi-only arrays. The implementation is currently
63// identical. Note that the order must match that of the ElementsKind enum for
64// the |accessor_array[]| below to work.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065#define ELEMENTS_LIST(V) \
66 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
67 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
68 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
69 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
70 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
71 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
72 FixedDoubleArray) \
73 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
74 V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
75 FixedArray) \
76 V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
77 FixedArray) \
Ben Murdoch097c5b22016-05-18 11:27:45 +010078 V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS, \
79 FixedArray) \
80 V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS, \
81 FixedArray) \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
83 V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
84 V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
85 V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
86 V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
87 V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
88 V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
89 V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
90 V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 FixedUint8ClampedArray)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010092
Ben Murdoch3ef787d2012-04-12 10:51:47 +010093template<ElementsKind Kind> class ElementsKindTraits {
94 public:
95 typedef FixedArrayBase BackingStore;
96};
97
98#define ELEMENTS_TRAITS(Class, KindParam, Store) \
99template<> class ElementsKindTraits<KindParam> { \
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 public: /* NOLINT */ \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100101 static const ElementsKind Kind = KindParam; \
102 typedef Store BackingStore; \
103};
104ELEMENTS_LIST(ELEMENTS_TRAITS)
105#undef ELEMENTS_TRAITS
106
107
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108MUST_USE_RESULT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
110 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100112}
113
114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115void CopyObjectToObjectElements(FixedArrayBase* from_base,
116 ElementsKind from_kind, uint32_t from_start,
117 FixedArrayBase* to_base, ElementsKind to_kind,
118 uint32_t to_start, int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 DCHECK(to_base->map() !=
120 from_base->GetIsolate()->heap()->fixed_cow_array_map());
121 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100122 int copy_size = raw_copy_size;
123 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100125 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 copy_size = Min(from_base->length() - from_start,
127 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100128 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 int start = to_start + copy_size;
130 int length = to_base->length() - start;
131 if (length > 0) {
132 Heap* heap = from_base->GetHeap();
133 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
134 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100135 }
136 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
139 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 FixedArray* from = FixedArray::cast(from_base);
142 FixedArray* to = FixedArray::cast(to_base);
Ben Murdochc5610432016-08-08 18:44:38 +0100143 DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145
146 WriteBarrierMode write_barrier_mode =
Ben Murdochc5610432016-08-08 18:44:38 +0100147 (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 ? UPDATE_WRITE_BARRIER
149 : SKIP_WRITE_BARRIER;
150 for (int i = 0; i < copy_size; i++) {
151 Object* value = from->get(from_start + i);
152 to->set(to_start + i, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100153 }
154}
155
156
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157static void CopyDictionaryToObjectElements(
158 FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
159 ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
160 DisallowHeapAllocation no_allocation;
161 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100162 int copy_size = raw_copy_size;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100163 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100165 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
166 copy_size = from->max_number_key() + 1 - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100167 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 int start = to_start + copy_size;
169 int length = to_base->length() - start;
170 if (length > 0) {
171 Heap* heap = from->GetHeap();
172 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
173 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100174 }
175 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 DCHECK(to_base != from_base);
178 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100179 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 FixedArray* to = FixedArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 uint32_t to_length = to->length();
182 if (to_start + copy_size > to_length) {
183 copy_size = to_length - to_start;
184 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185 WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
186 ? UPDATE_WRITE_BARRIER
187 : SKIP_WRITE_BARRIER;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100188 for (int i = 0; i < copy_size; i++) {
189 int entry = from->FindEntry(i + from_start);
190 if (entry != SeededNumberDictionary::kNotFound) {
191 Object* value = from->ValueAt(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 DCHECK(!value->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 to->set(i + to_start, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100194 } else {
195 to->set_the_hole(i + to_start);
196 }
197 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100198}
199
200
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400201// NOTE: this method violates the handlified function signature convention:
202// raw pointer parameters in the function that allocates.
203// See ElementsAccessorBase::CopyElements() for details.
204static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 uint32_t from_start,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206 FixedArrayBase* to_base,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 uint32_t to_start, int raw_copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100208 int copy_size = raw_copy_size;
209 if (raw_copy_size < 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100212 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 copy_size = Min(from_base->length() - from_start,
214 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 // Also initialize the area that will be copied over since HeapNumber
217 // allocation below can cause an incremental marking step, requiring all
218 // existing heap objects to be propertly initialized.
219 int start = to_start;
220 int length = to_base->length() - start;
221 if (length > 0) {
222 Heap* heap = from_base->GetHeap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100225 }
226 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100227 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
230 (copy_size + static_cast<int>(from_start)) <= from_base->length());
231 if (copy_size == 0) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400232
233 // From here on, the code below could actually allocate. Therefore the raw
234 // values are wrapped into handles.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 Isolate* isolate = from_base->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
237 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238
Ben Murdoch097c5b22016-05-18 11:27:45 +0100239 // Use an outer loop to not waste too much time on creating HandleScopes.
240 // On the other hand we might overflow a single handle scope depending on
241 // the copy_size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 int offset = 0;
243 while (offset < copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 offset += 100;
246 for (int i = offset - 100; i < offset && i < copy_size; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 Handle<Object> value =
248 FixedDoubleArray::get(*from, i + from_start, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100250 }
251 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252}
253
254
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100256 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 FixedArrayBase* to_base,
258 uint32_t to_start, int raw_copy_size) {
259 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260 int copy_size = raw_copy_size;
261 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100263 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 copy_size = Min(from_base->length() - from_start,
265 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
268 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269 }
270 }
271 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
273 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
276 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100277 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
278 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
279 to_address += kDoubleSize * to_start;
280 from_address += kDoubleSize * from_start;
281 int words_per_double = (kDoubleSize / kPointerSize);
282 CopyWords(reinterpret_cast<Object**>(to_address),
283 reinterpret_cast<Object**>(from_address),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 static_cast<size_t>(words_per_double * copy_size));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100285}
286
287
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288static void CopySmiToDoubleElements(FixedArrayBase* from_base,
289 uint32_t from_start,
290 FixedArrayBase* to_base, uint32_t to_start,
291 int raw_copy_size) {
292 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100293 int copy_size = raw_copy_size;
294 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100296 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 copy_size = from_base->length() - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100298 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
300 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100301 }
302 }
303 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
305 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100306 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 FixedArray* from = FixedArray::cast(from_base);
308 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
309 Object* the_hole = from->GetHeap()->the_hole_value();
310 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
311 from_start < from_end; from_start++, to_start++) {
312 Object* hole_or_smi = from->get(from_start);
313 if (hole_or_smi == the_hole) {
314 to->set_the_hole(to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100315 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 to->set(to_start, Smi::cast(hole_or_smi)->value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100317 }
318 }
319}
320
321
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
323 uint32_t from_start,
324 FixedArrayBase* to_base,
325 uint32_t to_start, int packed_size,
326 int raw_copy_size) {
327 DisallowHeapAllocation no_allocation;
328 int copy_size = raw_copy_size;
329 uint32_t to_end;
330 if (raw_copy_size < 0) {
331 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
332 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
333 copy_size = packed_size - from_start;
334 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
335 to_end = to_base->length();
336 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
337 FixedDoubleArray::cast(to_base)->set_the_hole(i);
338 }
339 } else {
340 to_end = to_start + static_cast<uint32_t>(copy_size);
341 }
342 } else {
343 to_end = to_start + static_cast<uint32_t>(copy_size);
344 }
345 DCHECK(static_cast<int>(to_end) <= to_base->length());
346 DCHECK(packed_size >= 0 && packed_size <= copy_size);
347 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
348 (copy_size + static_cast<int>(from_start)) <= from_base->length());
349 if (copy_size == 0) return;
350 FixedArray* from = FixedArray::cast(from_base);
351 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
352 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
353 from_start < from_end; from_start++, to_start++) {
354 Object* smi = from->get(from_start);
355 DCHECK(!smi->IsTheHole());
356 to->set(to_start, Smi::cast(smi)->value());
357 }
358}
359
360
361static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
362 uint32_t from_start,
363 FixedArrayBase* to_base,
364 uint32_t to_start, int raw_copy_size) {
365 DisallowHeapAllocation no_allocation;
366 int copy_size = raw_copy_size;
367 if (raw_copy_size < 0) {
368 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
369 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
370 copy_size = from_base->length() - from_start;
371 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
372 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
373 FixedDoubleArray::cast(to_base)->set_the_hole(i);
374 }
375 }
376 }
377 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
378 (copy_size + static_cast<int>(from_start)) <= from_base->length());
379 if (copy_size == 0) return;
380 FixedArray* from = FixedArray::cast(from_base);
381 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
382 Object* the_hole = from->GetHeap()->the_hole_value();
383 for (uint32_t from_end = from_start + copy_size;
384 from_start < from_end; from_start++, to_start++) {
385 Object* hole_or_object = from->get(from_start);
386 if (hole_or_object == the_hole) {
387 to->set_the_hole(to_start);
388 } else {
389 to->set(to_start, hole_or_object->Number());
390 }
391 }
392}
393
394
395static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 FixedArrayBase* to_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398 uint32_t to_start,
399 int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000400 DisallowHeapAllocation no_allocation;
401 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100402 int copy_size = raw_copy_size;
403 if (copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100405 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
406 copy_size = from->max_number_key() + 1 - from_start;
407 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000408 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
409 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100410 }
411 }
412 }
413 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100415 uint32_t to_length = to->length();
416 if (to_start + copy_size > to_length) {
417 copy_size = to_length - to_start;
418 }
419 for (int i = 0; i < copy_size; i++) {
420 int entry = from->FindEntry(i + from_start);
421 if (entry != SeededNumberDictionary::kNotFound) {
422 to->set(i + to_start, from->ValueAt(entry)->Number());
423 } else {
424 to->set_the_hole(i + to_start);
425 }
426 }
427}
428
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429static void TraceTopFrame(Isolate* isolate) {
430 StackFrameIterator it(isolate);
431 if (it.done()) {
432 PrintF("unknown location (no JavaScript frames present)");
433 return;
434 }
435 StackFrame* raw_frame = it.frame();
436 if (raw_frame->is_internal()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 Code* apply_builtin =
438 isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 if (raw_frame->unchecked_code() == apply_builtin) {
440 PrintF("apply from ");
441 it.Advance();
442 raw_frame = it.frame();
443 }
444 }
445 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
446}
447
448
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000449// Base class for element handler implementations. Contains the
450// the common logic for objects with different ElementsKinds.
451// Subclasses must specialize method for which the element
452// implementation differs from the base class implementation.
453//
454// This class is intended to be used in the following way:
455//
456// class SomeElementsAccessor :
457// public ElementsAccessorBase<SomeElementsAccessor,
458// BackingStoreClass> {
459// ...
460// }
461//
462// This is an example of the Curiously Recurring Template Pattern (see
463// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
464// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
465// specialization of SomeElementsAccessor methods).
Ben Murdochc5610432016-08-08 18:44:38 +0100466template <typename Subclass, typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000467class ElementsAccessorBase : public ElementsAccessor {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100469 explicit ElementsAccessorBase(const char* name)
470 : ElementsAccessor(name) { }
471
472 typedef ElementsTraitsParam ElementsTraits;
473 typedef typename ElementsTraitsParam::BackingStore BackingStore;
474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 static ElementsKind kind() { return ElementsTraits::Kind; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100476
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 static void ValidateContents(Handle<JSObject> holder, int length) {
478 }
479
480 static void ValidateImpl(Handle<JSObject> holder) {
481 Handle<FixedArrayBase> fixed_array_base(holder->elements());
482 if (!fixed_array_base->IsHeapObject()) return;
483 // Arrays that have been shifted in place can't be verified.
484 if (fixed_array_base->IsFiller()) return;
485 int length = 0;
486 if (holder->IsJSArray()) {
487 Object* length_obj = Handle<JSArray>::cast(holder)->length();
488 if (length_obj->IsSmi()) {
489 length = Smi::cast(length_obj)->value();
490 }
491 } else {
492 length = fixed_array_base->length();
493 }
Ben Murdochc5610432016-08-08 18:44:38 +0100494 Subclass::ValidateContents(holder, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 }
496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 void Validate(Handle<JSObject> holder) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +0100499 Subclass::ValidateImpl(holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 }
501
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502 static bool IsPackedImpl(Handle<JSObject> holder,
503 Handle<FixedArrayBase> backing_store, uint32_t start,
504 uint32_t end) {
505 if (IsFastPackedElementsKind(kind())) return true;
506 for (uint32_t i = start; i < end; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100507 if (!Subclass::HasElementImpl(holder, i, backing_store, ALL_PROPERTIES)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508 return false;
509 }
510 }
511 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100512 }
513
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514 static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
515 if (!IsHoleyElementsKind(kind())) return;
516 int length = Smi::cast(array->length())->value();
517 Handle<FixedArrayBase> backing_store(array->elements());
Ben Murdochc5610432016-08-08 18:44:38 +0100518 if (!Subclass::IsPackedImpl(array, backing_store, 0, length)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519 return;
520 }
521 ElementsKind packed_kind = GetPackedElementsKind(kind());
522 Handle<Map> new_map =
523 JSObject::GetElementsTransitionMap(array, packed_kind);
524 JSObject::MigrateToMap(array, new_map);
525 if (FLAG_trace_elements_transitions) {
526 JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
527 packed_kind, backing_store);
528 }
529 }
530
531 bool HasElement(Handle<JSObject> holder, uint32_t index,
532 Handle<FixedArrayBase> backing_store,
533 PropertyFilter filter) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100534 return Subclass::HasElementImpl(holder, index, backing_store, filter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000535 }
536
537 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
538 Handle<FixedArrayBase> backing_store,
539 PropertyFilter filter) {
Ben Murdochc5610432016-08-08 18:44:38 +0100540 return Subclass::GetEntryForIndexImpl(*holder, *backing_store, index,
541 filter) != kMaxUInt32;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 }
543
Ben Murdoch097c5b22016-05-18 11:27:45 +0100544 bool HasAccessors(JSObject* holder) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100545 return Subclass::HasAccessorsImpl(holder, holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 }
547
Ben Murdoch097c5b22016-05-18 11:27:45 +0100548 static bool HasAccessorsImpl(JSObject* holder,
549 FixedArrayBase* backing_store) {
550 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 }
552
Ben Murdoch097c5b22016-05-18 11:27:45 +0100553 Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100554 return Subclass::GetImpl(holder, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 }
556
Ben Murdoch097c5b22016-05-18 11:27:45 +0100557 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +0100558 return Subclass::GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000559 }
560
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
562 Isolate* isolate = backing_store->GetIsolate();
563 uint32_t index = GetIndexForEntryImpl(backing_store, entry);
564 return handle(BackingStore::cast(backing_store)->get(index), isolate);
565 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566
Ben Murdoch097c5b22016-05-18 11:27:45 +0100567 void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100568 Subclass::SetImpl(holder, entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 }
570
571 void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
572 uint32_t entry, Handle<Object> value,
573 PropertyAttributes attributes) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100574 Subclass::ReconfigureImpl(object, store, entry, value, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000575 }
576
577 static void ReconfigureImpl(Handle<JSObject> object,
578 Handle<FixedArrayBase> store, uint32_t entry,
579 Handle<Object> value,
580 PropertyAttributes attributes) {
581 UNREACHABLE();
582 }
583
584 void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
585 PropertyAttributes attributes, uint32_t new_capacity) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100586 Subclass::AddImpl(object, index, value, attributes, new_capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 }
588
589 static void AddImpl(Handle<JSObject> object, uint32_t index,
590 Handle<Object> value, PropertyAttributes attributes,
591 uint32_t new_capacity) {
592 UNREACHABLE();
593 }
594
Ben Murdochda12d292016-06-02 14:46:10 +0100595 uint32_t Push(Handle<JSArray> receiver, Arguments* args,
596 uint32_t push_size) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100597 return Subclass::PushImpl(receiver, args, push_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 }
599
Ben Murdochda12d292016-06-02 14:46:10 +0100600 static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 uint32_t push_sized) {
602 UNREACHABLE();
603 return 0;
604 }
605
Ben Murdochda12d292016-06-02 14:46:10 +0100606 uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000607 uint32_t unshift_size) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100608 return Subclass::UnshiftImpl(receiver, args, unshift_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 }
610
Ben Murdochda12d292016-06-02 14:46:10 +0100611 static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 uint32_t unshift_size) {
613 UNREACHABLE();
614 return 0;
615 }
616
Ben Murdochda12d292016-06-02 14:46:10 +0100617 Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618 uint32_t end) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100619 return Subclass::SliceImpl(receiver, start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 }
621
622 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 uint32_t start, uint32_t end) {
624 UNREACHABLE();
625 return Handle<JSArray>();
626 }
627
Ben Murdochda12d292016-06-02 14:46:10 +0100628 Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 uint32_t delete_count, Arguments* args,
630 uint32_t add_count) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100631 return Subclass::SpliceImpl(receiver, start, delete_count, args, add_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 }
633
634 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000635 uint32_t start, uint32_t delete_count,
636 Arguments* args, uint32_t add_count) {
637 UNREACHABLE();
638 return Handle<JSArray>();
639 }
640
Ben Murdochda12d292016-06-02 14:46:10 +0100641 Handle<Object> Pop(Handle<JSArray> receiver) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100642 return Subclass::PopImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 }
644
Ben Murdochda12d292016-06-02 14:46:10 +0100645 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 UNREACHABLE();
647 return Handle<Object>();
648 }
649
Ben Murdochda12d292016-06-02 14:46:10 +0100650 Handle<Object> Shift(Handle<JSArray> receiver) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100651 return Subclass::ShiftImpl(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652 }
653
Ben Murdochda12d292016-06-02 14:46:10 +0100654 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000655 UNREACHABLE();
656 return Handle<Object>();
657 }
658
659 void SetLength(Handle<JSArray> array, uint32_t length) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100660 Subclass::SetLengthImpl(array->GetIsolate(), array, length,
661 handle(array->elements()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 }
663
664 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
665 uint32_t length,
666 Handle<FixedArrayBase> backing_store) {
667 DCHECK(!array->SetLengthWouldNormalize(length));
668 DCHECK(IsFastElementsKind(array->GetElementsKind()));
669 uint32_t old_length = 0;
670 CHECK(array->length()->ToArrayIndex(&old_length));
671
672 if (old_length < length) {
673 ElementsKind kind = array->GetElementsKind();
674 if (!IsFastHoleyElementsKind(kind)) {
675 kind = GetHoleyElementsKind(kind);
676 JSObject::TransitionElementsKind(array, kind);
677 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100678 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 // Check whether the backing store should be shrunk.
681 uint32_t capacity = backing_store->length();
682 old_length = Min(old_length, capacity);
683 if (length == 0) {
684 array->initialize_elements();
685 } else if (length <= capacity) {
Ben Murdochda12d292016-06-02 14:46:10 +0100686 if (IsFastSmiOrObjectElementsKind(kind())) {
687 JSObject::EnsureWritableFastElements(array);
688 if (array->elements() != *backing_store) {
689 backing_store = handle(array->elements(), isolate);
690 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 }
692 if (2 * length <= capacity) {
693 // If more than half the elements won't be used, trim the array.
694 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
695 *backing_store, capacity - length);
696 } else {
697 // Otherwise, fill the unused tail with holes.
698 for (uint32_t i = length; i < old_length; i++) {
699 BackingStore::cast(*backing_store)->set_the_hole(i);
700 }
701 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000702 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 // Check whether the backing store should be expanded.
704 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
Ben Murdochc5610432016-08-08 18:44:38 +0100705 Subclass::GrowCapacityAndConvertImpl(array, capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706 }
707
708 array->set_length(Smi::FromInt(length));
709 JSObject::ValidateElements(array);
710 }
711
Ben Murdochda12d292016-06-02 14:46:10 +0100712 static uint32_t GetIterationLength(JSObject* receiver,
713 FixedArrayBase* elements) {
714 if (receiver->IsJSArray()) {
715 DCHECK(JSArray::cast(receiver)->length()->IsSmi());
716 return static_cast<uint32_t>(
717 Smi::cast(JSArray::cast(receiver)->length())->value());
718 }
Ben Murdochc5610432016-08-08 18:44:38 +0100719 return Subclass::GetCapacityImpl(receiver, elements);
Ben Murdochda12d292016-06-02 14:46:10 +0100720 }
721
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
723 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
724 ElementsKind from_kind, uint32_t capacity) {
725 return ConvertElementsWithCapacity(
726 object, old_elements, from_kind, capacity, 0, 0,
727 ElementsAccessor::kCopyToEndAndInitializeToHole);
728 }
729
730 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
731 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
732 ElementsKind from_kind, uint32_t capacity, int copy_size) {
733 return ConvertElementsWithCapacity(object, old_elements, from_kind,
734 capacity, 0, 0, copy_size);
735 }
736
737 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
738 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
739 ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
740 uint32_t dst_index, int copy_size) {
741 Isolate* isolate = object->GetIsolate();
742 Handle<FixedArrayBase> new_elements;
743 if (IsFastDoubleElementsKind(kind())) {
744 new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
745 } else {
746 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
747 }
748
749 int packed_size = kPackedSizeNotKnown;
750 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
751 packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
752 }
753
Ben Murdochc5610432016-08-08 18:44:38 +0100754 Subclass::CopyElementsImpl(*old_elements, src_index, *new_elements,
755 from_kind, dst_index, packed_size, copy_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756
757 return new_elements;
758 }
759
760 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
761 uint32_t capacity) {
762 ElementsKind from_kind = object->GetElementsKind();
763 if (IsFastSmiOrObjectElementsKind(from_kind)) {
764 // Array optimizations rely on the prototype lookups of Array objects
765 // always returning undefined. If there is a store to the initial
766 // prototype object, make sure all of these optimizations are invalidated.
767 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
768 }
769 Handle<FixedArrayBase> old_elements(object->elements());
770 // This method should only be called if there's a reason to update the
771 // elements.
772 DCHECK(IsFastDoubleElementsKind(from_kind) !=
773 IsFastDoubleElementsKind(kind()) ||
774 IsDictionaryElementsKind(from_kind) ||
775 static_cast<uint32_t>(old_elements->length()) < capacity);
Ben Murdochc5610432016-08-08 18:44:38 +0100776 Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
777 kind(), capacity);
778 }
779
780 static void BasicGrowCapacityAndConvertImpl(
781 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
782 ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000783 Handle<FixedArrayBase> elements =
784 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
785
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000786 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
787 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
788 JSObject::SetMapAndElements(object, new_map, elements);
789
790 // Transition through the allocation site as well if present.
791 JSObject::UpdateAllocationSite(object, to_kind);
792
793 if (FLAG_trace_elements_transitions) {
794 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
795 to_kind, elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100797 }
798
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799 void GrowCapacityAndConvert(Handle<JSObject> object,
800 uint32_t capacity) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100801 Subclass::GrowCapacityAndConvertImpl(object, capacity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802 }
803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 void Delete(Handle<JSObject> obj, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100805 Subclass::DeleteImpl(obj, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 }
807
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400808 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
809 FixedArrayBase* to, ElementsKind from_kind,
810 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811 int copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100812 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100813 }
814
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 void CopyElements(JSObject* from_holder, uint32_t from_start,
816 ElementsKind from_kind, Handle<FixedArrayBase> to,
817 uint32_t to_start, int copy_size) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818 int packed_size = kPackedSizeNotKnown;
819 bool is_packed = IsFastPackedElementsKind(from_kind) &&
820 from_holder->IsJSArray();
821 if (is_packed) {
822 packed_size =
823 Smi::cast(JSArray::cast(from_holder)->length())->value();
824 if (copy_size >= 0 && packed_size > copy_size) {
825 packed_size = copy_size;
826 }
827 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400828 FixedArrayBase* from = from_holder->elements();
Ben Murdochc5610432016-08-08 18:44:38 +0100829 // NOTE: the Subclass::CopyElementsImpl() methods
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400830 // violate the handlified function signature convention:
831 // raw pointer parameters in the function that allocates. This is done
832 // intentionally to avoid ArrayConcat() builtin performance degradation.
833 //
834 // Details: The idea is that allocations actually happen only in case of
835 // copying from object with fast double elements to object with object
836 // elements. In all the other cases there are no allocations performed and
837 // handle creation causes noticeable performance degradation of the builtin.
Ben Murdochc5610432016-08-08 18:44:38 +0100838 Subclass::CopyElementsImpl(from, from_start, *to, from_kind, to_start,
839 packed_size, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 }
841
Ben Murdochda12d292016-06-02 14:46:10 +0100842 Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100843 return Subclass::NormalizeImpl(object, handle(object->elements()));
Ben Murdochda12d292016-06-02 14:46:10 +0100844 }
845
846 static Handle<SeededNumberDictionary> NormalizeImpl(
847 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
848 UNREACHABLE();
849 return Handle<SeededNumberDictionary>();
850 }
851
852 Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
853 Handle<FixedArray> values_or_entries,
854 bool get_entries, int* nof_items,
855 PropertyFilter filter) {
Ben Murdochc5610432016-08-08 18:44:38 +0100856 return Subclass::CollectValuesOrEntriesImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100857 isolate, object, values_or_entries, get_entries, nof_items, filter);
858 }
859
860 static Maybe<bool> CollectValuesOrEntriesImpl(
861 Isolate* isolate, Handle<JSObject> object,
862 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
863 PropertyFilter filter) {
864 int count = 0;
865 KeyAccumulator accumulator(isolate, OWN_ONLY, ALL_PROPERTIES);
866 accumulator.NextPrototype();
Ben Murdochc5610432016-08-08 18:44:38 +0100867 Subclass::CollectElementIndicesImpl(
868 object, handle(object->elements(), isolate), &accumulator);
Ben Murdochda12d292016-06-02 14:46:10 +0100869 Handle<FixedArray> keys = accumulator.GetKeys();
870
871 for (int i = 0; i < keys->length(); ++i) {
872 Handle<Object> key(keys->get(i), isolate);
873 Handle<Object> value;
874 uint32_t index;
875 if (!key->ToUint32(&index)) continue;
876
Ben Murdochc5610432016-08-08 18:44:38 +0100877 uint32_t entry = Subclass::GetEntryForIndexImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100878 *object, object->elements(), index, filter);
879 if (entry == kMaxUInt32) continue;
880
Ben Murdochc5610432016-08-08 18:44:38 +0100881 PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
Ben Murdochda12d292016-06-02 14:46:10 +0100882
883 if (details.kind() == kData) {
Ben Murdochc5610432016-08-08 18:44:38 +0100884 value = Subclass::GetImpl(object, entry);
Ben Murdochda12d292016-06-02 14:46:10 +0100885 } else {
886 LookupIterator it(isolate, object, index, LookupIterator::OWN);
887 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
888 isolate, value, Object::GetProperty(&it), Nothing<bool>());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100889 }
Ben Murdochda12d292016-06-02 14:46:10 +0100890 if (get_entries) {
891 value = MakeEntryPair(isolate, index, value);
892 }
893 values_or_entries->set(count++, *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000894 }
Ben Murdochda12d292016-06-02 14:46:10 +0100895
896 *nof_items = count;
897 return Just(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000898 }
899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900 void CollectElementIndices(Handle<JSObject> object,
901 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +0100902 KeyAccumulator* keys) final {
903 if (keys->filter() & ONLY_ALL_CAN_READ) return;
904 Subclass::CollectElementIndicesImpl(object, backing_store, keys);
Ben Murdochda12d292016-06-02 14:46:10 +0100905 }
906
907 static void CollectElementIndicesImpl(Handle<JSObject> object,
908 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +0100909 KeyAccumulator* keys) {
Ben Murdochda12d292016-06-02 14:46:10 +0100910 DCHECK_NE(DICTIONARY_ELEMENTS, kind());
911 // Non-dictionary elements can't have all-can-read accessors.
912 uint32_t length = GetIterationLength(*object, *backing_store);
Ben Murdochc5610432016-08-08 18:44:38 +0100913 PropertyFilter filter = keys->filter();
914 for (uint32_t i = 0; i < length; i++) {
915 if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100916 keys->AddKey(i);
917 }
918 }
919 }
920
921 static Handle<FixedArray> DirectCollectElementIndicesImpl(
922 Isolate* isolate, Handle<JSObject> object,
923 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
924 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
925 uint32_t insertion_index = 0) {
Ben Murdochc5610432016-08-08 18:44:38 +0100926 uint32_t length = Subclass::GetIterationLength(*object, *backing_store);
Ben Murdochda12d292016-06-02 14:46:10 +0100927 for (uint32_t i = 0; i < length; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100928 if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100929 if (convert == CONVERT_TO_STRING) {
930 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
931 list->set(insertion_index, *index_string);
932 } else {
933 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
934 }
935 insertion_index++;
936 }
937 }
938 *nof_indices = insertion_index;
939 return list;
940 }
941
942 Handle<FixedArray> PrependElementIndices(Handle<JSObject> object,
943 Handle<FixedArrayBase> backing_store,
944 Handle<FixedArray> keys,
945 GetKeysConversion convert,
946 PropertyFilter filter) final {
Ben Murdochc5610432016-08-08 18:44:38 +0100947 return Subclass::PrependElementIndicesImpl(object, backing_store, keys,
948 convert, filter);
Ben Murdochda12d292016-06-02 14:46:10 +0100949 }
950
951 static Handle<FixedArray> PrependElementIndicesImpl(
952 Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
953 Handle<FixedArray> keys, GetKeysConversion convert,
954 PropertyFilter filter) {
955 Isolate* isolate = object->GetIsolate();
956 uint32_t nof_property_keys = keys->length();
957 uint32_t initial_list_length =
Ben Murdochc5610432016-08-08 18:44:38 +0100958 Subclass::GetCapacityImpl(*object, *backing_store);
Ben Murdochda12d292016-06-02 14:46:10 +0100959 initial_list_length += nof_property_keys;
960
961 // Collect the element indices into a new list.
962 uint32_t nof_indices = 0;
963 Handle<FixedArray> combined_keys =
964 isolate->factory()->NewFixedArray(initial_list_length);
Ben Murdochc5610432016-08-08 18:44:38 +0100965 combined_keys = Subclass::DirectCollectElementIndicesImpl(
Ben Murdochda12d292016-06-02 14:46:10 +0100966 isolate, object, backing_store, convert, filter, combined_keys,
967 &nof_indices);
968
969 // Sort the indices list if necessary.
970 if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
971 struct {
972 bool operator()(Object* a, Object* b) {
973 if (!a->IsUndefined()) {
974 if (b->IsUndefined()) return true;
975 return a->Number() < b->Number();
976 }
977 return !b->IsUndefined();
978 }
979 } cmp;
980 Object** start =
981 reinterpret_cast<Object**>(combined_keys->GetFirstElementAddress());
982 std::sort(start, start + nof_indices, cmp);
983 uint32_t array_length = 0;
984 // Indices from dictionary elements should only be converted after
985 // sorting.
986 if (convert == CONVERT_TO_STRING) {
987 for (uint32_t i = 0; i < nof_indices; i++) {
988 Handle<Object> index_string = isolate->factory()->Uint32ToString(
989 combined_keys->get(i)->Number());
990 combined_keys->set(i, *index_string);
991 }
992 } else if (!(object->IsJSArray() &&
993 JSArray::cast(*object)->length()->ToArrayLength(
994 &array_length) &&
995 array_length <= Smi::kMaxValue)) {
996 // Since we use std::sort above, the GC will no longer know where the
Ben Murdochc5610432016-08-08 18:44:38 +0100997 // HeapNumbers are. For Arrays with valid Smi length, we are sure to
998 // have no HeapNumber indices and thus we can skip this step.
999 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(isolate->heap(), *combined_keys, 0,
1000 nof_indices);
Ben Murdochda12d292016-06-02 14:46:10 +01001001 }
1002 }
1003
1004 // Copy over the passed-in property keys.
1005 CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
1006 FAST_ELEMENTS, nof_indices, nof_property_keys);
1007
1008 if (IsHoleyElementsKind(kind())) {
1009 // Shrink combined_keys to the final size.
1010 int final_size = nof_indices + nof_property_keys;
1011 DCHECK_LE(final_size, combined_keys->length());
1012 combined_keys->Shrink(final_size);
1013 }
1014
1015 return combined_keys;
1016 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017
1018 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
1019 KeyAccumulator* accumulator,
1020 AddKeyConversion convert) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001021 Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 }
1023
1024 static uint32_t GetCapacityImpl(JSObject* holder,
1025 FixedArrayBase* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001026 return backing_store->length();
1027 }
1028
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001030 return Subclass::GetCapacityImpl(holder, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001031 }
1032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001033 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1034 uint32_t entry) {
1035 return entry;
1036 }
1037
1038 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1039 FixedArrayBase* backing_store,
1040 uint32_t index, PropertyFilter filter) {
1041 if (IsHoleyElementsKind(kind())) {
Ben Murdochc5610432016-08-08 18:44:38 +01001042 return index < Subclass::GetCapacityImpl(holder, backing_store) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 !BackingStore::cast(backing_store)->is_the_hole(index)
1044 ? index
1045 : kMaxUInt32;
1046 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001047 uint32_t length = GetIterationLength(holder, backing_store);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048 return index < length ? index : kMaxUInt32;
1049 }
1050 }
1051
1052 uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
1053 uint32_t index) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001054 return Subclass::GetEntryForIndexImpl(holder, backing_store, index,
1055 ALL_PROPERTIES);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056 }
1057
1058 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1059 uint32_t entry) {
1060 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1061 }
1062
Ben Murdoch097c5b22016-05-18 11:27:45 +01001063 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1064 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1065 }
1066
1067 PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
Ben Murdochc5610432016-08-08 18:44:38 +01001068 return Subclass::GetDetailsImpl(holder, entry);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001069 }
1070
1071 private:
1072 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1073};
1074
1075
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076class DictionaryElementsAccessor
1077 : public ElementsAccessorBase<DictionaryElementsAccessor,
1078 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1079 public:
1080 explicit DictionaryElementsAccessor(const char* name)
1081 : ElementsAccessorBase<DictionaryElementsAccessor,
1082 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1083
Ben Murdochda12d292016-06-02 14:46:10 +01001084 static uint32_t GetIterationLength(JSObject* receiver,
1085 FixedArrayBase* elements) {
1086 uint32_t length;
1087 if (receiver->IsJSArray()) {
1088 // Special-case GetIterationLength for dictionary elements since the
1089 // length of the array might be a HeapNumber.
1090 JSArray::cast(receiver)->length()->ToArrayLength(&length);
1091 } else {
1092 length = GetCapacityImpl(receiver, elements);
1093 }
1094 return length;
1095 }
1096
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001097 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1098 uint32_t length,
1099 Handle<FixedArrayBase> backing_store) {
1100 Handle<SeededNumberDictionary> dict =
1101 Handle<SeededNumberDictionary>::cast(backing_store);
1102 int capacity = dict->Capacity();
1103 uint32_t old_length = 0;
1104 CHECK(array->length()->ToArrayLength(&old_length));
1105 if (length < old_length) {
1106 if (dict->requires_slow_elements()) {
1107 // Find last non-deletable element in range of elements to be
1108 // deleted and adjust range accordingly.
1109 for (int entry = 0; entry < capacity; entry++) {
1110 DisallowHeapAllocation no_gc;
1111 Object* index = dict->KeyAt(entry);
1112 if (index->IsNumber()) {
1113 uint32_t number = static_cast<uint32_t>(index->Number());
1114 if (length <= number && number < old_length) {
1115 PropertyDetails details = dict->DetailsAt(entry);
1116 if (!details.IsConfigurable()) length = number + 1;
1117 }
1118 }
1119 }
1120 }
1121
1122 if (length == 0) {
1123 // Flush the backing store.
1124 JSObject::ResetElements(array);
1125 } else {
1126 DisallowHeapAllocation no_gc;
1127 // Remove elements that should be deleted.
1128 int removed_entries = 0;
1129 Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1130 for (int entry = 0; entry < capacity; entry++) {
1131 Object* index = dict->KeyAt(entry);
1132 if (index->IsNumber()) {
1133 uint32_t number = static_cast<uint32_t>(index->Number());
1134 if (length <= number && number < old_length) {
1135 dict->SetEntry(entry, the_hole_value, the_hole_value);
1136 removed_entries++;
1137 }
1138 }
1139 }
1140
1141 // Update the number of elements.
1142 dict->ElementsRemoved(removed_entries);
1143 }
1144 }
1145
1146 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1147 array->set_length(*length_obj);
1148 }
1149
1150 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1151 FixedArrayBase* to, ElementsKind from_kind,
1152 uint32_t to_start, int packed_size,
1153 int copy_size) {
1154 UNREACHABLE();
1155 }
1156
1157
1158 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1159 // TODO(verwaest): Remove reliance on index in Shrink.
1160 Handle<SeededNumberDictionary> dict(
1161 SeededNumberDictionary::cast(obj->elements()));
1162 uint32_t index = GetIndexForEntryImpl(*dict, entry);
1163 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1164 USE(result);
1165 DCHECK(result->IsTrue());
1166 Handle<FixedArray> new_elements =
1167 SeededNumberDictionary::Shrink(dict, index);
1168 obj->set_elements(*new_elements);
1169 }
1170
Ben Murdoch097c5b22016-05-18 11:27:45 +01001171 static bool HasAccessorsImpl(JSObject* holder,
1172 FixedArrayBase* backing_store) {
Ben Murdochda12d292016-06-02 14:46:10 +01001173 DisallowHeapAllocation no_gc;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001174 SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1175 if (!dict->requires_slow_elements()) return false;
1176 int capacity = dict->Capacity();
Ben Murdochda12d292016-06-02 14:46:10 +01001177 Heap* heap = holder->GetHeap();
1178 Object* undefined = heap->undefined_value();
1179 Object* the_hole = heap->the_hole_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001180 for (int i = 0; i < capacity; i++) {
1181 Object* key = dict->KeyAt(i);
Ben Murdochda12d292016-06-02 14:46:10 +01001182 if (key == the_hole || key == undefined) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001183 DCHECK(!dict->IsDeleted(i));
1184 PropertyDetails details = dict->DetailsAt(i);
1185 if (details.type() == ACCESSOR_CONSTANT) return true;
1186 }
1187 return false;
1188 }
1189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190 static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1191 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1192 return backing_store->ValueAt(entry);
1193 }
1194
Ben Murdoch097c5b22016-05-18 11:27:45 +01001195 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1196 return GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197 }
1198
Ben Murdoch097c5b22016-05-18 11:27:45 +01001199 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1200 return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
1201 }
1202
1203 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001204 Object* value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001205 SetImpl(holder->elements(), entry, value);
1206 }
1207
1208 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1209 Object* value) {
1210 SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 }
1212
1213 static void ReconfigureImpl(Handle<JSObject> object,
1214 Handle<FixedArrayBase> store, uint32_t entry,
1215 Handle<Object> value,
1216 PropertyAttributes attributes) {
1217 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1218 if (attributes != NONE) object->RequireSlowElements(dictionary);
1219 dictionary->ValueAtPut(entry, *value);
1220 PropertyDetails details = dictionary->DetailsAt(entry);
1221 details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1222 PropertyCellType::kNoCell);
1223 dictionary->DetailsAtPut(entry, details);
1224 }
1225
1226 static void AddImpl(Handle<JSObject> object, uint32_t index,
1227 Handle<Object> value, PropertyAttributes attributes,
1228 uint32_t new_capacity) {
1229 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1230 Handle<SeededNumberDictionary> dictionary =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001231 object->HasFastElements() || object->HasFastStringWrapperElements()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 ? JSObject::NormalizeElements(object)
1233 : handle(SeededNumberDictionary::cast(object->elements()));
1234 Handle<SeededNumberDictionary> new_dictionary =
1235 SeededNumberDictionary::AddNumberEntry(
1236 dictionary, index, value, details,
1237 object->map()->is_prototype_map());
1238 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1239 if (dictionary.is_identical_to(new_dictionary)) return;
1240 object->set_elements(*new_dictionary);
1241 }
1242
1243 static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1244 DisallowHeapAllocation no_gc;
1245 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1246 Object* index = dict->KeyAt(entry);
1247 return !index->IsTheHole();
1248 }
1249
1250 static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1251 DisallowHeapAllocation no_gc;
1252 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1253 uint32_t result = 0;
1254 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1255 return result;
1256 }
1257
1258 static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1259 uint32_t index, PropertyFilter filter) {
1260 DisallowHeapAllocation no_gc;
1261 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1262 int entry = dictionary->FindEntry(index);
1263 if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1264 if (filter != ALL_PROPERTIES) {
1265 PropertyDetails details = dictionary->DetailsAt(entry);
1266 PropertyAttributes attr = details.attributes();
1267 if ((attr & filter) != 0) return kMaxUInt32;
1268 }
1269 return static_cast<uint32_t>(entry);
1270 }
1271
Ben Murdoch097c5b22016-05-18 11:27:45 +01001272 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1273 return GetDetailsImpl(holder->elements(), entry);
1274 }
1275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1277 uint32_t entry) {
1278 return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1279 }
1280
Ben Murdochda12d292016-06-02 14:46:10 +01001281 static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
1282 int entry, Object* raw_key, PropertyFilter filter) {
1283 DCHECK(!dictionary->IsDeleted(entry));
1284 DCHECK(raw_key->IsNumber());
1285 DCHECK_LE(raw_key->Number(), kMaxUInt32);
1286 PropertyDetails details = dictionary->DetailsAt(entry);
1287 PropertyAttributes attr = details.attributes();
1288 if ((attr & filter) != 0) return kMaxUInt32;
1289 return static_cast<uint32_t>(raw_key->Number());
1290 }
1291
1292 static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
1293 int entry, PropertyFilter filter) {
1294 DisallowHeapAllocation no_gc;
1295 Object* raw_key = dictionary->KeyAt(entry);
1296 if (!dictionary->IsKey(raw_key)) return kMaxUInt32;
1297 return FilterKey(dictionary, entry, raw_key, filter);
1298 }
1299
1300 static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
1301 int entry, PropertyFilter filter,
1302 Object* undefined, Object* the_hole) {
1303 DisallowHeapAllocation no_gc;
1304 Object* raw_key = dictionary->KeyAt(entry);
1305 // Replace the IsKey check with a direct comparison which is much faster.
1306 if (raw_key == undefined || raw_key == the_hole) {
1307 return kMaxUInt32;
1308 }
1309 return FilterKey(dictionary, entry, raw_key, filter);
1310 }
1311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 static void CollectElementIndicesImpl(Handle<JSObject> object,
1313 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01001314 KeyAccumulator* keys) {
1315 if (keys->filter() & SKIP_STRINGS) return;
Ben Murdochda12d292016-06-02 14:46:10 +01001316 Isolate* isolate = keys->isolate();
1317 Handle<Object> undefined = isolate->factory()->undefined_value();
1318 Handle<Object> the_hole = isolate->factory()->the_hole_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001319 Handle<SeededNumberDictionary> dictionary =
1320 Handle<SeededNumberDictionary>::cast(backing_store);
1321 int capacity = dictionary->Capacity();
Ben Murdochc5610432016-08-08 18:44:38 +01001322 PropertyFilter filter = keys->filter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001323 for (int i = 0; i < capacity; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +01001324 uint32_t key =
1325 GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
1326 if (key == kMaxUInt32) continue;
1327 keys->AddKey(key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 }
1329
1330 keys->SortCurrentElementsList();
1331 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001332
Ben Murdochda12d292016-06-02 14:46:10 +01001333 static Handle<FixedArray> DirectCollectElementIndicesImpl(
1334 Isolate* isolate, Handle<JSObject> object,
1335 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1336 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1337 uint32_t insertion_index = 0) {
1338 if (filter & SKIP_STRINGS) return list;
1339 if (filter & ONLY_ALL_CAN_READ) return list;
1340
1341 Handle<Object> undefined = isolate->factory()->undefined_value();
1342 Handle<Object> the_hole = isolate->factory()->the_hole_value();
1343 Handle<SeededNumberDictionary> dictionary =
1344 Handle<SeededNumberDictionary>::cast(backing_store);
1345 uint32_t capacity = dictionary->Capacity();
1346 for (uint32_t i = 0; i < capacity; i++) {
1347 uint32_t key =
1348 GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
1349 if (key == kMaxUInt32) continue;
1350 Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
1351 list->set(insertion_index, *index);
1352 insertion_index++;
1353 }
1354 *nof_indices = insertion_index;
1355 return list;
1356 }
1357
Ben Murdoch097c5b22016-05-18 11:27:45 +01001358 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1359 KeyAccumulator* accumulator,
1360 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01001361 Isolate* isolate = accumulator->isolate();
1362 Handle<Object> undefined = isolate->factory()->undefined_value();
1363 Handle<Object> the_hole = isolate->factory()->the_hole_value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001364 SeededNumberDictionary* dictionary =
1365 SeededNumberDictionary::cast(receiver->elements());
1366 int capacity = dictionary->Capacity();
1367 for (int i = 0; i < capacity; i++) {
1368 Object* k = dictionary->KeyAt(i);
Ben Murdochda12d292016-06-02 14:46:10 +01001369 if (k == *undefined) continue;
1370 if (k == *the_hole) continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001371 if (dictionary->IsDeleted(i)) continue;
1372 Object* value = dictionary->ValueAt(i);
1373 DCHECK(!value->IsTheHole());
1374 DCHECK(!value->IsAccessorPair());
1375 DCHECK(!value->IsAccessorInfo());
1376 accumulator->AddKey(value, convert);
1377 }
1378 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379};
1380
1381
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001382// Super class for all fast element arrays.
Ben Murdochc5610432016-08-08 18:44:38 +01001383template <typename Subclass, typename KindTraits>
1384class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001385 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001386 explicit FastElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001387 : ElementsAccessorBase<Subclass, KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388
1389 typedef typename KindTraits::BackingStore BackingStore;
1390
Ben Murdochda12d292016-06-02 14:46:10 +01001391 static Handle<SeededNumberDictionary> NormalizeImpl(
1392 Handle<JSObject> object, Handle<FixedArrayBase> store) {
1393 Isolate* isolate = store->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001394 ElementsKind kind = Subclass::kind();
Ben Murdochda12d292016-06-02 14:46:10 +01001395
1396 // Ensure that notifications fire if the array or object prototypes are
1397 // normalizing.
1398 if (IsFastSmiOrObjectElementsKind(kind)) {
1399 isolate->UpdateArrayProtectorOnNormalizeElements(object);
1400 }
1401
1402 int capacity = object->GetFastElementsUsage();
1403 Handle<SeededNumberDictionary> dictionary =
1404 SeededNumberDictionary::New(isolate, capacity);
1405
1406 PropertyDetails details = PropertyDetails::Empty();
1407 bool used_as_prototype = object->map()->is_prototype_map();
1408 int j = 0;
1409 for (int i = 0; j < capacity; i++) {
1410 if (IsHoleyElementsKind(kind)) {
1411 if (BackingStore::cast(*store)->is_the_hole(i)) continue;
1412 }
Ben Murdochc5610432016-08-08 18:44:38 +01001413 Handle<Object> value = Subclass::GetImpl(*store, i);
Ben Murdochda12d292016-06-02 14:46:10 +01001414 dictionary = SeededNumberDictionary::AddNumberEntry(
1415 dictionary, i, value, details, used_as_prototype);
1416 j++;
1417 }
1418 return dictionary;
1419 }
1420
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001421 static void DeleteAtEnd(Handle<JSObject> obj,
1422 Handle<BackingStore> backing_store, uint32_t entry) {
1423 uint32_t length = static_cast<uint32_t>(backing_store->length());
1424 Heap* heap = obj->GetHeap();
1425 for (; entry > 0; entry--) {
1426 if (!backing_store->is_the_hole(entry - 1)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 if (entry == 0) {
1429 FixedArray* empty = heap->empty_fixed_array();
Ben Murdochc5610432016-08-08 18:44:38 +01001430 // Dynamically ask for the elements kind here since we manually redirect
1431 // the operations for argument backing stores.
1432 if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001433 FixedArray::cast(obj->elements())->set(1, empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001434 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 obj->set_elements(empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001437 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001438 }
1439
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1441 length - entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001442 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1445 Handle<FixedArrayBase> store) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001446 DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
1447 obj->HasFastArgumentsElements() ||
1448 obj->HasFastStringWrapperElements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1450 if (!obj->IsJSArray() &&
1451 entry == static_cast<uint32_t>(store->length()) - 1) {
1452 DeleteAtEnd(obj, backing_store, entry);
1453 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455
1456 backing_store->set_the_hole(entry);
1457
1458 // TODO(verwaest): Move this out of elements.cc.
1459 // If an old space backing store is larger than a certain size and
1460 // has too few used values, normalize it.
1461 // To avoid doing the check on every delete we require at least
1462 // one adjacent hole to the value being deleted.
1463 const int kMinLengthForSparsenessCheck = 64;
1464 if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1465 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1466 uint32_t length = 0;
1467 if (obj->IsJSArray()) {
1468 JSArray::cast(*obj)->length()->ToArrayLength(&length);
1469 } else {
1470 length = static_cast<uint32_t>(store->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001471 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472 if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1473 (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1474 if (!obj->IsJSArray()) {
1475 uint32_t i;
1476 for (i = entry + 1; i < length; i++) {
1477 if (!backing_store->is_the_hole(i)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479 if (i == length) {
1480 DeleteAtEnd(obj, backing_store, entry);
1481 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482 }
1483 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001484 int num_used = 0;
1485 for (int i = 0; i < backing_store->length(); ++i) {
1486 if (!backing_store->is_the_hole(i)) {
1487 ++num_used;
1488 // Bail out if a number dictionary wouldn't be able to save at least
1489 // 75% space.
1490 if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1491 SeededNumberDictionary::kEntrySize >
1492 backing_store->length()) {
1493 return;
1494 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001495 }
1496 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497 JSObject::NormalizeElements(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001498 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001499 }
1500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 static void ReconfigureImpl(Handle<JSObject> object,
1502 Handle<FixedArrayBase> store, uint32_t entry,
1503 Handle<Object> value,
1504 PropertyAttributes attributes) {
1505 Handle<SeededNumberDictionary> dictionary =
1506 JSObject::NormalizeElements(object);
1507 entry = dictionary->FindEntry(entry);
1508 DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1509 value, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510 }
1511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001512 static void AddImpl(Handle<JSObject> object, uint32_t index,
1513 Handle<Object> value, PropertyAttributes attributes,
1514 uint32_t new_capacity) {
1515 DCHECK_EQ(NONE, attributes);
1516 ElementsKind from_kind = object->GetElementsKind();
Ben Murdochc5610432016-08-08 18:44:38 +01001517 ElementsKind to_kind = Subclass::kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 if (IsDictionaryElementsKind(from_kind) ||
1519 IsFastDoubleElementsKind(from_kind) !=
1520 IsFastDoubleElementsKind(to_kind) ||
Ben Murdochc5610432016-08-08 18:44:38 +01001521 Subclass::GetCapacityImpl(*object, object->elements()) !=
1522 new_capacity) {
1523 Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001525 if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 JSObject::TransitionElementsKind(object, to_kind);
1527 }
1528 if (IsFastSmiOrObjectElementsKind(from_kind)) {
1529 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1530 JSObject::EnsureWritableFastElements(object);
1531 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001532 }
Ben Murdochc5610432016-08-08 18:44:38 +01001533 Subclass::SetImpl(object, index, *value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534 }
1535
1536 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1537 ElementsKind kind = KindTraits::Kind;
1538 if (IsFastPackedElementsKind(kind)) {
1539 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1540 }
1541 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1542 JSObject::EnsureWritableFastElements(obj);
1543 }
1544 DeleteCommon(obj, entry, handle(obj->elements()));
1545 }
1546
1547 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1548 return !BackingStore::cast(backing_store)->is_the_hole(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001549 }
1550
Ben Murdoch097c5b22016-05-18 11:27:45 +01001551 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1552 KeyAccumulator* accumulator,
1553 AddKeyConversion convert) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001554 Handle<FixedArrayBase> elements(receiver->elements(),
1555 receiver->GetIsolate());
Ben Murdochc5610432016-08-08 18:44:38 +01001556 uint32_t length = Subclass::GetIterationLength(*receiver, *elements);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001557 for (uint32_t i = 0; i < length; i++) {
1558 if (IsFastPackedElementsKind(KindTraits::Kind) ||
1559 HasEntryImpl(*elements, i)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001560 accumulator->AddKey(Subclass::GetImpl(*elements, i), convert);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001561 }
1562 }
1563 }
1564
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001565 static void ValidateContents(Handle<JSObject> holder, int length) {
1566#if DEBUG
1567 Isolate* isolate = holder->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001568 Heap* heap = isolate->heap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001569 HandleScope scope(isolate);
1570 Handle<FixedArrayBase> elements(holder->elements(), isolate);
1571 Map* map = elements->map();
Ben Murdochc5610432016-08-08 18:44:38 +01001572 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1573 DCHECK_NE(map, heap->fixed_double_array_map());
1574 } else if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1575 DCHECK_NE(map, heap->fixed_cow_array_map());
1576 if (map == heap->fixed_array_map()) DCHECK_EQ(0, length);
1577 } else {
1578 UNREACHABLE();
1579 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 if (length == 0) return; // nothing to do!
Ben Murdochc5610432016-08-08 18:44:38 +01001581#if ENABLE_SLOW_DCHECKS
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001582 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001583 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1584 if (IsFastSmiElementsKind(KindTraits::Kind)) {
1585 for (int i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001586 DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001587 (IsFastHoleyElementsKind(KindTraits::Kind) &&
1588 backing_store->is_the_hole(i)));
1589 }
Ben Murdochc5610432016-08-08 18:44:38 +01001590 } else if (KindTraits::Kind == FAST_ELEMENTS ||
1591 KindTraits::Kind == FAST_DOUBLE_ELEMENTS) {
1592 for (int i = 0; i < length; i++) {
1593 DCHECK(!backing_store->is_the_hole(i));
1594 }
1595 } else {
1596 DCHECK(IsFastHoleyElementsKind(KindTraits::Kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001597 }
1598#endif
Ben Murdochc5610432016-08-08 18:44:38 +01001599#endif
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001600 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001601
Ben Murdochda12d292016-06-02 14:46:10 +01001602 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
Ben Murdochc5610432016-08-08 18:44:38 +01001603 return Subclass::RemoveElement(receiver, AT_END);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001604 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001605
Ben Murdochda12d292016-06-02 14:46:10 +01001606 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
Ben Murdochc5610432016-08-08 18:44:38 +01001607 return Subclass::RemoveElement(receiver, AT_START);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608 }
1609
1610 static uint32_t PushImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001611 Arguments* args, uint32_t push_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001612 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdochc5610432016-08-08 18:44:38 +01001613 return Subclass::AddArguments(receiver, backing_store, args, push_size,
1614 AT_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001615 }
1616
1617 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001618 Arguments* args, uint32_t unshift_size) {
Ben Murdochda12d292016-06-02 14:46:10 +01001619 Handle<FixedArrayBase> backing_store(receiver->elements());
Ben Murdochc5610432016-08-08 18:44:38 +01001620 return Subclass::AddArguments(receiver, backing_store, args, unshift_size,
1621 AT_START);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001622 }
1623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001624 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001625 uint32_t start, uint32_t end) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001627 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1628 int result_len = end < start ? 0u : end - start;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001629 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1630 KindTraits::Kind, result_len, result_len);
1631 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +01001632 Subclass::CopyElementsImpl(*backing_store, start, result_array->elements(),
1633 KindTraits::Kind, 0, kPackedSizeNotKnown,
1634 result_len);
1635 Subclass::TryTransitionResultArrayToPacked(result_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 return result_array;
1637 }
1638
1639 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 uint32_t start, uint32_t delete_count,
1641 Arguments* args, uint32_t add_count) {
1642 Isolate* isolate = receiver->GetIsolate();
1643 Heap* heap = isolate->heap();
1644 uint32_t length = Smi::cast(receiver->length())->value();
1645 uint32_t new_length = length - delete_count + add_count;
1646
Ben Murdochda12d292016-06-02 14:46:10 +01001647 ElementsKind kind = KindTraits::Kind;
1648 if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
1649 IsFastSmiOrObjectElementsKind(kind)) {
1650 HandleScope scope(isolate);
1651 JSObject::EnsureWritableFastElements(receiver);
1652 }
1653
1654 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
1655
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 if (new_length == 0) {
1657 receiver->set_elements(heap->empty_fixed_array());
1658 receiver->set_length(Smi::FromInt(0));
1659 return isolate->factory()->NewJSArrayWithElements(
1660 backing_store, KindTraits::Kind, delete_count);
1661 }
1662
1663 // Construct the result array which holds the deleted elements.
1664 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1665 KindTraits::Kind, delete_count, delete_count);
1666 if (delete_count > 0) {
1667 DisallowHeapAllocation no_gc;
Ben Murdochc5610432016-08-08 18:44:38 +01001668 Subclass::CopyElementsImpl(*backing_store, start,
1669 deleted_elements->elements(), KindTraits::Kind,
1670 0, kPackedSizeNotKnown, delete_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 }
1672
1673 // Delete and move elements to make space for add_count new elements.
1674 if (add_count < delete_count) {
Ben Murdochc5610432016-08-08 18:44:38 +01001675 Subclass::SpliceShrinkStep(isolate, receiver, backing_store, start,
1676 delete_count, add_count, length, new_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 } else if (add_count > delete_count) {
Ben Murdochc5610432016-08-08 18:44:38 +01001678 backing_store =
1679 Subclass::SpliceGrowStep(isolate, receiver, backing_store, start,
1680 delete_count, add_count, length, new_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001681 }
1682
1683 // Copy over the arguments.
Ben Murdochc5610432016-08-08 18:44:38 +01001684 Subclass::CopyArguments(args, backing_store, add_count, 3, start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001685
1686 receiver->set_length(Smi::FromInt(new_length));
Ben Murdochc5610432016-08-08 18:44:38 +01001687 Subclass::TryTransitionResultArrayToPacked(deleted_elements);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 return deleted_elements;
1689 }
1690
Ben Murdochda12d292016-06-02 14:46:10 +01001691 static Maybe<bool> CollectValuesOrEntriesImpl(
1692 Isolate* isolate, Handle<JSObject> object,
1693 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
1694 PropertyFilter filter) {
1695 int count = 0;
1696 uint32_t length = object->elements()->length();
1697 for (uint32_t index = 0; index < length; ++index) {
1698 if (!HasEntryImpl(object->elements(), index)) continue;
Ben Murdochc5610432016-08-08 18:44:38 +01001699 Handle<Object> value = Subclass::GetImpl(object->elements(), index);
Ben Murdochda12d292016-06-02 14:46:10 +01001700 if (get_entries) {
1701 value = MakeEntryPair(isolate, index, value);
1702 }
1703 values_or_entries->set(count++, *value);
1704 }
1705 *nof_items = count;
1706 return Just(true);
1707 }
1708
1709 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1710 Handle<FixedArrayBase> backing_store, int dst_index,
1711 int src_index, int len, int hole_start,
1712 int hole_end) {
1713 Heap* heap = isolate->heap();
1714 Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
1715 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1716 // Update all the copies of this backing_store handle.
1717 *dst_elms.location() =
1718 BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1719 receiver->set_elements(*dst_elms);
1720 // Adjust the hole offset as the array has been shrunk.
1721 hole_end -= src_index;
1722 DCHECK_LE(hole_start, backing_store->length());
1723 DCHECK_LE(hole_end, backing_store->length());
1724 } else if (len != 0) {
1725 if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1726 MemMove(dst_elms->data_start() + dst_index,
1727 dst_elms->data_start() + src_index, len * kDoubleSize);
1728 } else {
1729 DisallowHeapAllocation no_gc;
1730 heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
1731 len);
1732 }
1733 }
1734 if (hole_start != hole_end) {
1735 dst_elms->FillWithHoles(hole_start, hole_end);
1736 }
1737 }
1738
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739 private:
1740 // SpliceShrinkStep might modify the backing_store.
1741 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1742 Handle<FixedArrayBase> backing_store,
1743 uint32_t start, uint32_t delete_count,
1744 uint32_t add_count, uint32_t len,
1745 uint32_t new_length) {
1746 const int move_left_count = len - delete_count - start;
1747 const int move_left_dst_index = start + add_count;
Ben Murdochc5610432016-08-08 18:44:38 +01001748 Subclass::MoveElements(isolate, receiver, backing_store,
1749 move_left_dst_index, start + delete_count,
1750 move_left_count, new_length, len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 }
1752
1753 // SpliceGrowStep might modify the backing_store.
1754 static Handle<FixedArrayBase> SpliceGrowStep(
1755 Isolate* isolate, Handle<JSArray> receiver,
1756 Handle<FixedArrayBase> backing_store, uint32_t start,
1757 uint32_t delete_count, uint32_t add_count, uint32_t length,
1758 uint32_t new_length) {
1759 // Check we do not overflow the new_length.
1760 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1761 // Check if backing_store is big enough.
1762 if (new_length <= static_cast<uint32_t>(backing_store->length())) {
Ben Murdochc5610432016-08-08 18:44:38 +01001763 Subclass::MoveElements(isolate, receiver, backing_store,
1764 start + add_count, start + delete_count,
1765 (length - delete_count - start), 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001766 // MoveElements updates the backing_store in-place.
1767 return backing_store;
1768 }
1769 // New backing storage is needed.
1770 int capacity = JSObject::NewElementsCapacity(new_length);
1771 // Partially copy all elements up to start.
Ben Murdochc5610432016-08-08 18:44:38 +01001772 Handle<FixedArrayBase> new_elms = Subclass::ConvertElementsWithCapacity(
1773 receiver, backing_store, KindTraits::Kind, capacity, start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001774 // Copy the trailing elements after start + delete_count
Ben Murdochc5610432016-08-08 18:44:38 +01001775 Subclass::CopyElementsImpl(*backing_store, start + delete_count, *new_elms,
1776 KindTraits::Kind, start + add_count,
1777 kPackedSizeNotKnown,
1778 ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001779 receiver->set_elements(*new_elms);
1780 return new_elms;
1781 }
1782
1783 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001784 Where remove_position) {
1785 Isolate* isolate = receiver->GetIsolate();
Ben Murdochda12d292016-06-02 14:46:10 +01001786 ElementsKind kind = KindTraits::Kind;
1787 if (IsFastSmiOrObjectElementsKind(kind)) {
1788 HandleScope scope(isolate);
1789 JSObject::EnsureWritableFastElements(receiver);
1790 }
1791 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001792 uint32_t length =
1793 static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1794 DCHECK(length > 0);
1795 int new_length = length - 1;
1796 int remove_index = remove_position == AT_START ? 0 : new_length;
Ben Murdochc5610432016-08-08 18:44:38 +01001797 Handle<Object> result = Subclass::GetImpl(*backing_store, remove_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001798 if (remove_position == AT_START) {
Ben Murdochc5610432016-08-08 18:44:38 +01001799 Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
1800 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001801 }
Ben Murdochc5610432016-08-08 18:44:38 +01001802 Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001803
Ben Murdochda12d292016-06-02 14:46:10 +01001804 if (IsHoleyElementsKind(kind) && result->IsTheHole()) {
1805 return isolate->factory()->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001806 }
1807 return result;
1808 }
1809
1810 static uint32_t AddArguments(Handle<JSArray> receiver,
1811 Handle<FixedArrayBase> backing_store,
1812 Arguments* args, uint32_t add_size,
Ben Murdochc5610432016-08-08 18:44:38 +01001813 Where add_position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814 uint32_t length = Smi::cast(receiver->length())->value();
Ben Murdochda12d292016-06-02 14:46:10 +01001815 DCHECK(0 < add_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001816 uint32_t elms_len = backing_store->length();
1817 // Check we do not overflow the new_length.
1818 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1819 uint32_t new_length = length + add_size;
1820
1821 if (new_length > elms_len) {
1822 // New backing storage is needed.
1823 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1824 // If we add arguments to the start we have to shift the existing objects.
Ben Murdochc5610432016-08-08 18:44:38 +01001825 int copy_dst_index = add_position == AT_START ? add_size : 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001826 // Copy over all objects to a new backing_store.
Ben Murdochc5610432016-08-08 18:44:38 +01001827 backing_store = Subclass::ConvertElementsWithCapacity(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828 receiver, backing_store, KindTraits::Kind, capacity, 0,
1829 copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1830 receiver->set_elements(*backing_store);
Ben Murdochc5610432016-08-08 18:44:38 +01001831 } else if (add_position == AT_START) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832 // If the backing store has enough capacity and we add elements to the
1833 // start we have to shift the existing objects.
1834 Isolate* isolate = receiver->GetIsolate();
Ben Murdochc5610432016-08-08 18:44:38 +01001835 Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
1836 length, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001837 }
1838
Ben Murdochc5610432016-08-08 18:44:38 +01001839 int insertion_index = add_position == AT_START ? 0 : length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001840 // Copy the arguments to the start.
Ben Murdochc5610432016-08-08 18:44:38 +01001841 Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001842 // Set the length.
1843 receiver->set_length(Smi::FromInt(new_length));
1844 return new_length;
1845 }
1846
1847 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1848 uint32_t copy_size, uint32_t src_index,
1849 uint32_t dst_index) {
1850 // Add the provided values.
1851 DisallowHeapAllocation no_gc;
1852 FixedArrayBase* raw_backing_store = *dst_store;
1853 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1854 for (uint32_t i = 0; i < copy_size; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01001855 Object* argument = (*args)[src_index + i];
1856 DCHECK(!argument->IsTheHole());
1857 Subclass::SetImpl(raw_backing_store, dst_index + i, argument, mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001858 }
1859 }
1860};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001861
Ben Murdochc5610432016-08-08 18:44:38 +01001862template <typename Subclass, typename KindTraits>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863class FastSmiOrObjectElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01001864 : public FastElementsAccessor<Subclass, KindTraits> {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001865 public:
1866 explicit FastSmiOrObjectElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001867 : FastElementsAccessor<Subclass, KindTraits>(name) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001868
Ben Murdoch097c5b22016-05-18 11:27:45 +01001869 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1870 Object* value) {
1871 SetImpl(holder->elements(), entry, value);
1872 }
1873
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001874 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1875 Object* value) {
1876 FixedArray::cast(backing_store)->set(entry, value);
1877 }
1878
1879 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1880 Object* value, WriteBarrierMode mode) {
1881 FixedArray::cast(backing_store)->set(entry, value, mode);
1882 }
1883
1884 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +01001885 uint32_t index = Subclass::GetIndexForEntryImpl(backing_store, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886 return backing_store->get(index);
1887 }
1888
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001890 // NOTE: this method violates the handlified function signature convention:
1891 // raw pointer parameters in the function that allocates.
1892 // See ElementsAccessor::CopyElements() for details.
1893 // This method could actually allocate if copying from double elements to
1894 // object elements.
1895 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1896 FixedArrayBase* to, ElementsKind from_kind,
1897 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001899 DisallowHeapAllocation no_gc;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 ElementsKind to_kind = KindTraits::Kind;
1901 switch (from_kind) {
1902 case FAST_SMI_ELEMENTS:
1903 case FAST_HOLEY_SMI_ELEMENTS:
1904 case FAST_ELEMENTS:
1905 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001906 CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 to_start, copy_size);
1908 break;
1909 case FAST_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001910 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1911 AllowHeapAllocation allow_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 DCHECK(IsFastObjectElementsKind(to_kind));
1913 CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001915 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001917 CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1918 copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001919 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1921 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdochc5610432016-08-08 18:44:38 +01001922 case FAST_STRING_WRAPPER_ELEMENTS:
1923 case SLOW_STRING_WRAPPER_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001924#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001925 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1926#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01001927 // This function is currently only used for JSArrays with non-zero
1928 // length.
1929 UNREACHABLE();
1930 break;
1931 case NO_ELEMENTS:
1932 break; // Nothing to do.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 }
1934 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935};
1936
1937
1938class FastPackedSmiElementsAccessor
1939 : public FastSmiOrObjectElementsAccessor<
1940 FastPackedSmiElementsAccessor,
1941 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1942 public:
1943 explicit FastPackedSmiElementsAccessor(const char* name)
1944 : FastSmiOrObjectElementsAccessor<
1945 FastPackedSmiElementsAccessor,
1946 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1947};
1948
1949
1950class FastHoleySmiElementsAccessor
1951 : public FastSmiOrObjectElementsAccessor<
1952 FastHoleySmiElementsAccessor,
1953 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1954 public:
1955 explicit FastHoleySmiElementsAccessor(const char* name)
1956 : FastSmiOrObjectElementsAccessor<
1957 FastHoleySmiElementsAccessor,
1958 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1959};
1960
1961
1962class FastPackedObjectElementsAccessor
1963 : public FastSmiOrObjectElementsAccessor<
1964 FastPackedObjectElementsAccessor,
1965 ElementsKindTraits<FAST_ELEMENTS> > {
1966 public:
1967 explicit FastPackedObjectElementsAccessor(const char* name)
1968 : FastSmiOrObjectElementsAccessor<
1969 FastPackedObjectElementsAccessor,
1970 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1971};
1972
1973
1974class FastHoleyObjectElementsAccessor
1975 : public FastSmiOrObjectElementsAccessor<
1976 FastHoleyObjectElementsAccessor,
1977 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1978 public:
1979 explicit FastHoleyObjectElementsAccessor(const char* name)
1980 : FastSmiOrObjectElementsAccessor<
1981 FastHoleyObjectElementsAccessor,
1982 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1983};
1984
Ben Murdochc5610432016-08-08 18:44:38 +01001985template <typename Subclass, typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001986class FastDoubleElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01001987 : public FastElementsAccessor<Subclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001988 public:
1989 explicit FastDoubleElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01001990 : FastElementsAccessor<Subclass, KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001991
Ben Murdoch097c5b22016-05-18 11:27:45 +01001992 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1993 return GetImpl(holder->elements(), entry);
1994 }
1995
1996 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1997 Isolate* isolate = backing_store->GetIsolate();
1998 return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
1999 isolate);
2000 }
2001
2002 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2003 Object* value) {
2004 SetImpl(holder->elements(), entry, value);
2005 }
2006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002007 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2008 Object* value) {
2009 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002010 }
2011
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2013 Object* value, WriteBarrierMode mode) {
2014 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2015 }
2016
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002017 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2018 FixedArrayBase* to, ElementsKind from_kind,
2019 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002020 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002021 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002022 switch (from_kind) {
2023 case FAST_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002024 CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002025 packed_size, copy_size);
2026 break;
2027 case FAST_HOLEY_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002028 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002029 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002030 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031 case FAST_HOLEY_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002032 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002033 break;
2034 case FAST_ELEMENTS:
2035 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002036 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037 break;
2038 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002039 CopyDictionaryToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040 copy_size);
2041 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002042 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2043 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002044 case FAST_STRING_WRAPPER_ELEMENTS:
2045 case SLOW_STRING_WRAPPER_ELEMENTS:
2046 case NO_ELEMENTS:
2047#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002048 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2049#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01002050 // This function is currently only used for JSArrays with non-zero
2051 // length.
2052 UNREACHABLE();
2053 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002054 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002055 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002057
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002058
2059class FastPackedDoubleElementsAccessor
2060 : public FastDoubleElementsAccessor<
2061 FastPackedDoubleElementsAccessor,
2062 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
2063 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002064 explicit FastPackedDoubleElementsAccessor(const char* name)
2065 : FastDoubleElementsAccessor<
2066 FastPackedDoubleElementsAccessor,
2067 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
2068};
2069
2070
2071class FastHoleyDoubleElementsAccessor
2072 : public FastDoubleElementsAccessor<
2073 FastHoleyDoubleElementsAccessor,
2074 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
2075 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002076 explicit FastHoleyDoubleElementsAccessor(const char* name)
2077 : FastDoubleElementsAccessor<
2078 FastHoleyDoubleElementsAccessor,
2079 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002080};
2081
2082
2083// Super class for all external element arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002084template<ElementsKind Kind>
2085class TypedElementsAccessor
2086 : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002087 ElementsKindTraits<Kind> > {
2088 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 explicit TypedElementsAccessor(const char* name)
2090 : ElementsAccessorBase<AccessorClass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002091 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01002092
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002093 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002094 typedef TypedElementsAccessor<Kind> AccessorClass;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002095
Ben Murdoch097c5b22016-05-18 11:27:45 +01002096 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2097 Object* value) {
2098 SetImpl(holder->elements(), entry, value);
2099 }
2100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002101 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2102 Object* value) {
2103 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002104 }
2105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002106 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2107 Object* value, WriteBarrierMode mode) {
2108 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002109 }
2110
Ben Murdoch097c5b22016-05-18 11:27:45 +01002111 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2112 return GetImpl(holder->elements(), entry);
2113 }
2114
2115 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2116 return BackingStore::get(BackingStore::cast(backing_store), entry);
2117 }
2118
2119 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2120 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002121 }
2122
2123 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
2124 uint32_t entry) {
2125 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
2126 }
2127
Ben Murdoch097c5b22016-05-18 11:27:45 +01002128 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
2129 Handle<FixedArrayBase> backing_store,
2130 PropertyFilter filter) {
2131 return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
2132 }
2133
2134 static bool HasAccessorsImpl(JSObject* holder,
2135 FixedArrayBase* backing_store) {
2136 return false;
2137 }
2138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002139 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2140 uint32_t length,
2141 Handle<FixedArrayBase> backing_store) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002142 // External arrays do not support changing their length.
2143 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002144 }
2145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002146 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2147 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002148 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002150 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
2151 uint32_t entry) {
2152 return entry;
2153 }
2154
2155 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2156 FixedArrayBase* backing_store,
2157 uint32_t index, PropertyFilter filter) {
2158 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
2159 ? index
2160 : kMaxUInt32;
2161 }
2162
2163 static uint32_t GetCapacityImpl(JSObject* holder,
2164 FixedArrayBase* backing_store) {
2165 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
2166 if (view->WasNeutered()) return 0;
2167 return backing_store->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002168 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002169
2170 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2171 KeyAccumulator* accumulator,
2172 AddKeyConversion convert) {
Ben Murdochda12d292016-06-02 14:46:10 +01002173 Handle<FixedArrayBase> elements(receiver->elements());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002174 uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
2175 for (uint32_t i = 0; i < length; i++) {
2176 Handle<Object> value = AccessorClass::GetImpl(*elements, i);
2177 accumulator->AddKey(value, convert);
2178 }
2179 }
Ben Murdochda12d292016-06-02 14:46:10 +01002180
2181 static Maybe<bool> CollectValuesOrEntriesImpl(
2182 Isolate* isolate, Handle<JSObject> object,
2183 Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2184 PropertyFilter filter) {
2185 int count = 0;
2186 if ((filter & ONLY_CONFIGURABLE) == 0) {
2187 Handle<FixedArrayBase> elements(object->elements());
2188 uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements);
2189 for (uint32_t index = 0; index < length; ++index) {
2190 Handle<Object> value = AccessorClass::GetImpl(*elements, index);
2191 if (get_entries) {
2192 value = MakeEntryPair(isolate, index, value);
2193 }
2194 values_or_entries->set(count++, *value);
2195 }
2196 }
2197 *nof_items = count;
2198 return Just(true);
2199 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002200};
2201
2202
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002203
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002204#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
2205 typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
2206 Fixed##Type##ElementsAccessor;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002207
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002208TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
2209#undef FIXED_ELEMENTS_ACCESSOR
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002210
Ben Murdochc5610432016-08-08 18:44:38 +01002211template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002212class SloppyArgumentsElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01002213 : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002214 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002215 explicit SloppyArgumentsElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01002216 : ElementsAccessorBase<Subclass, KindTraits>(name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002217 USE(KindTraits::Kind);
2218 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002219
Ben Murdoch097c5b22016-05-18 11:27:45 +01002220 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2221 return GetImpl(holder->elements(), entry);
2222 }
2223
2224 static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002225 Isolate* isolate = parameters->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002226 Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002227 uint32_t length = parameter_map->length() - 2;
2228 if (entry < length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002229 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002230 Object* probe = parameter_map->get(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002231 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002232 int context_entry = Smi::cast(probe)->value();
2233 DCHECK(!context->get(context_entry)->IsTheHole());
2234 return handle(context->get(context_entry), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002235 } else {
2236 // Object is not mapped, defer to the arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002237 Handle<Object> result = ArgumentsAccessor::GetImpl(
2238 FixedArray::cast(parameter_map->get(1)), entry - length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002239 // Elements of the arguments object in slow mode might be slow aliases.
2240 if (result->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002241 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002242 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002243 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002244 int context_entry = alias->aliased_context_slot();
2245 DCHECK(!context->get(context_entry)->IsTheHole());
2246 return handle(context->get(context_entry), isolate);
2247 }
2248 return result;
2249 }
2250 }
2251
2252 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2253 uint32_t capacity) {
2254 UNREACHABLE();
2255 }
2256
Ben Murdoch097c5b22016-05-18 11:27:45 +01002257 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2258 Object* value) {
2259 SetImpl(holder->elements(), entry, value);
2260 }
2261
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002262 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
2263 Object* value) {
2264 FixedArray* parameter_map = FixedArray::cast(store);
2265 uint32_t length = parameter_map->length() - 2;
2266 if (entry < length) {
2267 Object* probe = parameter_map->get(entry + 2);
2268 Context* context = Context::cast(parameter_map->get(0));
2269 int context_entry = Smi::cast(probe)->value();
2270 DCHECK(!context->get(context_entry)->IsTheHole());
2271 context->set(context_entry, value);
2272 } else {
2273 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2274 Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
2275 if (current->IsAliasedArgumentsEntry()) {
2276 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
2277 Context* context = Context::cast(parameter_map->get(0));
2278 int context_entry = alias->aliased_context_slot();
2279 DCHECK(!context->get(context_entry)->IsTheHole());
2280 context->set(context_entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002281 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002282 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002283 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002284 }
2285 }
2286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002287 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2288 uint32_t length,
2289 Handle<FixedArrayBase> parameter_map) {
2290 // Sloppy arguments objects are not arrays.
2291 UNREACHABLE();
2292 }
2293
2294 static uint32_t GetCapacityImpl(JSObject* holder,
2295 FixedArrayBase* backing_store) {
2296 FixedArray* parameter_map = FixedArray::cast(backing_store);
2297 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2298 return parameter_map->length() - 2 +
2299 ArgumentsAccessor::GetCapacityImpl(holder, arguments);
2300 }
2301
Ben Murdoch097c5b22016-05-18 11:27:45 +01002302 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2303 KeyAccumulator* accumulator,
2304 AddKeyConversion convert) {
2305 FixedArrayBase* elements = receiver->elements();
2306 uint32_t length = GetCapacityImpl(*receiver, elements);
2307 for (uint32_t entry = 0; entry < length; entry++) {
2308 if (!HasEntryImpl(elements, entry)) continue;
2309 Handle<Object> value = GetImpl(elements, entry);
2310 accumulator->AddKey(value, convert);
2311 }
2312 }
2313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002314 static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
2315 FixedArray* parameter_map = FixedArray::cast(parameters);
2316 uint32_t length = parameter_map->length() - 2;
2317 if (entry < length) {
2318 return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002319 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002320
2321 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2322 return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002323 }
2324
Ben Murdoch097c5b22016-05-18 11:27:45 +01002325 static bool HasAccessorsImpl(JSObject* holder,
2326 FixedArrayBase* backing_store) {
2327 FixedArray* parameter_map = FixedArray::cast(backing_store);
2328 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2329 return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
2330 }
2331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332 static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
2333 uint32_t entry) {
2334 FixedArray* parameter_map = FixedArray::cast(parameters);
2335 uint32_t length = parameter_map->length() - 2;
2336 if (entry < length) return entry;
2337
2338 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2339 return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
2340 }
2341
2342 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2343 FixedArrayBase* parameters,
2344 uint32_t index, PropertyFilter filter) {
2345 FixedArray* parameter_map = FixedArray::cast(parameters);
2346 Object* probe = GetParameterMapArg(parameter_map, index);
2347 if (!probe->IsTheHole()) return index;
2348
2349 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2350 uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
2351 index, filter);
Ben Murdochc5610432016-08-08 18:44:38 +01002352 if (entry == kMaxUInt32) return kMaxUInt32;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002353 return (parameter_map->length() - 2) + entry;
2354 }
2355
Ben Murdoch097c5b22016-05-18 11:27:45 +01002356 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2357 FixedArray* parameter_map = FixedArray::cast(holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002358 uint32_t length = parameter_map->length() - 2;
2359 if (entry < length) {
2360 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002362 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2363 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002364 }
2365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002366 static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2367 uint32_t length = parameter_map->length() - 2;
2368 return index < length
2369 ? parameter_map->get(index + 2)
2370 : Object::cast(parameter_map->GetHeap()->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002371 }
2372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002373 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2374 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2375 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2376 if (entry < length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002377 // TODO(kmillikin): We could check if this was the last aliased
2378 // parameter, and revert to normal elements in that case. That
2379 // would enable GC of the context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002380 parameter_map->set_the_hole(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002381 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002382 Subclass::DeleteFromArguments(obj, entry - length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002383 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002384 }
Ben Murdochda12d292016-06-02 14:46:10 +01002385
2386 static void CollectElementIndicesImpl(Handle<JSObject> object,
2387 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01002388 KeyAccumulator* keys) {
Ben Murdochda12d292016-06-02 14:46:10 +01002389 FixedArray* parameter_map = FixedArray::cast(*backing_store);
2390 uint32_t length = parameter_map->length() - 2;
Ben Murdochc5610432016-08-08 18:44:38 +01002391 for (uint32_t i = 0; i < length; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +01002392 if (!parameter_map->get(i + 2)->IsTheHole()) {
2393 keys->AddKey(i);
2394 }
2395 }
2396
2397 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
Ben Murdochc5610432016-08-08 18:44:38 +01002398 ArgumentsAccessor::CollectElementIndicesImpl(object, store, keys);
2399 if (Subclass::kind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
Ben Murdochda12d292016-06-02 14:46:10 +01002400 keys->SortCurrentElementsList();
2401 }
2402 }
2403
2404 static Handle<FixedArray> DirectCollectElementIndicesImpl(
2405 Isolate* isolate, Handle<JSObject> object,
2406 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
2407 PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
2408 uint32_t insertion_index = 0) {
2409 FixedArray* parameter_map = FixedArray::cast(*backing_store);
2410 uint32_t length = parameter_map->length() - 2;
2411
2412 for (uint32_t i = 0; i < length; ++i) {
2413 if (parameter_map->get(i + 2)->IsTheHole()) continue;
2414 if (convert == CONVERT_TO_STRING) {
2415 Handle<String> index_string = isolate->factory()->Uint32ToString(i);
2416 list->set(insertion_index, *index_string);
2417 } else {
2418 list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
2419 }
2420 insertion_index++;
2421 }
2422
2423 Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
2424 return ArgumentsAccessor::DirectCollectElementIndicesImpl(
2425 isolate, object, store, convert, filter, list, nof_indices,
2426 insertion_index);
2427 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002428};
2429
2430
2431class SlowSloppyArgumentsElementsAccessor
2432 : public SloppyArgumentsElementsAccessor<
2433 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2434 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2435 public:
2436 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2437 : SloppyArgumentsElementsAccessor<
2438 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2439 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2440
2441 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2442 Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2443 Handle<SeededNumberDictionary> dict(
2444 SeededNumberDictionary::cast(parameter_map->get(1)));
2445 // TODO(verwaest): Remove reliance on index in Shrink.
2446 uint32_t index = GetIndexForEntryImpl(*dict, entry);
2447 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2448 USE(result);
2449 DCHECK(result->IsTrue());
2450 Handle<FixedArray> new_elements =
2451 SeededNumberDictionary::Shrink(dict, index);
2452 parameter_map->set(1, *new_elements);
2453 }
2454
2455 static void AddImpl(Handle<JSObject> object, uint32_t index,
2456 Handle<Object> value, PropertyAttributes attributes,
2457 uint32_t new_capacity) {
2458 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2459 Handle<FixedArrayBase> old_elements(
2460 FixedArrayBase::cast(parameter_map->get(1)));
2461 Handle<SeededNumberDictionary> dictionary =
2462 old_elements->IsSeededNumberDictionary()
2463 ? Handle<SeededNumberDictionary>::cast(old_elements)
2464 : JSObject::NormalizeElements(object);
2465 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2466 Handle<SeededNumberDictionary> new_dictionary =
2467 SeededNumberDictionary::AddNumberEntry(
2468 dictionary, index, value, details,
2469 object->map()->is_prototype_map());
2470 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2471 if (*dictionary != *new_dictionary) {
2472 FixedArray::cast(object->elements())->set(1, *new_dictionary);
2473 }
2474 }
2475
2476 static void ReconfigureImpl(Handle<JSObject> object,
2477 Handle<FixedArrayBase> store, uint32_t entry,
2478 Handle<Object> value,
2479 PropertyAttributes attributes) {
2480 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2481 uint32_t length = parameter_map->length() - 2;
2482 if (entry < length) {
2483 Object* probe = parameter_map->get(entry + 2);
2484 DCHECK(!probe->IsTheHole());
2485 Context* context = Context::cast(parameter_map->get(0));
2486 int context_entry = Smi::cast(probe)->value();
2487 DCHECK(!context->get(context_entry)->IsTheHole());
2488 context->set(context_entry, *value);
2489
2490 // Redefining attributes of an aliased element destroys fast aliasing.
2491 parameter_map->set_the_hole(entry + 2);
2492 // For elements that are still writable we re-establish slow aliasing.
2493 if ((attributes & READ_ONLY) == 0) {
2494 Isolate* isolate = store->GetIsolate();
2495 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2496 }
2497
2498 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2499 Handle<SeededNumberDictionary> arguments(
2500 SeededNumberDictionary::cast(parameter_map->get(1)));
2501 arguments = SeededNumberDictionary::AddNumberEntry(
2502 arguments, entry, value, details, object->map()->is_prototype_map());
2503 // If the attributes were NONE, we would have called set rather than
2504 // reconfigure.
2505 DCHECK_NE(NONE, attributes);
2506 object->RequireSlowElements(*arguments);
2507 parameter_map->set(1, *arguments);
2508 } else {
2509 Handle<FixedArrayBase> arguments(
2510 FixedArrayBase::cast(parameter_map->get(1)));
2511 DictionaryElementsAccessor::ReconfigureImpl(
2512 object, arguments, entry - length, value, attributes);
2513 }
2514 }
2515};
2516
2517
2518class FastSloppyArgumentsElementsAccessor
2519 : public SloppyArgumentsElementsAccessor<
2520 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2521 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2522 public:
2523 explicit FastSloppyArgumentsElementsAccessor(const char* name)
2524 : SloppyArgumentsElementsAccessor<
2525 FastSloppyArgumentsElementsAccessor,
2526 FastHoleyObjectElementsAccessor,
2527 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2528
Ben Murdochc5610432016-08-08 18:44:38 +01002529 static Handle<FixedArray> GetArguments(Isolate* isolate,
2530 FixedArrayBase* backing_store) {
2531 FixedArray* parameter_map = FixedArray::cast(backing_store);
2532 return Handle<FixedArray>(FixedArray::cast(parameter_map->get(1)), isolate);
2533 }
2534
2535 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, uint32_t start,
2536 uint32_t end) {
2537 Isolate* isolate = receiver->GetIsolate();
2538 uint32_t result_len = end < start ? 0u : end - start;
2539 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2540 FAST_HOLEY_ELEMENTS, result_len, result_len);
2541 DisallowHeapAllocation no_gc;
2542 FixedArray* elements = FixedArray::cast(result_array->elements());
2543 FixedArray* parameters = FixedArray::cast(receiver->elements());
2544 uint32_t insertion_index = 0;
2545 for (uint32_t i = start; i < end; i++) {
2546 uint32_t entry =
2547 GetEntryForIndexImpl(*receiver, parameters, i, ALL_PROPERTIES);
2548 if (entry != kMaxUInt32 && HasEntryImpl(parameters, entry)) {
2549 elements->set(insertion_index, *GetImpl(parameters, entry));
2550 } else {
2551 elements->set_the_hole(insertion_index);
2552 }
2553 insertion_index++;
2554 }
2555 return result_array;
2556 }
2557
Ben Murdochda12d292016-06-02 14:46:10 +01002558 static Handle<SeededNumberDictionary> NormalizeImpl(
2559 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
Ben Murdochc5610432016-08-08 18:44:38 +01002560 Handle<FixedArray> arguments =
2561 GetArguments(elements->GetIsolate(), *elements);
Ben Murdochda12d292016-06-02 14:46:10 +01002562 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
2563 }
2564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002565 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
Ben Murdochc5610432016-08-08 18:44:38 +01002566 Handle<FixedArray> arguments =
2567 GetArguments(obj->GetIsolate(), obj->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002568 FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2569 }
2570
2571 static void AddImpl(Handle<JSObject> object, uint32_t index,
2572 Handle<Object> value, PropertyAttributes attributes,
2573 uint32_t new_capacity) {
2574 DCHECK_EQ(NONE, attributes);
2575 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2576 Handle<FixedArrayBase> old_elements(
2577 FixedArrayBase::cast(parameter_map->get(1)));
2578 if (old_elements->IsSeededNumberDictionary() ||
2579 static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2580 GrowCapacityAndConvertImpl(object, new_capacity);
2581 }
2582 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2583 // For fast holey objects, the entry equals the index. The code above made
2584 // sure that there's enough space to store the value. We cannot convert
2585 // index to entry explicitly since the slot still contains the hole, so the
2586 // current EntryForIndex would indicate that it is "absent" by returning
2587 // kMaxUInt32.
2588 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2589 }
2590
2591 static void ReconfigureImpl(Handle<JSObject> object,
2592 Handle<FixedArrayBase> store, uint32_t entry,
2593 Handle<Object> value,
2594 PropertyAttributes attributes) {
2595 Handle<SeededNumberDictionary> dictionary =
2596 JSObject::NormalizeElements(object);
2597 FixedArray::cast(*store)->set(1, *dictionary);
2598 uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2599 if (entry >= length) {
2600 entry = dictionary->FindEntry(entry - length) + length;
2601 }
2602 SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2603 value, attributes);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002604 }
2605
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002606 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2607 FixedArrayBase* to, ElementsKind from_kind,
2608 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002609 int copy_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002610 DCHECK(!to->IsDictionary());
2611 if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2612 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2613 to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002614 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002615 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2616 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2617 FAST_HOLEY_ELEMENTS, to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002618 }
2619 }
2620
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002621 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2622 uint32_t capacity) {
2623 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2624 Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2625 ElementsKind from_kind = object->GetElementsKind();
2626 // This method should only be called if there's a reason to update the
2627 // elements.
2628 DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2629 static_cast<uint32_t>(old_elements->length()) < capacity);
2630 Handle<FixedArrayBase> elements =
2631 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2632 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2633 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2634 JSObject::MigrateToMap(object, new_map);
2635 parameter_map->set(1, *elements);
2636 JSObject::ValidateElements(object);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002637 }
2638};
2639
Ben Murdochc5610432016-08-08 18:44:38 +01002640template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
Ben Murdoch097c5b22016-05-18 11:27:45 +01002641class StringWrapperElementsAccessor
Ben Murdochc5610432016-08-08 18:44:38 +01002642 : public ElementsAccessorBase<Subclass, KindTraits> {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002643 public:
2644 explicit StringWrapperElementsAccessor(const char* name)
Ben Murdochc5610432016-08-08 18:44:38 +01002645 : ElementsAccessorBase<Subclass, KindTraits>(name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002646 USE(KindTraits::Kind);
2647 }
2648
2649 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2650 Isolate* isolate = holder->GetIsolate();
2651 Handle<String> string(GetString(*holder), isolate);
2652 uint32_t length = static_cast<uint32_t>(string->length());
2653 if (entry < length) {
2654 return isolate->factory()->LookupSingleCharacterStringFromCode(
2655 String::Flatten(string)->Get(entry));
2656 }
2657 return BackingStoreAccessor::GetImpl(holder, entry - length);
2658 }
2659
2660 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2661 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2662 if (entry < length) {
2663 PropertyAttributes attributes =
2664 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
2665 return PropertyDetails(attributes, v8::internal::DATA, 0,
2666 PropertyCellType::kNoCell);
2667 }
2668 return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
2669 }
2670
2671 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2672 FixedArrayBase* backing_store,
2673 uint32_t index, PropertyFilter filter) {
2674 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2675 if (index < length) return index;
2676 uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
2677 holder, backing_store, index, filter);
2678 if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
2679 DCHECK(backing_store_entry < kMaxUInt32 - length);
2680 return backing_store_entry + length;
2681 }
2682
2683 static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
2684 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2685 if (entry < length) {
2686 return; // String contents can't be deleted.
2687 }
2688 BackingStoreAccessor::DeleteImpl(holder, entry - length);
2689 }
2690
2691 static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
2692 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2693 if (entry < length) {
2694 return; // String contents are read-only.
2695 }
2696 BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
2697 }
2698
2699 static void AddImpl(Handle<JSObject> object, uint32_t index,
2700 Handle<Object> value, PropertyAttributes attributes,
2701 uint32_t new_capacity) {
2702 DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
2703 // Explicitly grow fast backing stores if needed. Dictionaries know how to
2704 // extend their capacity themselves.
2705 if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
2706 (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
2707 BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
2708 new_capacity)) {
Ben Murdochc5610432016-08-08 18:44:38 +01002709 GrowCapacityAndConvertImpl(object, new_capacity);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002710 }
2711 BackingStoreAccessor::AddImpl(object, index, value, attributes,
2712 new_capacity);
2713 }
2714
2715 static void ReconfigureImpl(Handle<JSObject> object,
2716 Handle<FixedArrayBase> store, uint32_t entry,
2717 Handle<Object> value,
2718 PropertyAttributes attributes) {
2719 uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
2720 if (entry < length) {
2721 return; // String contents can't be reconfigured.
2722 }
2723 BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
2724 attributes);
2725 }
2726
2727 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2728 KeyAccumulator* accumulator,
2729 AddKeyConversion convert) {
2730 Isolate* isolate = receiver->GetIsolate();
2731 Handle<String> string(GetString(*receiver), isolate);
2732 string = String::Flatten(string);
2733 uint32_t length = static_cast<uint32_t>(string->length());
2734 for (uint32_t i = 0; i < length; i++) {
2735 accumulator->AddKey(
2736 isolate->factory()->LookupSingleCharacterStringFromCode(
2737 string->Get(i)),
2738 convert);
2739 }
2740 BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
2741 convert);
2742 }
2743
2744 static void CollectElementIndicesImpl(Handle<JSObject> object,
2745 Handle<FixedArrayBase> backing_store,
Ben Murdochc5610432016-08-08 18:44:38 +01002746 KeyAccumulator* keys) {
Ben Murdochda12d292016-06-02 14:46:10 +01002747 uint32_t length = GetString(*object)->length();
2748 for (uint32_t i = 0; i < length; i++) {
2749 keys->AddKey(i);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002750 }
Ben Murdochc5610432016-08-08 18:44:38 +01002751 BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
2752 keys);
2753 }
2754
2755 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2756 uint32_t capacity) {
2757 Handle<FixedArrayBase> old_elements(object->elements());
2758 ElementsKind from_kind = object->GetElementsKind();
2759 // This method should only be called if there's a reason to update the
2760 // elements.
2761 DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
2762 static_cast<uint32_t>(old_elements->length()) < capacity);
2763 Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
2764 FAST_STRING_WRAPPER_ELEMENTS,
2765 capacity);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002766 }
2767
2768 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2769 FixedArrayBase* to, ElementsKind from_kind,
2770 uint32_t to_start, int packed_size,
2771 int copy_size) {
Ben Murdochc5610432016-08-08 18:44:38 +01002772 DCHECK(!to->IsDictionary());
2773 if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
2774 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2775 to_start, copy_size);
2776 } else {
2777 DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
2778 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2779 FAST_HOLEY_ELEMENTS, to_start, copy_size);
2780 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002781 }
2782
2783 private:
2784 static String* GetString(JSObject* holder) {
2785 DCHECK(holder->IsJSValue());
2786 JSValue* js_value = JSValue::cast(holder);
2787 DCHECK(js_value->value()->IsString());
2788 return String::cast(js_value->value());
2789 }
2790};
2791
2792class FastStringWrapperElementsAccessor
2793 : public StringWrapperElementsAccessor<
2794 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2795 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
2796 public:
2797 explicit FastStringWrapperElementsAccessor(const char* name)
2798 : StringWrapperElementsAccessor<
2799 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2800 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
Ben Murdochda12d292016-06-02 14:46:10 +01002801
2802 static Handle<SeededNumberDictionary> NormalizeImpl(
2803 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
2804 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
2805 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002806};
2807
2808class SlowStringWrapperElementsAccessor
2809 : public StringWrapperElementsAccessor<
2810 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2811 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
2812 public:
2813 explicit SlowStringWrapperElementsAccessor(const char* name)
2814 : StringWrapperElementsAccessor<
2815 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2816 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
2817
2818 static bool HasAccessorsImpl(JSObject* holder,
2819 FixedArrayBase* backing_store) {
2820 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
2821 }
2822};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002823
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002824} // namespace
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002825
2826
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002827void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2828 bool allow_appending) {
2829 DisallowHeapAllocation no_allocation;
2830 Object* raw_length = NULL;
2831 const char* elements_type = "array";
2832 if (obj->IsJSArray()) {
2833 JSArray* array = JSArray::cast(*obj);
2834 raw_length = array->length();
2835 } else {
2836 raw_length = Smi::FromInt(obj->elements()->length());
2837 elements_type = "object";
2838 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002839
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002840 if (raw_length->IsNumber()) {
2841 double n = raw_length->Number();
2842 if (FastI2D(FastD2UI(n)) == n) {
2843 int32_t int32_length = DoubleToInt32(n);
2844 uint32_t compare_length = static_cast<uint32_t>(int32_length);
2845 if (allow_appending) compare_length++;
2846 if (index >= compare_length) {
2847 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2848 elements_type, op, elements_type, static_cast<int>(int32_length),
2849 static_cast<int>(index));
2850 TraceTopFrame(obj->GetIsolate());
2851 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002852 }
2853 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002854 PrintF("[%s elements length not integer value in ", elements_type);
2855 TraceTopFrame(obj->GetIsolate());
2856 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002857 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002858 } else {
2859 PrintF("[%s elements length not a number in ", elements_type);
2860 TraceTopFrame(obj->GetIsolate());
2861 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002862 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002863}
2864
2865
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002866MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2867 Arguments* args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002868 if (args->length() == 0) {
2869 // Optimize the case where there are no parameters passed.
2870 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2871 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002873 } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2874 uint32_t length;
2875 if (!args->at<Object>(0)->ToArrayLength(&length)) {
2876 return ThrowArrayLengthRangeError(array->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002877 }
2878
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002879 // Optimize the case where there is one argument and the argument is a small
2880 // smi.
2881 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2882 ElementsKind elements_kind = array->GetElementsKind();
2883 JSArray::Initialize(array, length, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002884
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002885 if (!IsFastHoleyElementsKind(elements_kind)) {
2886 elements_kind = GetHoleyElementsKind(elements_kind);
2887 JSObject::TransitionElementsKind(array, elements_kind);
2888 }
2889 } else if (length == 0) {
2890 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2891 } else {
2892 // Take the argument as the length.
2893 JSArray::Initialize(array, 0);
2894 JSArray::SetLength(array, length);
2895 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002896 return array;
2897 }
2898
2899 Factory* factory = array->GetIsolate()->factory();
2900
2901 // Set length and elements on the array.
2902 int number_of_elements = args->length();
2903 JSObject::EnsureCanContainElements(
2904 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2905
2906 // Allocate an appropriately typed elements array.
2907 ElementsKind elements_kind = array->GetElementsKind();
2908 Handle<FixedArrayBase> elms;
2909 if (IsFastDoubleElementsKind(elements_kind)) {
2910 elms = Handle<FixedArrayBase>::cast(
2911 factory->NewFixedDoubleArray(number_of_elements));
2912 } else {
2913 elms = Handle<FixedArrayBase>::cast(
2914 factory->NewFixedArrayWithHoles(number_of_elements));
2915 }
2916
2917 // Fill in the content
Ben Murdochc5610432016-08-08 18:44:38 +01002918 switch (elements_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002919 case FAST_HOLEY_SMI_ELEMENTS:
2920 case FAST_SMI_ELEMENTS: {
2921 Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002922 for (int entry = 0; entry < number_of_elements; entry++) {
2923 smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 }
2925 break;
2926 }
2927 case FAST_HOLEY_ELEMENTS:
2928 case FAST_ELEMENTS: {
2929 DisallowHeapAllocation no_gc;
2930 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2931 Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002932 for (int entry = 0; entry < number_of_elements; entry++) {
2933 object_elms->set(entry, (*args)[entry], mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002934 }
2935 break;
2936 }
2937 case FAST_HOLEY_DOUBLE_ELEMENTS:
2938 case FAST_DOUBLE_ELEMENTS: {
2939 Handle<FixedDoubleArray> double_elms =
2940 Handle<FixedDoubleArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002941 for (int entry = 0; entry < number_of_elements; entry++) {
2942 double_elms->set(entry, (*args)[entry]->Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002943 }
2944 break;
2945 }
2946 default:
2947 UNREACHABLE();
2948 break;
2949 }
2950
2951 array->set_elements(*elms);
2952 array->set_length(Smi::FromInt(number_of_elements));
2953 return array;
2954}
2955
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002956
2957void ElementsAccessor::InitializeOncePerProcess() {
2958 static ElementsAccessor* accessor_array[] = {
2959#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2960 ELEMENTS_LIST(ACCESSOR_ARRAY)
2961#undef ACCESSOR_ARRAY
2962 };
2963
2964 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2965 kElementsKindCount);
2966
2967 elements_accessors_ = accessor_array;
2968}
2969
2970
2971void ElementsAccessor::TearDown() {
2972 if (elements_accessors_ == NULL) return;
2973#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2974 ELEMENTS_LIST(ACCESSOR_DELETE)
2975#undef ACCESSOR_DELETE
2976 elements_accessors_ = NULL;
2977}
2978
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002979Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
Ben Murdochc5610432016-08-08 18:44:38 +01002980 uint32_t concat_size,
2981 uint32_t result_len) {
Ben Murdochda12d292016-06-02 14:46:10 +01002982 ElementsKind result_elements_kind = GetInitialFastElementsKind();
Ben Murdochc5610432016-08-08 18:44:38 +01002983 bool has_raw_doubles = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002984 {
2985 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +01002986 bool is_holey = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002987 for (uint32_t i = 0; i < concat_size; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01002988 Object* arg = (*args)[i];
2989 ElementsKind arg_kind = JSArray::cast(arg)->GetElementsKind();
Ben Murdochda12d292016-06-02 14:46:10 +01002990 has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002991 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
Ben Murdochda12d292016-06-02 14:46:10 +01002992 result_elements_kind =
2993 GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002994 }
2995 if (is_holey) {
Ben Murdochda12d292016-06-02 14:46:10 +01002996 result_elements_kind = GetHoleyElementsKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002997 }
2998 }
2999
3000 // If a double array is concatted into a fast elements array, the fast
3001 // elements array needs to be initialized to contain proper holes, since
3002 // boxing doubles may cause incremental marking.
Ben Murdochda12d292016-06-02 14:46:10 +01003003 bool requires_double_boxing =
3004 has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
3005 ArrayStorageAllocationMode mode = requires_double_boxing
3006 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
3007 : DONT_INITIALIZE_ARRAY_ELEMENTS;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003008 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
Ben Murdochda12d292016-06-02 14:46:10 +01003009 result_elements_kind, result_len, result_len, mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003010 if (result_len == 0) return result_array;
Ben Murdochda12d292016-06-02 14:46:10 +01003011
3012 uint32_t insertion_index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003013 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
Ben Murdochda12d292016-06-02 14:46:10 +01003014 ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003015 for (uint32_t i = 0; i < concat_size; i++) {
3016 // It is crucial to keep |array| in a raw pointer form to avoid
3017 // performance degradation.
3018 JSArray* array = JSArray::cast((*args)[i]);
Ben Murdochda12d292016-06-02 14:46:10 +01003019 uint32_t len = 0;
3020 array->length()->ToArrayLength(&len);
3021 if (len == 0) continue;
3022 ElementsKind from_kind = array->GetElementsKind();
3023 accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
3024 insertion_index += len;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003025 }
3026
Ben Murdochda12d292016-06-02 14:46:10 +01003027 DCHECK_EQ(insertion_index, result_len);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003028 return result_array;
3029}
3030
3031ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3032} // namespace internal
3033} // namespace v8