• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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 
34 
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 
58 namespace v8 {
59 namespace internal {
60 
61 
62 // 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 
94 template<ElementsKind Kind> class ElementsKindTraits {
95  public:
96   typedef FixedArrayBase BackingStore;
97 };
98 
99 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
100 template<> class ElementsKindTraits<KindParam> {               \
101   public:                                                      \
102   static const ElementsKind Kind = KindParam;                  \
103   typedef Store BackingStore;                                  \
104 };
105 ELEMENTS_LIST(ELEMENTS_TRAITS)
106 #undef ELEMENTS_TRAITS
107 
108 
109 ElementsAccessor** ElementsAccessor::elements_accessors_;
110 
111 
HasKey(FixedArray * array,Object * key)112 static bool HasKey(FixedArray* array, Object* key) {
113   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 
ThrowArrayLengthRangeError(Heap * heap)126 static 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 
CopyObjectToObjectElements(FixedArray * from,ElementsKind from_kind,uint32_t from_start,FixedArray * to,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)134 void 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 
CopyDictionaryToObjectElements(SeededNumberDictionary * from,uint32_t from_start,FixedArray * to,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)180 static 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 
CopyDoubleToObjectElements(FixedDoubleArray * from,uint32_t from_start,FixedArray * to,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)230 MUST_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 
CopyDoubleToDoubleElements(FixedDoubleArray * from,uint32_t from_start,FixedDoubleArray * to,uint32_t to_start,int raw_copy_size)285 static 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 
CopyObjectToDoubleElements(FixedArray * from,uint32_t from_start,FixedDoubleArray * to,uint32_t to_start,int raw_copy_size)316 static 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 
CopyDictionaryToDoubleElements(SeededNumberDictionary * from,uint32_t from_start,FixedDoubleArray * to,uint32_t to_start,int raw_copy_size)346 static 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 
378 // 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).
395 template <typename ElementsAccessorSubclass,
396           typename ElementsTraitsParam>
397 class ElementsAccessorBase : public ElementsAccessor {
398  protected:
ElementsAccessorBase(const char * name)399   explicit ElementsAccessorBase(const char* name)
400       : ElementsAccessor(name) { }
401 
402   typedef ElementsTraitsParam ElementsTraits;
403   typedef typename ElementsTraitsParam::BackingStore BackingStore;
404 
kind() const405   virtual ElementsKind kind() const { return ElementsTraits::Kind; }
406 
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,BackingStore * backing_store)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();
414   }
415 
HasElement(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)416   virtual bool HasElement(Object* receiver,
417                           JSObject* holder,
418                           uint32_t key,
419                           FixedArrayBase* backing_store) {
420     if (backing_store == NULL) {
421       backing_store = holder->elements();
422     }
423     return ElementsAccessorSubclass::HasElementImpl(
424         receiver, holder, key, BackingStore::cast(backing_store));
425   }
426 
Get(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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 
GetImpl(Object * receiver,JSObject * obj,uint32_t key,BackingStore * backing_store)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 
SetLength(JSArray * array,Object * length)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 
SetCapacityAndLength(JSArray * array,int capacity,int length)457   virtual MaybeObject* SetCapacityAndLength(JSArray* array,
458                                             int capacity,
459                                             int length) {
460     return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
461         array,
462         capacity,
463         length);
464   }
465 
SetFastElementsCapacityAndLength(JSObject * obj,int capacity,int length)466   static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
467                                                        int capacity,
468                                                        int length) {
469     UNIMPLEMENTED();
470     return obj;
471   }
472 
473   virtual MaybeObject* Delete(JSObject* obj,
474                               uint32_t key,
475                               JSReceiver::DeleteMode mode) = 0;
476 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size)477   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 
CopyElements(JSObject * from_holder,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size,FixedArrayBase * from)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 
AddElementsToFixedArray(Object * receiver,JSObject * holder,FixedArray * to,FixedArrayBase * from)504   virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
505                                                JSObject* holder,
506                                                FixedArray* to,
507                                                FixedArrayBase* from) {
508     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
516     if (from == NULL) {
517       from = holder->elements();
518     }
519     BackingStore* backing_store = BackingStore::cast(from);
520     uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
521 
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.
527     uint32_t extra = 0;
528     for (uint32_t y = 0; y < len1; y++) {
529       uint32_t key =
530           ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
531       if (ElementsAccessorSubclass::HasElementImpl(
532               receiver, holder, key, backing_store)) {
533         MaybeObject* maybe_value =
534             ElementsAccessorSubclass::GetImpl(receiver, holder,
535                                               key, backing_store);
536         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.
564     uint32_t index = 0;
565     for (uint32_t y = 0; y < len1; y++) {
566       uint32_t key =
567           ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
568       if (ElementsAccessorSubclass::HasElementImpl(
569               receiver, holder, key, backing_store)) {
570         MaybeObject* maybe_value =
571             ElementsAccessorSubclass::GetImpl(receiver, holder,
572                                               key, backing_store);
573         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:
GetCapacityImpl(BackingStore * backing_store)586   static uint32_t GetCapacityImpl(BackingStore* backing_store) {
587     return backing_store->length();
588   }
589 
GetCapacity(FixedArrayBase * backing_store)590   virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
591     return ElementsAccessorSubclass::GetCapacityImpl(
592         BackingStore::cast(backing_store));
593   }
594 
GetKeyForIndexImpl(BackingStore * backing_store,uint32_t index)595   static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
596                                      uint32_t index) {
597     return index;
598   }
599 
GetKeyForIndex(FixedArrayBase * backing_store,uint32_t index)600   virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
601                                   uint32_t index) {
602     return ElementsAccessorSubclass::GetKeyForIndexImpl(
603         BackingStore::cast(backing_store), index);
604   }
605 
606  private:
607   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
608 };
609 
610 
611 // Super class for all fast element arrays.
612 template<typename FastElementsAccessorSubclass,
613          typename KindTraits,
614          int ElementSize>
615 class FastElementsAccessor
616     : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
617  public:
FastElementsAccessor(const char * name)618   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.
SetLengthWithoutNormalize(BackingStore * backing_store,JSArray * array,Object * length_object,uint32_t length)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 
677 class FastObjectElementsAccessor
678     : public FastElementsAccessor<FastObjectElementsAccessor,
679                                   ElementsKindTraits<FAST_ELEMENTS>,
680                                   kPointerSize> {
681  public:
FastObjectElementsAccessor(const char * name)682   explicit FastObjectElementsAccessor(const char* name)
683       : FastElementsAccessor<FastObjectElementsAccessor,
684                              ElementsKindTraits<FAST_ELEMENTS>,
685                              kPointerSize>(name) {}
686 
DeleteCommon(JSObject * obj,uint32_t key)687   static MaybeObject* DeleteCommon(JSObject* obj,
688                                    uint32_t key) {
689     ASSERT(obj->HasFastElements() ||
690            obj->HasFastSmiOnlyElements() ||
691            obj->HasFastArgumentsElements());
692     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 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size)733   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 
SetFastElementsCapacityAndLength(JSObject * obj,uint32_t capacity,uint32_t length)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 
771  protected:
772   friend class FastElementsAccessor<FastObjectElementsAccessor,
773                                     ElementsKindTraits<FAST_ELEMENTS>,
774                                     kPointerSize>;
775 
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)776   virtual MaybeObject* Delete(JSObject* obj,
777                               uint32_t key,
778                               JSReceiver::DeleteMode mode) {
779     return DeleteCommon(obj, key);
780   }
781 };
782 
783 
784 class FastDoubleElementsAccessor
785     : public FastElementsAccessor<FastDoubleElementsAccessor,
786                                   ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
787                                   kDoubleSize> {
788  public:
FastDoubleElementsAccessor(const char * name)789   explicit FastDoubleElementsAccessor(const char* name)
790       : FastElementsAccessor<FastDoubleElementsAccessor,
791                              ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
792                              kDoubleSize>(name) {}
793 
SetFastElementsCapacityAndLength(JSObject * obj,uint32_t capacity,uint32_t length)794   static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
795                                                        uint32_t capacity,
796                                                        uint32_t length) {
797     return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
798   }
799 
800  protected:
801   friend class ElementsAccessorBase<FastDoubleElementsAccessor,
802                                     ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
803   friend class FastElementsAccessor<FastDoubleElementsAccessor,
804                                     ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
805                                     kDoubleSize>;
806 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size)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   }
829 
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)830   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 
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedDoubleArray * backing_store)842   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);
848   }
849 };
850 
851 
852 // Super class for all external element arrays.
853 template<typename ExternalElementsAccessorSubclass,
854          ElementsKind Kind>
855 class ExternalElementsAccessor
856     : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
857                                   ElementsKindTraits<Kind> > {
858  public:
ExternalElementsAccessor(const char * name)859   explicit ExternalElementsAccessor(const char* name)
860       : ElementsAccessorBase<ExternalElementsAccessorSubclass,
861                              ElementsKindTraits<Kind> >(name) {}
862 
863  protected:
864   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
865 
866   friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
867                                     ElementsKindTraits<Kind> >;
868 
GetImpl(Object * receiver,JSObject * obj,uint32_t key,BackingStore * backing_store)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 
SetLengthImpl(JSObject * obj,Object * length,BackingStore * backing_store)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;
885   }
886 
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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   }
893 
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,BackingStore * backing_store)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   }
902 };
903 
904 
905 class ExternalByteElementsAccessor
906     : public ExternalElementsAccessor<ExternalByteElementsAccessor,
907                                       EXTERNAL_BYTE_ELEMENTS> {
908  public:
ExternalByteElementsAccessor(const char * name)909   explicit ExternalByteElementsAccessor(const char* name)
910       : ExternalElementsAccessor<ExternalByteElementsAccessor,
911                                  EXTERNAL_BYTE_ELEMENTS>(name) {}
912 };
913 
914 
915 class ExternalUnsignedByteElementsAccessor
916     : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
917                                       EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
918  public:
ExternalUnsignedByteElementsAccessor(const char * name)919   explicit ExternalUnsignedByteElementsAccessor(const char* name)
920       : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
921                                  EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
922 };
923 
924 
925 class ExternalShortElementsAccessor
926     : public ExternalElementsAccessor<ExternalShortElementsAccessor,
927                                       EXTERNAL_SHORT_ELEMENTS> {
928  public:
ExternalShortElementsAccessor(const char * name)929   explicit ExternalShortElementsAccessor(const char* name)
930       : ExternalElementsAccessor<ExternalShortElementsAccessor,
931                                  EXTERNAL_SHORT_ELEMENTS>(name) {}
932 };
933 
934 
935 class ExternalUnsignedShortElementsAccessor
936     : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
937                                       EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
938  public:
ExternalUnsignedShortElementsAccessor(const char * name)939   explicit ExternalUnsignedShortElementsAccessor(const char* name)
940       : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
941                                  EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
942 };
943 
944 
945 class ExternalIntElementsAccessor
946     : public ExternalElementsAccessor<ExternalIntElementsAccessor,
947                                       EXTERNAL_INT_ELEMENTS> {
948  public:
ExternalIntElementsAccessor(const char * name)949   explicit ExternalIntElementsAccessor(const char* name)
950       : ExternalElementsAccessor<ExternalIntElementsAccessor,
951                                  EXTERNAL_INT_ELEMENTS>(name) {}
952 };
953 
954 
955 class ExternalUnsignedIntElementsAccessor
956     : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
957                                       EXTERNAL_UNSIGNED_INT_ELEMENTS> {
958  public:
ExternalUnsignedIntElementsAccessor(const char * name)959   explicit ExternalUnsignedIntElementsAccessor(const char* name)
960       : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
961                                  EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
962 };
963 
964 
965 class ExternalFloatElementsAccessor
966     : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
967                                       EXTERNAL_FLOAT_ELEMENTS> {
968  public:
ExternalFloatElementsAccessor(const char * name)969   explicit ExternalFloatElementsAccessor(const char* name)
970       : ExternalElementsAccessor<ExternalFloatElementsAccessor,
971                                  EXTERNAL_FLOAT_ELEMENTS>(name) {}
972 };
973 
974 
975 class ExternalDoubleElementsAccessor
976     : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
977                                       EXTERNAL_DOUBLE_ELEMENTS> {
978  public:
ExternalDoubleElementsAccessor(const char * name)979   explicit ExternalDoubleElementsAccessor(const char* name)
980       : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
981                                  EXTERNAL_DOUBLE_ELEMENTS>(name) {}
982 };
983 
984 
985 class PixelElementsAccessor
986     : public ExternalElementsAccessor<PixelElementsAccessor,
987                                       EXTERNAL_PIXEL_ELEMENTS> {
988  public:
PixelElementsAccessor(const char * name)989   explicit PixelElementsAccessor(const char* name)
990       : ExternalElementsAccessor<PixelElementsAccessor,
991                                  EXTERNAL_PIXEL_ELEMENTS>(name) {}
992 };
993 
994 
995 class DictionaryElementsAccessor
996     : public ElementsAccessorBase<DictionaryElementsAccessor,
997                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
998  public:
DictionaryElementsAccessor(const char * name)999   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.
SetLengthWithoutNormalize(SeededNumberDictionary * dict,JSArray * array,Object * length_object,uint32_t length)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 
DeleteCommon(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)1060   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 =
1067         (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
1068     if (is_arguments) {
1069       backing_store = FixedArray::cast(backing_store->get(1));
1070     }
1071     SeededNumberDictionary* dictionary =
1072         SeededNumberDictionary::cast(backing_store);
1073     int entry = dictionary->FindEntry(key);
1074     if (entry != SeededNumberDictionary::kNotFound) {
1075       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 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size)1105   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 
1130  protected:
1131   friend class ElementsAccessorBase<DictionaryElementsAccessor,
1132                                     ElementsKindTraits<DICTIONARY_ELEMENTS> >;
1133 
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)1134   virtual MaybeObject* Delete(JSObject* obj,
1135                               uint32_t key,
1136                               JSReceiver::DeleteMode mode) {
1137     return DeleteCommon(obj, key, mode);
1138   }
1139 
GetImpl(Object * receiver,JSObject * obj,uint32_t key,SeededNumberDictionary * backing_store)1140   static MaybeObject* GetImpl(Object* receiver,
1141                               JSObject* obj,
1142                               uint32_t key,
1143                               SeededNumberDictionary* backing_store) {
1144     int entry = backing_store->FindEntry(key);
1145     if (entry != SeededNumberDictionary::kNotFound) {
1146       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 
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,SeededNumberDictionary * backing_store)1160   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 
GetKeyForIndexImpl(SeededNumberDictionary * dict,uint32_t index)1168   static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
1169                                      uint32_t index) {
1170     Object* key = dict->KeyAt(index);
1171     return Smi::cast(key)->value();
1172   }
1173 };
1174 
1175 
1176 class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1177     NonStrictArgumentsElementsAccessor,
1178     ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
1179  public:
NonStrictArgumentsElementsAccessor(const char * name)1180   explicit NonStrictArgumentsElementsAccessor(const char* name)
1181       : ElementsAccessorBase<
1182           NonStrictArgumentsElementsAccessor,
1183           ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
1184  protected:
1185   friend class ElementsAccessorBase<
1186       NonStrictArgumentsElementsAccessor,
1187       ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
1188 
GetImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArray * parameter_map)1189   static MaybeObject* GetImpl(Object* receiver,
1190                               JSObject* obj,
1191                               uint32_t key,
1192                               FixedArray* parameter_map) {
1193     Object* probe = GetParameterMapArg(obj, parameter_map, key);
1194     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));
1202       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       }
1216     }
1217   }
1218 
SetLengthImpl(JSObject * obj,Object * length,FixedArray * parameter_map)1219   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 
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)1228   virtual MaybeObject* Delete(JSObject* obj,
1229                               uint32_t key,
1230                               JSReceiver::DeleteMode mode) {
1231     FixedArray* parameter_map = FixedArray::cast(obj->elements());
1232     Object* probe = GetParameterMapArg(obj, parameter_map, key);
1233     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 {
1243         return FastObjectElementsAccessor::DeleteCommon(obj, key);
1244       }
1245     }
1246     return obj->GetHeap()->true_value();
1247   }
1248 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind to_kind,uint32_t to_start,int copy_size)1249   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 
GetCapacityImpl(FixedArray * parameter_map)1262   static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
1263     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 
GetKeyForIndexImpl(FixedArray * dict,uint32_t index)1268   static uint32_t GetKeyForIndexImpl(FixedArray* dict,
1269                                      uint32_t index) {
1270     return index;
1271   }
1272 
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArray * parameter_map)1273   static bool HasElementImpl(Object* receiver,
1274                              JSObject* holder,
1275                              uint32_t key,
1276                              FixedArray* parameter_map) {
1277     Object* probe = GetParameterMapArg(holder, parameter_map, key);
1278     if (!probe->IsTheHole()) {
1279       return true;
1280     } else {
1281       FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1282       ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
1283       return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
1284     }
1285   }
1286 
1287  private:
GetParameterMapArg(JSObject * holder,FixedArray * parameter_map,uint32_t key)1288   static Object* GetParameterMapArg(JSObject* holder,
1289                                     FixedArray* parameter_map,
1290                                     uint32_t key) {
1291     uint32_t length = holder->IsJSArray()
1292         ? Smi::cast(JSArray::cast(holder)->length())->value()
1293         : parameter_map->length();
1294     return key < (length - 2 )
1295         ? parameter_map->get(key + 2)
1296         : parameter_map->GetHeap()->the_hole_value();
1297   }
1298 };
1299 
1300 
ForArray(FixedArrayBase * array)1301 ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
1302   switch (array->map()->instance_type()) {
1303     case FIXED_ARRAY_TYPE:
1304       if (array->IsDictionary()) {
1305         return elements_accessors_[DICTIONARY_ELEMENTS];
1306       } else {
1307         return elements_accessors_[FAST_ELEMENTS];
1308       }
1309     case EXTERNAL_BYTE_ARRAY_TYPE:
1310       return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
1311     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1312       return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
1313     case EXTERNAL_SHORT_ARRAY_TYPE:
1314       return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
1315     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1316       return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
1317     case EXTERNAL_INT_ARRAY_TYPE:
1318       return elements_accessors_[EXTERNAL_INT_ELEMENTS];
1319     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1320       return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
1321     case EXTERNAL_FLOAT_ARRAY_TYPE:
1322       return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
1323     case EXTERNAL_DOUBLE_ARRAY_TYPE:
1324       return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
1325     case EXTERNAL_PIXEL_ARRAY_TYPE:
1326       return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
1327     default:
1328       UNREACHABLE();
1329       return NULL;
1330   }
1331 }
1332 
1333 
InitializeOncePerProcess()1334 void ElementsAccessor::InitializeOncePerProcess() {
1335   static struct ConcreteElementsAccessors {
1336 #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
1343   };
1344 
1345   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 
1354   elements_accessors_ = accessor_array;
1355 }
1356 
1357 
1358 template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
1359 MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1360                                   ElementsKindTraits>::
SetLengthImpl(JSObject * obj,Object * length,typename ElementsKindTraits::BackingStore * backing_store)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 
1419 } }  // namespace v8::internal
1420