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