Chromium Code Reviews| 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* ArrayLengthRangeError(Heap* heap) { | |
|
danno
2011/11/07 19:26:02
Call this ThrowArrayLengthRangeError
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 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->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS | |
|
danno
2011/11/07 19:26:02
Use obj->HasFastSmiOnlyElements()
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 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(); | |
|
danno
2011/11/07 19:26:02
This weird formatting is an artifact of an automat
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 550 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 551 } | |
| 552 } else { | |
| 553 uint32_t new_length = length; | |
| 554 uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); | |
| 555 if (new_length < old_length) { | |
| 556 // Find last non-deletable element in range of elements to be | |
| 557 // deleted and adjust range accordingly. | |
| 558 Heap* heap = array->GetHeap(); | |
| 559 int capacity = dict->Capacity(); | |
| 560 for (int i = 0; i < capacity; i++) { | |
| 561 Object* key = dict->KeyAt(i); | |
| 562 if (key->IsNumber()) { | |
| 563 uint32_t number = static_cast<uint32_t>(key->Number()); | |
| 564 if (new_length <= number && number < old_length) { | |
| 565 PropertyDetails details = dict->DetailsAt(i); | |
| 566 if (details.IsDontDelete()) new_length = number + 1; | |
| 567 } | |
| 568 } | |
| 569 } | |
| 570 if (new_length != length) { | |
| 571 MaybeObject* maybe_object = heap->NumberFromUint32(new_length); | |
| 572 if (!maybe_object->To(&length_object)) return maybe_object; | |
| 573 } | |
| 574 | |
| 575 // Remove elements that should be deleted. | |
| 576 int removed_entries = 0; | |
| 577 Object* sentinel = heap->null_value(); | |
| 578 for (int i = 0; i < capacity; i++) { | |
| 579 Object* key = dict->KeyAt(i); | |
| 580 if (key->IsNumber()) { | |
| 581 uint32_t number = static_cast<uint32_t>(key->Number()); | |
| 582 if (new_length <= number && number < old_length) { | |
| 583 dict->SetEntry(i, sentinel, sentinel); | |
| 584 removed_entries++; | |
| 585 } | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 // Update the number of elements. | |
| 590 dict->ElementsRemoved(removed_entries); | |
| 591 } | |
| 592 } | |
| 593 return length_object; | |
| 594 } | |
| 595 | |
| 399 static MaybeObject* DeleteCommon(JSObject* obj, | 596 static MaybeObject* DeleteCommon(JSObject* obj, |
| 400 uint32_t key, | 597 uint32_t key, |
| 401 JSReceiver::DeleteMode mode) { | 598 JSReceiver::DeleteMode mode) { |
| 402 Isolate* isolate = obj->GetIsolate(); | 599 Isolate* isolate = obj->GetIsolate(); |
| 403 Heap* heap = isolate->heap(); | 600 Heap* heap = isolate->heap(); |
| 404 FixedArray* backing_store = FixedArray::cast(obj->elements()); | 601 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 405 bool is_arguments = | 602 bool is_arguments = |
| 406 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); | 603 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); |
| 407 if (is_arguments) { | 604 if (is_arguments) { |
| 408 backing_store = FixedArray::cast(backing_store->get(1)); | 605 backing_store = FixedArray::cast(backing_store->get(1)); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 } else { | 695 } else { |
| 499 // Object is not mapped, defer to the arguments. | 696 // Object is not mapped, defer to the arguments. |
| 500 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 697 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 501 return ElementsAccessor::ForArray(arguments)->Get(arguments, | 698 return ElementsAccessor::ForArray(arguments)->Get(arguments, |
| 502 key, | 699 key, |
| 503 obj, | 700 obj, |
| 504 receiver); | 701 receiver); |
| 505 } | 702 } |
| 506 } | 703 } |
| 507 | 704 |
| 705 static MaybeObject* SetLength(FixedArray* parameter_map, | |
| 706 JSObject* obj, | |
| 707 Object* length) { | |
| 708 // TODO(mstarzinger): This was never implemented but will be used once we | |
| 709 // correctly implement [[DefineOwnProperty]] on arrays. | |
| 710 UNIMPLEMENTED(); | |
| 711 return obj; | |
| 712 } | |
| 713 | |
| 508 virtual MaybeObject* Delete(JSObject* obj, | 714 virtual MaybeObject* Delete(JSObject* obj, |
| 509 uint32_t key | 715 uint32_t key, |
| 510 , | |
| 511 JSReceiver::DeleteMode mode) { | 716 JSReceiver::DeleteMode mode) { |
| 512 FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 717 FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
| 513 Object* probe = GetParameterMapArg(parameter_map, key); | 718 Object* probe = GetParameterMapArg(parameter_map, key); |
| 514 if (!probe->IsTheHole()) { | 719 if (!probe->IsTheHole()) { |
| 515 // TODO(kmillikin): We could check if this was the last aliased | 720 // TODO(kmillikin): We could check if this was the last aliased |
| 516 // parameter, and revert to normal elements in that case. That | 721 // parameter, and revert to normal elements in that case. That |
| 517 // would enable GC of the context. | 722 // would enable GC of the context. |
| 518 parameter_map->set_the_hole(key + 2); | 723 parameter_map->set_the_hole(key + 2); |
| 519 } else { | 724 } else { |
| 520 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 725 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 521 if (arguments->IsDictionary()) { | 726 if (arguments->IsDictionary()) { |
| 522 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); | 727 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); |
| 523 } else { | 728 } else { |
| 524 return FastElementsAccessor::DeleteCommon(obj, key); | 729 return FastObjectElementsAccessor::DeleteCommon(obj, key); |
| 525 } | 730 } |
| 526 } | 731 } |
| 527 return obj->GetHeap()->true_value(); | 732 return obj->GetHeap()->true_value(); |
| 528 } | 733 } |
| 529 | 734 |
| 530 static uint32_t GetCapacity(FixedArray* parameter_map) { | 735 static uint32_t GetCapacity(FixedArray* parameter_map) { |
| 531 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); | 736 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
| 532 return Max(static_cast<uint32_t>(parameter_map->length() - 2), | 737 return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
| 533 ForArray(arguments)->GetCapacity(arguments)); | 738 ForArray(arguments)->GetCapacity(arguments)); |
| 534 } | 739 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 UNREACHABLE(); | 798 UNREACHABLE(); |
| 594 return NULL; | 799 return NULL; |
| 595 } | 800 } |
| 596 } | 801 } |
| 597 | 802 |
| 598 | 803 |
| 599 void ElementsAccessor::InitializeOncePerProcess() { | 804 void ElementsAccessor::InitializeOncePerProcess() { |
| 600 static struct ConcreteElementsAccessors { | 805 static struct ConcreteElementsAccessors { |
| 601 // Use the fast element handler for smi-only arrays. The implementation is | 806 // Use the fast element handler for smi-only arrays. The implementation is |
| 602 // currently identical. | 807 // currently identical. |
| 603 FastElementsAccessor fast_smi_elements_handler; | 808 FastObjectElementsAccessor fast_smi_elements_handler; |
| 604 FastElementsAccessor fast_elements_handler; | 809 FastObjectElementsAccessor fast_elements_handler; |
| 605 FastDoubleElementsAccessor fast_double_elements_handler; | 810 FastDoubleElementsAccessor fast_double_elements_handler; |
| 606 DictionaryElementsAccessor dictionary_elements_handler; | 811 DictionaryElementsAccessor dictionary_elements_handler; |
| 607 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; | 812 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
| 608 ExternalByteElementsAccessor byte_elements_handler; | 813 ExternalByteElementsAccessor byte_elements_handler; |
| 609 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; | 814 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
| 610 ExternalShortElementsAccessor short_elements_handler; | 815 ExternalShortElementsAccessor short_elements_handler; |
| 611 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; | 816 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
| 612 ExternalIntElementsAccessor int_elements_handler; | 817 ExternalIntElementsAccessor int_elements_handler; |
| 613 ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; | 818 ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; |
| 614 ExternalFloatElementsAccessor float_elements_handler; | 819 ExternalFloatElementsAccessor float_elements_handler; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 633 &element_accessors.pixel_elements_handler | 838 &element_accessors.pixel_elements_handler |
| 634 }; | 839 }; |
| 635 | 840 |
| 636 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == | 841 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == |
| 637 kElementsKindCount); | 842 kElementsKindCount); |
| 638 | 843 |
| 639 elements_accessors_ = accessor_array; | 844 elements_accessors_ = accessor_array; |
| 640 } | 845 } |
| 641 | 846 |
| 642 | 847 |
| 848 template <typename ElementsAccessorSubclass, typename BackingStoreClass> | |
| 849 MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, BackingStoreClass>:: | |
| 850 SetLength(BackingStoreClass* backing_store, | |
| 851 JSObject* obj, | |
| 852 Object* length) { | |
| 853 JSArray* array = JSArray::cast(obj); | |
| 854 | |
| 855 // Fast case: The new length fits into a Smi. | |
| 856 MaybeObject* maybe_smi_length = length->ToSmi(); | |
| 857 Object* smi_length = Smi::FromInt(0); | |
| 858 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { | |
| 859 const int value = Smi::cast(smi_length)->value(); | |
| 860 if (value >= 0) { | |
| 861 Object* new_length; | |
| 862 MaybeObject* result = ElementsAccessorSubclass:: | |
| 863 SetLengthWithoutNormalize(backing_store, array, smi_length, value); | |
| 864 if (!result->ToObject(&new_length)) return result; | |
| 865 ASSERT(new_length->IsSmi() || new_length->IsUndefined()); | |
| 866 if (new_length->IsSmi()) { | |
| 867 array->set_length(Smi::cast(new_length)); | |
| 868 return array; | |
| 869 } | |
| 870 } else { | |
| 871 return ArrayLengthRangeError(array->GetHeap()); | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 // Slow case: The new length does not fit into a Smi or conversion | |
| 876 // to slow elements is needed for other reasons. | |
| 877 if (length->IsNumber()) { | |
| 878 uint32_t value; | |
| 879 if (length->ToArrayIndex(&value)) { | |
| 880 NumberDictionary* dictionary; | |
| 881 { MaybeObject* maybe_object = array->NormalizeElements(); | |
| 882 if (!maybe_object->To(&dictionary)) return maybe_object; | |
|
danno
2011/11/07 19:26:02
remove extra scope
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 883 } | |
| 884 Object* new_length; | |
| 885 MaybeObject* result = DictionaryElementsAccessor:: | |
| 886 SetLengthWithoutNormalize(dictionary, array, length, value); | |
| 887 if (!result->ToObject(&new_length)) return result; | |
| 888 ASSERT(new_length->IsNumber()); | |
| 889 array->set_length(new_length); | |
| 890 return array; | |
| 891 } else { | |
| 892 return ArrayLengthRangeError(array->GetHeap()); | |
| 893 } | |
| 894 } | |
| 895 | |
| 896 // Fall-back case: The new length is not a number so make the array | |
| 897 // size one and set only element to length. | |
| 898 FixedArray* new_backing_store; | |
| 899 { MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1); | |
|
danno
2011/11/07 19:26:02
prune extra scope
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 900 if (!maybe_obj->To(&new_backing_store)) return maybe_obj; | |
| 901 } | |
| 902 new_backing_store->set(0, length); | |
| 903 | |
| 904 { MaybeObject* maybe_obj = array->EnsureCanContainElements(&length, 1); | |
|
danno
2011/11/07 19:26:02
prune extra scope
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 905 if (maybe_obj->IsFailure()) return maybe_obj; | |
| 906 } | |
| 907 | |
| 908 array->set_length(Smi::FromInt(1)); | |
| 909 array->set_elements(new_backing_store); | |
|
danno
2011/11/07 19:26:02
Consider using array->SetContent to simplify the p
Michael Starzinger
2011/11/08 12:00:33
Done.
| |
| 910 return array; | |
| 911 } | |
| 912 | |
| 913 | |
| 643 } } // namespace v8::internal | 914 } } // namespace v8::internal |
| OLD | NEW |