| 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 |