blob: 9fd450a75ae1325892be91d05a1154b993c8669b [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"
10#include "src/messages.h"
11#include "src/objects-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/utils.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013
14// Each concrete ElementsAccessor can handle exactly one ElementsKind,
15// several abstract ElementsAccessor classes are used to allow sharing
16// common code.
17//
18// Inheritance hierarchy:
19// - ElementsAccessorBase (abstract)
20// - FastElementsAccessor (abstract)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021// - FastSmiOrObjectElementsAccessor
22// - FastPackedSmiElementsAccessor
23// - FastHoleySmiElementsAccessor
24// - FastPackedObjectElementsAccessor
25// - FastHoleyObjectElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010026// - FastDoubleElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027// - FastPackedDoubleElementsAccessor
28// - FastHoleyDoubleElementsAccessor
29// - TypedElementsAccessor: template, with instantiations:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030// - FixedUint8ElementsAccessor
31// - FixedInt8ElementsAccessor
32// - FixedUint16ElementsAccessor
33// - FixedInt16ElementsAccessor
34// - FixedUint32ElementsAccessor
35// - FixedInt32ElementsAccessor
36// - FixedFloat32ElementsAccessor
37// - FixedFloat64ElementsAccessor
38// - FixedUint8ClampedElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010039// - DictionaryElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040// - SloppyArgumentsElementsAccessor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041// - FastSloppyArgumentsElementsAccessor
42// - SlowSloppyArgumentsElementsAccessor
Ben Murdoch097c5b22016-05-18 11:27:45 +010043// - StringWrapperElementsAccessor
44// - FastStringWrapperElementsAccessor
45// - SlowStringWrapperElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +010046
Ben Murdoch69a99ed2011-11-30 16:03:39 +000047namespace v8 {
48namespace internal {
49
50
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051namespace {
52
53
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054static const int kPackedSizeNotKnown = -1;
55
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056enum Where { AT_START, AT_END };
57
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058
Ben Murdoch3ef787d2012-04-12 10:51:47 +010059// First argument in list is the accessor class, the second argument is the
60// accessor ElementsKind, and the third is the backing store class. Use the
61// fast element handler for smi-only arrays. The implementation is currently
62// identical. Note that the order must match that of the ElementsKind enum for
63// the |accessor_array[]| below to work.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064#define ELEMENTS_LIST(V) \
65 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
66 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
67 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
68 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
69 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
70 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
71 FixedDoubleArray) \
72 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
73 V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
74 FixedArray) \
75 V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
76 FixedArray) \
Ben Murdoch097c5b22016-05-18 11:27:45 +010077 V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS, \
78 FixedArray) \
79 V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS, \
80 FixedArray) \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
82 V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
83 V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
84 V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
85 V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
86 V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
87 V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
88 V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
89 V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 FixedUint8ClampedArray)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010091
Ben Murdoch3ef787d2012-04-12 10:51:47 +010092template<ElementsKind Kind> class ElementsKindTraits {
93 public:
94 typedef FixedArrayBase BackingStore;
95};
96
97#define ELEMENTS_TRAITS(Class, KindParam, Store) \
98template<> class ElementsKindTraits<KindParam> { \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 public: /* NOLINT */ \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100100 static const ElementsKind Kind = KindParam; \
101 typedef Store BackingStore; \
102};
103ELEMENTS_LIST(ELEMENTS_TRAITS)
104#undef ELEMENTS_TRAITS
105
106
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107MUST_USE_RESULT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
109 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100111}
112
113
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114void CopyObjectToObjectElements(FixedArrayBase* from_base,
115 ElementsKind from_kind, uint32_t from_start,
116 FixedArrayBase* to_base, ElementsKind to_kind,
117 uint32_t to_start, int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 DCHECK(to_base->map() !=
119 from_base->GetIsolate()->heap()->fixed_cow_array_map());
120 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100121 int copy_size = raw_copy_size;
122 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100124 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 copy_size = Min(from_base->length() - from_start,
126 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 int start = to_start + copy_size;
129 int length = to_base->length() - start;
130 if (length > 0) {
131 Heap* heap = from_base->GetHeap();
132 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
133 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100134 }
135 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100136 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
138 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100139 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 FixedArray* from = FixedArray::cast(from_base);
141 FixedArray* to = FixedArray::cast(to_base);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 DCHECK(IsFastSmiOrObjectElementsKind(from_kind) ||
143 from_kind == FAST_STRING_WRAPPER_ELEMENTS);
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 Murdoch097c5b22016-05-18 11:27:45 +0100147 ((IsFastObjectElementsKind(from_kind) &&
148 IsFastObjectElementsKind(to_kind)) ||
149 from_kind == FAST_STRING_WRAPPER_ELEMENTS)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 ? UPDATE_WRITE_BARRIER
151 : SKIP_WRITE_BARRIER;
152 for (int i = 0; i < copy_size; i++) {
153 Object* value = from->get(from_start + i);
154 to->set(to_start + i, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 }
156}
157
158
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159static void CopyDictionaryToObjectElements(
160 FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
161 ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
162 DisallowHeapAllocation no_allocation;
163 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100164 int copy_size = raw_copy_size;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100165 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100167 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
168 copy_size = from->max_number_key() + 1 - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100169 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 int start = to_start + copy_size;
171 int length = to_base->length() - start;
172 if (length > 0) {
173 Heap* heap = from->GetHeap();
174 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
175 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100176 }
177 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100178 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 DCHECK(to_base != from_base);
180 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000182 FixedArray* to = FixedArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100183 uint32_t to_length = to->length();
184 if (to_start + copy_size > to_length) {
185 copy_size = to_length - to_start;
186 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187 WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
188 ? UPDATE_WRITE_BARRIER
189 : SKIP_WRITE_BARRIER;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100190 for (int i = 0; i < copy_size; i++) {
191 int entry = from->FindEntry(i + from_start);
192 if (entry != SeededNumberDictionary::kNotFound) {
193 Object* value = from->ValueAt(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194 DCHECK(!value->IsTheHole());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 to->set(i + to_start, value, write_barrier_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100196 } else {
197 to->set_the_hole(i + to_start);
198 }
199 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100200}
201
202
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203// NOTE: this method violates the handlified function signature convention:
204// raw pointer parameters in the function that allocates.
205// See ElementsAccessorBase::CopyElements() for details.
206static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 uint32_t from_start,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400208 FixedArrayBase* to_base,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 uint32_t to_start, int raw_copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100210 int copy_size = raw_copy_size;
211 if (raw_copy_size < 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400212 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100214 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 copy_size = Min(from_base->length() - from_start,
216 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100217 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 // Also initialize the area that will be copied over since HeapNumber
219 // allocation below can cause an incremental marking step, requiring all
220 // existing heap objects to be propertly initialized.
221 int start = to_start;
222 int length = to_base->length() - start;
223 if (length > 0) {
224 Heap* heap = from_base->GetHeap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400225 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226 heap->the_hole_value(), length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100227 }
228 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100229 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
232 (copy_size + static_cast<int>(from_start)) <= from_base->length());
233 if (copy_size == 0) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234
235 // From here on, the code below could actually allocate. Therefore the raw
236 // values are wrapped into handles.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 Isolate* isolate = from_base->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400238 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
239 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 // Use an outer loop to not waste too much time on creating HandleScopes.
242 // On the other hand we might overflow a single handle scope depending on
243 // the copy_size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 int offset = 0;
245 while (offset < copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 offset += 100;
248 for (int i = offset - 100; i < offset && i < copy_size; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100249 Handle<Object> value =
250 FixedDoubleArray::get(*from, i + from_start, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252 }
253 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100254}
255
256
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100258 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 FixedArrayBase* to_base,
260 uint32_t to_start, int raw_copy_size) {
261 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100262 int copy_size = raw_copy_size;
263 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100265 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 copy_size = Min(from_base->length() - from_start,
267 to_base->length() - to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100268 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
270 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100271 }
272 }
273 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
275 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100276 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
278 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100279 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
280 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
281 to_address += kDoubleSize * to_start;
282 from_address += kDoubleSize * from_start;
283 int words_per_double = (kDoubleSize / kPointerSize);
284 CopyWords(reinterpret_cast<Object**>(to_address),
285 reinterpret_cast<Object**>(from_address),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 static_cast<size_t>(words_per_double * copy_size));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100287}
288
289
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290static void CopySmiToDoubleElements(FixedArrayBase* from_base,
291 uint32_t from_start,
292 FixedArrayBase* to_base, uint32_t to_start,
293 int raw_copy_size) {
294 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100295 int copy_size = raw_copy_size;
296 if (raw_copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100298 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 copy_size = from_base->length() - from_start;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100300 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
302 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100303 }
304 }
305 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
307 (copy_size + static_cast<int>(from_start)) <= from_base->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100308 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000309 FixedArray* from = FixedArray::cast(from_base);
310 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
311 Object* the_hole = from->GetHeap()->the_hole_value();
312 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
313 from_start < from_end; from_start++, to_start++) {
314 Object* hole_or_smi = from->get(from_start);
315 if (hole_or_smi == the_hole) {
316 to->set_the_hole(to_start);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100317 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 to->set(to_start, Smi::cast(hole_or_smi)->value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100319 }
320 }
321}
322
323
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
325 uint32_t from_start,
326 FixedArrayBase* to_base,
327 uint32_t to_start, int packed_size,
328 int raw_copy_size) {
329 DisallowHeapAllocation no_allocation;
330 int copy_size = raw_copy_size;
331 uint32_t to_end;
332 if (raw_copy_size < 0) {
333 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
334 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
335 copy_size = packed_size - from_start;
336 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
337 to_end = to_base->length();
338 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
339 FixedDoubleArray::cast(to_base)->set_the_hole(i);
340 }
341 } else {
342 to_end = to_start + static_cast<uint32_t>(copy_size);
343 }
344 } else {
345 to_end = to_start + static_cast<uint32_t>(copy_size);
346 }
347 DCHECK(static_cast<int>(to_end) <= to_base->length());
348 DCHECK(packed_size >= 0 && packed_size <= copy_size);
349 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
350 (copy_size + static_cast<int>(from_start)) <= from_base->length());
351 if (copy_size == 0) return;
352 FixedArray* from = FixedArray::cast(from_base);
353 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
354 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
355 from_start < from_end; from_start++, to_start++) {
356 Object* smi = from->get(from_start);
357 DCHECK(!smi->IsTheHole());
358 to->set(to_start, Smi::cast(smi)->value());
359 }
360}
361
362
363static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
364 uint32_t from_start,
365 FixedArrayBase* to_base,
366 uint32_t to_start, int raw_copy_size) {
367 DisallowHeapAllocation no_allocation;
368 int copy_size = raw_copy_size;
369 if (raw_copy_size < 0) {
370 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
371 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
372 copy_size = from_base->length() - from_start;
373 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
374 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
375 FixedDoubleArray::cast(to_base)->set_the_hole(i);
376 }
377 }
378 }
379 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
380 (copy_size + static_cast<int>(from_start)) <= from_base->length());
381 if (copy_size == 0) return;
382 FixedArray* from = FixedArray::cast(from_base);
383 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
384 Object* the_hole = from->GetHeap()->the_hole_value();
385 for (uint32_t from_end = from_start + copy_size;
386 from_start < from_end; from_start++, to_start++) {
387 Object* hole_or_object = from->get(from_start);
388 if (hole_or_object == the_hole) {
389 to->set_the_hole(to_start);
390 } else {
391 to->set(to_start, hole_or_object->Number());
392 }
393 }
394}
395
396
397static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398 uint32_t from_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000399 FixedArrayBase* to_base,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100400 uint32_t to_start,
401 int raw_copy_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000402 DisallowHeapAllocation no_allocation;
403 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100404 int copy_size = raw_copy_size;
405 if (copy_size < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406 DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100407 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
408 copy_size = from->max_number_key() + 1 - from_start;
409 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
411 FixedDoubleArray::cast(to_base)->set_the_hole(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100412 }
413 }
414 }
415 if (copy_size == 0) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100417 uint32_t to_length = to->length();
418 if (to_start + copy_size > to_length) {
419 copy_size = to_length - to_start;
420 }
421 for (int i = 0; i < copy_size; i++) {
422 int entry = from->FindEntry(i + from_start);
423 if (entry != SeededNumberDictionary::kNotFound) {
424 to->set(i + to_start, from->ValueAt(entry)->Number());
425 } else {
426 to->set_the_hole(i + to_start);
427 }
428 }
429}
430
431
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432static void TraceTopFrame(Isolate* isolate) {
433 StackFrameIterator it(isolate);
434 if (it.done()) {
435 PrintF("unknown location (no JavaScript frames present)");
436 return;
437 }
438 StackFrame* raw_frame = it.frame();
439 if (raw_frame->is_internal()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 Code* apply_builtin =
441 isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 if (raw_frame->unchecked_code() == apply_builtin) {
443 PrintF("apply from ");
444 it.Advance();
445 raw_frame = it.frame();
446 }
447 }
448 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
449}
450
451
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000452// Base class for element handler implementations. Contains the
453// the common logic for objects with different ElementsKinds.
454// Subclasses must specialize method for which the element
455// implementation differs from the base class implementation.
456//
457// This class is intended to be used in the following way:
458//
459// class SomeElementsAccessor :
460// public ElementsAccessorBase<SomeElementsAccessor,
461// BackingStoreClass> {
462// ...
463// }
464//
465// This is an example of the Curiously Recurring Template Pattern (see
466// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
467// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
468// specialization of SomeElementsAccessor methods).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100469template <typename ElementsAccessorSubclass,
470 typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000471class ElementsAccessorBase : public ElementsAccessor {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100473 explicit ElementsAccessorBase(const char* name)
474 : ElementsAccessor(name) { }
475
476 typedef ElementsTraitsParam ElementsTraits;
477 typedef typename ElementsTraitsParam::BackingStore BackingStore;
478
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 static ElementsKind kind() { return ElementsTraits::Kind; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100480
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 static void ValidateContents(Handle<JSObject> holder, int length) {
482 }
483
484 static void ValidateImpl(Handle<JSObject> holder) {
485 Handle<FixedArrayBase> fixed_array_base(holder->elements());
486 if (!fixed_array_base->IsHeapObject()) return;
487 // Arrays that have been shifted in place can't be verified.
488 if (fixed_array_base->IsFiller()) return;
489 int length = 0;
490 if (holder->IsJSArray()) {
491 Object* length_obj = Handle<JSArray>::cast(holder)->length();
492 if (length_obj->IsSmi()) {
493 length = Smi::cast(length_obj)->value();
494 }
495 } else {
496 length = fixed_array_base->length();
497 }
498 ElementsAccessorSubclass::ValidateContents(holder, length);
499 }
500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 void Validate(Handle<JSObject> holder) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 DisallowHeapAllocation no_gc;
503 ElementsAccessorSubclass::ValidateImpl(holder);
504 }
505
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
507 uint32_t start, uint32_t end) final {
508 return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
509 end);
Ben Murdoch85b71792012-04-11 18:30:58 +0100510 }
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 static bool IsPackedImpl(Handle<JSObject> holder,
513 Handle<FixedArrayBase> backing_store, uint32_t start,
514 uint32_t end) {
515 if (IsFastPackedElementsKind(kind())) return true;
516 for (uint32_t i = start; i < end; i++) {
517 if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
518 ALL_PROPERTIES)) {
519 return false;
520 }
521 }
522 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100523 }
524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
526 if (!IsHoleyElementsKind(kind())) return;
527 int length = Smi::cast(array->length())->value();
528 Handle<FixedArrayBase> backing_store(array->elements());
529 if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
530 length)) {
531 return;
532 }
533 ElementsKind packed_kind = GetPackedElementsKind(kind());
534 Handle<Map> new_map =
535 JSObject::GetElementsTransitionMap(array, packed_kind);
536 JSObject::MigrateToMap(array, new_map);
537 if (FLAG_trace_elements_transitions) {
538 JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
539 packed_kind, backing_store);
540 }
541 }
542
543 bool HasElement(Handle<JSObject> holder, uint32_t index,
544 Handle<FixedArrayBase> backing_store,
545 PropertyFilter filter) final {
546 return ElementsAccessorSubclass::HasElementImpl(holder, index,
547 backing_store, filter);
548 }
549
550 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
551 Handle<FixedArrayBase> backing_store,
552 PropertyFilter filter) {
553 return ElementsAccessorSubclass::GetEntryForIndexImpl(
554 *holder, *backing_store, index, filter) != kMaxUInt32;
555 }
556
Ben Murdoch097c5b22016-05-18 11:27:45 +0100557 bool HasAccessors(JSObject* holder) final {
558 return ElementsAccessorSubclass::HasAccessorsImpl(holder,
559 holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560 }
561
Ben Murdoch097c5b22016-05-18 11:27:45 +0100562 static bool HasAccessorsImpl(JSObject* holder,
563 FixedArrayBase* backing_store) {
564 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 }
566
Ben Murdoch097c5b22016-05-18 11:27:45 +0100567 Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
568 return ElementsAccessorSubclass::GetImpl(holder, entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 }
570
Ben Murdoch097c5b22016-05-18 11:27:45 +0100571 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
572 return ElementsAccessorSubclass::GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 }
574
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
576 Isolate* isolate = backing_store->GetIsolate();
577 uint32_t index = GetIndexForEntryImpl(backing_store, entry);
578 return handle(BackingStore::cast(backing_store)->get(index), isolate);
579 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580
Ben Murdoch097c5b22016-05-18 11:27:45 +0100581 void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
582 ElementsAccessorSubclass::SetImpl(holder, entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583 }
584
585 void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
586 uint32_t entry, Handle<Object> value,
587 PropertyAttributes attributes) final {
588 ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
589 attributes);
590 }
591
592 static void ReconfigureImpl(Handle<JSObject> object,
593 Handle<FixedArrayBase> store, uint32_t entry,
594 Handle<Object> value,
595 PropertyAttributes attributes) {
596 UNREACHABLE();
597 }
598
599 void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
600 PropertyAttributes attributes, uint32_t new_capacity) final {
601 ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
602 new_capacity);
603 }
604
605 static void AddImpl(Handle<JSObject> object, uint32_t index,
606 Handle<Object> value, PropertyAttributes attributes,
607 uint32_t new_capacity) {
608 UNREACHABLE();
609 }
610
611 uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
612 Arguments* args, uint32_t push_size) final {
613 return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
614 push_size);
615 }
616
617 static uint32_t PushImpl(Handle<JSArray> receiver,
618 Handle<FixedArrayBase> elms_obj, Arguments* args,
619 uint32_t push_sized) {
620 UNREACHABLE();
621 return 0;
622 }
623
624 uint32_t Unshift(Handle<JSArray> receiver,
625 Handle<FixedArrayBase> backing_store, Arguments* args,
626 uint32_t unshift_size) final {
627 return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
628 unshift_size);
629 }
630
631 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
632 Handle<FixedArrayBase> elms_obj, Arguments* args,
633 uint32_t unshift_size) {
634 UNREACHABLE();
635 return 0;
636 }
637
638 Handle<JSArray> Slice(Handle<JSObject> receiver,
639 Handle<FixedArrayBase> backing_store, uint32_t start,
640 uint32_t end) final {
641 return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
642 end);
643 }
644
645 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
646 Handle<FixedArrayBase> backing_store,
647 uint32_t start, uint32_t end) {
648 UNREACHABLE();
649 return Handle<JSArray>();
650 }
651
652 Handle<JSArray> Splice(Handle<JSArray> receiver,
653 Handle<FixedArrayBase> backing_store, uint32_t start,
654 uint32_t delete_count, Arguments* args,
655 uint32_t add_count) final {
656 return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
657 delete_count, args, add_count);
658 }
659
660 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
661 Handle<FixedArrayBase> backing_store,
662 uint32_t start, uint32_t delete_count,
663 Arguments* args, uint32_t add_count) {
664 UNREACHABLE();
665 return Handle<JSArray>();
666 }
667
668 Handle<Object> Pop(Handle<JSArray> receiver,
669 Handle<FixedArrayBase> backing_store) final {
670 return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
671 }
672
673 static Handle<Object> PopImpl(Handle<JSArray> receiver,
674 Handle<FixedArrayBase> backing_store) {
675 UNREACHABLE();
676 return Handle<Object>();
677 }
678
679 Handle<Object> Shift(Handle<JSArray> receiver,
680 Handle<FixedArrayBase> backing_store) final {
681 return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
682 }
683
684 static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
685 Handle<FixedArrayBase> backing_store) {
686 UNREACHABLE();
687 return Handle<Object>();
688 }
689
690 void SetLength(Handle<JSArray> array, uint32_t length) final {
691 ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
692 handle(array->elements()));
693 }
694
695 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
696 uint32_t length,
697 Handle<FixedArrayBase> backing_store) {
698 DCHECK(!array->SetLengthWouldNormalize(length));
699 DCHECK(IsFastElementsKind(array->GetElementsKind()));
700 uint32_t old_length = 0;
701 CHECK(array->length()->ToArrayIndex(&old_length));
702
703 if (old_length < length) {
704 ElementsKind kind = array->GetElementsKind();
705 if (!IsFastHoleyElementsKind(kind)) {
706 kind = GetHoleyElementsKind(kind);
707 JSObject::TransitionElementsKind(array, kind);
708 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100709 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711 // Check whether the backing store should be shrunk.
712 uint32_t capacity = backing_store->length();
713 old_length = Min(old_length, capacity);
714 if (length == 0) {
715 array->initialize_elements();
716 } else if (length <= capacity) {
717 if (array->HasFastSmiOrObjectElements()) {
718 backing_store = JSObject::EnsureWritableFastElements(array);
719 }
720 if (2 * length <= capacity) {
721 // If more than half the elements won't be used, trim the array.
722 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
723 *backing_store, capacity - length);
724 } else {
725 // Otherwise, fill the unused tail with holes.
726 for (uint32_t i = length; i < old_length; i++) {
727 BackingStore::cast(*backing_store)->set_the_hole(i);
728 }
729 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 // Check whether the backing store should be expanded.
732 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
733 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
734 }
735
736 array->set_length(Smi::FromInt(length));
737 JSObject::ValidateElements(array);
738 }
739
740 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
741 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
742 ElementsKind from_kind, uint32_t capacity) {
743 return ConvertElementsWithCapacity(
744 object, old_elements, from_kind, capacity, 0, 0,
745 ElementsAccessor::kCopyToEndAndInitializeToHole);
746 }
747
748 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
749 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
750 ElementsKind from_kind, uint32_t capacity, int copy_size) {
751 return ConvertElementsWithCapacity(object, old_elements, from_kind,
752 capacity, 0, 0, copy_size);
753 }
754
755 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
756 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
757 ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
758 uint32_t dst_index, int copy_size) {
759 Isolate* isolate = object->GetIsolate();
760 Handle<FixedArrayBase> new_elements;
761 if (IsFastDoubleElementsKind(kind())) {
762 new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
763 } else {
764 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
765 }
766
767 int packed_size = kPackedSizeNotKnown;
768 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
769 packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
770 }
771
772 ElementsAccessorSubclass::CopyElementsImpl(
773 *old_elements, src_index, *new_elements, from_kind, dst_index,
774 packed_size, copy_size);
775
776 return new_elements;
777 }
778
779 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
780 uint32_t capacity) {
781 ElementsKind from_kind = object->GetElementsKind();
782 if (IsFastSmiOrObjectElementsKind(from_kind)) {
783 // Array optimizations rely on the prototype lookups of Array objects
784 // always returning undefined. If there is a store to the initial
785 // prototype object, make sure all of these optimizations are invalidated.
786 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
787 }
788 Handle<FixedArrayBase> old_elements(object->elements());
789 // This method should only be called if there's a reason to update the
790 // elements.
791 DCHECK(IsFastDoubleElementsKind(from_kind) !=
792 IsFastDoubleElementsKind(kind()) ||
793 IsDictionaryElementsKind(from_kind) ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100794 from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795 static_cast<uint32_t>(old_elements->length()) < capacity);
796 Handle<FixedArrayBase> elements =
797 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
798
799 ElementsKind to_kind = kind();
800 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
801 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
802 JSObject::SetMapAndElements(object, new_map, elements);
803
804 // Transition through the allocation site as well if present.
805 JSObject::UpdateAllocationSite(object, to_kind);
806
807 if (FLAG_trace_elements_transitions) {
808 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
809 to_kind, elements);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100811 }
812
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 void GrowCapacityAndConvert(Handle<JSObject> object,
814 uint32_t capacity) final {
815 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 }
817
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 void Delete(Handle<JSObject> obj, uint32_t entry) final {
819 ElementsAccessorSubclass::DeleteImpl(obj, entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 }
821
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
823 FixedArrayBase* to, ElementsKind from_kind,
824 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 int copy_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100826 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100827 }
828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 void CopyElements(JSObject* from_holder, uint32_t from_start,
830 ElementsKind from_kind, Handle<FixedArrayBase> to,
831 uint32_t to_start, int copy_size) final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 int packed_size = kPackedSizeNotKnown;
833 bool is_packed = IsFastPackedElementsKind(from_kind) &&
834 from_holder->IsJSArray();
835 if (is_packed) {
836 packed_size =
837 Smi::cast(JSArray::cast(from_holder)->length())->value();
838 if (copy_size >= 0 && packed_size > copy_size) {
839 packed_size = copy_size;
840 }
841 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400842 FixedArrayBase* from = from_holder->elements();
843 // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
844 // violate the handlified function signature convention:
845 // raw pointer parameters in the function that allocates. This is done
846 // intentionally to avoid ArrayConcat() builtin performance degradation.
847 //
848 // Details: The idea is that allocations actually happen only in case of
849 // copying from object with fast double elements to object with object
850 // elements. In all the other cases there are no allocations performed and
851 // handle creation causes noticeable performance degradation of the builtin.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000852 ElementsAccessorSubclass::CopyElementsImpl(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400853 from, from_start, *to, from_kind, to_start, packed_size, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000854 }
855
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000856 static void CollectElementIndicesImpl(Handle<JSObject> object,
857 Handle<FixedArrayBase> backing_store,
858 KeyAccumulator* keys, uint32_t range,
859 PropertyFilter filter,
860 uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100861 DCHECK_NE(DICTIONARY_ELEMENTS, kind());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 if (filter & ONLY_ALL_CAN_READ) {
863 // Non-dictionary elements can't have all-can-read accessors.
864 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000865 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 uint32_t length = 0;
867 if (object->IsJSArray()) {
868 length = Smi::cast(JSArray::cast(*object)->length())->value();
869 } else {
870 length =
871 ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000872 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000873 if (range < length) length = range;
874 for (uint32_t i = offset; i < length; i++) {
875 if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100876 filter)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000877 continue;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100878 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000879 keys->AddKey(i);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000880 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000881 }
882
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000883 void CollectElementIndices(Handle<JSObject> object,
884 Handle<FixedArrayBase> backing_store,
885 KeyAccumulator* keys, uint32_t range,
886 PropertyFilter filter, uint32_t offset) final {
887 ElementsAccessorSubclass::CollectElementIndicesImpl(
888 object, backing_store, keys, range, filter, offset);
889 };
890
891 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
892 KeyAccumulator* accumulator,
893 AddKeyConversion convert) final {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100894 ElementsAccessorSubclass::AddElementsToKeyAccumulatorImpl(
895 receiver, accumulator, convert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000896 }
897
898 static uint32_t GetCapacityImpl(JSObject* holder,
899 FixedArrayBase* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000900 return backing_store->length();
901 }
902
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
904 return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000905 }
906
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000907 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
908 uint32_t entry) {
909 return entry;
910 }
911
912 static uint32_t GetEntryForIndexImpl(JSObject* holder,
913 FixedArrayBase* backing_store,
914 uint32_t index, PropertyFilter filter) {
915 if (IsHoleyElementsKind(kind())) {
916 return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
917 backing_store) &&
918 !BackingStore::cast(backing_store)->is_the_hole(index)
919 ? index
920 : kMaxUInt32;
921 } else {
922 uint32_t length =
923 holder->IsJSArray()
924 ? static_cast<uint32_t>(
925 Smi::cast(JSArray::cast(holder)->length())->value())
926 : ElementsAccessorSubclass::GetCapacityImpl(holder,
927 backing_store);
928 return index < length ? index : kMaxUInt32;
929 }
930 }
931
932 uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
933 uint32_t index) final {
934 return ElementsAccessorSubclass::GetEntryForIndexImpl(
935 holder, backing_store, index, ALL_PROPERTIES);
936 }
937
938 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
939 uint32_t entry) {
940 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
941 }
942
Ben Murdoch097c5b22016-05-18 11:27:45 +0100943 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
944 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
945 }
946
947 PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
948 return ElementsAccessorSubclass::GetDetailsImpl(holder, entry);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000949 }
950
951 private:
952 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
953};
954
955
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956class DictionaryElementsAccessor
957 : public ElementsAccessorBase<DictionaryElementsAccessor,
958 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
959 public:
960 explicit DictionaryElementsAccessor(const char* name)
961 : ElementsAccessorBase<DictionaryElementsAccessor,
962 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
963
964 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
965 uint32_t length,
966 Handle<FixedArrayBase> backing_store) {
967 Handle<SeededNumberDictionary> dict =
968 Handle<SeededNumberDictionary>::cast(backing_store);
969 int capacity = dict->Capacity();
970 uint32_t old_length = 0;
971 CHECK(array->length()->ToArrayLength(&old_length));
972 if (length < old_length) {
973 if (dict->requires_slow_elements()) {
974 // Find last non-deletable element in range of elements to be
975 // deleted and adjust range accordingly.
976 for (int entry = 0; entry < capacity; entry++) {
977 DisallowHeapAllocation no_gc;
978 Object* index = dict->KeyAt(entry);
979 if (index->IsNumber()) {
980 uint32_t number = static_cast<uint32_t>(index->Number());
981 if (length <= number && number < old_length) {
982 PropertyDetails details = dict->DetailsAt(entry);
983 if (!details.IsConfigurable()) length = number + 1;
984 }
985 }
986 }
987 }
988
989 if (length == 0) {
990 // Flush the backing store.
991 JSObject::ResetElements(array);
992 } else {
993 DisallowHeapAllocation no_gc;
994 // Remove elements that should be deleted.
995 int removed_entries = 0;
996 Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
997 for (int entry = 0; entry < capacity; entry++) {
998 Object* index = dict->KeyAt(entry);
999 if (index->IsNumber()) {
1000 uint32_t number = static_cast<uint32_t>(index->Number());
1001 if (length <= number && number < old_length) {
1002 dict->SetEntry(entry, the_hole_value, the_hole_value);
1003 removed_entries++;
1004 }
1005 }
1006 }
1007
1008 // Update the number of elements.
1009 dict->ElementsRemoved(removed_entries);
1010 }
1011 }
1012
1013 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1014 array->set_length(*length_obj);
1015 }
1016
1017 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1018 FixedArrayBase* to, ElementsKind from_kind,
1019 uint32_t to_start, int packed_size,
1020 int copy_size) {
1021 UNREACHABLE();
1022 }
1023
1024
1025 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1026 // TODO(verwaest): Remove reliance on index in Shrink.
1027 Handle<SeededNumberDictionary> dict(
1028 SeededNumberDictionary::cast(obj->elements()));
1029 uint32_t index = GetIndexForEntryImpl(*dict, entry);
1030 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1031 USE(result);
1032 DCHECK(result->IsTrue());
1033 Handle<FixedArray> new_elements =
1034 SeededNumberDictionary::Shrink(dict, index);
1035 obj->set_elements(*new_elements);
1036 }
1037
Ben Murdoch097c5b22016-05-18 11:27:45 +01001038 static bool HasAccessorsImpl(JSObject* holder,
1039 FixedArrayBase* backing_store) {
1040 SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1041 if (!dict->requires_slow_elements()) return false;
1042 int capacity = dict->Capacity();
1043 for (int i = 0; i < capacity; i++) {
1044 Object* key = dict->KeyAt(i);
1045 if (!dict->IsKey(key)) continue;
1046 DCHECK(!dict->IsDeleted(i));
1047 PropertyDetails details = dict->DetailsAt(i);
1048 if (details.type() == ACCESSOR_CONSTANT) return true;
1049 }
1050 return false;
1051 }
1052
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1054 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1055 return backing_store->ValueAt(entry);
1056 }
1057
Ben Murdoch097c5b22016-05-18 11:27:45 +01001058 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1059 return GetImpl(holder->elements(), entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001060 }
1061
Ben Murdoch097c5b22016-05-18 11:27:45 +01001062 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1063 return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
1064 }
1065
1066 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 Object* value) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001068 SetImpl(holder->elements(), entry, value);
1069 }
1070
1071 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1072 Object* value) {
1073 SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 }
1075
1076 static void ReconfigureImpl(Handle<JSObject> object,
1077 Handle<FixedArrayBase> store, uint32_t entry,
1078 Handle<Object> value,
1079 PropertyAttributes attributes) {
1080 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1081 if (attributes != NONE) object->RequireSlowElements(dictionary);
1082 dictionary->ValueAtPut(entry, *value);
1083 PropertyDetails details = dictionary->DetailsAt(entry);
1084 details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1085 PropertyCellType::kNoCell);
1086 dictionary->DetailsAtPut(entry, details);
1087 }
1088
1089 static void AddImpl(Handle<JSObject> object, uint32_t index,
1090 Handle<Object> value, PropertyAttributes attributes,
1091 uint32_t new_capacity) {
1092 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1093 Handle<SeededNumberDictionary> dictionary =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001094 object->HasFastElements() || object->HasFastStringWrapperElements()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 ? JSObject::NormalizeElements(object)
1096 : handle(SeededNumberDictionary::cast(object->elements()));
1097 Handle<SeededNumberDictionary> new_dictionary =
1098 SeededNumberDictionary::AddNumberEntry(
1099 dictionary, index, value, details,
1100 object->map()->is_prototype_map());
1101 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1102 if (dictionary.is_identical_to(new_dictionary)) return;
1103 object->set_elements(*new_dictionary);
1104 }
1105
1106 static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1107 DisallowHeapAllocation no_gc;
1108 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1109 Object* index = dict->KeyAt(entry);
1110 return !index->IsTheHole();
1111 }
1112
1113 static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1114 DisallowHeapAllocation no_gc;
1115 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1116 uint32_t result = 0;
1117 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1118 return result;
1119 }
1120
1121 static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1122 uint32_t index, PropertyFilter filter) {
1123 DisallowHeapAllocation no_gc;
1124 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1125 int entry = dictionary->FindEntry(index);
1126 if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1127 if (filter != ALL_PROPERTIES) {
1128 PropertyDetails details = dictionary->DetailsAt(entry);
1129 PropertyAttributes attr = details.attributes();
1130 if ((attr & filter) != 0) return kMaxUInt32;
1131 }
1132 return static_cast<uint32_t>(entry);
1133 }
1134
Ben Murdoch097c5b22016-05-18 11:27:45 +01001135 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1136 return GetDetailsImpl(holder->elements(), entry);
1137 }
1138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001139 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1140 uint32_t entry) {
1141 return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1142 }
1143
1144 static void CollectElementIndicesImpl(Handle<JSObject> object,
1145 Handle<FixedArrayBase> backing_store,
1146 KeyAccumulator* keys, uint32_t range,
1147 PropertyFilter filter,
1148 uint32_t offset) {
1149 Handle<SeededNumberDictionary> dictionary =
1150 Handle<SeededNumberDictionary>::cast(backing_store);
1151 int capacity = dictionary->Capacity();
1152 for (int i = 0; i < capacity; i++) {
1153 Object* k = dictionary->KeyAt(i);
1154 if (!dictionary->IsKey(k)) continue;
1155 if (k->FilterKey(filter)) continue;
1156 if (dictionary->IsDeleted(i)) continue;
1157 DCHECK(k->IsNumber());
1158 DCHECK_LE(k->Number(), kMaxUInt32);
1159 uint32_t index = static_cast<uint32_t>(k->Number());
1160 if (index < offset) continue;
1161 PropertyDetails details = dictionary->DetailsAt(i);
1162 if (filter & ONLY_ALL_CAN_READ) {
1163 if (details.kind() != kAccessor) continue;
1164 Object* accessors = dictionary->ValueAt(i);
1165 if (!accessors->IsAccessorInfo()) continue;
1166 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
1167 }
1168 PropertyAttributes attr = details.attributes();
1169 if ((attr & filter) != 0) continue;
1170 keys->AddKey(index);
1171 }
1172
1173 keys->SortCurrentElementsList();
1174 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001175
1176 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1177 KeyAccumulator* accumulator,
1178 AddKeyConversion convert) {
1179 SeededNumberDictionary* dictionary =
1180 SeededNumberDictionary::cast(receiver->elements());
1181 int capacity = dictionary->Capacity();
1182 for (int i = 0; i < capacity; i++) {
1183 Object* k = dictionary->KeyAt(i);
1184 if (!dictionary->IsKey(k)) continue;
1185 if (dictionary->IsDeleted(i)) continue;
1186 Object* value = dictionary->ValueAt(i);
1187 DCHECK(!value->IsTheHole());
1188 DCHECK(!value->IsAccessorPair());
1189 DCHECK(!value->IsAccessorInfo());
1190 accumulator->AddKey(value, convert);
1191 }
1192 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193};
1194
1195
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001196// Super class for all fast element arrays.
1197template<typename FastElementsAccessorSubclass,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198 typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001199class FastElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001200 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001201 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001202 explicit FastElementsAccessor(const char* name)
1203 : ElementsAccessorBase<FastElementsAccessorSubclass,
1204 KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001205
1206 typedef typename KindTraits::BackingStore BackingStore;
1207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208 static void DeleteAtEnd(Handle<JSObject> obj,
1209 Handle<BackingStore> backing_store, uint32_t entry) {
1210 uint32_t length = static_cast<uint32_t>(backing_store->length());
1211 Heap* heap = obj->GetHeap();
1212 for (; entry > 0; entry--) {
1213 if (!backing_store->is_the_hole(entry - 1)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001215 if (entry == 0) {
1216 FixedArray* empty = heap->empty_fixed_array();
1217 if (obj->HasFastArgumentsElements()) {
1218 FixedArray::cast(obj->elements())->set(1, empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001219 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 obj->set_elements(empty);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001221 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001223 }
1224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001225 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1226 length - entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001227 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001229 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1230 Handle<FixedArrayBase> store) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001231 DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
1232 obj->HasFastArgumentsElements() ||
1233 obj->HasFastStringWrapperElements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1235 if (!obj->IsJSArray() &&
1236 entry == static_cast<uint32_t>(store->length()) - 1) {
1237 DeleteAtEnd(obj, backing_store, entry);
1238 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240
1241 backing_store->set_the_hole(entry);
1242
1243 // TODO(verwaest): Move this out of elements.cc.
1244 // If an old space backing store is larger than a certain size and
1245 // has too few used values, normalize it.
1246 // To avoid doing the check on every delete we require at least
1247 // one adjacent hole to the value being deleted.
1248 const int kMinLengthForSparsenessCheck = 64;
1249 if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1250 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1251 uint32_t length = 0;
1252 if (obj->IsJSArray()) {
1253 JSArray::cast(*obj)->length()->ToArrayLength(&length);
1254 } else {
1255 length = static_cast<uint32_t>(store->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001256 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1258 (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1259 if (!obj->IsJSArray()) {
1260 uint32_t i;
1261 for (i = entry + 1; i < length; i++) {
1262 if (!backing_store->is_the_hole(i)) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001263 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 if (i == length) {
1265 DeleteAtEnd(obj, backing_store, entry);
1266 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267 }
1268 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001269 int num_used = 0;
1270 for (int i = 0; i < backing_store->length(); ++i) {
1271 if (!backing_store->is_the_hole(i)) {
1272 ++num_used;
1273 // Bail out if a number dictionary wouldn't be able to save at least
1274 // 75% space.
1275 if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1276 SeededNumberDictionary::kEntrySize >
1277 backing_store->length()) {
1278 return;
1279 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001280 }
1281 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 JSObject::NormalizeElements(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001283 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001284 }
1285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 static void ReconfigureImpl(Handle<JSObject> object,
1287 Handle<FixedArrayBase> store, uint32_t entry,
1288 Handle<Object> value,
1289 PropertyAttributes attributes) {
1290 Handle<SeededNumberDictionary> dictionary =
1291 JSObject::NormalizeElements(object);
1292 entry = dictionary->FindEntry(entry);
1293 DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1294 value, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001295 }
1296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001297 static void AddImpl(Handle<JSObject> object, uint32_t index,
1298 Handle<Object> value, PropertyAttributes attributes,
1299 uint32_t new_capacity) {
1300 DCHECK_EQ(NONE, attributes);
1301 ElementsKind from_kind = object->GetElementsKind();
1302 ElementsKind to_kind = FastElementsAccessorSubclass::kind();
1303 if (IsDictionaryElementsKind(from_kind) ||
1304 IsFastDoubleElementsKind(from_kind) !=
1305 IsFastDoubleElementsKind(to_kind) ||
1306 FastElementsAccessorSubclass::GetCapacityImpl(
1307 *object, object->elements()) != new_capacity) {
1308 FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
1309 new_capacity);
1310 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001311 if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 JSObject::TransitionElementsKind(object, to_kind);
1313 }
1314 if (IsFastSmiOrObjectElementsKind(from_kind)) {
1315 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1316 JSObject::EnsureWritableFastElements(object);
1317 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001318 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001319 FastElementsAccessorSubclass::SetImpl(object, index, *value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 }
1321
1322 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1323 ElementsKind kind = KindTraits::Kind;
1324 if (IsFastPackedElementsKind(kind)) {
1325 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1326 }
1327 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1328 JSObject::EnsureWritableFastElements(obj);
1329 }
1330 DeleteCommon(obj, entry, handle(obj->elements()));
1331 }
1332
1333 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1334 return !BackingStore::cast(backing_store)->is_the_hole(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001335 }
1336
Ben Murdoch097c5b22016-05-18 11:27:45 +01001337 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1338 KeyAccumulator* accumulator,
1339 AddKeyConversion convert) {
1340 uint32_t length = 0;
1341 Handle<FixedArrayBase> elements(receiver->elements(),
1342 receiver->GetIsolate());
1343 if (receiver->IsJSArray()) {
1344 length = Smi::cast(JSArray::cast(*receiver)->length())->value();
1345 } else {
1346 length =
1347 FastElementsAccessorSubclass::GetCapacityImpl(*receiver, *elements);
1348 }
1349 for (uint32_t i = 0; i < length; i++) {
1350 if (IsFastPackedElementsKind(KindTraits::Kind) ||
1351 HasEntryImpl(*elements, i)) {
1352 accumulator->AddKey(FastElementsAccessorSubclass::GetImpl(*elements, i),
1353 convert);
1354 }
1355 }
1356 }
1357
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 static void ValidateContents(Handle<JSObject> holder, int length) {
1359#if DEBUG
1360 Isolate* isolate = holder->GetIsolate();
1361 HandleScope scope(isolate);
1362 Handle<FixedArrayBase> elements(holder->elements(), isolate);
1363 Map* map = elements->map();
1364 DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
1365 (map == isolate->heap()->fixed_array_map() ||
1366 map == isolate->heap()->fixed_cow_array_map())) ||
1367 (IsFastDoubleElementsKind(KindTraits::Kind) ==
1368 ((map == isolate->heap()->fixed_array_map() && length == 0) ||
1369 map == isolate->heap()->fixed_double_array_map())));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001370 if (length == 0) return; // nothing to do!
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001371 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001372 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1373 if (IsFastSmiElementsKind(KindTraits::Kind)) {
1374 for (int i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001375 DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 (IsFastHoleyElementsKind(KindTraits::Kind) &&
1377 backing_store->is_the_hole(i)));
1378 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001379 }
1380#endif
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001381 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001382
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 static Handle<Object> PopImpl(Handle<JSArray> receiver,
1384 Handle<FixedArrayBase> backing_store) {
1385 return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1386 AT_END);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388
1389 static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
1390 Handle<FixedArrayBase> backing_store) {
1391 return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1392 AT_START);
1393 }
1394
1395 static uint32_t PushImpl(Handle<JSArray> receiver,
1396 Handle<FixedArrayBase> backing_store,
1397 Arguments* args, uint32_t push_size) {
1398 return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
1399 args, push_size, AT_END);
1400 }
1401
1402 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
1403 Handle<FixedArrayBase> backing_store,
1404 Arguments* args, uint32_t unshift_size) {
1405 return FastElementsAccessorSubclass::AddArguments(
1406 receiver, backing_store, args, unshift_size, AT_START);
1407 }
1408
1409 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1410 Handle<FixedArrayBase> backing_store, int dst_index,
1411 int src_index, int len, int hole_start,
1412 int hole_end) {
1413 UNREACHABLE();
1414 }
1415
1416 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
1417 Handle<FixedArrayBase> backing_store,
1418 uint32_t start, uint32_t end) {
1419 DCHECK(start < end);
1420 Isolate* isolate = receiver->GetIsolate();
1421 int result_len = end - start;
1422 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1423 KindTraits::Kind, result_len, result_len);
1424 DisallowHeapAllocation no_gc;
1425 FastElementsAccessorSubclass::CopyElementsImpl(
1426 *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
1427 kPackedSizeNotKnown, result_len);
1428 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1429 result_array);
1430 return result_array;
1431 }
1432
1433 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
1434 Handle<FixedArrayBase> backing_store,
1435 uint32_t start, uint32_t delete_count,
1436 Arguments* args, uint32_t add_count) {
1437 Isolate* isolate = receiver->GetIsolate();
1438 Heap* heap = isolate->heap();
1439 uint32_t length = Smi::cast(receiver->length())->value();
1440 uint32_t new_length = length - delete_count + add_count;
1441
1442 if (new_length == 0) {
1443 receiver->set_elements(heap->empty_fixed_array());
1444 receiver->set_length(Smi::FromInt(0));
1445 return isolate->factory()->NewJSArrayWithElements(
1446 backing_store, KindTraits::Kind, delete_count);
1447 }
1448
1449 // Construct the result array which holds the deleted elements.
1450 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1451 KindTraits::Kind, delete_count, delete_count);
1452 if (delete_count > 0) {
1453 DisallowHeapAllocation no_gc;
1454 FastElementsAccessorSubclass::CopyElementsImpl(
1455 *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
1456 0, kPackedSizeNotKnown, delete_count);
1457 }
1458
1459 // Delete and move elements to make space for add_count new elements.
1460 if (add_count < delete_count) {
1461 FastElementsAccessorSubclass::SpliceShrinkStep(
1462 isolate, receiver, backing_store, start, delete_count, add_count,
1463 length, new_length);
1464 } else if (add_count > delete_count) {
1465 backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
1466 isolate, receiver, backing_store, start, delete_count, add_count,
1467 length, new_length);
1468 }
1469
1470 // Copy over the arguments.
1471 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
1472 3, start);
1473
1474 receiver->set_length(Smi::FromInt(new_length));
1475 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1476 deleted_elements);
1477 return deleted_elements;
1478 }
1479
1480 private:
1481 // SpliceShrinkStep might modify the backing_store.
1482 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1483 Handle<FixedArrayBase> backing_store,
1484 uint32_t start, uint32_t delete_count,
1485 uint32_t add_count, uint32_t len,
1486 uint32_t new_length) {
1487 const int move_left_count = len - delete_count - start;
1488 const int move_left_dst_index = start + add_count;
1489 FastElementsAccessorSubclass::MoveElements(
1490 isolate, receiver, backing_store, move_left_dst_index,
1491 start + delete_count, move_left_count, new_length, len);
1492 }
1493
1494 // SpliceGrowStep might modify the backing_store.
1495 static Handle<FixedArrayBase> SpliceGrowStep(
1496 Isolate* isolate, Handle<JSArray> receiver,
1497 Handle<FixedArrayBase> backing_store, uint32_t start,
1498 uint32_t delete_count, uint32_t add_count, uint32_t length,
1499 uint32_t new_length) {
1500 // Check we do not overflow the new_length.
1501 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1502 // Check if backing_store is big enough.
1503 if (new_length <= static_cast<uint32_t>(backing_store->length())) {
1504 FastElementsAccessorSubclass::MoveElements(
1505 isolate, receiver, backing_store, start + add_count,
1506 start + delete_count, (length - delete_count - start), 0, 0);
1507 // MoveElements updates the backing_store in-place.
1508 return backing_store;
1509 }
1510 // New backing storage is needed.
1511 int capacity = JSObject::NewElementsCapacity(new_length);
1512 // Partially copy all elements up to start.
1513 Handle<FixedArrayBase> new_elms =
1514 FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1515 receiver, backing_store, KindTraits::Kind, capacity, start);
1516 // Copy the trailing elements after start + delete_count
1517 FastElementsAccessorSubclass::CopyElementsImpl(
1518 *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
1519 start + add_count, kPackedSizeNotKnown,
1520 ElementsAccessor::kCopyToEndAndInitializeToHole);
1521 receiver->set_elements(*new_elms);
1522 return new_elms;
1523 }
1524
1525 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
1526 Handle<FixedArrayBase> backing_store,
1527 Where remove_position) {
1528 Isolate* isolate = receiver->GetIsolate();
1529 uint32_t length =
1530 static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1531 DCHECK(length > 0);
1532 int new_length = length - 1;
1533 int remove_index = remove_position == AT_START ? 0 : new_length;
1534 Handle<Object> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001535 FastElementsAccessorSubclass::GetImpl(*backing_store, remove_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 if (remove_position == AT_START) {
1537 FastElementsAccessorSubclass::MoveElements(
1538 isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
1539 }
1540 FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
1541 backing_store);
1542
1543 if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
1544 return receiver->GetIsolate()->factory()->undefined_value();
1545 }
1546 return result;
1547 }
1548
1549 static uint32_t AddArguments(Handle<JSArray> receiver,
1550 Handle<FixedArrayBase> backing_store,
1551 Arguments* args, uint32_t add_size,
1552 Where remove_position) {
1553 uint32_t length = Smi::cast(receiver->length())->value();
1554 DCHECK(add_size > 0);
1555 uint32_t elms_len = backing_store->length();
1556 // Check we do not overflow the new_length.
1557 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1558 uint32_t new_length = length + add_size;
1559
1560 if (new_length > elms_len) {
1561 // New backing storage is needed.
1562 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1563 // If we add arguments to the start we have to shift the existing objects.
1564 int copy_dst_index = remove_position == AT_START ? add_size : 0;
1565 // Copy over all objects to a new backing_store.
1566 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1567 receiver, backing_store, KindTraits::Kind, capacity, 0,
1568 copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1569 receiver->set_elements(*backing_store);
1570 } else if (remove_position == AT_START) {
1571 // If the backing store has enough capacity and we add elements to the
1572 // start we have to shift the existing objects.
1573 Isolate* isolate = receiver->GetIsolate();
1574 FastElementsAccessorSubclass::MoveElements(
1575 isolate, receiver, backing_store, add_size, 0, length, 0, 0);
1576 }
1577
1578 int insertion_index = remove_position == AT_START ? 0 : length;
1579 // Copy the arguments to the start.
1580 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
1581 1, insertion_index);
1582 // Set the length.
1583 receiver->set_length(Smi::FromInt(new_length));
1584 return new_length;
1585 }
1586
1587 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1588 uint32_t copy_size, uint32_t src_index,
1589 uint32_t dst_index) {
1590 // Add the provided values.
1591 DisallowHeapAllocation no_gc;
1592 FixedArrayBase* raw_backing_store = *dst_store;
1593 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1594 for (uint32_t i = 0; i < copy_size; i++) {
1595 Object* argument = (*args)[i + src_index];
1596 FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
1597 argument, mode);
1598 }
1599 }
1600};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001601
1602
1603template<typename FastElementsAccessorSubclass,
1604 typename KindTraits>
1605class FastSmiOrObjectElementsAccessor
1606 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1607 public:
1608 explicit FastSmiOrObjectElementsAccessor(const char* name)
1609 : FastElementsAccessor<FastElementsAccessorSubclass,
1610 KindTraits>(name) {}
1611
Ben Murdoch097c5b22016-05-18 11:27:45 +01001612 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1613 Object* value) {
1614 SetImpl(holder->elements(), entry, value);
1615 }
1616
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001617 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1618 Object* value) {
1619 FixedArray::cast(backing_store)->set(entry, value);
1620 }
1621
1622 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1623 Object* value, WriteBarrierMode mode) {
1624 FixedArray::cast(backing_store)->set(entry, value, mode);
1625 }
1626
1627 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
1628 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
1629 backing_store, entry);
1630 return backing_store->get(index);
1631 }
1632
1633 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1634 Handle<FixedArrayBase> backing_store, int dst_index,
1635 int src_index, int len, int hole_start,
1636 int hole_end) {
1637 Heap* heap = isolate->heap();
1638 Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
1639 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1640 // Update all the copies of this backing_store handle.
1641 *dst_elms.location() =
1642 FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1643 receiver->set_elements(*dst_elms);
1644 // Adjust the hole offset as the array has been shrunk.
1645 hole_end -= src_index;
1646 DCHECK_LE(hole_start, backing_store->length());
1647 DCHECK_LE(hole_end, backing_store->length());
1648 } else if (len != 0) {
1649 DisallowHeapAllocation no_gc;
1650 heap->MoveElements(*dst_elms, dst_index, src_index, len);
1651 }
1652 if (hole_start != hole_end) {
1653 dst_elms->FillWithHoles(hole_start, hole_end);
1654 }
1655 }
1656
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001657 // NOTE: this method violates the handlified function signature convention:
1658 // raw pointer parameters in the function that allocates.
1659 // See ElementsAccessor::CopyElements() for details.
1660 // This method could actually allocate if copying from double elements to
1661 // object elements.
1662 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1663 FixedArrayBase* to, ElementsKind from_kind,
1664 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001666 DisallowHeapAllocation no_gc;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001667 ElementsKind to_kind = KindTraits::Kind;
1668 switch (from_kind) {
1669 case FAST_SMI_ELEMENTS:
1670 case FAST_HOLEY_SMI_ELEMENTS:
1671 case FAST_ELEMENTS:
1672 case FAST_HOLEY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001673 case FAST_STRING_WRAPPER_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001674 CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 to_start, copy_size);
1676 break;
1677 case FAST_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001678 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1679 AllowHeapAllocation allow_allocation;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 DCHECK(IsFastObjectElementsKind(to_kind));
1681 CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001682 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001683 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001684 case DICTIONARY_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001685 case SLOW_STRING_WRAPPER_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001686 CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1687 copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001688 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001689 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1690 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001691#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1693#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01001694 // This function is currently only used for JSArrays with non-zero
1695 // length.
1696 UNREACHABLE();
1697 break;
1698 case NO_ELEMENTS:
1699 break; // Nothing to do.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001700 }
1701 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001702};
1703
1704
1705class FastPackedSmiElementsAccessor
1706 : public FastSmiOrObjectElementsAccessor<
1707 FastPackedSmiElementsAccessor,
1708 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1709 public:
1710 explicit FastPackedSmiElementsAccessor(const char* name)
1711 : FastSmiOrObjectElementsAccessor<
1712 FastPackedSmiElementsAccessor,
1713 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1714};
1715
1716
1717class FastHoleySmiElementsAccessor
1718 : public FastSmiOrObjectElementsAccessor<
1719 FastHoleySmiElementsAccessor,
1720 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1721 public:
1722 explicit FastHoleySmiElementsAccessor(const char* name)
1723 : FastSmiOrObjectElementsAccessor<
1724 FastHoleySmiElementsAccessor,
1725 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1726};
1727
1728
1729class FastPackedObjectElementsAccessor
1730 : public FastSmiOrObjectElementsAccessor<
1731 FastPackedObjectElementsAccessor,
1732 ElementsKindTraits<FAST_ELEMENTS> > {
1733 public:
1734 explicit FastPackedObjectElementsAccessor(const char* name)
1735 : FastSmiOrObjectElementsAccessor<
1736 FastPackedObjectElementsAccessor,
1737 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1738};
1739
1740
1741class FastHoleyObjectElementsAccessor
1742 : public FastSmiOrObjectElementsAccessor<
1743 FastHoleyObjectElementsAccessor,
1744 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1745 public:
1746 explicit FastHoleyObjectElementsAccessor(const char* name)
1747 : FastSmiOrObjectElementsAccessor<
1748 FastHoleyObjectElementsAccessor,
1749 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1750};
1751
1752
1753template<typename FastElementsAccessorSubclass,
1754 typename KindTraits>
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001755class FastDoubleElementsAccessor
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001757 public:
1758 explicit FastDoubleElementsAccessor(const char* name)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001759 : FastElementsAccessor<FastElementsAccessorSubclass,
1760 KindTraits>(name) {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001761
Ben Murdoch097c5b22016-05-18 11:27:45 +01001762 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1763 return GetImpl(holder->elements(), entry);
1764 }
1765
1766 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1767 Isolate* isolate = backing_store->GetIsolate();
1768 return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
1769 isolate);
1770 }
1771
1772 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1773 Object* value) {
1774 SetImpl(holder->elements(), entry, value);
1775 }
1776
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001777 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1778 Object* value) {
1779 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001780 }
1781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001782 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1783 Object* value, WriteBarrierMode mode) {
1784 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
1785 }
1786
1787 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1788 Handle<FixedArrayBase> backing_store, int dst_index,
1789 int src_index, int len, int hole_start,
1790 int hole_end) {
1791 Heap* heap = isolate->heap();
1792 Handle<FixedDoubleArray> dst_elms =
1793 Handle<FixedDoubleArray>::cast(backing_store);
1794 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1795 // Update all the copies of this backing_store handle.
1796 *dst_elms.location() = FixedDoubleArray::cast(
1797 heap->LeftTrimFixedArray(*dst_elms, src_index));
1798 receiver->set_elements(*dst_elms);
1799 // Adjust the hole offset as the array has been shrunk.
1800 hole_end -= src_index;
1801 DCHECK_LE(hole_start, backing_store->length());
1802 DCHECK_LE(hole_end, backing_store->length());
1803 } else if (len != 0) {
1804 MemMove(dst_elms->data_start() + dst_index,
1805 dst_elms->data_start() + src_index, len * kDoubleSize);
1806 }
1807 if (hole_start != hole_end) {
1808 dst_elms->FillWithHoles(hole_start, hole_end);
1809 }
1810 }
1811
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001812 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1813 FixedArrayBase* to, ElementsKind from_kind,
1814 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 int copy_size) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001816 DisallowHeapAllocation no_allocation;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001817 switch (from_kind) {
1818 case FAST_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001819 CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001820 packed_size, copy_size);
1821 break;
1822 case FAST_HOLEY_SMI_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001823 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001824 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001825 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001826 case FAST_HOLEY_DOUBLE_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001827 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828 break;
1829 case FAST_ELEMENTS:
1830 case FAST_HOLEY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001831 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001832 break;
1833 case DICTIONARY_ELEMENTS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001834 CopyDictionaryToDoubleElements(from, from_start, to, to_start,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 copy_size);
1836 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001837 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1838 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001839 case FAST_STRING_WRAPPER_ELEMENTS:
1840 case SLOW_STRING_WRAPPER_ELEMENTS:
1841 case NO_ELEMENTS:
1842#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001843 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1844#undef TYPED_ARRAY_CASE
Ben Murdoch097c5b22016-05-18 11:27:45 +01001845 // This function is currently only used for JSArrays with non-zero
1846 // length.
1847 UNREACHABLE();
1848 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001849 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001850 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001851};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001852
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001853
1854class FastPackedDoubleElementsAccessor
1855 : public FastDoubleElementsAccessor<
1856 FastPackedDoubleElementsAccessor,
1857 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
1858 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001859 explicit FastPackedDoubleElementsAccessor(const char* name)
1860 : FastDoubleElementsAccessor<
1861 FastPackedDoubleElementsAccessor,
1862 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
1863};
1864
1865
1866class FastHoleyDoubleElementsAccessor
1867 : public FastDoubleElementsAccessor<
1868 FastHoleyDoubleElementsAccessor,
1869 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
1870 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001871 explicit FastHoleyDoubleElementsAccessor(const char* name)
1872 : FastDoubleElementsAccessor<
1873 FastHoleyDoubleElementsAccessor,
1874 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001875};
1876
1877
1878// Super class for all external element arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879template<ElementsKind Kind>
1880class TypedElementsAccessor
1881 : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001882 ElementsKindTraits<Kind> > {
1883 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 explicit TypedElementsAccessor(const char* name)
1885 : ElementsAccessorBase<AccessorClass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001886 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001887
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001888 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 typedef TypedElementsAccessor<Kind> AccessorClass;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001890
Ben Murdoch097c5b22016-05-18 11:27:45 +01001891 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1892 Object* value) {
1893 SetImpl(holder->elements(), entry, value);
1894 }
1895
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1897 Object* value) {
1898 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001899 }
1900
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1902 Object* value, WriteBarrierMode mode) {
1903 BackingStore::cast(backing_store)->SetValue(entry, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001904 }
1905
Ben Murdoch097c5b22016-05-18 11:27:45 +01001906 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1907 return GetImpl(holder->elements(), entry);
1908 }
1909
1910 static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1911 return BackingStore::get(BackingStore::cast(backing_store), entry);
1912 }
1913
1914 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1915 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001916 }
1917
1918 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1919 uint32_t entry) {
1920 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
1921 }
1922
Ben Murdoch097c5b22016-05-18 11:27:45 +01001923 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
1924 Handle<FixedArrayBase> backing_store,
1925 PropertyFilter filter) {
1926 return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
1927 }
1928
1929 static bool HasAccessorsImpl(JSObject* holder,
1930 FixedArrayBase* backing_store) {
1931 return false;
1932 }
1933
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001934 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1935 uint32_t length,
1936 Handle<FixedArrayBase> backing_store) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001937 // External arrays do not support changing their length.
1938 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001939 }
1940
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001941 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1942 UNREACHABLE();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001943 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001944
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001945 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1946 uint32_t entry) {
1947 return entry;
1948 }
1949
1950 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1951 FixedArrayBase* backing_store,
1952 uint32_t index, PropertyFilter filter) {
1953 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
1954 ? index
1955 : kMaxUInt32;
1956 }
1957
1958 static uint32_t GetCapacityImpl(JSObject* holder,
1959 FixedArrayBase* backing_store) {
1960 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
1961 if (view->WasNeutered()) return 0;
1962 return backing_store->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001963 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001964
1965 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1966 KeyAccumulator* accumulator,
1967 AddKeyConversion convert) {
1968 Handle<FixedArrayBase> elements(receiver->elements(),
1969 receiver->GetIsolate());
1970 uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
1971 for (uint32_t i = 0; i < length; i++) {
1972 Handle<Object> value = AccessorClass::GetImpl(*elements, i);
1973 accumulator->AddKey(value, convert);
1974 }
1975 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001976};
1977
1978
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001979
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001980#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
1981 typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
1982 Fixed##Type##ElementsAccessor;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001983
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001984TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
1985#undef FIXED_ELEMENTS_ACCESSOR
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001986
1987
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001988template <typename SloppyArgumentsElementsAccessorSubclass,
1989 typename ArgumentsAccessor, typename KindTraits>
1990class SloppyArgumentsElementsAccessor
1991 : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1992 KindTraits> {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001993 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001994 explicit SloppyArgumentsElementsAccessor(const char* name)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1996 KindTraits>(name) {
1997 USE(KindTraits::Kind);
1998 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001999
Ben Murdoch097c5b22016-05-18 11:27:45 +01002000 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2001 return GetImpl(holder->elements(), entry);
2002 }
2003
2004 static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002005 Isolate* isolate = parameters->GetIsolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002006 Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002007 uint32_t length = parameter_map->length() - 2;
2008 if (entry < length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002010 Object* probe = parameter_map->get(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002011 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012 int context_entry = Smi::cast(probe)->value();
2013 DCHECK(!context->get(context_entry)->IsTheHole());
2014 return handle(context->get(context_entry), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002015 } else {
2016 // Object is not mapped, defer to the arguments.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002017 Handle<Object> result = ArgumentsAccessor::GetImpl(
2018 FixedArray::cast(parameter_map->get(1)), entry - length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002019 // Elements of the arguments object in slow mode might be slow aliases.
2020 if (result->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002021 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002022 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002023 Context* context = Context::cast(parameter_map->get(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002024 int context_entry = alias->aliased_context_slot();
2025 DCHECK(!context->get(context_entry)->IsTheHole());
2026 return handle(context->get(context_entry), isolate);
2027 }
2028 return result;
2029 }
2030 }
2031
2032 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2033 uint32_t capacity) {
2034 UNREACHABLE();
2035 }
2036
Ben Murdoch097c5b22016-05-18 11:27:45 +01002037 static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2038 Object* value) {
2039 SetImpl(holder->elements(), entry, value);
2040 }
2041
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002042 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
2043 Object* value) {
2044 FixedArray* parameter_map = FixedArray::cast(store);
2045 uint32_t length = parameter_map->length() - 2;
2046 if (entry < length) {
2047 Object* probe = parameter_map->get(entry + 2);
2048 Context* context = Context::cast(parameter_map->get(0));
2049 int context_entry = Smi::cast(probe)->value();
2050 DCHECK(!context->get(context_entry)->IsTheHole());
2051 context->set(context_entry, value);
2052 } else {
2053 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2054 Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
2055 if (current->IsAliasedArgumentsEntry()) {
2056 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
2057 Context* context = Context::cast(parameter_map->get(0));
2058 int context_entry = alias->aliased_context_slot();
2059 DCHECK(!context->get(context_entry)->IsTheHole());
2060 context->set(context_entry, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002061 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002062 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002063 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002064 }
2065 }
2066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2068 uint32_t length,
2069 Handle<FixedArrayBase> parameter_map) {
2070 // Sloppy arguments objects are not arrays.
2071 UNREACHABLE();
2072 }
2073
2074 static uint32_t GetCapacityImpl(JSObject* holder,
2075 FixedArrayBase* backing_store) {
2076 FixedArray* parameter_map = FixedArray::cast(backing_store);
2077 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2078 return parameter_map->length() - 2 +
2079 ArgumentsAccessor::GetCapacityImpl(holder, arguments);
2080 }
2081
Ben Murdoch097c5b22016-05-18 11:27:45 +01002082 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2083 KeyAccumulator* accumulator,
2084 AddKeyConversion convert) {
2085 FixedArrayBase* elements = receiver->elements();
2086 uint32_t length = GetCapacityImpl(*receiver, elements);
2087 for (uint32_t entry = 0; entry < length; entry++) {
2088 if (!HasEntryImpl(elements, entry)) continue;
2089 Handle<Object> value = GetImpl(elements, entry);
2090 accumulator->AddKey(value, convert);
2091 }
2092 }
2093
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002094 static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
2095 FixedArray* parameter_map = FixedArray::cast(parameters);
2096 uint32_t length = parameter_map->length() - 2;
2097 if (entry < length) {
2098 return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002099 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002100
2101 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2102 return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002103 }
2104
Ben Murdoch097c5b22016-05-18 11:27:45 +01002105 static bool HasAccessorsImpl(JSObject* holder,
2106 FixedArrayBase* backing_store) {
2107 FixedArray* parameter_map = FixedArray::cast(backing_store);
2108 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2109 return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
2110 }
2111
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002112 static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
2113 uint32_t entry) {
2114 FixedArray* parameter_map = FixedArray::cast(parameters);
2115 uint32_t length = parameter_map->length() - 2;
2116 if (entry < length) return entry;
2117
2118 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2119 return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
2120 }
2121
2122 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2123 FixedArrayBase* parameters,
2124 uint32_t index, PropertyFilter filter) {
2125 FixedArray* parameter_map = FixedArray::cast(parameters);
2126 Object* probe = GetParameterMapArg(parameter_map, index);
2127 if (!probe->IsTheHole()) return index;
2128
2129 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2130 uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
2131 index, filter);
2132 if (entry == kMaxUInt32) return entry;
2133 return (parameter_map->length() - 2) + entry;
2134 }
2135
Ben Murdoch097c5b22016-05-18 11:27:45 +01002136 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2137 FixedArray* parameter_map = FixedArray::cast(holder->elements());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002138 uint32_t length = parameter_map->length() - 2;
2139 if (entry < length) {
2140 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002141 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002142 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2143 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002144 }
2145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002146 static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2147 uint32_t length = parameter_map->length() - 2;
2148 return index < length
2149 ? parameter_map->get(index + 2)
2150 : Object::cast(parameter_map->GetHeap()->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002151 }
2152
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002153 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2154 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2155 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2156 if (entry < length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002157 // TODO(kmillikin): We could check if this was the last aliased
2158 // parameter, and revert to normal elements in that case. That
2159 // would enable GC of the context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002160 parameter_map->set_the_hole(entry + 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002161 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002162 SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
2163 obj, entry - length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002164 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002165 }
2166};
2167
2168
2169class SlowSloppyArgumentsElementsAccessor
2170 : public SloppyArgumentsElementsAccessor<
2171 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2172 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2173 public:
2174 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2175 : SloppyArgumentsElementsAccessor<
2176 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2177 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2178
2179 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2180 Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2181 Handle<SeededNumberDictionary> dict(
2182 SeededNumberDictionary::cast(parameter_map->get(1)));
2183 // TODO(verwaest): Remove reliance on index in Shrink.
2184 uint32_t index = GetIndexForEntryImpl(*dict, entry);
2185 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2186 USE(result);
2187 DCHECK(result->IsTrue());
2188 Handle<FixedArray> new_elements =
2189 SeededNumberDictionary::Shrink(dict, index);
2190 parameter_map->set(1, *new_elements);
2191 }
2192
2193 static void AddImpl(Handle<JSObject> object, uint32_t index,
2194 Handle<Object> value, PropertyAttributes attributes,
2195 uint32_t new_capacity) {
2196 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2197 Handle<FixedArrayBase> old_elements(
2198 FixedArrayBase::cast(parameter_map->get(1)));
2199 Handle<SeededNumberDictionary> dictionary =
2200 old_elements->IsSeededNumberDictionary()
2201 ? Handle<SeededNumberDictionary>::cast(old_elements)
2202 : JSObject::NormalizeElements(object);
2203 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2204 Handle<SeededNumberDictionary> new_dictionary =
2205 SeededNumberDictionary::AddNumberEntry(
2206 dictionary, index, value, details,
2207 object->map()->is_prototype_map());
2208 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2209 if (*dictionary != *new_dictionary) {
2210 FixedArray::cast(object->elements())->set(1, *new_dictionary);
2211 }
2212 }
2213
2214 static void ReconfigureImpl(Handle<JSObject> object,
2215 Handle<FixedArrayBase> store, uint32_t entry,
2216 Handle<Object> value,
2217 PropertyAttributes attributes) {
2218 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2219 uint32_t length = parameter_map->length() - 2;
2220 if (entry < length) {
2221 Object* probe = parameter_map->get(entry + 2);
2222 DCHECK(!probe->IsTheHole());
2223 Context* context = Context::cast(parameter_map->get(0));
2224 int context_entry = Smi::cast(probe)->value();
2225 DCHECK(!context->get(context_entry)->IsTheHole());
2226 context->set(context_entry, *value);
2227
2228 // Redefining attributes of an aliased element destroys fast aliasing.
2229 parameter_map->set_the_hole(entry + 2);
2230 // For elements that are still writable we re-establish slow aliasing.
2231 if ((attributes & READ_ONLY) == 0) {
2232 Isolate* isolate = store->GetIsolate();
2233 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2234 }
2235
2236 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2237 Handle<SeededNumberDictionary> arguments(
2238 SeededNumberDictionary::cast(parameter_map->get(1)));
2239 arguments = SeededNumberDictionary::AddNumberEntry(
2240 arguments, entry, value, details, object->map()->is_prototype_map());
2241 // If the attributes were NONE, we would have called set rather than
2242 // reconfigure.
2243 DCHECK_NE(NONE, attributes);
2244 object->RequireSlowElements(*arguments);
2245 parameter_map->set(1, *arguments);
2246 } else {
2247 Handle<FixedArrayBase> arguments(
2248 FixedArrayBase::cast(parameter_map->get(1)));
2249 DictionaryElementsAccessor::ReconfigureImpl(
2250 object, arguments, entry - length, value, attributes);
2251 }
2252 }
2253};
2254
2255
2256class FastSloppyArgumentsElementsAccessor
2257 : public SloppyArgumentsElementsAccessor<
2258 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2259 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2260 public:
2261 explicit FastSloppyArgumentsElementsAccessor(const char* name)
2262 : SloppyArgumentsElementsAccessor<
2263 FastSloppyArgumentsElementsAccessor,
2264 FastHoleyObjectElementsAccessor,
2265 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2266
2267 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2268 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2269 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
2270 FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2271 }
2272
2273 static void AddImpl(Handle<JSObject> object, uint32_t index,
2274 Handle<Object> value, PropertyAttributes attributes,
2275 uint32_t new_capacity) {
2276 DCHECK_EQ(NONE, attributes);
2277 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2278 Handle<FixedArrayBase> old_elements(
2279 FixedArrayBase::cast(parameter_map->get(1)));
2280 if (old_elements->IsSeededNumberDictionary() ||
2281 static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2282 GrowCapacityAndConvertImpl(object, new_capacity);
2283 }
2284 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2285 // For fast holey objects, the entry equals the index. The code above made
2286 // sure that there's enough space to store the value. We cannot convert
2287 // index to entry explicitly since the slot still contains the hole, so the
2288 // current EntryForIndex would indicate that it is "absent" by returning
2289 // kMaxUInt32.
2290 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2291 }
2292
2293 static void ReconfigureImpl(Handle<JSObject> object,
2294 Handle<FixedArrayBase> store, uint32_t entry,
2295 Handle<Object> value,
2296 PropertyAttributes attributes) {
2297 Handle<SeededNumberDictionary> dictionary =
2298 JSObject::NormalizeElements(object);
2299 FixedArray::cast(*store)->set(1, *dictionary);
2300 uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2301 if (entry >= length) {
2302 entry = dictionary->FindEntry(entry - length) + length;
2303 }
2304 SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2305 value, attributes);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002306 }
2307
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002308 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2309 FixedArrayBase* to, ElementsKind from_kind,
2310 uint32_t to_start, int packed_size,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 int copy_size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002312 DCHECK(!to->IsDictionary());
2313 if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2314 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2315 to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002316 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002317 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2318 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2319 FAST_HOLEY_ELEMENTS, to_start, copy_size);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002320 }
2321 }
2322
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002323 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2324 uint32_t capacity) {
2325 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2326 Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2327 ElementsKind from_kind = object->GetElementsKind();
2328 // This method should only be called if there's a reason to update the
2329 // elements.
2330 DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2331 static_cast<uint32_t>(old_elements->length()) < capacity);
2332 Handle<FixedArrayBase> elements =
2333 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2334 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2335 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2336 JSObject::MigrateToMap(object, new_map);
2337 parameter_map->set(1, *elements);
2338 JSObject::ValidateElements(object);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002339 }
2340};
2341
Ben Murdoch097c5b22016-05-18 11:27:45 +01002342template <typename StringWrapperElementsAccessorSubclass,
2343 typename BackingStoreAccessor, typename KindTraits>
2344class StringWrapperElementsAccessor
2345 : public ElementsAccessorBase<StringWrapperElementsAccessorSubclass,
2346 KindTraits> {
2347 public:
2348 explicit StringWrapperElementsAccessor(const char* name)
2349 : ElementsAccessorBase<StringWrapperElementsAccessorSubclass, KindTraits>(
2350 name) {
2351 USE(KindTraits::Kind);
2352 }
2353
2354 static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2355 Isolate* isolate = holder->GetIsolate();
2356 Handle<String> string(GetString(*holder), isolate);
2357 uint32_t length = static_cast<uint32_t>(string->length());
2358 if (entry < length) {
2359 return isolate->factory()->LookupSingleCharacterStringFromCode(
2360 String::Flatten(string)->Get(entry));
2361 }
2362 return BackingStoreAccessor::GetImpl(holder, entry - length);
2363 }
2364
2365 static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2366 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2367 if (entry < length) {
2368 PropertyAttributes attributes =
2369 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
2370 return PropertyDetails(attributes, v8::internal::DATA, 0,
2371 PropertyCellType::kNoCell);
2372 }
2373 return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
2374 }
2375
2376 static uint32_t GetEntryForIndexImpl(JSObject* holder,
2377 FixedArrayBase* backing_store,
2378 uint32_t index, PropertyFilter filter) {
2379 uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
2380 if (index < length) return index;
2381 uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
2382 holder, backing_store, index, filter);
2383 if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
2384 DCHECK(backing_store_entry < kMaxUInt32 - length);
2385 return backing_store_entry + length;
2386 }
2387
2388 static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
2389 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2390 if (entry < length) {
2391 return; // String contents can't be deleted.
2392 }
2393 BackingStoreAccessor::DeleteImpl(holder, entry - length);
2394 }
2395
2396 static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
2397 uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
2398 if (entry < length) {
2399 return; // String contents are read-only.
2400 }
2401 BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
2402 }
2403
2404 static void AddImpl(Handle<JSObject> object, uint32_t index,
2405 Handle<Object> value, PropertyAttributes attributes,
2406 uint32_t new_capacity) {
2407 DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
2408 // Explicitly grow fast backing stores if needed. Dictionaries know how to
2409 // extend their capacity themselves.
2410 if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
2411 (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
2412 BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
2413 new_capacity)) {
2414 StringWrapperElementsAccessorSubclass::GrowCapacityAndConvertImpl(
2415 object, new_capacity);
2416 }
2417 BackingStoreAccessor::AddImpl(object, index, value, attributes,
2418 new_capacity);
2419 }
2420
2421 static void ReconfigureImpl(Handle<JSObject> object,
2422 Handle<FixedArrayBase> store, uint32_t entry,
2423 Handle<Object> value,
2424 PropertyAttributes attributes) {
2425 uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
2426 if (entry < length) {
2427 return; // String contents can't be reconfigured.
2428 }
2429 BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
2430 attributes);
2431 }
2432
2433 static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2434 KeyAccumulator* accumulator,
2435 AddKeyConversion convert) {
2436 Isolate* isolate = receiver->GetIsolate();
2437 Handle<String> string(GetString(*receiver), isolate);
2438 string = String::Flatten(string);
2439 uint32_t length = static_cast<uint32_t>(string->length());
2440 for (uint32_t i = 0; i < length; i++) {
2441 accumulator->AddKey(
2442 isolate->factory()->LookupSingleCharacterStringFromCode(
2443 string->Get(i)),
2444 convert);
2445 }
2446 BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
2447 convert);
2448 }
2449
2450 static void CollectElementIndicesImpl(Handle<JSObject> object,
2451 Handle<FixedArrayBase> backing_store,
2452 KeyAccumulator* keys, uint32_t range,
2453 PropertyFilter filter,
2454 uint32_t offset) {
2455 if ((filter & ONLY_ALL_CAN_READ) == 0) {
2456 uint32_t length = GetString(*object)->length();
2457 for (uint32_t i = 0; i < length; i++) {
2458 keys->AddKey(i);
2459 }
2460 }
2461 BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store, keys,
2462 range, filter, offset);
2463 }
2464
2465 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2466 FixedArrayBase* to, ElementsKind from_kind,
2467 uint32_t to_start, int packed_size,
2468 int copy_size) {
2469 BackingStoreAccessor::CopyElementsImpl(from, from_start, to, from_kind,
2470 to_start, packed_size, copy_size);
2471 }
2472
2473 private:
2474 static String* GetString(JSObject* holder) {
2475 DCHECK(holder->IsJSValue());
2476 JSValue* js_value = JSValue::cast(holder);
2477 DCHECK(js_value->value()->IsString());
2478 return String::cast(js_value->value());
2479 }
2480};
2481
2482class FastStringWrapperElementsAccessor
2483 : public StringWrapperElementsAccessor<
2484 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2485 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
2486 public:
2487 explicit FastStringWrapperElementsAccessor(const char* name)
2488 : StringWrapperElementsAccessor<
2489 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
2490 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
2491};
2492
2493class SlowStringWrapperElementsAccessor
2494 : public StringWrapperElementsAccessor<
2495 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2496 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
2497 public:
2498 explicit SlowStringWrapperElementsAccessor(const char* name)
2499 : StringWrapperElementsAccessor<
2500 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
2501 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
2502
2503 static bool HasAccessorsImpl(JSObject* holder,
2504 FixedArrayBase* backing_store) {
2505 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
2506 }
2507};
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002509} // namespace
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002510
2511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002512void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2513 bool allow_appending) {
2514 DisallowHeapAllocation no_allocation;
2515 Object* raw_length = NULL;
2516 const char* elements_type = "array";
2517 if (obj->IsJSArray()) {
2518 JSArray* array = JSArray::cast(*obj);
2519 raw_length = array->length();
2520 } else {
2521 raw_length = Smi::FromInt(obj->elements()->length());
2522 elements_type = "object";
2523 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002525 if (raw_length->IsNumber()) {
2526 double n = raw_length->Number();
2527 if (FastI2D(FastD2UI(n)) == n) {
2528 int32_t int32_length = DoubleToInt32(n);
2529 uint32_t compare_length = static_cast<uint32_t>(int32_length);
2530 if (allow_appending) compare_length++;
2531 if (index >= compare_length) {
2532 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2533 elements_type, op, elements_type, static_cast<int>(int32_length),
2534 static_cast<int>(index));
2535 TraceTopFrame(obj->GetIsolate());
2536 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002537 }
2538 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002539 PrintF("[%s elements length not integer value in ", elements_type);
2540 TraceTopFrame(obj->GetIsolate());
2541 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002542 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002543 } else {
2544 PrintF("[%s elements length not a number in ", elements_type);
2545 TraceTopFrame(obj->GetIsolate());
2546 PrintF("]\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002547 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002548}
2549
2550
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002551MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2552 Arguments* args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002553 if (args->length() == 0) {
2554 // Optimize the case where there are no parameters passed.
2555 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2556 return array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002558 } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2559 uint32_t length;
2560 if (!args->at<Object>(0)->ToArrayLength(&length)) {
2561 return ThrowArrayLengthRangeError(array->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002562 }
2563
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002564 // Optimize the case where there is one argument and the argument is a small
2565 // smi.
2566 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2567 ElementsKind elements_kind = array->GetElementsKind();
2568 JSArray::Initialize(array, length, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002570 if (!IsFastHoleyElementsKind(elements_kind)) {
2571 elements_kind = GetHoleyElementsKind(elements_kind);
2572 JSObject::TransitionElementsKind(array, elements_kind);
2573 }
2574 } else if (length == 0) {
2575 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2576 } else {
2577 // Take the argument as the length.
2578 JSArray::Initialize(array, 0);
2579 JSArray::SetLength(array, length);
2580 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002581 return array;
2582 }
2583
2584 Factory* factory = array->GetIsolate()->factory();
2585
2586 // Set length and elements on the array.
2587 int number_of_elements = args->length();
2588 JSObject::EnsureCanContainElements(
2589 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2590
2591 // Allocate an appropriately typed elements array.
2592 ElementsKind elements_kind = array->GetElementsKind();
2593 Handle<FixedArrayBase> elms;
2594 if (IsFastDoubleElementsKind(elements_kind)) {
2595 elms = Handle<FixedArrayBase>::cast(
2596 factory->NewFixedDoubleArray(number_of_elements));
2597 } else {
2598 elms = Handle<FixedArrayBase>::cast(
2599 factory->NewFixedArrayWithHoles(number_of_elements));
2600 }
2601
2602 // Fill in the content
2603 switch (array->GetElementsKind()) {
2604 case FAST_HOLEY_SMI_ELEMENTS:
2605 case FAST_SMI_ELEMENTS: {
2606 Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002607 for (int entry = 0; entry < number_of_elements; entry++) {
2608 smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002609 }
2610 break;
2611 }
2612 case FAST_HOLEY_ELEMENTS:
2613 case FAST_ELEMENTS: {
2614 DisallowHeapAllocation no_gc;
2615 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2616 Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002617 for (int entry = 0; entry < number_of_elements; entry++) {
2618 object_elms->set(entry, (*args)[entry], mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002619 }
2620 break;
2621 }
2622 case FAST_HOLEY_DOUBLE_ELEMENTS:
2623 case FAST_DOUBLE_ELEMENTS: {
2624 Handle<FixedDoubleArray> double_elms =
2625 Handle<FixedDoubleArray>::cast(elms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 for (int entry = 0; entry < number_of_elements; entry++) {
2627 double_elms->set(entry, (*args)[entry]->Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002628 }
2629 break;
2630 }
2631 default:
2632 UNREACHABLE();
2633 break;
2634 }
2635
2636 array->set_elements(*elms);
2637 array->set_length(Smi::FromInt(number_of_elements));
2638 return array;
2639}
2640
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002641
2642void ElementsAccessor::InitializeOncePerProcess() {
2643 static ElementsAccessor* accessor_array[] = {
2644#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2645 ELEMENTS_LIST(ACCESSOR_ARRAY)
2646#undef ACCESSOR_ARRAY
2647 };
2648
2649 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2650 kElementsKindCount);
2651
2652 elements_accessors_ = accessor_array;
2653}
2654
2655
2656void ElementsAccessor::TearDown() {
2657 if (elements_accessors_ == NULL) return;
2658#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2659 ELEMENTS_LIST(ACCESSOR_DELETE)
2660#undef ACCESSOR_DELETE
2661 elements_accessors_ = NULL;
2662}
2663
2664
2665Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
2666 uint32_t concat_size) {
2667 int result_len = 0;
2668 ElementsKind elements_kind = GetInitialFastElementsKind();
2669 bool has_double = false;
2670 {
2671 DisallowHeapAllocation no_gc;
2672 // Iterate through all the arguments performing checks
2673 // and calculating total length.
2674 bool is_holey = false;
2675 for (uint32_t i = 0; i < concat_size; i++) {
2676 Object* arg = (*args)[i];
2677 int len = Smi::cast(JSArray::cast(arg)->length())->value();
2678
2679 // We shouldn't overflow when adding another len.
2680 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
2681 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
2682 USE(kHalfOfMaxInt);
2683 result_len += len;
2684 DCHECK(0 <= result_len);
2685 DCHECK(result_len <= FixedDoubleArray::kMaxLength);
2686
2687 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
2688 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
2689 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
2690 elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
2691 }
2692 if (is_holey) {
2693 elements_kind = GetHoleyElementsKind(elements_kind);
2694 }
2695 }
2696
2697 // If a double array is concatted into a fast elements array, the fast
2698 // elements array needs to be initialized to contain proper holes, since
2699 // boxing doubles may cause incremental marking.
2700 ArrayStorageAllocationMode mode =
2701 has_double && IsFastObjectElementsKind(elements_kind)
2702 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
2703 : DONT_INITIALIZE_ARRAY_ELEMENTS;
2704 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2705 elements_kind, result_len, result_len, Strength::WEAK, mode);
2706 if (result_len == 0) return result_array;
2707 int j = 0;
2708 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
2709 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
2710 for (uint32_t i = 0; i < concat_size; i++) {
2711 // It is crucial to keep |array| in a raw pointer form to avoid
2712 // performance degradation.
2713 JSArray* array = JSArray::cast((*args)[i]);
2714 int len = Smi::cast(array->length())->value();
2715 if (len > 0) {
2716 ElementsKind from_kind = array->GetElementsKind();
2717 accessor->CopyElements(array, 0, from_kind, storage, j, len);
2718 j += len;
2719 }
2720 }
2721
2722 DCHECK(j == result_len);
2723 return result_array;
2724}
2725
2726ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
2727} // namespace internal
2728} // namespace v8