blob: f0e1414de4aeebe9ef9089ecd2b1cc5fc6f1b682 [file] [log] [blame]
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "objects.h"
31#include "elements.h"
rossberg@chromium.org28a37082011-08-22 11:03:23 +000032#include "utils.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000033
danno@chromium.orgc612e022011-11-10 11:38:15 +000034
35// Each concrete ElementsAccessor can handle exactly one ElementsKind,
36// several abstract ElementsAccessor classes are used to allow sharing
37// common code.
38//
39// Inheritance hierarchy:
40// - ElementsAccessorBase (abstract)
41// - FastElementsAccessor (abstract)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000042// - FastSmiOrObjectElementsAccessor
43// - FastPackedSmiElementsAccessor
44// - FastHoleySmiElementsAccessor
45// - FastPackedObjectElementsAccessor
46// - FastHoleyObjectElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +000047// - FastDoubleElementsAccessor
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000048// - FastPackedDoubleElementsAccessor
49// - FastHoleyDoubleElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +000050// - ExternalElementsAccessor (abstract)
51// - ExternalByteElementsAccessor
52// - ExternalUnsignedByteElementsAccessor
53// - ExternalShortElementsAccessor
54// - ExternalUnsignedShortElementsAccessor
55// - ExternalIntElementsAccessor
56// - ExternalUnsignedIntElementsAccessor
57// - ExternalFloatElementsAccessor
58// - ExternalDoubleElementsAccessor
59// - PixelElementsAccessor
60// - DictionaryElementsAccessor
61// - NonStrictArgumentsElementsAccessor
62
63
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000064namespace v8 {
65namespace internal {
66
67
mmassi@chromium.org7028c052012-06-13 11:51:58 +000068static const int kPackedSizeNotKnown = -1;
69
70
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000071// First argument in list is the accessor class, the second argument is the
72// accessor ElementsKind, and the third is the backing store class. Use the
73// fast element handler for smi-only arrays. The implementation is currently
74// identical. Note that the order must match that of the ElementsKind enum for
75// the |accessor_array[]| below to work.
76#define ELEMENTS_LIST(V) \
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000077 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
78 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \
79 FixedArray) \
80 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
81 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
82 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \
83 FixedDoubleArray) \
84 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
85 FixedDoubleArray) \
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000086 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \
87 SeededNumberDictionary) \
88 V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \
89 FixedArray) \
90 V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS, \
91 ExternalByteArray) \
92 V(ExternalUnsignedByteElementsAccessor, \
93 EXTERNAL_UNSIGNED_BYTE_ELEMENTS, ExternalUnsignedByteArray) \
94 V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS, \
95 ExternalShortArray) \
96 V(ExternalUnsignedShortElementsAccessor, \
97 EXTERNAL_UNSIGNED_SHORT_ELEMENTS, ExternalUnsignedShortArray) \
98 V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS, \
99 ExternalIntArray) \
100 V(ExternalUnsignedIntElementsAccessor, \
101 EXTERNAL_UNSIGNED_INT_ELEMENTS, ExternalUnsignedIntArray) \
102 V(ExternalFloatElementsAccessor, \
103 EXTERNAL_FLOAT_ELEMENTS, ExternalFloatArray) \
104 V(ExternalDoubleElementsAccessor, \
105 EXTERNAL_DOUBLE_ELEMENTS, ExternalDoubleArray) \
106 V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS, ExternalPixelArray)
107
108
109template<ElementsKind Kind> class ElementsKindTraits {
110 public:
111 typedef FixedArrayBase BackingStore;
112};
113
114#define ELEMENTS_TRAITS(Class, KindParam, Store) \
115template<> class ElementsKindTraits<KindParam> { \
116 public: \
117 static const ElementsKind Kind = KindParam; \
118 typedef Store BackingStore; \
119};
120ELEMENTS_LIST(ELEMENTS_TRAITS)
121#undef ELEMENTS_TRAITS
122
123
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000124ElementsAccessor** ElementsAccessor::elements_accessors_;
125
126
danno@chromium.orgc612e022011-11-10 11:38:15 +0000127static bool HasKey(FixedArray* array, Object* key) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000128 int len0 = array->length();
129 for (int i = 0; i < len0; i++) {
130 Object* element = array->get(i);
131 if (element->IsSmi() && element == key) return true;
132 if (element->IsString() &&
133 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
134 return true;
135 }
136 }
137 return false;
138}
139
140
danno@chromium.orgc612e022011-11-10 11:38:15 +0000141static Failure* ThrowArrayLengthRangeError(Heap* heap) {
142 HandleScope scope(heap->isolate());
143 return heap->isolate()->Throw(
144 *heap->isolate()->factory()->NewRangeError("invalid_array_length",
145 HandleVector<Object>(NULL, 0)));
146}
147
148
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000149void CopyObjectToObjectElements(FixedArray* from,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000150 ElementsKind from_kind,
151 uint32_t from_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000152 FixedArray* to,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000153 ElementsKind to_kind,
154 uint32_t to_start,
danno@chromium.orgc7406162012-03-26 09:46:02 +0000155 int raw_copy_size) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000156 ASSERT(to->map() != HEAP->fixed_cow_array_map());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000157 int copy_size = raw_copy_size;
158 if (raw_copy_size < 0) {
159 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
160 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
161 copy_size = Min(from->length() - from_start,
162 to->length() - to_start);
163#ifdef DEBUG
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000164 // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000165 // marked with the hole.
166 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
167 for (int i = to_start + copy_size; i < to->length(); ++i) {
168 ASSERT(to->get(i)->IsTheHole());
169 }
170 }
171#endif
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000172 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000173 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
174 (copy_size + static_cast<int>(from_start)) <= from->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000175 if (copy_size == 0) return;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000176 ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
177 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000178 Address to_address = to->address() + FixedArray::kHeaderSize;
179 Address from_address = from->address() + FixedArray::kHeaderSize;
180 CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
181 reinterpret_cast<Object**>(from_address) + from_start,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000182 copy_size);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000183 if (IsFastObjectElementsKind(from_kind) &&
184 IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000185 Heap* heap = from->GetHeap();
186 if (!heap->InNewSpace(to)) {
187 heap->RecordWrites(to->address(),
188 to->OffsetOfElementAt(to_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000189 copy_size);
190 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000191 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000192 }
193}
194
195
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000196static void CopyDictionaryToObjectElements(SeededNumberDictionary* from,
197 uint32_t from_start,
198 FixedArray* to,
199 ElementsKind to_kind,
200 uint32_t to_start,
danno@chromium.orgc7406162012-03-26 09:46:02 +0000201 int raw_copy_size) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000202 int copy_size = raw_copy_size;
203 Heap* heap = from->GetHeap();
204 if (raw_copy_size < 0) {
205 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
206 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
207 copy_size = from->max_number_key() + 1 - from_start;
208#ifdef DEBUG
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000209 // Fast object arrays cannot be uninitialized. Ensure they are already
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000210 // marked with the hole.
211 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
212 for (int i = to_start + copy_size; i < to->length(); ++i) {
213 ASSERT(to->get(i)->IsTheHole());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000214 }
215 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000216#endif
217 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000218 ASSERT(to != from);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000219 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000220 if (copy_size == 0) return;
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000221 uint32_t to_length = to->length();
222 if (to_start + copy_size > to_length) {
223 copy_size = to_length - to_start;
224 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000225 for (int i = 0; i < copy_size; i++) {
226 int entry = from->FindEntry(i + from_start);
227 if (entry != SeededNumberDictionary::kNotFound) {
228 Object* value = from->ValueAt(entry);
229 ASSERT(!value->IsTheHole());
230 to->set(i + to_start, value, SKIP_WRITE_BARRIER);
231 } else {
232 to->set_the_hole(i + to_start);
233 }
234 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000235 if (IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000236 if (!heap->InNewSpace(to)) {
237 heap->RecordWrites(to->address(),
238 to->OffsetOfElementAt(to_start),
239 copy_size);
240 }
241 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000242 }
243}
244
245
246MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000247 FixedDoubleArray* from,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000248 uint32_t from_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000249 FixedArray* to,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000250 ElementsKind to_kind,
251 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000252 int raw_copy_size) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000253 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000254 int copy_size = raw_copy_size;
255 if (raw_copy_size < 0) {
256 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
257 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
258 copy_size = Min(from->length() - from_start,
259 to->length() - to_start);
260#ifdef DEBUG
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000261 // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000262 // marked with the hole.
263 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
264 for (int i = to_start + copy_size; i < to->length(); ++i) {
265 ASSERT(to->get(i)->IsTheHole());
266 }
267 }
268#endif
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000269 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000270 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
271 (copy_size + static_cast<int>(from_start)) <= from->length());
272 if (copy_size == 0) return from;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000273 for (int i = 0; i < copy_size; ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000274 if (IsFastSmiElementsKind(to_kind)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000275 UNIMPLEMENTED();
276 return Failure::Exception();
277 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000278 MaybeObject* maybe_value = from->get(i + from_start);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000279 Object* value;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000280 ASSERT(IsFastObjectElementsKind(to_kind));
281 // Because Double -> Object elements transitions allocate HeapObjects
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000282 // iteratively, the allocate must succeed within a single GC cycle,
283 // otherwise the retry after the GC will also fail. In order to ensure
284 // that no GC is triggered, allocate HeapNumbers from old space if they
285 // can't be taken from new space.
286 if (!maybe_value->ToObject(&value)) {
287 ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000288 Heap* heap = from->GetHeap();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000289 MaybeObject* maybe_value_object =
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000290 heap->AllocateHeapNumber(from->get_scalar(i + from_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000291 TENURED);
292 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
293 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000294 to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000295 }
296 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000297 return to;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000298}
299
300
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000301static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000302 uint32_t from_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000303 FixedDoubleArray* to,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000304 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000305 int raw_copy_size) {
306 int copy_size = raw_copy_size;
307 if (raw_copy_size < 0) {
308 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
309 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
310 copy_size = Min(from->length() - from_start,
311 to->length() - to_start);
312 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
313 for (int i = to_start + copy_size; i < to->length(); ++i) {
314 to->set_the_hole(i);
315 }
316 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000317 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000318 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
319 (copy_size + static_cast<int>(from_start)) <= from->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000320 if (copy_size == 0) return;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000321 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
322 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
323 to_address += kDoubleSize * to_start;
324 from_address += kDoubleSize * from_start;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000325 int words_per_double = (kDoubleSize / kPointerSize);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000326 CopyWords(reinterpret_cast<Object**>(to_address),
327 reinterpret_cast<Object**>(from_address),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000328 words_per_double * copy_size);
329}
330
331
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000332static void CopySmiToDoubleElements(FixedArray* from,
333 uint32_t from_start,
334 FixedDoubleArray* to,
335 uint32_t to_start,
336 int raw_copy_size) {
337 int copy_size = raw_copy_size;
338 if (raw_copy_size < 0) {
339 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
340 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
341 copy_size = from->length() - from_start;
342 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
343 for (int i = to_start + copy_size; i < to->length(); ++i) {
344 to->set_the_hole(i);
345 }
346 }
347 }
348 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
349 (copy_size + static_cast<int>(from_start)) <= from->length());
350 if (copy_size == 0) return;
351 Object* the_hole = from->GetHeap()->the_hole_value();
352 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
353 from_start < from_end; from_start++, to_start++) {
354 Object* hole_or_smi = from->get(from_start);
355 if (hole_or_smi == the_hole) {
356 to->set_the_hole(to_start);
357 } else {
358 to->set(to_start, Smi::cast(hole_or_smi)->value());
359 }
360 }
361}
362
363
364static void CopyPackedSmiToDoubleElements(FixedArray* from,
365 uint32_t from_start,
366 FixedDoubleArray* to,
367 uint32_t to_start,
368 int packed_size,
369 int raw_copy_size) {
370 int copy_size = raw_copy_size;
371 uint32_t to_end;
372 if (raw_copy_size < 0) {
373 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
374 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
375 copy_size = from->length() - from_start;
376 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
377 to_end = to->length();
378 } else {
379 to_end = to_start + static_cast<uint32_t>(copy_size);
380 }
381 } else {
382 to_end = to_start + static_cast<uint32_t>(copy_size);
383 }
384 ASSERT(static_cast<int>(to_end) <= to->length());
385 ASSERT(packed_size >= 0 && packed_size <= copy_size);
386 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
387 (copy_size + static_cast<int>(from_start)) <= from->length());
388 if (copy_size == 0) return;
389 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
390 from_start < from_end; from_start++, to_start++) {
391 Object* smi = from->get(from_start);
392 ASSERT(!smi->IsTheHole());
393 to->set(to_start, Smi::cast(smi)->value());
394 }
395
396 while (to_start < to_end) {
397 to->set_the_hole(to_start++);
398 }
399}
400
401
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000402static void CopyObjectToDoubleElements(FixedArray* from,
403 uint32_t from_start,
404 FixedDoubleArray* to,
405 uint32_t to_start,
406 int raw_copy_size) {
407 int copy_size = raw_copy_size;
408 if (raw_copy_size < 0) {
409 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
410 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
411 copy_size = from->length() - from_start;
412 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
413 for (int i = to_start + copy_size; i < to->length(); ++i) {
414 to->set_the_hole(i);
415 }
416 }
417 }
418 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
419 (copy_size + static_cast<int>(from_start)) <= from->length());
420 if (copy_size == 0) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000421 Object* the_hole = from->GetHeap()->the_hole_value();
422 for (uint32_t from_end = from_start + copy_size;
423 from_start < from_end; from_start++, to_start++) {
424 Object* hole_or_object = from->get(from_start);
425 if (hole_or_object == the_hole) {
426 to->set_the_hole(to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000427 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000428 to->set(to_start, hole_or_object->Number());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000429 }
430 }
431}
432
433
434static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
435 uint32_t from_start,
436 FixedDoubleArray* to,
437 uint32_t to_start,
438 int raw_copy_size) {
439 int copy_size = raw_copy_size;
440 if (copy_size < 0) {
441 ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
442 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
443 copy_size = from->max_number_key() + 1 - from_start;
444 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
445 for (int i = to_start + copy_size; i < to->length(); ++i) {
446 to->set_the_hole(i);
447 }
448 }
449 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000450 if (copy_size == 0) return;
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000451 uint32_t to_length = to->length();
452 if (to_start + copy_size > to_length) {
453 copy_size = to_length - to_start;
454 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000455 for (int i = 0; i < copy_size; i++) {
456 int entry = from->FindEntry(i + from_start);
457 if (entry != SeededNumberDictionary::kNotFound) {
458 to->set(i + to_start, from->ValueAt(entry)->Number());
459 } else {
460 to->set_the_hole(i + to_start);
461 }
462 }
463}
464
465
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000466// Base class for element handler implementations. Contains the
467// the common logic for objects with different ElementsKinds.
468// Subclasses must specialize method for which the element
469// implementation differs from the base class implementation.
470//
471// This class is intended to be used in the following way:
472//
473// class SomeElementsAccessor :
474// public ElementsAccessorBase<SomeElementsAccessor,
475// BackingStoreClass> {
476// ...
477// }
478//
479// This is an example of the Curiously Recurring Template Pattern (see
480// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
481// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
482// specialization of SomeElementsAccessor methods).
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000483template <typename ElementsAccessorSubclass,
484 typename ElementsTraitsParam>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000485class ElementsAccessorBase : public ElementsAccessor {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000486 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000487 explicit ElementsAccessorBase(const char* name)
488 : ElementsAccessor(name) { }
489
490 typedef ElementsTraitsParam ElementsTraits;
491 typedef typename ElementsTraitsParam::BackingStore BackingStore;
492
493 virtual ElementsKind kind() const { return ElementsTraits::Kind; }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000494
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000495 static void ValidateContents(JSObject* holder, int length) {
496 }
497
498 static void ValidateImpl(JSObject* holder) {
499 FixedArrayBase* fixed_array_base = holder->elements();
500 // When objects are first allocated, its elements are Failures.
501 if (fixed_array_base->IsFailure()) return;
502 if (!fixed_array_base->IsHeapObject()) return;
503 Map* map = fixed_array_base->map();
504 // Arrays that have been shifted in place can't be verified.
505 Heap* heap = holder->GetHeap();
506 if (map == heap->raw_unchecked_one_pointer_filler_map() ||
507 map == heap->raw_unchecked_two_pointer_filler_map() ||
508 map == heap->free_space_map()) {
509 return;
510 }
511 int length = 0;
512 if (holder->IsJSArray()) {
513 Object* length_obj = JSArray::cast(holder)->length();
514 if (length_obj->IsSmi()) {
515 length = Smi::cast(length_obj)->value();
516 }
517 } else {
518 length = fixed_array_base->length();
519 }
520 ElementsAccessorSubclass::ValidateContents(holder, length);
521 }
522
523 virtual void Validate(JSObject* holder) {
524 ElementsAccessorSubclass::ValidateImpl(holder);
525 }
526
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000527 static bool HasElementImpl(Object* receiver,
528 JSObject* holder,
529 uint32_t key,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000530 BackingStore* backing_store) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000531 MaybeObject* element =
532 ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store);
533 return !element->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000534 }
535
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000536 virtual bool HasElement(Object* receiver,
537 JSObject* holder,
538 uint32_t key,
539 FixedArrayBase* backing_store) {
540 if (backing_store == NULL) {
541 backing_store = holder->elements();
542 }
543 return ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000544 receiver, holder, key, BackingStore::cast(backing_store));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000545 }
546
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000547 MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
548 JSObject* holder,
549 uint32_t key,
550 FixedArrayBase* backing_store) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000551 if (backing_store == NULL) {
552 backing_store = holder->elements();
553 }
554 return ElementsAccessorSubclass::GetImpl(
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000555 receiver, holder, key, BackingStore::cast(backing_store));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000556 }
557
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000558 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
559 JSObject* obj,
560 uint32_t key,
561 BackingStore* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000562 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
563 ? backing_store->get(key)
564 : backing_store->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000565 }
566
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000567 MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
568 Object* length) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 return ElementsAccessorSubclass::SetLengthImpl(
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000570 array, length, BackingStore::cast(array->elements()));
danno@chromium.orgc612e022011-11-10 11:38:15 +0000571 }
572
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000573 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
574 JSObject* obj,
575 Object* length,
576 BackingStore* backing_store);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000577
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000578 MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
579 JSArray* array,
580 int capacity,
581 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000582 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
583 array,
584 capacity,
585 length);
586 }
587
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000588 MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
589 JSObject* obj,
590 int capacity,
591 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000592 UNIMPLEMENTED();
593 return obj;
594 }
595
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000596 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
597 uint32_t key,
598 JSReceiver::DeleteMode mode) = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000599
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000600 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
601 uint32_t from_start,
602 FixedArrayBase* to,
603 ElementsKind to_kind,
604 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000605 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000606 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000607 UNREACHABLE();
608 return NULL;
609 }
610
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000611 MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder,
612 uint32_t from_start,
613 FixedArrayBase* to,
614 ElementsKind to_kind,
615 uint32_t to_start,
616 int copy_size,
617 FixedArrayBase* from) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000618 int packed_size = kPackedSizeNotKnown;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000619 if (from == NULL) {
620 from = from_holder->elements();
621 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000622
623 if (from_holder) {
624 ElementsKind elements_kind = from_holder->GetElementsKind();
625 bool is_packed = IsFastPackedElementsKind(elements_kind) &&
626 from_holder->IsJSArray();
627 if (is_packed) {
628 packed_size = Smi::cast(JSArray::cast(from_holder)->length())->value();
629 if (copy_size >= 0 && packed_size > copy_size) {
630 packed_size = copy_size;
631 }
632 }
633 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000634 if (from->length() == 0) {
635 return from;
636 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000637 return ElementsAccessorSubclass::CopyElementsImpl(
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000638 from, from_start, to, to_kind, to_start, packed_size, copy_size);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000639 }
640
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000641 MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
642 Object* receiver,
643 JSObject* holder,
644 FixedArray* to,
645 FixedArrayBase* from) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000646 int len0 = to->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000647#ifdef DEBUG
648 if (FLAG_enable_slow_asserts) {
649 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000650 ASSERT(!to->get(i)->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000651 }
652 }
653#endif
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000654 if (from == NULL) {
655 from = holder->elements();
656 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000657 BackingStore* backing_store = BackingStore::cast(from);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000658 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000659
660 // Optimize if 'other' is empty.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000661 // We cannot optimize if 'this' is empty, as other may have holes.
662 if (len1 == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000663
664 // Compute how many elements are not in other.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000665 uint32_t extra = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000666 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000667 uint32_t key =
668 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
669 if (ElementsAccessorSubclass::HasElementImpl(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000670 receiver, holder, key, backing_store)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000671 MaybeObject* maybe_value =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000672 ElementsAccessorSubclass::GetImpl(receiver, holder,
673 key, backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000674 Object* value;
675 if (!maybe_value->ToObject(&value)) return maybe_value;
676 ASSERT(!value->IsTheHole());
677 if (!HasKey(to, value)) {
678 extra++;
679 }
680 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000681 }
682
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000683 if (extra == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000684
685 // Allocate the result
686 FixedArray* result;
687 MaybeObject* maybe_obj =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000688 backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
690
691 // Fill in the content
692 {
693 AssertNoAllocation no_gc;
694 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
695 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000696 Object* e = to->get(i);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000697 ASSERT(e->IsString() || e->IsNumber());
698 result->set(i, e, mode);
699 }
700 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000701 // Fill in the extra values.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000702 uint32_t index = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000703 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000704 uint32_t key =
705 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
706 if (ElementsAccessorSubclass::HasElementImpl(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000707 receiver, holder, key, backing_store)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000708 MaybeObject* maybe_value =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000709 ElementsAccessorSubclass::GetImpl(receiver, holder,
710 key, backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000711 Object* value;
712 if (!maybe_value->ToObject(&value)) return maybe_value;
713 if (!value->IsTheHole() && !HasKey(to, value)) {
714 result->set(len0 + index, value);
715 index++;
716 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000717 }
718 }
719 ASSERT(extra == index);
720 return result;
721 }
722
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000723 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000724 static uint32_t GetCapacityImpl(BackingStore* backing_store) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000725 return backing_store->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000726 }
727
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000728 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000729 return ElementsAccessorSubclass::GetCapacityImpl(
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000730 BackingStore::cast(backing_store));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000731 }
732
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000733 static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000734 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000735 return index;
736 }
737
738 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000739 uint32_t index) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000740 return ElementsAccessorSubclass::GetKeyForIndexImpl(
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000741 BackingStore::cast(backing_store), index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000742 }
743
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000744 private:
745 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
746};
747
748
danno@chromium.orgc612e022011-11-10 11:38:15 +0000749// Super class for all fast element arrays.
750template<typename FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000751 typename KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000752 int ElementSize>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000753class FastElementsAccessor
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000754 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000755 public:
756 explicit FastElementsAccessor(const char* name)
757 : ElementsAccessorBase<FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000758 KindTraits>(name) {}
danno@chromium.orgc612e022011-11-10 11:38:15 +0000759 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000760 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000761 friend class NonStrictArgumentsElementsAccessor;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000762
763 typedef typename KindTraits::BackingStore BackingStore;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000764
765 // Adjusts the length of the fast backing store or returns the new length or
766 // undefined in case conversion to a slow backing store should be performed.
767 static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
768 JSArray* array,
769 Object* length_object,
770 uint32_t length) {
771 uint32_t old_capacity = backing_store->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000772 Object* old_length = array->length();
773 bool same_size = old_length->IsSmi() &&
774 static_cast<uint32_t>(Smi::cast(old_length)->value()) == length;
775 ElementsKind kind = array->GetElementsKind();
776
777 if (!same_size && IsFastElementsKind(kind) &&
778 !IsFastHoleyElementsKind(kind)) {
779 kind = GetHoleyElementsKind(kind);
780 MaybeObject* maybe_obj = array->TransitionElementsKind(kind);
781 if (maybe_obj->IsFailure()) return maybe_obj;
782 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000783
784 // Check whether the backing store should be shrunk.
785 if (length <= old_capacity) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000786 if (array->HasFastSmiOrObjectElements()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000787 MaybeObject* maybe_obj = array->EnsureWritableFastElements();
788 if (!maybe_obj->To(&backing_store)) return maybe_obj;
789 }
790 if (2 * length <= old_capacity) {
791 // If more than half the elements won't be used, trim the array.
792 if (length == 0) {
793 array->initialize_elements();
794 } else {
795 backing_store->set_length(length);
796 Address filler_start = backing_store->address() +
797 BackingStore::OffsetOfElementAt(length);
798 int filler_size = (old_capacity - length) * ElementSize;
799 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
800 }
801 } else {
802 // Otherwise, fill the unused tail with holes.
803 int old_length = FastD2I(array->length()->Number());
804 for (int i = length; i < old_length; i++) {
805 backing_store->set_the_hole(i);
806 }
807 }
808 return length_object;
809 }
810
811 // Check whether the backing store should be expanded.
812 uint32_t min = JSObject::NewElementsCapacity(old_capacity);
813 uint32_t new_capacity = length > min ? length : min;
814 if (!array->ShouldConvertToSlowElements(new_capacity)) {
815 MaybeObject* result = FastElementsAccessorSubclass::
816 SetFastElementsCapacityAndLength(array, new_capacity, length);
817 if (result->IsFailure()) return result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000818 array->ValidateElements();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000819 return length_object;
820 }
821
822 // Request conversion to slow elements.
823 return array->GetHeap()->undefined_value();
824 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000825
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000826 static MaybeObject* DeleteCommon(JSObject* obj,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000827 uint32_t key,
828 JSReceiver::DeleteMode mode) {
829 ASSERT(obj->HasFastSmiOrObjectElements() ||
830 obj->HasFastDoubleElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 obj->HasFastArgumentsElements());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000832 typename KindTraits::BackingStore* backing_store =
833 KindTraits::BackingStore::cast(obj->elements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Heap* heap = obj->GetHeap();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000835 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000836 backing_store =
837 KindTraits::BackingStore::cast(
838 FixedArray::cast(backing_store)->get(1));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000839 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000840 ElementsKind kind = KindTraits::Kind;
841 if (IsFastPackedElementsKind(kind)) {
842 MaybeObject* transitioned =
843 obj->TransitionElementsKind(GetHoleyElementsKind(kind));
844 if (transitioned->IsFailure()) return transitioned;
845 }
846 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
847 Object* writable;
848 MaybeObject* maybe = obj->EnsureWritableFastElements();
849 if (!maybe->ToObject(&writable)) return maybe;
850 backing_store = KindTraits::BackingStore::cast(writable);
851 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000852 }
853 uint32_t length = static_cast<uint32_t>(
854 obj->IsJSArray()
855 ? Smi::cast(JSArray::cast(obj)->length())->value()
856 : backing_store->length());
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000857 if (key < length) {
858 backing_store->set_the_hole(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000859 // If an old space backing store is larger than a certain size and
860 // has too few used values, normalize it.
861 // To avoid doing the check on every delete we require at least
862 // one adjacent hole to the value being deleted.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000863 const int kMinLengthForSparsenessCheck = 64;
864 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
865 !heap->InNewSpace(backing_store) &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000866 ((key > 0 && backing_store->is_the_hole(key - 1)) ||
867 (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000868 int num_used = 0;
869 for (int i = 0; i < backing_store->length(); ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000870 if (!backing_store->is_the_hole(i)) ++num_used;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000871 // Bail out early if more than 1/4 is used.
872 if (4 * num_used > backing_store->length()) break;
873 }
874 if (4 * num_used <= backing_store->length()) {
875 MaybeObject* result = obj->NormalizeElements();
876 if (result->IsFailure()) return result;
877 }
878 }
879 }
880 return heap->true_value();
881 }
882
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000883 virtual MaybeObject* Delete(JSObject* obj,
884 uint32_t key,
885 JSReceiver::DeleteMode mode) {
886 return DeleteCommon(obj, key, mode);
887 }
888
889 static bool HasElementImpl(
890 Object* receiver,
891 JSObject* holder,
892 uint32_t key,
893 typename KindTraits::BackingStore* backing_store) {
894 if (key >= static_cast<uint32_t>(backing_store->length())) {
895 return false;
896 }
897 return !backing_store->is_the_hole(key);
898 }
899
900 static void ValidateContents(JSObject* holder, int length) {
901#if DEBUG
902 FixedArrayBase* elements = holder->elements();
903 Heap* heap = elements->GetHeap();
904 Map* map = elements->map();
905 ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
906 (map == heap->fixed_array_map() ||
907 map == heap->fixed_cow_array_map())) ||
908 (IsFastDoubleElementsKind(KindTraits::Kind) ==
909 ((map == heap->fixed_array_map() && length == 0) ||
910 map == heap->fixed_double_array_map())));
911 for (int i = 0; i < length; i++) {
912 typename KindTraits::BackingStore* backing_store =
913 KindTraits::BackingStore::cast(elements);
914 ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) ||
915 static_cast<Object*>(backing_store->get(i))->IsSmi()) ||
916 (IsFastHoleyElementsKind(KindTraits::Kind) ==
917 backing_store->is_the_hole(i)));
918 }
919#endif
920 }
921};
922
923
924template<typename FastElementsAccessorSubclass,
925 typename KindTraits>
926class FastSmiOrObjectElementsAccessor
927 : public FastElementsAccessor<FastElementsAccessorSubclass,
928 KindTraits,
929 kPointerSize> {
930 public:
931 explicit FastSmiOrObjectElementsAccessor(const char* name)
932 : FastElementsAccessor<FastElementsAccessorSubclass,
933 KindTraits,
934 kPointerSize>(name) {}
935
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000936 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
937 uint32_t from_start,
938 FixedArrayBase* to,
939 ElementsKind to_kind,
940 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000941 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +0000942 int copy_size) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000943 if (IsFastSmiOrObjectElementsKind(to_kind)) {
944 CopyObjectToObjectElements(
945 FixedArray::cast(from), KindTraits::Kind, from_start,
946 FixedArray::cast(to), to_kind, to_start, copy_size);
947 } else if (IsFastDoubleElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000948 if (IsFastSmiElementsKind(KindTraits::Kind)) {
949 if (IsFastPackedElementsKind(KindTraits::Kind) &&
950 packed_size != kPackedSizeNotKnown) {
951 CopyPackedSmiToDoubleElements(
952 FixedArray::cast(from), from_start,
953 FixedDoubleArray::cast(to), to_start,
954 packed_size, copy_size);
955 } else {
956 CopySmiToDoubleElements(
957 FixedArray::cast(from), from_start,
958 FixedDoubleArray::cast(to), to_start, copy_size);
959 }
960 } else {
961 CopyObjectToDoubleElements(
962 FixedArray::cast(from), from_start,
963 FixedDoubleArray::cast(to), to_start, copy_size);
964 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000965 } else {
966 UNREACHABLE();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000967 }
968 return to->GetHeap()->undefined_value();
969 }
970
971
danno@chromium.orgc612e022011-11-10 11:38:15 +0000972 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
973 uint32_t capacity,
974 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000975 JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
976 obj->HasFastSmiElements()
977 ? JSObject::kAllowSmiElements
978 : JSObject::kDontAllowSmiElements;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000979 return obj->SetFastElementsCapacityAndLength(capacity,
980 length,
981 set_capacity_mode);
982 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000983};
984
985
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000986class FastPackedSmiElementsAccessor
987 : public FastSmiOrObjectElementsAccessor<
988 FastPackedSmiElementsAccessor,
989 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
990 public:
991 explicit FastPackedSmiElementsAccessor(const char* name)
992 : FastSmiOrObjectElementsAccessor<
993 FastPackedSmiElementsAccessor,
994 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
995};
996
997
998class FastHoleySmiElementsAccessor
999 : public FastSmiOrObjectElementsAccessor<
1000 FastHoleySmiElementsAccessor,
1001 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1002 public:
1003 explicit FastHoleySmiElementsAccessor(const char* name)
1004 : FastSmiOrObjectElementsAccessor<
1005 FastHoleySmiElementsAccessor,
1006 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1007};
1008
1009
1010class FastPackedObjectElementsAccessor
1011 : public FastSmiOrObjectElementsAccessor<
1012 FastPackedObjectElementsAccessor,
1013 ElementsKindTraits<FAST_ELEMENTS> > {
1014 public:
1015 explicit FastPackedObjectElementsAccessor(const char* name)
1016 : FastSmiOrObjectElementsAccessor<
1017 FastPackedObjectElementsAccessor,
1018 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1019};
1020
1021
1022class FastHoleyObjectElementsAccessor
1023 : public FastSmiOrObjectElementsAccessor<
1024 FastHoleyObjectElementsAccessor,
1025 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1026 public:
1027 explicit FastHoleyObjectElementsAccessor(const char* name)
1028 : FastSmiOrObjectElementsAccessor<
1029 FastHoleyObjectElementsAccessor,
1030 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1031};
1032
1033
1034template<typename FastElementsAccessorSubclass,
1035 typename KindTraits>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001036class FastDoubleElementsAccessor
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001037 : public FastElementsAccessor<FastElementsAccessorSubclass,
1038 KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001039 kDoubleSize> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001040 public:
1041 explicit FastDoubleElementsAccessor(const char* name)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001042 : FastElementsAccessor<FastElementsAccessorSubclass,
1043 KindTraits,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001044 kDoubleSize>(name) {}
1045
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001046 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
1047 uint32_t capacity,
1048 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001049 return obj->SetFastDoubleElementsCapacityAndLength(capacity,
1050 length);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001051 }
1052
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001053 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001054 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1055 uint32_t from_start,
1056 FixedArrayBase* to,
1057 ElementsKind to_kind,
1058 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001059 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001060 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001061 switch (to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001062 case FAST_SMI_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001063 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001064 case FAST_HOLEY_SMI_ELEMENTS:
1065 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001066 return CopyDoubleToObjectElements(
1067 FixedDoubleArray::cast(from), from_start, FixedArray::cast(to),
1068 to_kind, to_start, copy_size);
1069 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001070 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001071 CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start,
1072 FixedDoubleArray::cast(to),
1073 to_start, copy_size);
1074 return from;
1075 default:
1076 UNREACHABLE();
1077 }
1078 return to->GetHeap()->undefined_value();
1079 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001080};
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001081
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001082
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001083class FastPackedDoubleElementsAccessor
1084 : public FastDoubleElementsAccessor<
1085 FastPackedDoubleElementsAccessor,
1086 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
1087 public:
1088 friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
1089 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
1090 explicit FastPackedDoubleElementsAccessor(const char* name)
1091 : FastDoubleElementsAccessor<
1092 FastPackedDoubleElementsAccessor,
1093 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
1094};
1095
1096
1097class FastHoleyDoubleElementsAccessor
1098 : public FastDoubleElementsAccessor<
1099 FastHoleyDoubleElementsAccessor,
1100 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
1101 public:
1102 friend class ElementsAccessorBase<
1103 FastHoleyDoubleElementsAccessor,
1104 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
1105 explicit FastHoleyDoubleElementsAccessor(const char* name)
1106 : FastDoubleElementsAccessor<
1107 FastHoleyDoubleElementsAccessor,
1108 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001109};
1110
1111
1112// Super class for all external element arrays.
1113template<typename ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001114 ElementsKind Kind>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001115class ExternalElementsAccessor
1116 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001117 ElementsKindTraits<Kind> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001118 public:
1119 explicit ExternalElementsAccessor(const char* name)
1120 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001121 ElementsKindTraits<Kind> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001122
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001123 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001124 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
1125
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001126 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001127 ElementsKindTraits<Kind> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001128
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001129 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1130 JSObject* obj,
1131 uint32_t key,
1132 BackingStore* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001133 return
1134 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
1135 ? backing_store->get(key)
1136 : backing_store->GetHeap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001137 }
1138
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001139 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1140 JSObject* obj,
1141 Object* length,
1142 BackingStore* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001143 // External arrays do not support changing their length.
1144 UNREACHABLE();
1145 return obj;
1146 }
1147
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001148 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1149 uint32_t key,
1150 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 // External arrays always ignore deletes.
1152 return obj->GetHeap()->true_value();
1153 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001154
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001155 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001156 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001157 uint32_t key,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001158 BackingStore* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001159 uint32_t capacity =
1160 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
1161 return key < capacity;
1162 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001163};
1164
1165
1166class ExternalByteElementsAccessor
1167 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001168 EXTERNAL_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001169 public:
1170 explicit ExternalByteElementsAccessor(const char* name)
1171 : ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001172 EXTERNAL_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001173};
1174
1175
1176class ExternalUnsignedByteElementsAccessor
1177 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001178 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001179 public:
1180 explicit ExternalUnsignedByteElementsAccessor(const char* name)
1181 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001182 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001183};
1184
1185
1186class ExternalShortElementsAccessor
1187 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001188 EXTERNAL_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001189 public:
1190 explicit ExternalShortElementsAccessor(const char* name)
1191 : ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001192 EXTERNAL_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001193};
1194
1195
1196class ExternalUnsignedShortElementsAccessor
1197 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001198 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001199 public:
1200 explicit ExternalUnsignedShortElementsAccessor(const char* name)
1201 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001202 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001203};
1204
1205
1206class ExternalIntElementsAccessor
1207 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001208 EXTERNAL_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001209 public:
1210 explicit ExternalIntElementsAccessor(const char* name)
1211 : ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001212 EXTERNAL_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001213};
1214
1215
1216class ExternalUnsignedIntElementsAccessor
1217 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001218 EXTERNAL_UNSIGNED_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001219 public:
1220 explicit ExternalUnsignedIntElementsAccessor(const char* name)
1221 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001222 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001223};
1224
1225
1226class ExternalFloatElementsAccessor
1227 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001228 EXTERNAL_FLOAT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001229 public:
1230 explicit ExternalFloatElementsAccessor(const char* name)
1231 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001232 EXTERNAL_FLOAT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001233};
1234
1235
1236class ExternalDoubleElementsAccessor
1237 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001238 EXTERNAL_DOUBLE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001239 public:
1240 explicit ExternalDoubleElementsAccessor(const char* name)
1241 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001242 EXTERNAL_DOUBLE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001243};
1244
1245
1246class PixelElementsAccessor
1247 : public ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001248 EXTERNAL_PIXEL_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001249 public:
1250 explicit PixelElementsAccessor(const char* name)
1251 : ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001252 EXTERNAL_PIXEL_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001253};
1254
1255
1256class DictionaryElementsAccessor
1257 : public ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001258 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001259 public:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001260 explicit DictionaryElementsAccessor(const char* name)
1261 : ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001262 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001263
danno@chromium.orgc612e022011-11-10 11:38:15 +00001264 // Adjusts the length of the dictionary backing store and returns the new
1265 // length according to ES5 section 15.4.5.2 behavior.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001266 MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
1267 SeededNumberDictionary* dict,
1268 JSArray* array,
1269 Object* length_object,
1270 uint32_t length) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001271 if (length == 0) {
1272 // If the length of a slow array is reset to zero, we clear
1273 // the array and flush backing storage. This has the added
1274 // benefit that the array returns to fast mode.
1275 Object* obj;
1276 MaybeObject* maybe_obj = array->ResetElements();
1277 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1278 } else {
1279 uint32_t new_length = length;
1280 uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
1281 if (new_length < old_length) {
1282 // Find last non-deletable element in range of elements to be
1283 // deleted and adjust range accordingly.
1284 Heap* heap = array->GetHeap();
1285 int capacity = dict->Capacity();
1286 for (int i = 0; i < capacity; i++) {
1287 Object* key = dict->KeyAt(i);
1288 if (key->IsNumber()) {
1289 uint32_t number = static_cast<uint32_t>(key->Number());
1290 if (new_length <= number && number < old_length) {
1291 PropertyDetails details = dict->DetailsAt(i);
1292 if (details.IsDontDelete()) new_length = number + 1;
1293 }
1294 }
1295 }
1296 if (new_length != length) {
1297 MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
1298 if (!maybe_object->To(&length_object)) return maybe_object;
1299 }
1300
1301 // Remove elements that should be deleted.
1302 int removed_entries = 0;
1303 Object* the_hole_value = heap->the_hole_value();
1304 for (int i = 0; i < capacity; i++) {
1305 Object* key = dict->KeyAt(i);
1306 if (key->IsNumber()) {
1307 uint32_t number = static_cast<uint32_t>(key->Number());
1308 if (new_length <= number && number < old_length) {
1309 dict->SetEntry(i, the_hole_value, the_hole_value);
1310 removed_entries++;
1311 }
1312 }
1313 }
1314
1315 // Update the number of elements.
1316 dict->ElementsRemoved(removed_entries);
1317 }
1318 }
1319 return length_object;
1320 }
1321
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001322 MUST_USE_RESULT static MaybeObject* DeleteCommon(
1323 JSObject* obj,
1324 uint32_t key,
1325 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001326 Isolate* isolate = obj->GetIsolate();
1327 Heap* heap = isolate->heap();
1328 FixedArray* backing_store = FixedArray::cast(obj->elements());
1329 bool is_arguments =
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001330 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001331 if (is_arguments) {
1332 backing_store = FixedArray::cast(backing_store->get(1));
1333 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001334 SeededNumberDictionary* dictionary =
1335 SeededNumberDictionary::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001336 int entry = dictionary->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001337 if (entry != SeededNumberDictionary::kNotFound) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001338 Object* result = dictionary->DeleteProperty(entry, mode);
1339 if (result == heap->true_value()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001340 MaybeObject* maybe_elements = dictionary->Shrink(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001341 FixedArray* new_elements = NULL;
1342 if (!maybe_elements->To(&new_elements)) {
1343 return maybe_elements;
1344 }
1345 if (is_arguments) {
1346 FixedArray::cast(obj->elements())->set(1, new_elements);
1347 } else {
1348 obj->set_elements(new_elements);
1349 }
1350 }
1351 if (mode == JSObject::STRICT_DELETION &&
1352 result == heap->false_value()) {
1353 // In strict mode, attempting to delete a non-configurable property
1354 // throws an exception.
1355 HandleScope scope(isolate);
1356 Handle<Object> holder(obj);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001357 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001358 Handle<Object> args[2] = { name, holder };
1359 Handle<Object> error =
1360 isolate->factory()->NewTypeError("strict_delete_property",
1361 HandleVector(args, 2));
1362 return isolate->Throw(*error);
1363 }
1364 }
1365 return heap->true_value();
1366 }
1367
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001368 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1369 uint32_t from_start,
1370 FixedArrayBase* to,
1371 ElementsKind to_kind,
1372 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001373 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001374 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001375 switch (to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001376 case FAST_SMI_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001377 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001378 case FAST_HOLEY_SMI_ELEMENTS:
1379 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001380 CopyDictionaryToObjectElements(
1381 SeededNumberDictionary::cast(from), from_start,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001382 FixedArray::cast(to), to_kind, to_start, copy_size);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001383 return from;
1384 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001385 case FAST_HOLEY_DOUBLE_ELEMENTS:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001386 CopyDictionaryToDoubleElements(
1387 SeededNumberDictionary::cast(from), from_start,
1388 FixedDoubleArray::cast(to), to_start, copy_size);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001389 return from;
1390 default:
1391 UNREACHABLE();
1392 }
1393 return to->GetHeap()->undefined_value();
1394 }
1395
1396
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001397 protected:
1398 friend class ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001399 ElementsKindTraits<DICTIONARY_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001400
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001401 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1402 uint32_t key,
1403 JSReceiver::DeleteMode mode) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001404 return DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001405 }
1406
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001407 MUST_USE_RESULT static MaybeObject* GetImpl(
1408 Object* receiver,
1409 JSObject* obj,
1410 uint32_t key,
1411 SeededNumberDictionary* backing_store) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001412 int entry = backing_store->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001413 if (entry != SeededNumberDictionary::kNotFound) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001414 Object* element = backing_store->ValueAt(entry);
1415 PropertyDetails details = backing_store->DetailsAt(entry);
1416 if (details.type() == CALLBACKS) {
1417 return obj->GetElementWithCallback(receiver,
1418 element,
1419 key,
1420 obj);
1421 } else {
1422 return element;
1423 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001424 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001425 return obj->GetHeap()->the_hole_value();
1426 }
1427
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001428 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001429 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001430 uint32_t key,
1431 SeededNumberDictionary* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001432 return backing_store->FindEntry(key) !=
1433 SeededNumberDictionary::kNotFound;
1434 }
1435
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001436 static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
1437 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001438 Object* key = dict->KeyAt(index);
1439 return Smi::cast(key)->value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001440 }
1441};
1442
1443
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001444class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1445 NonStrictArgumentsElementsAccessor,
1446 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001447 public:
1448 explicit NonStrictArgumentsElementsAccessor(const char* name)
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001449 : ElementsAccessorBase<
1450 NonStrictArgumentsElementsAccessor,
1451 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001452 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001453 friend class ElementsAccessorBase<
1454 NonStrictArgumentsElementsAccessor,
1455 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001456
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001457 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1458 JSObject* obj,
1459 uint32_t key,
1460 FixedArray* parameter_map) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001461 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001462 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001463 Context* context = Context::cast(parameter_map->get(0));
1464 int context_index = Smi::cast(probe)->value();
1465 ASSERT(!context->get(context_index)->IsTheHole());
1466 return context->get(context_index);
1467 } else {
1468 // Object is not mapped, defer to the arguments.
1469 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001470 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001471 receiver, obj, key, arguments);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001472 Object* result;
1473 if (!maybe_result->ToObject(&result)) return maybe_result;
1474 // Elements of the arguments object in slow mode might be slow aliases.
1475 if (result->IsAliasedArgumentsEntry()) {
1476 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
1477 Context* context = Context::cast(parameter_map->get(0));
1478 int context_index = entry->aliased_context_slot();
1479 ASSERT(!context->get(context_index)->IsTheHole());
1480 return context->get(context_index);
1481 } else {
1482 return result;
1483 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001484 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001485 }
1486
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001487 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1488 JSObject* obj,
1489 Object* length,
1490 FixedArray* parameter_map) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001491 // TODO(mstarzinger): This was never implemented but will be used once we
1492 // correctly implement [[DefineOwnProperty]] on arrays.
1493 UNIMPLEMENTED();
1494 return obj;
1495 }
1496
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001497 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1498 uint32_t key,
1499 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001500 FixedArray* parameter_map = FixedArray::cast(obj->elements());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001501 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001502 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001503 // TODO(kmillikin): We could check if this was the last aliased
1504 // parameter, and revert to normal elements in that case. That
1505 // would enable GC of the context.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001506 parameter_map->set_the_hole(key + 2);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001507 } else {
1508 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1509 if (arguments->IsDictionary()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001510 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001511 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001512 // It's difficult to access the version of DeleteCommon that is declared
1513 // in the templatized super class, call the concrete implementation in
1514 // the class for the most generalized ElementsKind subclass.
1515 return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001516 }
1517 }
1518 return obj->GetHeap()->true_value();
1519 }
1520
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001521 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1522 uint32_t from_start,
1523 FixedArrayBase* to,
1524 ElementsKind to_kind,
1525 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001526 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001527 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001528 FixedArray* parameter_map = FixedArray::cast(from);
1529 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1530 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
1531 return accessor->CopyElements(NULL, from_start, to, to_kind,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001532 to_start, copy_size, arguments);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001533 }
1534
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001535 static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001536 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1537 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
1538 ForArray(arguments)->GetCapacity(arguments));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001539 }
1540
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001541 static uint32_t GetKeyForIndexImpl(FixedArray* dict,
1542 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001543 return index;
1544 }
1545
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001546 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001547 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001548 uint32_t key,
1549 FixedArray* parameter_map) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001550 Object* probe = GetParameterMapArg(holder, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001551 if (!probe->IsTheHole()) {
1552 return true;
1553 } else {
1554 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1555 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001556 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001557 }
1558 }
1559
1560 private:
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001561 static Object* GetParameterMapArg(JSObject* holder,
1562 FixedArray* parameter_map,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001563 uint32_t key) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001564 uint32_t length = holder->IsJSArray()
1565 ? Smi::cast(JSArray::cast(holder)->length())->value()
1566 : parameter_map->length();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001567 return key < (length - 2 )
1568 ? parameter_map->get(key + 2)
1569 : parameter_map->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001570 }
1571};
1572
1573
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001574ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
1575 switch (array->map()->instance_type()) {
1576 case FIXED_ARRAY_TYPE:
1577 if (array->IsDictionary()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001578 return elements_accessors_[DICTIONARY_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001579 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001580 return elements_accessors_[FAST_HOLEY_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001581 }
1582 case EXTERNAL_BYTE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001583 return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001584 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001585 return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001586 case EXTERNAL_SHORT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001587 return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001588 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001589 return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001590 case EXTERNAL_INT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001591 return elements_accessors_[EXTERNAL_INT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001592 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001593 return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001594 case EXTERNAL_FLOAT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001595 return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001596 case EXTERNAL_DOUBLE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001597 return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001598 case EXTERNAL_PIXEL_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001599 return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001600 default:
1601 UNREACHABLE();
1602 return NULL;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001603 }
1604}
1605
1606
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001607void ElementsAccessor::InitializeOncePerProcess() {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001608 static ElementsAccessor* accessor_array[] = {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001609#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
erikcorry0ad885c2011-11-21 13:51:57 +00001610 ELEMENTS_LIST(ACCESSOR_ARRAY)
1611#undef ACCESSOR_ARRAY
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001612 };
1613
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
1615 kElementsKindCount);
1616
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001617 elements_accessors_ = accessor_array;
1618}
1619
1620
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001621void ElementsAccessor::TearDown() {
1622#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
1623 ELEMENTS_LIST(ACCESSOR_DELETE)
1624#undef ACCESSOR_DELETE
1625 elements_accessors_ = NULL;
1626}
1627
1628
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001629template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001630MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1631 ElementsKindTraits>::
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001632 SetLengthImpl(JSObject* obj,
1633 Object* length,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001634 typename ElementsKindTraits::BackingStore* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001635 JSArray* array = JSArray::cast(obj);
1636
1637 // Fast case: The new length fits into a Smi.
1638 MaybeObject* maybe_smi_length = length->ToSmi();
1639 Object* smi_length = Smi::FromInt(0);
1640 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
1641 const int value = Smi::cast(smi_length)->value();
1642 if (value >= 0) {
1643 Object* new_length;
1644 MaybeObject* result = ElementsAccessorSubclass::
1645 SetLengthWithoutNormalize(backing_store, array, smi_length, value);
1646 if (!result->ToObject(&new_length)) return result;
1647 ASSERT(new_length->IsSmi() || new_length->IsUndefined());
1648 if (new_length->IsSmi()) {
1649 array->set_length(Smi::cast(new_length));
1650 return array;
1651 }
1652 } else {
1653 return ThrowArrayLengthRangeError(array->GetHeap());
1654 }
1655 }
1656
1657 // Slow case: The new length does not fit into a Smi or conversion
1658 // to slow elements is needed for other reasons.
1659 if (length->IsNumber()) {
1660 uint32_t value;
1661 if (length->ToArrayIndex(&value)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001662 SeededNumberDictionary* dictionary;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001663 MaybeObject* maybe_object = array->NormalizeElements();
1664 if (!maybe_object->To(&dictionary)) return maybe_object;
1665 Object* new_length;
1666 MaybeObject* result = DictionaryElementsAccessor::
1667 SetLengthWithoutNormalize(dictionary, array, length, value);
1668 if (!result->ToObject(&new_length)) return result;
1669 ASSERT(new_length->IsNumber());
1670 array->set_length(new_length);
1671 return array;
1672 } else {
1673 return ThrowArrayLengthRangeError(array->GetHeap());
1674 }
1675 }
1676
1677 // Fall-back case: The new length is not a number so make the array
1678 // size one and set only element to length.
1679 FixedArray* new_backing_store;
1680 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
1681 if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
1682 new_backing_store->set(0, length);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001683 { MaybeObject* result = array->SetContent(new_backing_store);
1684 if (result->IsFailure()) return result;
1685 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001686 return array;
1687}
1688
1689
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001690} } // namespace v8::internal