blob: 1d043a153e148543b86befcc680605de2fd0da47 [file] [log] [blame]
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdoch69a99ed2011-11-30 16:03:39 +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"
32#include "utils.h"
33
Ben Murdoch592a9fc2012-03-05 11:04:45 +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)
42// - FastObjectElementsAccessor
43// - FastDoubleElementsAccessor
44// - ExternalElementsAccessor (abstract)
45// - ExternalByteElementsAccessor
46// - ExternalUnsignedByteElementsAccessor
47// - ExternalShortElementsAccessor
48// - ExternalUnsignedShortElementsAccessor
49// - ExternalIntElementsAccessor
50// - ExternalUnsignedIntElementsAccessor
51// - ExternalFloatElementsAccessor
52// - ExternalDoubleElementsAccessor
53// - PixelElementsAccessor
54// - DictionaryElementsAccessor
55// - NonStrictArgumentsElementsAccessor
56
57
Ben Murdoch69a99ed2011-11-30 16:03:39 +000058namespace v8 {
59namespace internal {
60
61
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010062// First argument in list is the accessor class, the second argument is the
63// accessor ElementsKind, and the third is the backing store class. Use the
64// fast element handler for smi-only arrays. The implementation is currently
65// identical. Note that the order must match that of the ElementsKind enum for
66// the |accessor_array[]| below to work.
67#define ELEMENTS_LIST(V) \
68 V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS, FixedArray) \
69 V(FastObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
70 V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
71 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \
72 SeededNumberDictionary) \
73 V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \
74 FixedArray) \
75 V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS, \
76 ExternalByteArray) \
77 V(ExternalUnsignedByteElementsAccessor, \
78 EXTERNAL_UNSIGNED_BYTE_ELEMENTS, ExternalUnsignedByteArray) \
79 V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS, \
80 ExternalShortArray) \
81 V(ExternalUnsignedShortElementsAccessor, \
82 EXTERNAL_UNSIGNED_SHORT_ELEMENTS, ExternalUnsignedShortArray) \
83 V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS, \
84 ExternalIntArray) \
85 V(ExternalUnsignedIntElementsAccessor, \
86 EXTERNAL_UNSIGNED_INT_ELEMENTS, ExternalUnsignedIntArray) \
87 V(ExternalFloatElementsAccessor, \
88 EXTERNAL_FLOAT_ELEMENTS, ExternalFloatArray) \
89 V(ExternalDoubleElementsAccessor, \
90 EXTERNAL_DOUBLE_ELEMENTS, ExternalDoubleArray) \
91 V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS, ExternalPixelArray)
92
93
94template<ElementsKind Kind> class ElementsKindTraits {
95 public:
96 typedef FixedArrayBase BackingStore;
97};
98
99#define ELEMENTS_TRAITS(Class, KindParam, Store) \
100template<> class ElementsKindTraits<KindParam> { \
101 public: \
102 static const ElementsKind Kind = KindParam; \
103 typedef Store BackingStore; \
104};
105ELEMENTS_LIST(ELEMENTS_TRAITS)
106#undef ELEMENTS_TRAITS
107
108
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000109ElementsAccessor** ElementsAccessor::elements_accessors_;
110
111
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000112static bool HasKey(FixedArray* array, Object* key) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000113 int len0 = array->length();
114 for (int i = 0; i < len0; i++) {
115 Object* element = array->get(i);
116 if (element->IsSmi() && element == key) return true;
117 if (element->IsString() &&
118 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
119 return true;
120 }
121 }
122 return false;
123}
124
125
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000126static Failure* ThrowArrayLengthRangeError(Heap* heap) {
127 HandleScope scope(heap->isolate());
128 return heap->isolate()->Throw(
129 *heap->isolate()->factory()->NewRangeError("invalid_array_length",
130 HandleVector<Object>(NULL, 0)));
131}
132
133
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100134void CopyObjectToObjectElements(FixedArray* from,
135 ElementsKind from_kind,
136 uint32_t from_start,
137 FixedArray* to,
138 ElementsKind to_kind,
139 uint32_t to_start,
140 int raw_copy_size) {
141 ASSERT(to->map() != HEAP->fixed_cow_array_map());
142 ASSERT(from_kind == FAST_ELEMENTS || from_kind == FAST_SMI_ONLY_ELEMENTS);
143 ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
144 int copy_size = raw_copy_size;
145 if (raw_copy_size < 0) {
146 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
147 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
148 copy_size = Min(from->length() - from_start,
149 to->length() - to_start);
150#ifdef DEBUG
151 // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
152 // marked with the hole.
153 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
154 for (int i = to_start + copy_size; i < to->length(); ++i) {
155 ASSERT(to->get(i)->IsTheHole());
156 }
157 }
158#endif
159 }
160 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
161 (copy_size + static_cast<int>(from_start)) <= from->length());
162 if (copy_size == 0) return;
163 Address to_address = to->address() + FixedArray::kHeaderSize;
164 Address from_address = from->address() + FixedArray::kHeaderSize;
165 CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
166 reinterpret_cast<Object**>(from_address) + from_start,
167 copy_size);
168 if (from_kind == FAST_ELEMENTS && to_kind == FAST_ELEMENTS) {
169 Heap* heap = from->GetHeap();
170 if (!heap->InNewSpace(to)) {
171 heap->RecordWrites(to->address(),
172 to->OffsetOfElementAt(to_start),
173 copy_size);
174 }
175 heap->incremental_marking()->RecordWrites(to);
176 }
177}
178
179
180static void CopyDictionaryToObjectElements(SeededNumberDictionary* from,
181 uint32_t from_start,
182 FixedArray* to,
183 ElementsKind to_kind,
184 uint32_t to_start,
185 int raw_copy_size) {
186 int copy_size = raw_copy_size;
187 Heap* heap = from->GetHeap();
188 if (raw_copy_size < 0) {
189 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
190 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
191 copy_size = from->max_number_key() + 1 - from_start;
192#ifdef DEBUG
193 // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
194 // marked with the hole.
195 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
196 for (int i = to_start + copy_size; i < to->length(); ++i) {
197 ASSERT(to->get(i)->IsTheHole());
198 }
199 }
200#endif
201 }
202 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length());
203 ASSERT(to != from);
204 ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
205 if (copy_size == 0) return;
206 for (int i = 0; i < copy_size; i++) {
207 int entry = from->FindEntry(i + from_start);
208 if (entry != SeededNumberDictionary::kNotFound) {
209 Object* value = from->ValueAt(entry);
210 ASSERT(!value->IsTheHole());
211 to->set(i + to_start, value, SKIP_WRITE_BARRIER);
212 } else {
213 to->set_the_hole(i + to_start);
214 }
215 }
216 if (to_kind == FAST_ELEMENTS) {
217 if (!heap->InNewSpace(to)) {
218 heap->RecordWrites(to->address(),
219 to->OffsetOfElementAt(to_start),
220 copy_size);
221 }
222 heap->incremental_marking()->RecordWrites(to);
223 }
224}
225
226
227MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
228 FixedDoubleArray* from,
229 uint32_t from_start,
230 FixedArray* to,
231 ElementsKind to_kind,
232 uint32_t to_start,
233 int raw_copy_size) {
234 ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
235 int copy_size = raw_copy_size;
236 if (raw_copy_size < 0) {
237 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
238 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
239 copy_size = Min(from->length() - from_start,
240 to->length() - to_start);
241#ifdef DEBUG
242 // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
243 // marked with the hole.
244 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
245 for (int i = to_start + copy_size; i < to->length(); ++i) {
246 ASSERT(to->get(i)->IsTheHole());
247 }
248 }
249#endif
250 }
251 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
252 (copy_size + static_cast<int>(from_start)) <= from->length());
253 if (copy_size == 0) return from;
254 for (int i = 0; i < copy_size; ++i) {
255 if (to_kind == FAST_SMI_ONLY_ELEMENTS) {
256 UNIMPLEMENTED();
257 return Failure::Exception();
258 } else {
259 MaybeObject* maybe_value = from->get(i + from_start);
260 Object* value;
261 ASSERT(to_kind == FAST_ELEMENTS);
262 // Because FAST_DOUBLE_ELEMENTS -> FAST_ELEMENT allocate HeapObjects
263 // iteratively, the allocate must succeed within a single GC cycle,
264 // otherwise the retry after the GC will also fail. In order to ensure
265 // that no GC is triggered, allocate HeapNumbers from old space if they
266 // can't be taken from new space.
267 if (!maybe_value->ToObject(&value)) {
268 ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
269 Heap* heap = from->GetHeap();
270 MaybeObject* maybe_value_object =
271 heap->AllocateHeapNumber(from->get_scalar(i + from_start),
272 TENURED);
273 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
274 }
275 to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
276 }
277 }
278 return to;
279}
280
281
282static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
283 uint32_t from_start,
284 FixedDoubleArray* to,
285 uint32_t to_start,
286 int raw_copy_size) {
287 int copy_size = raw_copy_size;
288 if (raw_copy_size < 0) {
289 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
290 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
291 copy_size = Min(from->length() - from_start,
292 to->length() - to_start);
293 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
294 for (int i = to_start + copy_size; i < to->length(); ++i) {
295 to->set_the_hole(i);
296 }
297 }
298 }
299 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
300 (copy_size + static_cast<int>(from_start)) <= from->length());
301 if (copy_size == 0) return;
302 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
303 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
304 to_address += kDoubleSize * to_start;
305 from_address += kDoubleSize * from_start;
306 int words_per_double = (kDoubleSize / kPointerSize);
307 CopyWords(reinterpret_cast<Object**>(to_address),
308 reinterpret_cast<Object**>(from_address),
309 words_per_double * copy_size);
310}
311
312
313static void CopyObjectToDoubleElements(FixedArray* from,
314 uint32_t from_start,
315 FixedDoubleArray* to,
316 uint32_t to_start,
317 int raw_copy_size) {
318 int copy_size = raw_copy_size;
319 if (raw_copy_size < 0) {
320 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
321 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
322 copy_size = from->length() - from_start;
323 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
324 for (int i = to_start + copy_size; i < to->length(); ++i) {
325 to->set_the_hole(i);
326 }
327 }
328 }
329 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
330 (copy_size + static_cast<int>(from_start)) <= from->length());
331 if (copy_size == 0) return;
332 for (int i = 0; i < copy_size; i++) {
333 Object* hole_or_object = from->get(i + from_start);
334 if (hole_or_object->IsTheHole()) {
335 to->set_the_hole(i + to_start);
336 } else {
337 to->set(i + to_start, hole_or_object->Number());
338 }
339 }
340}
341
342
343static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
344 uint32_t from_start,
345 FixedDoubleArray* to,
346 uint32_t to_start,
347 int raw_copy_size) {
348 int copy_size = raw_copy_size;
349 if (copy_size < 0) {
350 ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
351 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
352 copy_size = from->max_number_key() + 1 - from_start;
353 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
354 for (int i = to_start + copy_size; i < to->length(); ++i) {
355 to->set_the_hole(i);
356 }
357 }
358 }
359 ASSERT(copy_size + static_cast<int>(to_start) <= to->length());
360 if (copy_size == 0) return;
361 for (int i = 0; i < copy_size; i++) {
362 int entry = from->FindEntry(i + from_start);
363 if (entry != SeededNumberDictionary::kNotFound) {
364 to->set(i + to_start, from->ValueAt(entry)->Number());
365 } else {
366 to->set_the_hole(i + to_start);
367 }
368 }
369}
370
371
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000372// Base class for element handler implementations. Contains the
373// the common logic for objects with different ElementsKinds.
374// Subclasses must specialize method for which the element
375// implementation differs from the base class implementation.
376//
377// This class is intended to be used in the following way:
378//
379// class SomeElementsAccessor :
380// public ElementsAccessorBase<SomeElementsAccessor,
381// BackingStoreClass> {
382// ...
383// }
384//
385// This is an example of the Curiously Recurring Template Pattern (see
386// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
387// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
388// specialization of SomeElementsAccessor methods).
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100389template <typename ElementsAccessorSubclass,
390 typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000391class ElementsAccessorBase : public ElementsAccessor {
392 protected:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100393 explicit ElementsAccessorBase(const char* name)
394 : ElementsAccessor(name) { }
395
396 typedef ElementsTraitsParam ElementsTraits;
397 typedef typename ElementsTraitsParam::BackingStore BackingStore;
398
399 virtual ElementsKind kind() const { return ElementsTraits::Kind; }
400
401 static bool HasElementImpl(Object* receiver,
402 JSObject* holder,
403 uint32_t key,
404 BackingStore* backing_store) {
405 MaybeObject* element =
406 ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store);
407 return !element->IsTheHole();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000408 }
409
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100410 virtual bool HasElement(Object* receiver,
411 JSObject* holder,
412 uint32_t key,
413 FixedArrayBase* backing_store) {
414 if (backing_store == NULL) {
415 backing_store = holder->elements();
416 }
417 return ElementsAccessorSubclass::HasElementImpl(
418 receiver, holder, key, BackingStore::cast(backing_store));
419 }
420
421 virtual MaybeObject* Get(Object* receiver,
422 JSObject* holder,
423 uint32_t key,
424 FixedArrayBase* backing_store) {
425 if (backing_store == NULL) {
426 backing_store = holder->elements();
427 }
428 return ElementsAccessorSubclass::GetImpl(
429 receiver, holder, key, BackingStore::cast(backing_store));
430 }
431
432 static MaybeObject* GetImpl(Object* receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000433 JSObject* obj,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100434 uint32_t key,
435 BackingStore* backing_store) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000436 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
437 ? backing_store->get(key)
438 : backing_store->GetHeap()->the_hole_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000439 }
440
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100441 virtual MaybeObject* SetLength(JSArray* array,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000442 Object* length) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000443 return ElementsAccessorSubclass::SetLengthImpl(
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100444 array, length, BackingStore::cast(array->elements()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000445 }
446
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100447 static MaybeObject* SetLengthImpl(JSObject* obj,
448 Object* length,
449 BackingStore* backing_store);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000450
Ben Murdochc7cc0282012-03-05 14:35:55 +0000451 virtual MaybeObject* SetCapacityAndLength(JSArray* array,
452 int capacity,
453 int length) {
454 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
455 array,
456 capacity,
457 length);
458 }
459
460 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
461 int capacity,
462 int length) {
463 UNIMPLEMENTED();
464 return obj;
465 }
466
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000467 virtual MaybeObject* Delete(JSObject* obj,
468 uint32_t key,
469 JSReceiver::DeleteMode mode) = 0;
470
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100471 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
472 uint32_t from_start,
473 FixedArrayBase* to,
474 ElementsKind to_kind,
475 uint32_t to_start,
476 int copy_size) {
477 UNREACHABLE();
478 return NULL;
479 }
480
481 virtual MaybeObject* CopyElements(JSObject* from_holder,
482 uint32_t from_start,
483 FixedArrayBase* to,
484 ElementsKind to_kind,
485 uint32_t to_start,
486 int copy_size,
487 FixedArrayBase* from) {
488 if (from == NULL) {
489 from = from_holder->elements();
490 }
491 if (from->length() == 0) {
492 return from;
493 }
494 return ElementsAccessorSubclass::CopyElementsImpl(
495 from, from_start, to, to_kind, to_start, copy_size);
496 }
497
498 virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000499 JSObject* holder,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100500 FixedArray* to,
501 FixedArrayBase* from) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000502 int len0 = to->length();
503#ifdef DEBUG
504 if (FLAG_enable_slow_asserts) {
505 for (int i = 0; i < len0; i++) {
506 ASSERT(!to->get(i)->IsTheHole());
507 }
508 }
509#endif
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100510 if (from == NULL) {
511 from = holder->elements();
512 }
513 BackingStore* backing_store = BackingStore::cast(from);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000514 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000515
516 // Optimize if 'other' is empty.
517 // We cannot optimize if 'this' is empty, as other may have holes.
518 if (len1 == 0) return to;
519
520 // Compute how many elements are not in other.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100521 uint32_t extra = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000522 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100523 uint32_t key =
524 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
525 if (ElementsAccessorSubclass::HasElementImpl(
526 receiver, holder, key, backing_store)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000527 MaybeObject* maybe_value =
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100528 ElementsAccessorSubclass::GetImpl(receiver, holder,
529 key, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000530 Object* value;
531 if (!maybe_value->ToObject(&value)) return maybe_value;
532 ASSERT(!value->IsTheHole());
533 if (!HasKey(to, value)) {
534 extra++;
535 }
536 }
537 }
538
539 if (extra == 0) return to;
540
541 // Allocate the result
542 FixedArray* result;
543 MaybeObject* maybe_obj =
544 backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
545 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
546
547 // Fill in the content
548 {
549 AssertNoAllocation no_gc;
550 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
551 for (int i = 0; i < len0; i++) {
552 Object* e = to->get(i);
553 ASSERT(e->IsString() || e->IsNumber());
554 result->set(i, e, mode);
555 }
556 }
557 // Fill in the extra values.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100558 uint32_t index = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000559 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100560 uint32_t key =
561 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
562 if (ElementsAccessorSubclass::HasElementImpl(
563 receiver, holder, key, backing_store)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000564 MaybeObject* maybe_value =
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100565 ElementsAccessorSubclass::GetImpl(receiver, holder,
566 key, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000567 Object* value;
568 if (!maybe_value->ToObject(&value)) return maybe_value;
569 if (!value->IsTheHole() && !HasKey(to, value)) {
570 result->set(len0 + index, value);
571 index++;
572 }
573 }
574 }
575 ASSERT(extra == index);
576 return result;
577 }
578
579 protected:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100580 static uint32_t GetCapacityImpl(BackingStore* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000581 return backing_store->length();
582 }
583
584 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000585 return ElementsAccessorSubclass::GetCapacityImpl(
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100586 BackingStore::cast(backing_store));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000587 }
588
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100589 static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000590 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000591 return index;
592 }
593
594 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100595 uint32_t index) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000596 return ElementsAccessorSubclass::GetKeyForIndexImpl(
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100597 BackingStore::cast(backing_store), index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000598 }
599
600 private:
601 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
602};
603
604
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000605// Super class for all fast element arrays.
606template<typename FastElementsAccessorSubclass,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100607 typename KindTraits,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000608 int ElementSize>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000609class FastElementsAccessor
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100610 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
611 public:
612 explicit FastElementsAccessor(const char* name)
613 : ElementsAccessorBase<FastElementsAccessorSubclass,
614 KindTraits>(name) {}
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000615 protected:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100616 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
617
618 typedef typename KindTraits::BackingStore BackingStore;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000619
620 // Adjusts the length of the fast backing store or returns the new length or
621 // undefined in case conversion to a slow backing store should be performed.
622 static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
623 JSArray* array,
624 Object* length_object,
625 uint32_t length) {
626 uint32_t old_capacity = backing_store->length();
627
628 // Check whether the backing store should be shrunk.
629 if (length <= old_capacity) {
630 if (array->HasFastTypeElements()) {
631 MaybeObject* maybe_obj = array->EnsureWritableFastElements();
632 if (!maybe_obj->To(&backing_store)) return maybe_obj;
633 }
634 if (2 * length <= old_capacity) {
635 // If more than half the elements won't be used, trim the array.
636 if (length == 0) {
637 array->initialize_elements();
638 } else {
639 backing_store->set_length(length);
640 Address filler_start = backing_store->address() +
641 BackingStore::OffsetOfElementAt(length);
642 int filler_size = (old_capacity - length) * ElementSize;
643 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
644 }
645 } else {
646 // Otherwise, fill the unused tail with holes.
647 int old_length = FastD2I(array->length()->Number());
648 for (int i = length; i < old_length; i++) {
649 backing_store->set_the_hole(i);
650 }
651 }
652 return length_object;
653 }
654
655 // Check whether the backing store should be expanded.
656 uint32_t min = JSObject::NewElementsCapacity(old_capacity);
657 uint32_t new_capacity = length > min ? length : min;
658 if (!array->ShouldConvertToSlowElements(new_capacity)) {
659 MaybeObject* result = FastElementsAccessorSubclass::
660 SetFastElementsCapacityAndLength(array, new_capacity, length);
661 if (result->IsFailure()) return result;
662 return length_object;
663 }
664
665 // Request conversion to slow elements.
666 return array->GetHeap()->undefined_value();
667 }
668};
669
670
671class FastObjectElementsAccessor
672 : public FastElementsAccessor<FastObjectElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100673 ElementsKindTraits<FAST_ELEMENTS>,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000674 kPointerSize> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000675 public:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100676 explicit FastObjectElementsAccessor(const char* name)
677 : FastElementsAccessor<FastObjectElementsAccessor,
678 ElementsKindTraits<FAST_ELEMENTS>,
679 kPointerSize>(name) {}
680
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000681 static MaybeObject* DeleteCommon(JSObject* obj,
682 uint32_t key) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000683 ASSERT(obj->HasFastElements() ||
684 obj->HasFastSmiOnlyElements() ||
685 obj->HasFastArgumentsElements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000686 Heap* heap = obj->GetHeap();
687 FixedArray* backing_store = FixedArray::cast(obj->elements());
688 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
689 backing_store = FixedArray::cast(backing_store->get(1));
690 } else {
691 Object* writable;
692 MaybeObject* maybe = obj->EnsureWritableFastElements();
693 if (!maybe->ToObject(&writable)) return maybe;
694 backing_store = FixedArray::cast(writable);
695 }
696 uint32_t length = static_cast<uint32_t>(
697 obj->IsJSArray()
698 ? Smi::cast(JSArray::cast(obj)->length())->value()
699 : backing_store->length());
700 if (key < length) {
701 backing_store->set_the_hole(key);
702 // If an old space backing store is larger than a certain size and
703 // has too few used values, normalize it.
704 // To avoid doing the check on every delete we require at least
705 // one adjacent hole to the value being deleted.
706 Object* hole = heap->the_hole_value();
707 const int kMinLengthForSparsenessCheck = 64;
708 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
709 !heap->InNewSpace(backing_store) &&
710 ((key > 0 && backing_store->get(key - 1) == hole) ||
711 (key + 1 < length && backing_store->get(key + 1) == hole))) {
712 int num_used = 0;
713 for (int i = 0; i < backing_store->length(); ++i) {
714 if (backing_store->get(i) != hole) ++num_used;
715 // Bail out early if more than 1/4 is used.
716 if (4 * num_used > backing_store->length()) break;
717 }
718 if (4 * num_used <= backing_store->length()) {
719 MaybeObject* result = obj->NormalizeElements();
720 if (result->IsFailure()) return result;
721 }
722 }
723 }
724 return heap->true_value();
725 }
726
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100727 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
728 uint32_t from_start,
729 FixedArrayBase* to,
730 ElementsKind to_kind,
731 uint32_t to_start,
732 int copy_size) {
733 switch (to_kind) {
734 case FAST_SMI_ONLY_ELEMENTS:
735 case FAST_ELEMENTS: {
736 CopyObjectToObjectElements(
737 FixedArray::cast(from), ElementsTraits::Kind, from_start,
738 FixedArray::cast(to), to_kind, to_start, copy_size);
739 return from;
740 }
741 case FAST_DOUBLE_ELEMENTS:
742 CopyObjectToDoubleElements(
743 FixedArray::cast(from), from_start,
744 FixedDoubleArray::cast(to), to_start, copy_size);
745 return from;
746 default:
747 UNREACHABLE();
748 }
749 return to->GetHeap()->undefined_value();
750 }
751
752
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000753 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
754 uint32_t capacity,
755 uint32_t length) {
756 JSObject::SetFastElementsCapacityMode set_capacity_mode =
757 obj->HasFastSmiOnlyElements()
758 ? JSObject::kAllowSmiOnlyElements
759 : JSObject::kDontAllowSmiOnlyElements;
760 return obj->SetFastElementsCapacityAndLength(capacity,
761 length,
762 set_capacity_mode);
763 }
764
Ben Murdochc7cc0282012-03-05 14:35:55 +0000765 protected:
766 friend class FastElementsAccessor<FastObjectElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100767 ElementsKindTraits<FAST_ELEMENTS>,
Ben Murdochc7cc0282012-03-05 14:35:55 +0000768 kPointerSize>;
769
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000770 virtual MaybeObject* Delete(JSObject* obj,
771 uint32_t key,
772 JSReceiver::DeleteMode mode) {
773 return DeleteCommon(obj, key);
774 }
775};
776
777
778class FastDoubleElementsAccessor
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000779 : public FastElementsAccessor<FastDoubleElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100780 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000781 kDoubleSize> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100782 public:
783 explicit FastDoubleElementsAccessor(const char* name)
784 : FastElementsAccessor<FastDoubleElementsAccessor,
785 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
786 kDoubleSize>(name) {}
787
Ben Murdochc7cc0282012-03-05 14:35:55 +0000788 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
789 uint32_t capacity,
790 uint32_t length) {
791 return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
792 }
793
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000794 protected:
795 friend class ElementsAccessorBase<FastDoubleElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100796 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000797 friend class FastElementsAccessor<FastDoubleElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100798 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000799 kDoubleSize>;
800
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100801 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
802 uint32_t from_start,
803 FixedArrayBase* to,
804 ElementsKind to_kind,
805 uint32_t to_start,
806 int copy_size) {
807 switch (to_kind) {
808 case FAST_SMI_ONLY_ELEMENTS:
809 case FAST_ELEMENTS:
810 return CopyDoubleToObjectElements(
811 FixedDoubleArray::cast(from), from_start, FixedArray::cast(to),
812 to_kind, to_start, copy_size);
813 case FAST_DOUBLE_ELEMENTS:
814 CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start,
815 FixedDoubleArray::cast(to),
816 to_start, copy_size);
817 return from;
818 default:
819 UNREACHABLE();
820 }
821 return to->GetHeap()->undefined_value();
822 }
823
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000824 virtual MaybeObject* Delete(JSObject* obj,
825 uint32_t key,
826 JSReceiver::DeleteMode mode) {
827 int length = obj->IsJSArray()
828 ? Smi::cast(JSArray::cast(obj)->length())->value()
829 : FixedDoubleArray::cast(obj->elements())->length();
830 if (key < static_cast<uint32_t>(length)) {
831 FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
832 }
833 return obj->GetHeap()->true_value();
834 }
835
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100836 static bool HasElementImpl(Object* receiver,
837 JSObject* holder,
838 uint32_t key,
839 FixedDoubleArray* backing_store) {
840 return key < static_cast<uint32_t>(backing_store->length()) &&
841 !backing_store->is_the_hole(key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000842 }
843};
844
845
846// Super class for all external element arrays.
847template<typename ExternalElementsAccessorSubclass,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100848 ElementsKind Kind>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000849class ExternalElementsAccessor
850 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100851 ElementsKindTraits<Kind> > {
852 public:
853 explicit ExternalElementsAccessor(const char* name)
854 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
855 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000856
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100857 protected:
858 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
859
860 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
861 ElementsKindTraits<Kind> >;
862
863 static MaybeObject* GetImpl(Object* receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000864 JSObject* obj,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100865 uint32_t key,
866 BackingStore* backing_store) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000867 return
868 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
869 ? backing_store->get(key)
870 : backing_store->GetHeap()->undefined_value();
871 }
872
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100873 static MaybeObject* SetLengthImpl(JSObject* obj,
874 Object* length,
875 BackingStore* backing_store) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000876 // External arrays do not support changing their length.
877 UNREACHABLE();
878 return obj;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000879 }
880
881 virtual MaybeObject* Delete(JSObject* obj,
882 uint32_t key,
883 JSReceiver::DeleteMode mode) {
884 // External arrays always ignore deletes.
885 return obj->GetHeap()->true_value();
886 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100887
888 static bool HasElementImpl(Object* receiver,
889 JSObject* holder,
890 uint32_t key,
891 BackingStore* backing_store) {
892 uint32_t capacity =
893 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
894 return key < capacity;
895 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000896};
897
898
899class ExternalByteElementsAccessor
900 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100901 EXTERNAL_BYTE_ELEMENTS> {
902 public:
903 explicit ExternalByteElementsAccessor(const char* name)
904 : ExternalElementsAccessor<ExternalByteElementsAccessor,
905 EXTERNAL_BYTE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000906};
907
908
909class ExternalUnsignedByteElementsAccessor
910 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100911 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
912 public:
913 explicit ExternalUnsignedByteElementsAccessor(const char* name)
914 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
915 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000916};
917
918
919class ExternalShortElementsAccessor
920 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100921 EXTERNAL_SHORT_ELEMENTS> {
922 public:
923 explicit ExternalShortElementsAccessor(const char* name)
924 : ExternalElementsAccessor<ExternalShortElementsAccessor,
925 EXTERNAL_SHORT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000926};
927
928
929class ExternalUnsignedShortElementsAccessor
930 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100931 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
932 public:
933 explicit ExternalUnsignedShortElementsAccessor(const char* name)
934 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
935 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000936};
937
938
939class ExternalIntElementsAccessor
940 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100941 EXTERNAL_INT_ELEMENTS> {
942 public:
943 explicit ExternalIntElementsAccessor(const char* name)
944 : ExternalElementsAccessor<ExternalIntElementsAccessor,
945 EXTERNAL_INT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000946};
947
948
949class ExternalUnsignedIntElementsAccessor
950 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100951 EXTERNAL_UNSIGNED_INT_ELEMENTS> {
952 public:
953 explicit ExternalUnsignedIntElementsAccessor(const char* name)
954 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
955 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000956};
957
958
959class ExternalFloatElementsAccessor
960 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100961 EXTERNAL_FLOAT_ELEMENTS> {
962 public:
963 explicit ExternalFloatElementsAccessor(const char* name)
964 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
965 EXTERNAL_FLOAT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000966};
967
968
969class ExternalDoubleElementsAccessor
970 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100971 EXTERNAL_DOUBLE_ELEMENTS> {
972 public:
973 explicit ExternalDoubleElementsAccessor(const char* name)
974 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
975 EXTERNAL_DOUBLE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000976};
977
978
979class PixelElementsAccessor
980 : public ExternalElementsAccessor<PixelElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100981 EXTERNAL_PIXEL_ELEMENTS> {
982 public:
983 explicit PixelElementsAccessor(const char* name)
984 : ExternalElementsAccessor<PixelElementsAccessor,
985 EXTERNAL_PIXEL_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000986};
987
988
989class DictionaryElementsAccessor
990 : public ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100991 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000992 public:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100993 explicit DictionaryElementsAccessor(const char* name)
994 : ElementsAccessorBase<DictionaryElementsAccessor,
995 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
996
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000997 // Adjusts the length of the dictionary backing store and returns the new
998 // length according to ES5 section 15.4.5.2 behavior.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000999 static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001000 JSArray* array,
1001 Object* length_object,
1002 uint32_t length) {
1003 if (length == 0) {
1004 // If the length of a slow array is reset to zero, we clear
1005 // the array and flush backing storage. This has the added
1006 // benefit that the array returns to fast mode.
1007 Object* obj;
1008 MaybeObject* maybe_obj = array->ResetElements();
1009 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1010 } else {
1011 uint32_t new_length = length;
1012 uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
1013 if (new_length < old_length) {
1014 // Find last non-deletable element in range of elements to be
1015 // deleted and adjust range accordingly.
1016 Heap* heap = array->GetHeap();
1017 int capacity = dict->Capacity();
1018 for (int i = 0; i < capacity; i++) {
1019 Object* key = dict->KeyAt(i);
1020 if (key->IsNumber()) {
1021 uint32_t number = static_cast<uint32_t>(key->Number());
1022 if (new_length <= number && number < old_length) {
1023 PropertyDetails details = dict->DetailsAt(i);
1024 if (details.IsDontDelete()) new_length = number + 1;
1025 }
1026 }
1027 }
1028 if (new_length != length) {
1029 MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
1030 if (!maybe_object->To(&length_object)) return maybe_object;
1031 }
1032
1033 // Remove elements that should be deleted.
1034 int removed_entries = 0;
1035 Object* the_hole_value = heap->the_hole_value();
1036 for (int i = 0; i < capacity; i++) {
1037 Object* key = dict->KeyAt(i);
1038 if (key->IsNumber()) {
1039 uint32_t number = static_cast<uint32_t>(key->Number());
1040 if (new_length <= number && number < old_length) {
1041 dict->SetEntry(i, the_hole_value, the_hole_value);
1042 removed_entries++;
1043 }
1044 }
1045 }
1046
1047 // Update the number of elements.
1048 dict->ElementsRemoved(removed_entries);
1049 }
1050 }
1051 return length_object;
1052 }
1053
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001054 static MaybeObject* DeleteCommon(JSObject* obj,
1055 uint32_t key,
1056 JSReceiver::DeleteMode mode) {
1057 Isolate* isolate = obj->GetIsolate();
1058 Heap* heap = isolate->heap();
1059 FixedArray* backing_store = FixedArray::cast(obj->elements());
1060 bool is_arguments =
Ben Murdoch589d6972011-11-30 16:04:58 +00001061 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001062 if (is_arguments) {
1063 backing_store = FixedArray::cast(backing_store->get(1));
1064 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001065 SeededNumberDictionary* dictionary =
1066 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001067 int entry = dictionary->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001068 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001069 Object* result = dictionary->DeleteProperty(entry, mode);
1070 if (result == heap->true_value()) {
1071 MaybeObject* maybe_elements = dictionary->Shrink(key);
1072 FixedArray* new_elements = NULL;
1073 if (!maybe_elements->To(&new_elements)) {
1074 return maybe_elements;
1075 }
1076 if (is_arguments) {
1077 FixedArray::cast(obj->elements())->set(1, new_elements);
1078 } else {
1079 obj->set_elements(new_elements);
1080 }
1081 }
1082 if (mode == JSObject::STRICT_DELETION &&
1083 result == heap->false_value()) {
1084 // In strict mode, attempting to delete a non-configurable property
1085 // throws an exception.
1086 HandleScope scope(isolate);
1087 Handle<Object> holder(obj);
1088 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
1089 Handle<Object> args[2] = { name, holder };
1090 Handle<Object> error =
1091 isolate->factory()->NewTypeError("strict_delete_property",
1092 HandleVector(args, 2));
1093 return isolate->Throw(*error);
1094 }
1095 }
1096 return heap->true_value();
1097 }
1098
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001099 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1100 uint32_t from_start,
1101 FixedArrayBase* to,
1102 ElementsKind to_kind,
1103 uint32_t to_start,
1104 int copy_size) {
1105 switch (to_kind) {
1106 case FAST_SMI_ONLY_ELEMENTS:
1107 case FAST_ELEMENTS:
1108 CopyDictionaryToObjectElements(
1109 SeededNumberDictionary::cast(from), from_start,
1110 FixedArray::cast(to), to_kind, to_start, copy_size);
1111 return from;
1112 case FAST_DOUBLE_ELEMENTS:
1113 CopyDictionaryToDoubleElements(
1114 SeededNumberDictionary::cast(from), from_start,
1115 FixedDoubleArray::cast(to), to_start, copy_size);
1116 return from;
1117 default:
1118 UNREACHABLE();
1119 }
1120 return to->GetHeap()->undefined_value();
1121 }
1122
1123
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001124 protected:
1125 friend class ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001126 ElementsKindTraits<DICTIONARY_ELEMENTS> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001127
1128 virtual MaybeObject* Delete(JSObject* obj,
1129 uint32_t key,
1130 JSReceiver::DeleteMode mode) {
1131 return DeleteCommon(obj, key, mode);
1132 }
1133
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001134 static MaybeObject* GetImpl(Object* receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001135 JSObject* obj,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001136 uint32_t key,
1137 SeededNumberDictionary* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001138 int entry = backing_store->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001139 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001140 Object* element = backing_store->ValueAt(entry);
1141 PropertyDetails details = backing_store->DetailsAt(entry);
1142 if (details.type() == CALLBACKS) {
1143 return obj->GetElementWithCallback(receiver,
1144 element,
1145 key,
1146 obj);
1147 } else {
1148 return element;
1149 }
1150 }
1151 return obj->GetHeap()->the_hole_value();
1152 }
1153
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001154 static bool HasElementImpl(Object* receiver,
1155 JSObject* holder,
1156 uint32_t key,
1157 SeededNumberDictionary* backing_store) {
1158 return backing_store->FindEntry(key) !=
1159 SeededNumberDictionary::kNotFound;
1160 }
1161
Ben Murdochc7cc0282012-03-05 14:35:55 +00001162 static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001163 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001164 Object* key = dict->KeyAt(index);
1165 return Smi::cast(key)->value();
1166 }
1167};
1168
1169
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001170class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1171 NonStrictArgumentsElementsAccessor,
1172 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
1173 public:
1174 explicit NonStrictArgumentsElementsAccessor(const char* name)
1175 : ElementsAccessorBase<
1176 NonStrictArgumentsElementsAccessor,
1177 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001178 protected:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001179 friend class ElementsAccessorBase<
1180 NonStrictArgumentsElementsAccessor,
1181 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001182
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001183 static MaybeObject* GetImpl(Object* receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001184 JSObject* obj,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001185 uint32_t key,
1186 FixedArray* parameter_map) {
1187 Object* probe = GetParameterMapArg(obj, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001188 if (!probe->IsTheHole()) {
1189 Context* context = Context::cast(parameter_map->get(0));
1190 int context_index = Smi::cast(probe)->value();
1191 ASSERT(!context->get(context_index)->IsTheHole());
1192 return context->get(context_index);
1193 } else {
1194 // Object is not mapped, defer to the arguments.
1195 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001196 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
1197 receiver, obj, key, arguments);
1198 Object* result;
1199 if (!maybe_result->ToObject(&result)) return maybe_result;
1200 // Elements of the arguments object in slow mode might be slow aliases.
1201 if (result->IsAliasedArgumentsEntry()) {
1202 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
1203 Context* context = Context::cast(parameter_map->get(0));
1204 int context_index = entry->aliased_context_slot();
1205 ASSERT(!context->get(context_index)->IsTheHole());
1206 return context->get(context_index);
1207 } else {
1208 return result;
1209 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001210 }
1211 }
1212
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001213 static MaybeObject* SetLengthImpl(JSObject* obj,
1214 Object* length,
1215 FixedArray* parameter_map) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001216 // TODO(mstarzinger): This was never implemented but will be used once we
1217 // correctly implement [[DefineOwnProperty]] on arrays.
1218 UNIMPLEMENTED();
1219 return obj;
1220 }
1221
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001222 virtual MaybeObject* Delete(JSObject* obj,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001223 uint32_t key,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001224 JSReceiver::DeleteMode mode) {
1225 FixedArray* parameter_map = FixedArray::cast(obj->elements());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001226 Object* probe = GetParameterMapArg(obj, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001227 if (!probe->IsTheHole()) {
1228 // TODO(kmillikin): We could check if this was the last aliased
1229 // parameter, and revert to normal elements in that case. That
1230 // would enable GC of the context.
1231 parameter_map->set_the_hole(key + 2);
1232 } else {
1233 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1234 if (arguments->IsDictionary()) {
1235 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
1236 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001237 return FastObjectElementsAccessor::DeleteCommon(obj, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001238 }
1239 }
1240 return obj->GetHeap()->true_value();
1241 }
1242
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001243 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1244 uint32_t from_start,
1245 FixedArrayBase* to,
1246 ElementsKind to_kind,
1247 uint32_t to_start,
1248 int copy_size) {
1249 FixedArray* parameter_map = FixedArray::cast(from);
1250 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1251 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
1252 return accessor->CopyElements(NULL, from_start, to, to_kind,
1253 to_start, copy_size, arguments);
1254 }
1255
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001256 static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001257 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1258 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
1259 ForArray(arguments)->GetCapacity(arguments));
1260 }
1261
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001262 static uint32_t GetKeyForIndexImpl(FixedArray* dict,
1263 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001264 return index;
1265 }
1266
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001267 static bool HasElementImpl(Object* receiver,
1268 JSObject* holder,
1269 uint32_t key,
1270 FixedArray* parameter_map) {
1271 Object* probe = GetParameterMapArg(holder, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001272 if (!probe->IsTheHole()) {
1273 return true;
1274 } else {
1275 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1276 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001277 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001278 }
1279 }
1280
1281 private:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001282 static Object* GetParameterMapArg(JSObject* holder,
1283 FixedArray* parameter_map,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001284 uint32_t key) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001285 uint32_t length = holder->IsJSArray()
1286 ? Smi::cast(JSArray::cast(holder)->length())->value()
1287 : parameter_map->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001288 return key < (length - 2 )
1289 ? parameter_map->get(key + 2)
1290 : parameter_map->GetHeap()->the_hole_value();
1291 }
1292};
1293
1294
1295ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
1296 switch (array->map()->instance_type()) {
1297 case FIXED_ARRAY_TYPE:
1298 if (array->IsDictionary()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001299 return elements_accessors_[DICTIONARY_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001300 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +00001301 return elements_accessors_[FAST_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001302 }
1303 case EXTERNAL_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001304 return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001305 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001306 return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001307 case EXTERNAL_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001308 return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001309 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001310 return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001311 case EXTERNAL_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001312 return elements_accessors_[EXTERNAL_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001313 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001314 return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001315 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001316 return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001317 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001318 return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001319 case EXTERNAL_PIXEL_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001320 return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001321 default:
1322 UNREACHABLE();
1323 return NULL;
1324 }
1325}
1326
1327
1328void ElementsAccessor::InitializeOncePerProcess() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001329 static struct ConcreteElementsAccessors {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001330#define ACCESSOR_STRUCT(Class, Kind, Store) Class* Kind##_handler;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001331 ELEMENTS_LIST(ACCESSOR_STRUCT)
1332#undef ACCESSOR_STRUCT
1333 } element_accessors = {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001334#define ACCESSOR_INIT(Class, Kind, Store) new Class(#Kind),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001335 ELEMENTS_LIST(ACCESSOR_INIT)
1336#undef ACCESSOR_INIT
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001337 };
1338
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001339 static ElementsAccessor* accessor_array[] = {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001340#define ACCESSOR_ARRAY(Class, Kind, Store) element_accessors.Kind##_handler,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001341 ELEMENTS_LIST(ACCESSOR_ARRAY)
1342#undef ACCESSOR_ARRAY
1343 };
1344
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001345 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
1346 kElementsKindCount);
1347
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001348 elements_accessors_ = accessor_array;
1349}
1350
1351
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001352template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
1353MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1354 ElementsKindTraits>::
1355 SetLengthImpl(JSObject* obj,
1356 Object* length,
1357 typename ElementsKindTraits::BackingStore* backing_store) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001358 JSArray* array = JSArray::cast(obj);
1359
1360 // Fast case: The new length fits into a Smi.
1361 MaybeObject* maybe_smi_length = length->ToSmi();
1362 Object* smi_length = Smi::FromInt(0);
1363 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
1364 const int value = Smi::cast(smi_length)->value();
1365 if (value >= 0) {
1366 Object* new_length;
1367 MaybeObject* result = ElementsAccessorSubclass::
1368 SetLengthWithoutNormalize(backing_store, array, smi_length, value);
1369 if (!result->ToObject(&new_length)) return result;
1370 ASSERT(new_length->IsSmi() || new_length->IsUndefined());
1371 if (new_length->IsSmi()) {
1372 array->set_length(Smi::cast(new_length));
1373 return array;
1374 }
1375 } else {
1376 return ThrowArrayLengthRangeError(array->GetHeap());
1377 }
1378 }
1379
1380 // Slow case: The new length does not fit into a Smi or conversion
1381 // to slow elements is needed for other reasons.
1382 if (length->IsNumber()) {
1383 uint32_t value;
1384 if (length->ToArrayIndex(&value)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001385 SeededNumberDictionary* dictionary;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001386 MaybeObject* maybe_object = array->NormalizeElements();
1387 if (!maybe_object->To(&dictionary)) return maybe_object;
1388 Object* new_length;
1389 MaybeObject* result = DictionaryElementsAccessor::
1390 SetLengthWithoutNormalize(dictionary, array, length, value);
1391 if (!result->ToObject(&new_length)) return result;
1392 ASSERT(new_length->IsNumber());
1393 array->set_length(new_length);
1394 return array;
1395 } else {
1396 return ThrowArrayLengthRangeError(array->GetHeap());
1397 }
1398 }
1399
1400 // Fall-back case: The new length is not a number so make the array
1401 // size one and set only element to length.
1402 FixedArray* new_backing_store;
1403 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
1404 if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
1405 new_backing_store->set(0, length);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001406 { MaybeObject* result = array->SetContent(new_backing_store);
1407 if (result->IsFailure()) return result;
1408 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001409 return array;
1410}
1411
1412
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001413} } // namespace v8::internal