OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 13 matching lines...) Expand all Loading... |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "objects.h" | 30 #include "objects.h" |
31 #include "elements.h" | 31 #include "elements.h" |
32 #include "utils.h" | 32 #include "utils.h" |
33 | 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 |
34 namespace v8 { | 58 namespace v8 { |
35 namespace internal { | 59 namespace internal { |
36 | 60 |
37 | 61 |
38 ElementsAccessor** ElementsAccessor::elements_accessors_; | 62 ElementsAccessor** ElementsAccessor::elements_accessors_; |
39 | 63 |
40 | 64 |
41 bool HasKey(FixedArray* array, Object* key) { | 65 static bool HasKey(FixedArray* array, Object* key) { |
42 int len0 = array->length(); | 66 int len0 = array->length(); |
43 for (int i = 0; i < len0; i++) { | 67 for (int i = 0; i < len0; i++) { |
44 Object* element = array->get(i); | 68 Object* element = array->get(i); |
45 if (element->IsSmi() && element == key) return true; | 69 if (element->IsSmi() && element == key) return true; |
46 if (element->IsString() && | 70 if (element->IsString() && |
47 key->IsString() && String::cast(element)->Equals(String::cast(key))) { | 71 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
48 return true; | 72 return true; |
49 } | 73 } |
50 } | 74 } |
51 return false; | 75 return false; |
52 } | 76 } |
53 | 77 |
54 | 78 |
| 79 static Failure* ThrowArrayLengthRangeError(Heap* heap) { |
| 80 HandleScope scope(heap->isolate()); |
| 81 return heap->isolate()->Throw( |
| 82 *heap->isolate()->factory()->NewRangeError("invalid_array_length", |
| 83 HandleVector<Object>(NULL, 0))); |
| 84 } |
| 85 |
| 86 |
55 // Base class for element handler implementations. Contains the | 87 // Base class for element handler implementations. Contains the |
56 // the common logic for objects with different ElementsKinds. | 88 // the common logic for objects with different ElementsKinds. |
57 // Subclasses must specialize method for which the element | 89 // Subclasses must specialize method for which the element |
58 // implementation differs from the base class implementation. | 90 // implementation differs from the base class implementation. |
59 // | 91 // |
60 // This class is intended to be used in the following way: | 92 // This class is intended to be used in the following way: |
61 // | 93 // |
62 // class SomeElementsAccessor : | 94 // class SomeElementsAccessor : |
63 // public ElementsAccessorBase<SomeElementsAccessor, | 95 // public ElementsAccessorBase<SomeElementsAccessor, |
64 // BackingStoreClass> { | 96 // BackingStoreClass> { |
(...skipping 19 matching lines...) Expand all Loading... |
84 static MaybeObject* Get(BackingStoreClass* backing_store, | 116 static MaybeObject* Get(BackingStoreClass* backing_store, |
85 uint32_t key, | 117 uint32_t key, |
86 JSObject* obj, | 118 JSObject* obj, |
87 Object* receiver) { | 119 Object* receiver) { |
88 if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) { | 120 if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) { |
89 return backing_store->get(key); | 121 return backing_store->get(key); |
90 } | 122 } |
91 return backing_store->GetHeap()->the_hole_value(); | 123 return backing_store->GetHeap()->the_hole_value(); |
92 } | 124 } |
93 | 125 |
| 126 virtual MaybeObject* SetLength(JSObject* obj, |
| 127 Object* length) { |
| 128 ASSERT(obj->IsJSArray()); |
| 129 return ElementsAccessorSubclass::SetLength( |
| 130 BackingStoreClass::cast(obj->elements()), obj, length); |
| 131 } |
| 132 |
| 133 static MaybeObject* SetLength(BackingStoreClass* backing_store, |
| 134 JSObject* obj, |
| 135 Object* length); |
| 136 |
94 virtual MaybeObject* Delete(JSObject* obj, | 137 virtual MaybeObject* Delete(JSObject* obj, |
95 uint32_t key, | 138 uint32_t key, |
96 JSReceiver::DeleteMode mode) = 0; | 139 JSReceiver::DeleteMode mode) = 0; |
97 | 140 |
98 virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, | 141 virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
99 FixedArray* to, | 142 FixedArray* to, |
100 JSObject* holder, | 143 JSObject* holder, |
101 Object* receiver) { | 144 Object* receiver) { |
102 int len0 = to->length(); | 145 int len0 = to->length(); |
103 #ifdef DEBUG | 146 #ifdef DEBUG |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 uint32_t index) { | 258 uint32_t index) { |
216 return ElementsAccessorSubclass::GetKeyForIndex( | 259 return ElementsAccessorSubclass::GetKeyForIndex( |
217 BackingStoreClass::cast(backing_store), index); | 260 BackingStoreClass::cast(backing_store), index); |
218 } | 261 } |
219 | 262 |
220 private: | 263 private: |
221 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); | 264 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
222 }; | 265 }; |
223 | 266 |
224 | 267 |
| 268 // Super class for all fast element arrays. |
| 269 template<typename FastElementsAccessorSubclass, |
| 270 typename BackingStore, |
| 271 int ElementSize> |
225 class FastElementsAccessor | 272 class FastElementsAccessor |
226 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { | 273 : public ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore> { |
| 274 protected: |
| 275 friend class ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore>; |
| 276 |
| 277 // Adjusts the length of the fast backing store or returns the new length or |
| 278 // undefined in case conversion to a slow backing store should be performed. |
| 279 static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store, |
| 280 JSArray* array, |
| 281 Object* length_object, |
| 282 uint32_t length) { |
| 283 uint32_t old_capacity = backing_store->length(); |
| 284 |
| 285 // Check whether the backing store should be shrunk. |
| 286 if (length <= old_capacity) { |
| 287 if (array->HasFastTypeElements()) { |
| 288 MaybeObject* maybe_obj = array->EnsureWritableFastElements(); |
| 289 if (!maybe_obj->To(&backing_store)) return maybe_obj; |
| 290 } |
| 291 if (2 * length <= old_capacity) { |
| 292 // If more than half the elements won't be used, trim the array. |
| 293 if (length == 0) { |
| 294 array->initialize_elements(); |
| 295 } else { |
| 296 backing_store->set_length(length); |
| 297 Address filler_start = backing_store->address() + |
| 298 BackingStore::OffsetOfElementAt(length); |
| 299 int filler_size = (old_capacity - length) * ElementSize; |
| 300 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size); |
| 301 } |
| 302 } else { |
| 303 // Otherwise, fill the unused tail with holes. |
| 304 int old_length = FastD2I(array->length()->Number()); |
| 305 for (int i = length; i < old_length; i++) { |
| 306 backing_store->set_the_hole(i); |
| 307 } |
| 308 } |
| 309 return length_object; |
| 310 } |
| 311 |
| 312 // Check whether the backing store should be expanded. |
| 313 uint32_t min = JSObject::NewElementsCapacity(old_capacity); |
| 314 uint32_t new_capacity = length > min ? length : min; |
| 315 if (!array->ShouldConvertToSlowElements(new_capacity)) { |
| 316 MaybeObject* result = FastElementsAccessorSubclass:: |
| 317 SetFastElementsCapacityAndLength(array, new_capacity, length); |
| 318 if (result->IsFailure()) return result; |
| 319 return length_object; |
| 320 } |
| 321 |
| 322 // Request conversion to slow elements. |
| 323 return array->GetHeap()->undefined_value(); |
| 324 } |
| 325 }; |
| 326 |
| 327 |
| 328 class FastObjectElementsAccessor |
| 329 : public FastElementsAccessor<FastObjectElementsAccessor, |
| 330 FixedArray, |
| 331 kPointerSize> { |
227 public: | 332 public: |
228 static MaybeObject* DeleteCommon(JSObject* obj, | 333 static MaybeObject* DeleteCommon(JSObject* obj, |
229 uint32_t key) { | 334 uint32_t key) { |
230 ASSERT(obj->HasFastElements() || | 335 ASSERT(obj->HasFastElements() || |
231 obj->HasFastSmiOnlyElements() || | 336 obj->HasFastSmiOnlyElements() || |
232 obj->HasFastArgumentsElements()); | 337 obj->HasFastArgumentsElements()); |
233 Heap* heap = obj->GetHeap(); | 338 Heap* heap = obj->GetHeap(); |
234 FixedArray* backing_store = FixedArray::cast(obj->elements()); | 339 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
235 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | 340 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
236 backing_store = FixedArray::cast(backing_store->get(1)); | 341 backing_store = FixedArray::cast(backing_store->get(1)); |
(...skipping 28 matching lines...) Expand all Loading... |
265 if (4 * num_used <= backing_store->length()) { | 370 if (4 * num_used <= backing_store->length()) { |
266 MaybeObject* result = obj->NormalizeElements(); | 371 MaybeObject* result = obj->NormalizeElements(); |
267 if (result->IsFailure()) return result; | 372 if (result->IsFailure()) return result; |
268 } | 373 } |
269 } | 374 } |
270 } | 375 } |
271 return heap->true_value(); | 376 return heap->true_value(); |
272 } | 377 } |
273 | 378 |
274 protected: | 379 protected: |
| 380 friend class FastElementsAccessor<FastObjectElementsAccessor, |
| 381 FixedArray, |
| 382 kPointerSize>; |
| 383 |
| 384 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, |
| 385 uint32_t capacity, |
| 386 uint32_t length) { |
| 387 JSObject::SetFastElementsCapacityMode set_capacity_mode = |
| 388 obj->HasFastSmiOnlyElements() |
| 389 ? JSObject::kAllowSmiOnlyElements |
| 390 : JSObject::kDontAllowSmiOnlyElements; |
| 391 return obj->SetFastElementsCapacityAndLength(capacity, |
| 392 length, |
| 393 set_capacity_mode); |
| 394 } |
| 395 |
275 virtual MaybeObject* Delete(JSObject* obj, | 396 virtual MaybeObject* Delete(JSObject* obj, |
276 uint32_t key, | 397 uint32_t key, |
277 JSReceiver::DeleteMode mode) { | 398 JSReceiver::DeleteMode mode) { |
278 return DeleteCommon(obj, key); | 399 return DeleteCommon(obj, key); |
279 } | 400 } |
280 }; | 401 }; |
281 | 402 |
282 | 403 |
283 class FastDoubleElementsAccessor | 404 class FastDoubleElementsAccessor |
284 : public ElementsAccessorBase<FastDoubleElementsAccessor, | 405 : public FastElementsAccessor<FastDoubleElementsAccessor, |
285 FixedDoubleArray> { | 406 FixedDoubleArray, |
| 407 kDoubleSize> { |
286 protected: | 408 protected: |
287 friend class ElementsAccessorBase<FastDoubleElementsAccessor, | 409 friend class ElementsAccessorBase<FastDoubleElementsAccessor, |
288 FixedDoubleArray>; | 410 FixedDoubleArray>; |
| 411 friend class FastElementsAccessor<FastDoubleElementsAccessor, |
| 412 FixedDoubleArray, |
| 413 kDoubleSize>; |
| 414 |
| 415 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, |
| 416 uint32_t capacity, |
| 417 uint32_t length) { |
| 418 return obj->SetFastDoubleElementsCapacityAndLength(capacity, length); |
| 419 } |
289 | 420 |
290 virtual MaybeObject* Delete(JSObject* obj, | 421 virtual MaybeObject* Delete(JSObject* obj, |
291 uint32_t key, | 422 uint32_t key, |
292 JSReceiver::DeleteMode mode) { | 423 JSReceiver::DeleteMode mode) { |
293 int length = obj->IsJSArray() | 424 int length = obj->IsJSArray() |
294 ? Smi::cast(JSArray::cast(obj)->length())->value() | 425 ? Smi::cast(JSArray::cast(obj)->length())->value() |
295 : FixedDoubleArray::cast(obj->elements())->length(); | 426 : FixedDoubleArray::cast(obj->elements())->length(); |
296 if (key < static_cast<uint32_t>(length)) { | 427 if (key < static_cast<uint32_t>(length)) { |
297 FixedDoubleArray::cast(obj->elements())->set_the_hole(key); | 428 FixedDoubleArray::cast(obj->elements())->set_the_hole(key); |
298 } | 429 } |
(...skipping 23 matching lines...) Expand all Loading... |
322 uint32_t key, | 453 uint32_t key, |
323 JSObject* obj, | 454 JSObject* obj, |
324 Object* receiver) { | 455 Object* receiver) { |
325 if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { | 456 if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { |
326 return backing_store->get(key); | 457 return backing_store->get(key); |
327 } else { | 458 } else { |
328 return backing_store->GetHeap()->undefined_value(); | 459 return backing_store->GetHeap()->undefined_value(); |
329 } | 460 } |
330 } | 461 } |
331 | 462 |
| 463 static MaybeObject* SetLength(ExternalArray* backing_store, |
| 464 JSObject* obj, |
| 465 Object* length) { |
| 466 // External arrays do not support changing their length. |
| 467 UNREACHABLE(); |
| 468 return obj; |
| 469 } |
| 470 |
332 virtual MaybeObject* Delete(JSObject* obj, | 471 virtual MaybeObject* Delete(JSObject* obj, |
333 uint32_t key, | 472 uint32_t key, |
334 JSReceiver::DeleteMode mode) { | 473 JSReceiver::DeleteMode mode) { |
335 // External arrays always ignore deletes. | 474 // External arrays always ignore deletes. |
336 return obj->GetHeap()->true_value(); | 475 return obj->GetHeap()->true_value(); |
337 } | 476 } |
338 }; | 477 }; |
339 | 478 |
340 | 479 |
341 class ExternalByteElementsAccessor | 480 class ExternalByteElementsAccessor |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 class PixelElementsAccessor | 528 class PixelElementsAccessor |
390 : public ExternalElementsAccessor<PixelElementsAccessor, | 529 : public ExternalElementsAccessor<PixelElementsAccessor, |
391 ExternalPixelArray> { | 530 ExternalPixelArray> { |
392 }; | 531 }; |
393 | 532 |
394 | 533 |
395 class DictionaryElementsAccessor | 534 class DictionaryElementsAccessor |
396 : public ElementsAccessorBase<DictionaryElementsAccessor, | 535 : public ElementsAccessorBase<DictionaryElementsAccessor, |
397 NumberDictionary> { | 536 NumberDictionary> { |
398 public: | 537 public: |
| 538 // Adjusts the length of the dictionary backing store and returns the new |
| 539 // length according to ES5 section 15.4.5.2 behavior. |
| 540 static MaybeObject* SetLengthWithoutNormalize(NumberDictionary* dict, |
| 541 JSArray* array, |
| 542 Object* length_object, |
| 543 uint32_t length) { |
| 544 if (length == 0) { |
| 545 // If the length of a slow array is reset to zero, we clear |
| 546 // the array and flush backing storage. This has the added |
| 547 // benefit that the array returns to fast mode. |
| 548 Object* obj; |
| 549 MaybeObject* maybe_obj = array->ResetElements(); |
| 550 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 551 } else { |
| 552 uint32_t new_length = length; |
| 553 uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); |
| 554 if (new_length < old_length) { |
| 555 // Find last non-deletable element in range of elements to be |
| 556 // deleted and adjust range accordingly. |
| 557 Heap* heap = array->GetHeap(); |
| 558 int capacity = dict->Capacity(); |
| 559 for (int i = 0; i < capacity; i++) { |
| 560 Object* key = dict->KeyAt(i); |
| 561 if (key->IsNumber()) { |
| 562 uint32_t number = static_cast<uint32_t>(key->Number()); |
| 563 if (new_length <= number && number < old_length) { |
| 564 PropertyDetails details = dict->DetailsAt(i); |
| 565 if (details.IsDontDelete()) new_length = number + 1; |
| 566 } |
| 567 } |
| 568 } |
| 569 if (new_length != length) { |
| 570 MaybeObject* maybe_object = heap->NumberFromUint32(new_length); |
| 571 if (!maybe_object->To(&length_object)) return maybe_object; |
| 572 } |
| 573 |
| 574 // Remove elements that should be deleted. |
| 575 int removed_entries = 0; |
| 576 Object* sentinel = heap->null_value(); |
| 577 for (int i = 0; i < capacity; i++) { |
| 578 Object* key = dict->KeyAt(i); |
| 579 if (key->IsNumber()) { |
| 580 uint32_t number = static_cast<uint32_t>(key->Number()); |
| 581 if (new_length <= number && number < old_length) { |
| 582 dict->SetEntry(i, sentinel, sentinel); |
| 583 removed_entries++; |
| 584 } |
| 585 } |
| 586 } |
| 587 |
| 588 // Update the number of elements. |
| 589 dict->ElementsRemoved(removed_entries); |
| 590 } |
| 591 } |
| 592 return length_object; |
| 593 } |
| 594 |
399 static MaybeObject* DeleteCommon(JSObject* obj, | 595 static MaybeObject* DeleteCommon(JSObject* obj, |
400 uint32_t key, | 596 uint32_t key, |
401 JSReceiver::DeleteMode mode) { | 597 JSReceiver::DeleteMode mode) { |
402 Isolate* isolate = obj->GetIsolate(); | 598 Isolate* isolate = obj->GetIsolate(); |
403 Heap* heap = isolate->heap(); | 599 Heap* heap = isolate->heap(); |
404 FixedArray* backing_store = FixedArray::cast(obj->elements()); | 600 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
405 bool is_arguments = | 601 bool is_arguments = |
406 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); | 602 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); |
407 if (is_arguments) { | 603 if (is_arguments) { |
408 backing_store = FixedArray::cast(backing_store->get(1)); | 604 backing_store = FixedArray::cast(backing_store->get(1)); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 } else { | 694 } else { |
499 // Object is not mapped, defer to the arguments. | 695 // Object is not mapped, defer to the arguments. |
500 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 696 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
501 return ElementsAccessor::ForArray(arguments)->Get(arguments, | 697 return ElementsAccessor::ForArray(arguments)->Get(arguments, |
502 key, | 698 key, |
503 obj, | 699 obj, |
504 receiver); | 700 receiver); |
505 } | 701 } |
506 } | 702 } |
507 | 703 |
| 704 static MaybeObject* SetLength(FixedArray* parameter_map, |
| 705 JSObject* obj, |
| 706 Object* length) { |
| 707 // TODO(mstarzinger): This was never implemented but will be used once we |
| 708 // correctly implement [[DefineOwnProperty]] on arrays. |
| 709 UNIMPLEMENTED(); |
| 710 return obj; |
| 711 } |
| 712 |
508 virtual MaybeObject* Delete(JSObject* obj, | 713 virtual MaybeObject* Delete(JSObject* obj, |
509 uint32_t key | 714 uint32_t key, |
510 , | |
511 JSReceiver::DeleteMode mode) { | 715 JSReceiver::DeleteMode mode) { |
512 FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 716 FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
513 Object* probe = GetParameterMapArg(parameter_map, key); | 717 Object* probe = GetParameterMapArg(parameter_map, key); |
514 if (!probe->IsTheHole()) { | 718 if (!probe->IsTheHole()) { |
515 // TODO(kmillikin): We could check if this was the last aliased | 719 // TODO(kmillikin): We could check if this was the last aliased |
516 // parameter, and revert to normal elements in that case. That | 720 // parameter, and revert to normal elements in that case. That |
517 // would enable GC of the context. | 721 // would enable GC of the context. |
518 parameter_map->set_the_hole(key + 2); | 722 parameter_map->set_the_hole(key + 2); |
519 } else { | 723 } else { |
520 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 724 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
521 if (arguments->IsDictionary()) { | 725 if (arguments->IsDictionary()) { |
522 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); | 726 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); |
523 } else { | 727 } else { |
524 return FastElementsAccessor::DeleteCommon(obj, key); | 728 return FastObjectElementsAccessor::DeleteCommon(obj, key); |
525 } | 729 } |
526 } | 730 } |
527 return obj->GetHeap()->true_value(); | 731 return obj->GetHeap()->true_value(); |
528 } | 732 } |
529 | 733 |
530 static uint32_t GetCapacity(FixedArray* parameter_map) { | 734 static uint32_t GetCapacity(FixedArray* parameter_map) { |
531 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); | 735 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
532 return Max(static_cast<uint32_t>(parameter_map->length() - 2), | 736 return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
533 ForArray(arguments)->GetCapacity(arguments)); | 737 ForArray(arguments)->GetCapacity(arguments)); |
534 } | 738 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 UNREACHABLE(); | 797 UNREACHABLE(); |
594 return NULL; | 798 return NULL; |
595 } | 799 } |
596 } | 800 } |
597 | 801 |
598 | 802 |
599 void ElementsAccessor::InitializeOncePerProcess() { | 803 void ElementsAccessor::InitializeOncePerProcess() { |
600 static struct ConcreteElementsAccessors { | 804 static struct ConcreteElementsAccessors { |
601 // Use the fast element handler for smi-only arrays. The implementation is | 805 // Use the fast element handler for smi-only arrays. The implementation is |
602 // currently identical. | 806 // currently identical. |
603 FastElementsAccessor fast_smi_elements_handler; | 807 FastObjectElementsAccessor fast_smi_elements_handler; |
604 FastElementsAccessor fast_elements_handler; | 808 FastObjectElementsAccessor fast_elements_handler; |
605 FastDoubleElementsAccessor fast_double_elements_handler; | 809 FastDoubleElementsAccessor fast_double_elements_handler; |
606 DictionaryElementsAccessor dictionary_elements_handler; | 810 DictionaryElementsAccessor dictionary_elements_handler; |
607 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; | 811 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
608 ExternalByteElementsAccessor byte_elements_handler; | 812 ExternalByteElementsAccessor byte_elements_handler; |
609 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; | 813 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
610 ExternalShortElementsAccessor short_elements_handler; | 814 ExternalShortElementsAccessor short_elements_handler; |
611 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; | 815 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
612 ExternalIntElementsAccessor int_elements_handler; | 816 ExternalIntElementsAccessor int_elements_handler; |
613 ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; | 817 ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; |
614 ExternalFloatElementsAccessor float_elements_handler; | 818 ExternalFloatElementsAccessor float_elements_handler; |
(...skipping 18 matching lines...) Expand all Loading... |
633 &element_accessors.pixel_elements_handler | 837 &element_accessors.pixel_elements_handler |
634 }; | 838 }; |
635 | 839 |
636 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == | 840 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == |
637 kElementsKindCount); | 841 kElementsKindCount); |
638 | 842 |
639 elements_accessors_ = accessor_array; | 843 elements_accessors_ = accessor_array; |
640 } | 844 } |
641 | 845 |
642 | 846 |
| 847 template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
| 848 MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, BackingStoreClass>:: |
| 849 SetLength(BackingStoreClass* backing_store, |
| 850 JSObject* obj, |
| 851 Object* length) { |
| 852 JSArray* array = JSArray::cast(obj); |
| 853 |
| 854 // Fast case: The new length fits into a Smi. |
| 855 MaybeObject* maybe_smi_length = length->ToSmi(); |
| 856 Object* smi_length = Smi::FromInt(0); |
| 857 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { |
| 858 const int value = Smi::cast(smi_length)->value(); |
| 859 if (value >= 0) { |
| 860 Object* new_length; |
| 861 MaybeObject* result = ElementsAccessorSubclass:: |
| 862 SetLengthWithoutNormalize(backing_store, array, smi_length, value); |
| 863 if (!result->ToObject(&new_length)) return result; |
| 864 ASSERT(new_length->IsSmi() || new_length->IsUndefined()); |
| 865 if (new_length->IsSmi()) { |
| 866 array->set_length(Smi::cast(new_length)); |
| 867 return array; |
| 868 } |
| 869 } else { |
| 870 return ThrowArrayLengthRangeError(array->GetHeap()); |
| 871 } |
| 872 } |
| 873 |
| 874 // Slow case: The new length does not fit into a Smi or conversion |
| 875 // to slow elements is needed for other reasons. |
| 876 if (length->IsNumber()) { |
| 877 uint32_t value; |
| 878 if (length->ToArrayIndex(&value)) { |
| 879 NumberDictionary* dictionary; |
| 880 MaybeObject* maybe_object = array->NormalizeElements(); |
| 881 if (!maybe_object->To(&dictionary)) return maybe_object; |
| 882 Object* new_length; |
| 883 MaybeObject* result = DictionaryElementsAccessor:: |
| 884 SetLengthWithoutNormalize(dictionary, array, length, value); |
| 885 if (!result->ToObject(&new_length)) return result; |
| 886 ASSERT(new_length->IsNumber()); |
| 887 array->set_length(new_length); |
| 888 return array; |
| 889 } else { |
| 890 return ThrowArrayLengthRangeError(array->GetHeap()); |
| 891 } |
| 892 } |
| 893 |
| 894 // Fall-back case: The new length is not a number so make the array |
| 895 // size one and set only element to length. |
| 896 FixedArray* new_backing_store; |
| 897 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1); |
| 898 if (!maybe_obj->To(&new_backing_store)) return maybe_obj; |
| 899 new_backing_store->set(0, length); |
| 900 array->SetContent(new_backing_store); |
| 901 return array; |
| 902 } |
| 903 |
| 904 |
643 } } // namespace v8::internal | 905 } } // namespace v8::internal |
OLD | NEW |