blob: aa51ea9b783aa0e0f66a0751e56b4d260bce8692 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +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 Murdoch3ef787d2012-04-12 10:51:47 +010034
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 Murdoch3ef787d2012-04-12 10:51:47 +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 Murdoch3ef787d2012-04-12 10:51:47 +0100112static 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 Murdoch3ef787d2012-04-12 10:51:47 +0100126static 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
134void 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(to != from);
203 ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
204 if (copy_size == 0) return;
205 uint32_t to_length = to->length();
206 if (to_start + copy_size > to_length) {
207 copy_size = to_length - to_start;
208 }
209 for (int i = 0; i < copy_size; i++) {
210 int entry = from->FindEntry(i + from_start);
211 if (entry != SeededNumberDictionary::kNotFound) {
212 Object* value = from->ValueAt(entry);
213 ASSERT(!value->IsTheHole());
214 to->set(i + to_start, value, SKIP_WRITE_BARRIER);
215 } else {
216 to->set_the_hole(i + to_start);
217 }
218 }
219 if (to_kind == FAST_ELEMENTS) {
220 if (!heap->InNewSpace(to)) {
221 heap->RecordWrites(to->address(),
222 to->OffsetOfElementAt(to_start),
223 copy_size);
224 }
225 heap->incremental_marking()->RecordWrites(to);
226 }
227}
228
229
230MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
231 FixedDoubleArray* from,
232 uint32_t from_start,
233 FixedArray* to,
234 ElementsKind to_kind,
235 uint32_t to_start,
236 int raw_copy_size) {
237 ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
238 int copy_size = raw_copy_size;
239 if (raw_copy_size < 0) {
240 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
241 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
242 copy_size = Min(from->length() - from_start,
243 to->length() - to_start);
244#ifdef DEBUG
245 // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
246 // marked with the hole.
247 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
248 for (int i = to_start + copy_size; i < to->length(); ++i) {
249 ASSERT(to->get(i)->IsTheHole());
250 }
251 }
252#endif
253 }
254 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
255 (copy_size + static_cast<int>(from_start)) <= from->length());
256 if (copy_size == 0) return from;
257 for (int i = 0; i < copy_size; ++i) {
258 if (to_kind == FAST_SMI_ONLY_ELEMENTS) {
259 UNIMPLEMENTED();
260 return Failure::Exception();
261 } else {
262 MaybeObject* maybe_value = from->get(i + from_start);
263 Object* value;
264 ASSERT(to_kind == FAST_ELEMENTS);
265 // Because FAST_DOUBLE_ELEMENTS -> FAST_ELEMENT allocate HeapObjects
266 // iteratively, the allocate must succeed within a single GC cycle,
267 // otherwise the retry after the GC will also fail. In order to ensure
268 // that no GC is triggered, allocate HeapNumbers from old space if they
269 // can't be taken from new space.
270 if (!maybe_value->ToObject(&value)) {
271 ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
272 Heap* heap = from->GetHeap();
273 MaybeObject* maybe_value_object =
274 heap->AllocateHeapNumber(from->get_scalar(i + from_start),
275 TENURED);
276 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
277 }
278 to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
279 }
280 }
281 return to;
282}
283
284
285static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
286 uint32_t from_start,
287 FixedDoubleArray* to,
288 uint32_t to_start,
289 int raw_copy_size) {
290 int copy_size = raw_copy_size;
291 if (raw_copy_size < 0) {
292 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
293 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
294 copy_size = Min(from->length() - from_start,
295 to->length() - to_start);
296 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
297 for (int i = to_start + copy_size; i < to->length(); ++i) {
298 to->set_the_hole(i);
299 }
300 }
301 }
302 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
303 (copy_size + static_cast<int>(from_start)) <= from->length());
304 if (copy_size == 0) return;
305 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
306 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
307 to_address += kDoubleSize * to_start;
308 from_address += kDoubleSize * from_start;
309 int words_per_double = (kDoubleSize / kPointerSize);
310 CopyWords(reinterpret_cast<Object**>(to_address),
311 reinterpret_cast<Object**>(from_address),
312 words_per_double * copy_size);
313}
314
315
316static void CopyObjectToDoubleElements(FixedArray* from,
317 uint32_t from_start,
318 FixedDoubleArray* to,
319 uint32_t to_start,
320 int raw_copy_size) {
321 int copy_size = raw_copy_size;
322 if (raw_copy_size < 0) {
323 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
324 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
325 copy_size = from->length() - from_start;
326 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
327 for (int i = to_start + copy_size; i < to->length(); ++i) {
328 to->set_the_hole(i);
329 }
330 }
331 }
332 ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
333 (copy_size + static_cast<int>(from_start)) <= from->length());
334 if (copy_size == 0) return;
335 for (int i = 0; i < copy_size; i++) {
336 Object* hole_or_object = from->get(i + from_start);
337 if (hole_or_object->IsTheHole()) {
338 to->set_the_hole(i + to_start);
339 } else {
340 to->set(i + to_start, hole_or_object->Number());
341 }
342 }
343}
344
345
346static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
347 uint32_t from_start,
348 FixedDoubleArray* to,
349 uint32_t to_start,
350 int raw_copy_size) {
351 int copy_size = raw_copy_size;
352 if (copy_size < 0) {
353 ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
354 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
355 copy_size = from->max_number_key() + 1 - from_start;
356 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
357 for (int i = to_start + copy_size; i < to->length(); ++i) {
358 to->set_the_hole(i);
359 }
360 }
361 }
362 if (copy_size == 0) return;
363 uint32_t to_length = to->length();
364 if (to_start + copy_size > to_length) {
365 copy_size = to_length - to_start;
366 }
367 for (int i = 0; i < copy_size; i++) {
368 int entry = from->FindEntry(i + from_start);
369 if (entry != SeededNumberDictionary::kNotFound) {
370 to->set(i + to_start, from->ValueAt(entry)->Number());
371 } else {
372 to->set_the_hole(i + to_start);
373 }
374 }
375}
376
377
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000378// Base class for element handler implementations. Contains the
379// the common logic for objects with different ElementsKinds.
380// Subclasses must specialize method for which the element
381// implementation differs from the base class implementation.
382//
383// This class is intended to be used in the following way:
384//
385// class SomeElementsAccessor :
386// public ElementsAccessorBase<SomeElementsAccessor,
387// BackingStoreClass> {
388// ...
389// }
390//
391// This is an example of the Curiously Recurring Template Pattern (see
392// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
393// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
394// specialization of SomeElementsAccessor methods).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100395template <typename ElementsAccessorSubclass,
396 typename ElementsTraitsParam>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000397class ElementsAccessorBase : public ElementsAccessor {
398 protected:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399 explicit ElementsAccessorBase(const char* name)
400 : ElementsAccessor(name) { }
401
402 typedef ElementsTraitsParam ElementsTraits;
403 typedef typename ElementsTraitsParam::BackingStore BackingStore;
404
405 virtual ElementsKind kind() const { return ElementsTraits::Kind; }
406
407 static bool HasElementImpl(Object* receiver,
408 JSObject* holder,
409 uint32_t key,
410 BackingStore* backing_store) {
411 MaybeObject* element =
412 ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store);
413 return !element->IsTheHole();
Ben Murdoch85b71792012-04-11 18:30:58 +0100414 }
415
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100416 virtual bool HasElement(Object* receiver,
417 JSObject* holder,
Ben Murdoch85b71792012-04-11 18:30:58 +0100418 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100419 FixedArrayBase* backing_store) {
420 if (backing_store == NULL) {
421 backing_store = holder->elements();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100422 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423 return ElementsAccessorSubclass::HasElementImpl(
424 receiver, holder, key, BackingStore::cast(backing_store));
425 }
426
427 virtual MaybeObject* Get(Object* receiver,
428 JSObject* holder,
429 uint32_t key,
430 FixedArrayBase* backing_store) {
431 if (backing_store == NULL) {
432 backing_store = holder->elements();
433 }
434 return ElementsAccessorSubclass::GetImpl(
435 receiver, holder, key, BackingStore::cast(backing_store));
436 }
437
438 static MaybeObject* GetImpl(Object* receiver,
439 JSObject* obj,
440 uint32_t key,
441 BackingStore* backing_store) {
442 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
443 ? backing_store->get(key)
444 : backing_store->GetHeap()->the_hole_value();
445 }
446
447 virtual MaybeObject* SetLength(JSArray* array,
448 Object* length) {
449 return ElementsAccessorSubclass::SetLengthImpl(
450 array, length, BackingStore::cast(array->elements()));
451 }
452
453 static MaybeObject* SetLengthImpl(JSObject* obj,
454 Object* length,
455 BackingStore* backing_store);
456
457 virtual MaybeObject* SetCapacityAndLength(JSArray* array,
458 int capacity,
459 int length) {
460 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
461 array,
462 capacity,
463 length);
464 }
465
466 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
467 int capacity,
468 int length) {
469 UNIMPLEMENTED();
470 return obj;
Ben Murdochc7cc0282012-03-05 14:35:55 +0000471 }
472
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000473 virtual MaybeObject* Delete(JSObject* obj,
474 uint32_t key,
475 JSReceiver::DeleteMode mode) = 0;
476
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100477 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
478 uint32_t from_start,
479 FixedArrayBase* to,
480 ElementsKind to_kind,
481 uint32_t to_start,
482 int copy_size) {
483 UNREACHABLE();
484 return NULL;
485 }
486
487 virtual MaybeObject* CopyElements(JSObject* from_holder,
488 uint32_t from_start,
489 FixedArrayBase* to,
490 ElementsKind to_kind,
491 uint32_t to_start,
492 int copy_size,
493 FixedArrayBase* from) {
494 if (from == NULL) {
495 from = from_holder->elements();
496 }
497 if (from->length() == 0) {
498 return from;
499 }
500 return ElementsAccessorSubclass::CopyElementsImpl(
501 from, from_start, to, to_kind, to_start, copy_size);
502 }
503
504 virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
Ben Murdoch85b71792012-04-11 18:30:58 +0100505 JSObject* holder,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100506 FixedArray* to,
507 FixedArrayBase* from) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000508 int len0 = to->length();
509#ifdef DEBUG
510 if (FLAG_enable_slow_asserts) {
511 for (int i = 0; i < len0; i++) {
512 ASSERT(!to->get(i)->IsTheHole());
513 }
514 }
515#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100516 if (from == NULL) {
517 from = holder->elements();
518 }
519 BackingStore* backing_store = BackingStore::cast(from);
520 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000521
522 // Optimize if 'other' is empty.
523 // We cannot optimize if 'this' is empty, as other may have holes.
524 if (len1 == 0) return to;
525
526 // Compute how many elements are not in other.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100527 uint32_t extra = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000528 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100529 uint32_t key =
530 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
531 if (ElementsAccessorSubclass::HasElementImpl(
532 receiver, holder, key, backing_store)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000533 MaybeObject* maybe_value =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100534 ElementsAccessorSubclass::GetImpl(receiver, holder,
535 key, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000536 Object* value;
537 if (!maybe_value->ToObject(&value)) return maybe_value;
538 ASSERT(!value->IsTheHole());
539 if (!HasKey(to, value)) {
540 extra++;
541 }
542 }
543 }
544
545 if (extra == 0) return to;
546
547 // Allocate the result
548 FixedArray* result;
549 MaybeObject* maybe_obj =
550 backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
551 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
552
553 // Fill in the content
554 {
555 AssertNoAllocation no_gc;
556 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
557 for (int i = 0; i < len0; i++) {
558 Object* e = to->get(i);
559 ASSERT(e->IsString() || e->IsNumber());
560 result->set(i, e, mode);
561 }
562 }
563 // Fill in the extra values.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100564 uint32_t index = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000565 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100566 uint32_t key =
567 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
568 if (ElementsAccessorSubclass::HasElementImpl(
569 receiver, holder, key, backing_store)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000570 MaybeObject* maybe_value =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100571 ElementsAccessorSubclass::GetImpl(receiver, holder,
572 key, backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000573 Object* value;
574 if (!maybe_value->ToObject(&value)) return maybe_value;
575 if (!value->IsTheHole() && !HasKey(to, value)) {
576 result->set(len0 + index, value);
577 index++;
578 }
579 }
580 }
581 ASSERT(extra == index);
582 return result;
583 }
584
585 protected:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100586 static uint32_t GetCapacityImpl(BackingStore* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000587 return backing_store->length();
588 }
589
590 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100591 return ElementsAccessorSubclass::GetCapacityImpl(
592 BackingStore::cast(backing_store));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000593 }
594
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100595 static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
596 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000597 return index;
598 }
599
600 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100601 uint32_t index) {
602 return ElementsAccessorSubclass::GetKeyForIndexImpl(
603 BackingStore::cast(backing_store), index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000604 }
605
606 private:
607 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
608};
609
610
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100611// Super class for all fast element arrays.
612template<typename FastElementsAccessorSubclass,
613 typename KindTraits,
614 int ElementSize>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000615class FastElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100616 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100617 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100618 explicit FastElementsAccessor(const char* name)
619 : ElementsAccessorBase<FastElementsAccessorSubclass,
620 KindTraits>(name) {}
621 protected:
622 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
623
624 typedef typename KindTraits::BackingStore BackingStore;
625
626 // Adjusts the length of the fast backing store or returns the new length or
627 // undefined in case conversion to a slow backing store should be performed.
628 static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
629 JSArray* array,
630 Object* length_object,
631 uint32_t length) {
632 uint32_t old_capacity = backing_store->length();
633
634 // Check whether the backing store should be shrunk.
635 if (length <= old_capacity) {
636 if (array->HasFastTypeElements()) {
637 MaybeObject* maybe_obj = array->EnsureWritableFastElements();
638 if (!maybe_obj->To(&backing_store)) return maybe_obj;
639 }
640 if (2 * length <= old_capacity) {
641 // If more than half the elements won't be used, trim the array.
642 if (length == 0) {
643 array->initialize_elements();
644 } else {
645 backing_store->set_length(length);
646 Address filler_start = backing_store->address() +
647 BackingStore::OffsetOfElementAt(length);
648 int filler_size = (old_capacity - length) * ElementSize;
649 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
650 }
651 } else {
652 // Otherwise, fill the unused tail with holes.
653 int old_length = FastD2I(array->length()->Number());
654 for (int i = length; i < old_length; i++) {
655 backing_store->set_the_hole(i);
656 }
657 }
658 return length_object;
659 }
660
661 // Check whether the backing store should be expanded.
662 uint32_t min = JSObject::NewElementsCapacity(old_capacity);
663 uint32_t new_capacity = length > min ? length : min;
664 if (!array->ShouldConvertToSlowElements(new_capacity)) {
665 MaybeObject* result = FastElementsAccessorSubclass::
666 SetFastElementsCapacityAndLength(array, new_capacity, length);
667 if (result->IsFailure()) return result;
668 return length_object;
669 }
670
671 // Request conversion to slow elements.
672 return array->GetHeap()->undefined_value();
673 }
674};
675
676
677class FastObjectElementsAccessor
678 : public FastElementsAccessor<FastObjectElementsAccessor,
679 ElementsKindTraits<FAST_ELEMENTS>,
680 kPointerSize> {
681 public:
682 explicit FastObjectElementsAccessor(const char* name)
683 : FastElementsAccessor<FastObjectElementsAccessor,
684 ElementsKindTraits<FAST_ELEMENTS>,
685 kPointerSize>(name) {}
686
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000687 static MaybeObject* DeleteCommon(JSObject* obj,
688 uint32_t key) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 ASSERT(obj->HasFastElements() ||
690 obj->HasFastSmiOnlyElements() ||
691 obj->HasFastArgumentsElements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000692 Heap* heap = obj->GetHeap();
693 FixedArray* backing_store = FixedArray::cast(obj->elements());
694 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
695 backing_store = FixedArray::cast(backing_store->get(1));
696 } else {
697 Object* writable;
698 MaybeObject* maybe = obj->EnsureWritableFastElements();
699 if (!maybe->ToObject(&writable)) return maybe;
700 backing_store = FixedArray::cast(writable);
701 }
702 uint32_t length = static_cast<uint32_t>(
703 obj->IsJSArray()
704 ? Smi::cast(JSArray::cast(obj)->length())->value()
705 : backing_store->length());
706 if (key < length) {
707 backing_store->set_the_hole(key);
708 // If an old space backing store is larger than a certain size and
709 // has too few used values, normalize it.
710 // To avoid doing the check on every delete we require at least
711 // one adjacent hole to the value being deleted.
712 Object* hole = heap->the_hole_value();
713 const int kMinLengthForSparsenessCheck = 64;
714 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
715 !heap->InNewSpace(backing_store) &&
716 ((key > 0 && backing_store->get(key - 1) == hole) ||
717 (key + 1 < length && backing_store->get(key + 1) == hole))) {
718 int num_used = 0;
719 for (int i = 0; i < backing_store->length(); ++i) {
720 if (backing_store->get(i) != hole) ++num_used;
721 // Bail out early if more than 1/4 is used.
722 if (4 * num_used > backing_store->length()) break;
723 }
724 if (4 * num_used <= backing_store->length()) {
725 MaybeObject* result = obj->NormalizeElements();
726 if (result->IsFailure()) return result;
727 }
728 }
729 }
730 return heap->true_value();
731 }
732
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100733 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
734 uint32_t from_start,
735 FixedArrayBase* to,
736 ElementsKind to_kind,
737 uint32_t to_start,
738 int copy_size) {
739 switch (to_kind) {
740 case FAST_SMI_ONLY_ELEMENTS:
741 case FAST_ELEMENTS: {
742 CopyObjectToObjectElements(
743 FixedArray::cast(from), ElementsTraits::Kind, from_start,
744 FixedArray::cast(to), to_kind, to_start, copy_size);
745 return from;
746 }
747 case FAST_DOUBLE_ELEMENTS:
748 CopyObjectToDoubleElements(
749 FixedArray::cast(from), from_start,
750 FixedDoubleArray::cast(to), to_start, copy_size);
751 return from;
752 default:
753 UNREACHABLE();
754 }
755 return to->GetHeap()->undefined_value();
756 }
757
758
759 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
760 uint32_t capacity,
761 uint32_t length) {
762 JSObject::SetFastElementsCapacityMode set_capacity_mode =
763 obj->HasFastSmiOnlyElements()
764 ? JSObject::kAllowSmiOnlyElements
765 : JSObject::kDontAllowSmiOnlyElements;
766 return obj->SetFastElementsCapacityAndLength(capacity,
767 length,
768 set_capacity_mode);
769 }
770
Ben Murdochc7cc0282012-03-05 14:35:55 +0000771 protected:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100772 friend class FastElementsAccessor<FastObjectElementsAccessor,
773 ElementsKindTraits<FAST_ELEMENTS>,
774 kPointerSize>;
775
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000776 virtual MaybeObject* Delete(JSObject* obj,
777 uint32_t key,
778 JSReceiver::DeleteMode mode) {
779 return DeleteCommon(obj, key);
780 }
781};
782
783
784class FastDoubleElementsAccessor
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100785 : public FastElementsAccessor<FastDoubleElementsAccessor,
786 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
787 kDoubleSize> {
788 public:
789 explicit FastDoubleElementsAccessor(const char* name)
790 : FastElementsAccessor<FastDoubleElementsAccessor,
791 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
792 kDoubleSize>(name) {}
793
794 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
795 uint32_t capacity,
796 uint32_t length) {
797 return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
798 }
799
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000800 protected:
801 friend class ElementsAccessorBase<FastDoubleElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100802 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
803 friend class FastElementsAccessor<FastDoubleElementsAccessor,
804 ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
805 kDoubleSize>;
806
807 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
808 uint32_t from_start,
809 FixedArrayBase* to,
810 ElementsKind to_kind,
811 uint32_t to_start,
812 int copy_size) {
813 switch (to_kind) {
814 case FAST_SMI_ONLY_ELEMENTS:
815 case FAST_ELEMENTS:
816 return CopyDoubleToObjectElements(
817 FixedDoubleArray::cast(from), from_start, FixedArray::cast(to),
818 to_kind, to_start, copy_size);
819 case FAST_DOUBLE_ELEMENTS:
820 CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start,
821 FixedDoubleArray::cast(to),
822 to_start, copy_size);
823 return from;
824 default:
825 UNREACHABLE();
826 }
827 return to->GetHeap()->undefined_value();
828 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100829
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000830 virtual MaybeObject* Delete(JSObject* obj,
831 uint32_t key,
832 JSReceiver::DeleteMode mode) {
833 int length = obj->IsJSArray()
834 ? Smi::cast(JSArray::cast(obj)->length())->value()
835 : FixedDoubleArray::cast(obj->elements())->length();
836 if (key < static_cast<uint32_t>(length)) {
837 FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
838 }
839 return obj->GetHeap()->true_value();
840 }
841
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100842 static bool HasElementImpl(Object* receiver,
843 JSObject* holder,
844 uint32_t key,
845 FixedDoubleArray* backing_store) {
846 return key < static_cast<uint32_t>(backing_store->length()) &&
847 !backing_store->is_the_hole(key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000848 }
849};
850
851
852// Super class for all external element arrays.
853template<typename ExternalElementsAccessorSubclass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100854 ElementsKind Kind>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000855class ExternalElementsAccessor
856 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100857 ElementsKindTraits<Kind> > {
858 public:
859 explicit ExternalElementsAccessor(const char* name)
860 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
861 ElementsKindTraits<Kind> >(name) {}
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100862
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100863 protected:
864 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
865
866 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
867 ElementsKindTraits<Kind> >;
868
869 static MaybeObject* GetImpl(Object* receiver,
870 JSObject* obj,
871 uint32_t key,
872 BackingStore* backing_store) {
873 return
874 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
875 ? backing_store->get(key)
876 : backing_store->GetHeap()->undefined_value();
877 }
878
879 static MaybeObject* SetLengthImpl(JSObject* obj,
880 Object* length,
881 BackingStore* backing_store) {
882 // External arrays do not support changing their length.
883 UNREACHABLE();
884 return obj;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000885 }
886
887 virtual MaybeObject* Delete(JSObject* obj,
888 uint32_t key,
889 JSReceiver::DeleteMode mode) {
890 // External arrays always ignore deletes.
891 return obj->GetHeap()->true_value();
892 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100893
894 static bool HasElementImpl(Object* receiver,
895 JSObject* holder,
896 uint32_t key,
897 BackingStore* backing_store) {
898 uint32_t capacity =
899 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
900 return key < capacity;
901 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000902};
903
904
905class ExternalByteElementsAccessor
906 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100907 EXTERNAL_BYTE_ELEMENTS> {
908 public:
909 explicit ExternalByteElementsAccessor(const char* name)
910 : ExternalElementsAccessor<ExternalByteElementsAccessor,
911 EXTERNAL_BYTE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000912};
913
914
915class ExternalUnsignedByteElementsAccessor
916 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100917 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
918 public:
919 explicit ExternalUnsignedByteElementsAccessor(const char* name)
920 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
921 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000922};
923
924
925class ExternalShortElementsAccessor
926 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100927 EXTERNAL_SHORT_ELEMENTS> {
928 public:
929 explicit ExternalShortElementsAccessor(const char* name)
930 : ExternalElementsAccessor<ExternalShortElementsAccessor,
931 EXTERNAL_SHORT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000932};
933
934
935class ExternalUnsignedShortElementsAccessor
936 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100937 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
938 public:
939 explicit ExternalUnsignedShortElementsAccessor(const char* name)
940 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
941 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000942};
943
944
945class ExternalIntElementsAccessor
946 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100947 EXTERNAL_INT_ELEMENTS> {
948 public:
949 explicit ExternalIntElementsAccessor(const char* name)
950 : ExternalElementsAccessor<ExternalIntElementsAccessor,
951 EXTERNAL_INT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000952};
953
954
955class ExternalUnsignedIntElementsAccessor
956 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100957 EXTERNAL_UNSIGNED_INT_ELEMENTS> {
958 public:
959 explicit ExternalUnsignedIntElementsAccessor(const char* name)
960 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
961 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000962};
963
964
965class ExternalFloatElementsAccessor
966 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100967 EXTERNAL_FLOAT_ELEMENTS> {
968 public:
969 explicit ExternalFloatElementsAccessor(const char* name)
970 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
971 EXTERNAL_FLOAT_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000972};
973
974
975class ExternalDoubleElementsAccessor
976 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100977 EXTERNAL_DOUBLE_ELEMENTS> {
978 public:
979 explicit ExternalDoubleElementsAccessor(const char* name)
980 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
981 EXTERNAL_DOUBLE_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000982};
983
984
985class PixelElementsAccessor
986 : public ExternalElementsAccessor<PixelElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100987 EXTERNAL_PIXEL_ELEMENTS> {
988 public:
989 explicit PixelElementsAccessor(const char* name)
990 : ExternalElementsAccessor<PixelElementsAccessor,
991 EXTERNAL_PIXEL_ELEMENTS>(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000992};
993
994
995class DictionaryElementsAccessor
996 : public ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100997 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000998 public:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100999 explicit DictionaryElementsAccessor(const char* name)
1000 : ElementsAccessorBase<DictionaryElementsAccessor,
1001 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1002
1003 // Adjusts the length of the dictionary backing store and returns the new
1004 // length according to ES5 section 15.4.5.2 behavior.
1005 static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict,
1006 JSArray* array,
1007 Object* length_object,
1008 uint32_t length) {
1009 if (length == 0) {
1010 // If the length of a slow array is reset to zero, we clear
1011 // the array and flush backing storage. This has the added
1012 // benefit that the array returns to fast mode.
1013 Object* obj;
1014 MaybeObject* maybe_obj = array->ResetElements();
1015 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1016 } else {
1017 uint32_t new_length = length;
1018 uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
1019 if (new_length < old_length) {
1020 // Find last non-deletable element in range of elements to be
1021 // deleted and adjust range accordingly.
1022 Heap* heap = array->GetHeap();
1023 int capacity = dict->Capacity();
1024 for (int i = 0; i < capacity; i++) {
1025 Object* key = dict->KeyAt(i);
1026 if (key->IsNumber()) {
1027 uint32_t number = static_cast<uint32_t>(key->Number());
1028 if (new_length <= number && number < old_length) {
1029 PropertyDetails details = dict->DetailsAt(i);
1030 if (details.IsDontDelete()) new_length = number + 1;
1031 }
1032 }
1033 }
1034 if (new_length != length) {
1035 MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
1036 if (!maybe_object->To(&length_object)) return maybe_object;
1037 }
1038
1039 // Remove elements that should be deleted.
1040 int removed_entries = 0;
1041 Object* the_hole_value = heap->the_hole_value();
1042 for (int i = 0; i < capacity; i++) {
1043 Object* key = dict->KeyAt(i);
1044 if (key->IsNumber()) {
1045 uint32_t number = static_cast<uint32_t>(key->Number());
1046 if (new_length <= number && number < old_length) {
1047 dict->SetEntry(i, the_hole_value, the_hole_value);
1048 removed_entries++;
1049 }
1050 }
1051 }
1052
1053 // Update the number of elements.
1054 dict->ElementsRemoved(removed_entries);
1055 }
1056 }
1057 return length_object;
1058 }
1059
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001060 static MaybeObject* DeleteCommon(JSObject* obj,
1061 uint32_t key,
1062 JSReceiver::DeleteMode mode) {
1063 Isolate* isolate = obj->GetIsolate();
1064 Heap* heap = isolate->heap();
1065 FixedArray* backing_store = FixedArray::cast(obj->elements());
1066 bool is_arguments =
Ben Murdoch589d6972011-11-30 16:04:58 +00001067 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001068 if (is_arguments) {
1069 backing_store = FixedArray::cast(backing_store->get(1));
1070 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001071 SeededNumberDictionary* dictionary =
1072 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001073 int entry = dictionary->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001074 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001075 Object* result = dictionary->DeleteProperty(entry, mode);
1076 if (result == heap->true_value()) {
1077 MaybeObject* maybe_elements = dictionary->Shrink(key);
1078 FixedArray* new_elements = NULL;
1079 if (!maybe_elements->To(&new_elements)) {
1080 return maybe_elements;
1081 }
1082 if (is_arguments) {
1083 FixedArray::cast(obj->elements())->set(1, new_elements);
1084 } else {
1085 obj->set_elements(new_elements);
1086 }
1087 }
1088 if (mode == JSObject::STRICT_DELETION &&
1089 result == heap->false_value()) {
1090 // In strict mode, attempting to delete a non-configurable property
1091 // throws an exception.
1092 HandleScope scope(isolate);
1093 Handle<Object> holder(obj);
1094 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
1095 Handle<Object> args[2] = { name, holder };
1096 Handle<Object> error =
1097 isolate->factory()->NewTypeError("strict_delete_property",
1098 HandleVector(args, 2));
1099 return isolate->Throw(*error);
1100 }
1101 }
1102 return heap->true_value();
1103 }
1104
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001105 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1106 uint32_t from_start,
1107 FixedArrayBase* to,
1108 ElementsKind to_kind,
1109 uint32_t to_start,
1110 int copy_size) {
1111 switch (to_kind) {
1112 case FAST_SMI_ONLY_ELEMENTS:
1113 case FAST_ELEMENTS:
1114 CopyDictionaryToObjectElements(
1115 SeededNumberDictionary::cast(from), from_start,
1116 FixedArray::cast(to), to_kind, to_start, copy_size);
1117 return from;
1118 case FAST_DOUBLE_ELEMENTS:
1119 CopyDictionaryToDoubleElements(
1120 SeededNumberDictionary::cast(from), from_start,
1121 FixedDoubleArray::cast(to), to_start, copy_size);
1122 return from;
1123 default:
1124 UNREACHABLE();
1125 }
1126 return to->GetHeap()->undefined_value();
1127 }
1128
1129
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001130 protected:
1131 friend class ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001132 ElementsKindTraits<DICTIONARY_ELEMENTS> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001133
1134 virtual MaybeObject* Delete(JSObject* obj,
1135 uint32_t key,
1136 JSReceiver::DeleteMode mode) {
1137 return DeleteCommon(obj, key, mode);
1138 }
1139
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001140 static MaybeObject* GetImpl(Object* receiver,
1141 JSObject* obj,
1142 uint32_t key,
1143 SeededNumberDictionary* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001144 int entry = backing_store->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001145 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001146 Object* element = backing_store->ValueAt(entry);
1147 PropertyDetails details = backing_store->DetailsAt(entry);
1148 if (details.type() == CALLBACKS) {
1149 return obj->GetElementWithCallback(receiver,
1150 element,
1151 key,
1152 obj);
1153 } else {
1154 return element;
1155 }
1156 }
1157 return obj->GetHeap()->the_hole_value();
1158 }
1159
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001160 static bool HasElementImpl(Object* receiver,
1161 JSObject* holder,
1162 uint32_t key,
1163 SeededNumberDictionary* backing_store) {
1164 return backing_store->FindEntry(key) !=
1165 SeededNumberDictionary::kNotFound;
1166 }
1167
1168 static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
1169 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001170 Object* key = dict->KeyAt(index);
1171 return Smi::cast(key)->value();
1172 }
1173};
1174
1175
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001176class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1177 NonStrictArgumentsElementsAccessor,
1178 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
1179 public:
1180 explicit NonStrictArgumentsElementsAccessor(const char* name)
1181 : ElementsAccessorBase<
1182 NonStrictArgumentsElementsAccessor,
1183 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001184 protected:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001185 friend class ElementsAccessorBase<
1186 NonStrictArgumentsElementsAccessor,
1187 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001188
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001189 static MaybeObject* GetImpl(Object* receiver,
1190 JSObject* obj,
1191 uint32_t key,
1192 FixedArray* parameter_map) {
1193 Object* probe = GetParameterMapArg(obj, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001194 if (!probe->IsTheHole()) {
1195 Context* context = Context::cast(parameter_map->get(0));
1196 int context_index = Smi::cast(probe)->value();
1197 ASSERT(!context->get(context_index)->IsTheHole());
1198 return context->get(context_index);
1199 } else {
1200 // Object is not mapped, defer to the arguments.
1201 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001202 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
1203 receiver, obj, key, arguments);
1204 Object* result;
1205 if (!maybe_result->ToObject(&result)) return maybe_result;
1206 // Elements of the arguments object in slow mode might be slow aliases.
1207 if (result->IsAliasedArgumentsEntry()) {
1208 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
1209 Context* context = Context::cast(parameter_map->get(0));
1210 int context_index = entry->aliased_context_slot();
1211 ASSERT(!context->get(context_index)->IsTheHole());
1212 return context->get(context_index);
1213 } else {
1214 return result;
1215 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001216 }
1217 }
1218
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001219 static MaybeObject* SetLengthImpl(JSObject* obj,
1220 Object* length,
1221 FixedArray* parameter_map) {
1222 // TODO(mstarzinger): This was never implemented but will be used once we
1223 // correctly implement [[DefineOwnProperty]] on arrays.
1224 UNIMPLEMENTED();
1225 return obj;
1226 }
1227
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001228 virtual MaybeObject* Delete(JSObject* obj,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001229 uint32_t key,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001230 JSReceiver::DeleteMode mode) {
1231 FixedArray* parameter_map = FixedArray::cast(obj->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001232 Object* probe = GetParameterMapArg(obj, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001233 if (!probe->IsTheHole()) {
1234 // TODO(kmillikin): We could check if this was the last aliased
1235 // parameter, and revert to normal elements in that case. That
1236 // would enable GC of the context.
1237 parameter_map->set_the_hole(key + 2);
1238 } else {
1239 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1240 if (arguments->IsDictionary()) {
1241 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
1242 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001243 return FastObjectElementsAccessor::DeleteCommon(obj, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001244 }
1245 }
1246 return obj->GetHeap()->true_value();
1247 }
1248
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001249 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1250 uint32_t from_start,
1251 FixedArrayBase* to,
1252 ElementsKind to_kind,
1253 uint32_t to_start,
1254 int copy_size) {
1255 FixedArray* parameter_map = FixedArray::cast(from);
1256 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1257 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
1258 return accessor->CopyElements(NULL, from_start, to, to_kind,
1259 to_start, copy_size, arguments);
1260 }
1261
1262 static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001263 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1264 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
1265 ForArray(arguments)->GetCapacity(arguments));
1266 }
1267
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001268 static uint32_t GetKeyForIndexImpl(FixedArray* dict,
1269 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001270 return index;
1271 }
1272
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001273 static bool HasElementImpl(Object* receiver,
1274 JSObject* holder,
1275 uint32_t key,
1276 FixedArray* parameter_map) {
1277 Object* probe = GetParameterMapArg(holder, parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001278 if (!probe->IsTheHole()) {
1279 return true;
1280 } else {
1281 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1282 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001283 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001284 }
1285 }
1286
1287 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001288 static Object* GetParameterMapArg(JSObject* holder,
1289 FixedArray* parameter_map,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001290 uint32_t key) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001291 uint32_t length = holder->IsJSArray()
1292 ? Smi::cast(JSArray::cast(holder)->length())->value()
1293 : parameter_map->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001294 return key < (length - 2 )
1295 ? parameter_map->get(key + 2)
1296 : parameter_map->GetHeap()->the_hole_value();
1297 }
1298};
1299
1300
1301ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
1302 switch (array->map()->instance_type()) {
1303 case FIXED_ARRAY_TYPE:
1304 if (array->IsDictionary()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001305 return elements_accessors_[DICTIONARY_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001306 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +00001307 return elements_accessors_[FAST_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001308 }
1309 case EXTERNAL_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001310 return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001311 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001312 return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001313 case EXTERNAL_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001314 return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001315 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001316 return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001317 case EXTERNAL_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001318 return elements_accessors_[EXTERNAL_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001319 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001320 return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001321 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001322 return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001323 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001324 return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001325 case EXTERNAL_PIXEL_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00001326 return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001327 default:
1328 UNREACHABLE();
1329 return NULL;
1330 }
1331}
1332
1333
1334void ElementsAccessor::InitializeOncePerProcess() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001335 static struct ConcreteElementsAccessors {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001336#define ACCESSOR_STRUCT(Class, Kind, Store) Class* Kind##_handler;
1337 ELEMENTS_LIST(ACCESSOR_STRUCT)
1338#undef ACCESSOR_STRUCT
1339 } element_accessors = {
1340#define ACCESSOR_INIT(Class, Kind, Store) new Class(#Kind),
1341 ELEMENTS_LIST(ACCESSOR_INIT)
1342#undef ACCESSOR_INIT
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001343 };
1344
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001345 static ElementsAccessor* accessor_array[] = {
1346#define ACCESSOR_ARRAY(Class, Kind, Store) element_accessors.Kind##_handler,
1347 ELEMENTS_LIST(ACCESSOR_ARRAY)
1348#undef ACCESSOR_ARRAY
1349 };
1350
1351 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
1352 kElementsKindCount);
1353
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001354 elements_accessors_ = accessor_array;
1355}
1356
1357
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001358template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
1359MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1360 ElementsKindTraits>::
1361 SetLengthImpl(JSObject* obj,
1362 Object* length,
1363 typename ElementsKindTraits::BackingStore* backing_store) {
1364 JSArray* array = JSArray::cast(obj);
1365
1366 // Fast case: The new length fits into a Smi.
1367 MaybeObject* maybe_smi_length = length->ToSmi();
1368 Object* smi_length = Smi::FromInt(0);
1369 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
1370 const int value = Smi::cast(smi_length)->value();
1371 if (value >= 0) {
1372 Object* new_length;
1373 MaybeObject* result = ElementsAccessorSubclass::
1374 SetLengthWithoutNormalize(backing_store, array, smi_length, value);
1375 if (!result->ToObject(&new_length)) return result;
1376 ASSERT(new_length->IsSmi() || new_length->IsUndefined());
1377 if (new_length->IsSmi()) {
1378 array->set_length(Smi::cast(new_length));
1379 return array;
1380 }
1381 } else {
1382 return ThrowArrayLengthRangeError(array->GetHeap());
1383 }
1384 }
1385
1386 // Slow case: The new length does not fit into a Smi or conversion
1387 // to slow elements is needed for other reasons.
1388 if (length->IsNumber()) {
1389 uint32_t value;
1390 if (length->ToArrayIndex(&value)) {
1391 SeededNumberDictionary* dictionary;
1392 MaybeObject* maybe_object = array->NormalizeElements();
1393 if (!maybe_object->To(&dictionary)) return maybe_object;
1394 Object* new_length;
1395 MaybeObject* result = DictionaryElementsAccessor::
1396 SetLengthWithoutNormalize(dictionary, array, length, value);
1397 if (!result->ToObject(&new_length)) return result;
1398 ASSERT(new_length->IsNumber());
1399 array->set_length(new_length);
1400 return array;
1401 } else {
1402 return ThrowArrayLengthRangeError(array->GetHeap());
1403 }
1404 }
1405
1406 // Fall-back case: The new length is not a number so make the array
1407 // size one and set only element to length.
1408 FixedArray* new_backing_store;
1409 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
1410 if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
1411 new_backing_store->set(0, length);
1412 { MaybeObject* result = array->SetContent(new_backing_store);
1413 if (result->IsFailure()) return result;
1414 }
1415 return array;
1416}
1417
1418
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001419} } // namespace v8::internal