OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 3371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3382 array->HasFixedTypedArrayElements())) { | 3382 array->HasFixedTypedArrayElements())) { |
3383 CheckArrayAbuse(array, "typed elements write", it->index(), true); | 3383 CheckArrayAbuse(array, "typed elements write", it->index(), true); |
3384 } | 3384 } |
3385 | 3385 |
3386 if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() && | 3386 if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() && |
3387 !array->HasFixedTypedArrayElements()) { | 3387 !array->HasFixedTypedArrayElements()) { |
3388 CheckArrayAbuse(array, "elements write", it->index(), false); | 3388 CheckArrayAbuse(array, "elements write", it->index(), false); |
3389 } | 3389 } |
3390 } | 3390 } |
3391 | 3391 |
3392 return JSObject::AddDataElement(receiver, it->index(), value, attributes); | 3392 MaybeHandle<Object> result = |
| 3393 JSObject::AddDataElement(receiver, it->index(), value, attributes); |
| 3394 JSObject::ValidateElements(receiver); |
| 3395 return result; |
3393 } else { | 3396 } else { |
3394 // Migrate to the most up-to-date map that will be able to store |value| | 3397 // Migrate to the most up-to-date map that will be able to store |value| |
3395 // under it->name() with |attributes|. | 3398 // under it->name() with |attributes|. |
3396 it->PrepareTransitionToDataProperty(value, attributes, store_mode); | 3399 it->PrepareTransitionToDataProperty(value, attributes, store_mode); |
3397 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); | 3400 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); |
3398 it->ApplyTransitionToDataProperty(); | 3401 it->ApplyTransitionToDataProperty(); |
3399 | 3402 |
3400 // TODO(verwaest): Encapsulate dictionary handling better. | 3403 // TODO(verwaest): Encapsulate dictionary handling better. |
3401 if (receiver->map()->is_dictionary_map()) { | 3404 if (receiver->map()->is_dictionary_map()) { |
3402 // TODO(verwaest): Probably should ensure this is done beforehand. | 3405 // TODO(verwaest): Probably should ensure this is done beforehand. |
(...skipping 8392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11795 | 11798 |
11796 os << "RelocInfo (size = " << relocation_size() << ")\n"; | 11799 os << "RelocInfo (size = " << relocation_size() << ")\n"; |
11797 for (RelocIterator it(this); !it.done(); it.next()) { | 11800 for (RelocIterator it(this); !it.done(); it.next()) { |
11798 it.rinfo()->Print(GetIsolate(), os); | 11801 it.rinfo()->Print(GetIsolate(), os); |
11799 } | 11802 } |
11800 os << "\n"; | 11803 os << "\n"; |
11801 } | 11804 } |
11802 #endif // ENABLE_DISASSEMBLER | 11805 #endif // ENABLE_DISASSEMBLER |
11803 | 11806 |
11804 | 11807 |
11805 Handle<FixedArray> JSObject::SetFastElementsCapacity( | |
11806 Handle<JSObject> object, int capacity, | |
11807 SetFastElementsCapacitySmiMode smi_mode) { | |
11808 // We should never end in here with a pixel or external array. | |
11809 DCHECK(!object->HasExternalArrayElements()); | |
11810 | |
11811 // Allocate a new fast elements backing store. | |
11812 Isolate* isolate = object->GetIsolate(); | |
11813 Handle<FixedArray> new_elements = | |
11814 isolate->factory()->NewUninitializedFixedArray(capacity); | |
11815 | |
11816 isolate->UpdateArrayProtectorOnSetLength(object); | |
11817 | |
11818 ElementsKind elements_kind = object->GetElementsKind(); | |
11819 ElementsKind new_elements_kind; | |
11820 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it, | |
11821 // or if it's allowed and the old elements array contained only SMIs. | |
11822 bool has_fast_smi_elements = | |
11823 (smi_mode == kForceSmiElements) || | |
11824 ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements()); | |
11825 if (has_fast_smi_elements) { | |
11826 if (IsHoleyElementsKind(elements_kind)) { | |
11827 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS; | |
11828 } else { | |
11829 new_elements_kind = FAST_SMI_ELEMENTS; | |
11830 } | |
11831 } else { | |
11832 if (IsHoleyElementsKind(elements_kind)) { | |
11833 new_elements_kind = FAST_HOLEY_ELEMENTS; | |
11834 } else { | |
11835 new_elements_kind = FAST_ELEMENTS; | |
11836 } | |
11837 } | |
11838 Handle<FixedArrayBase> old_elements(object->elements()); | |
11839 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind); | |
11840 accessor->CopyElements(object, new_elements, elements_kind); | |
11841 | |
11842 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { | |
11843 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements); | |
11844 parameter_map->set(1, *new_elements); | |
11845 } else { | |
11846 Handle<Map> new_map = (new_elements_kind != elements_kind) | |
11847 ? GetElementsTransitionMap(object, new_elements_kind) | |
11848 : handle(object->map()); | |
11849 JSObject::ValidateElements(object); | |
11850 JSObject::SetMapAndElements(object, new_map, new_elements); | |
11851 | |
11852 // Transition through the allocation site as well if present. | |
11853 JSObject::UpdateAllocationSite(object, new_elements_kind); | |
11854 } | |
11855 | |
11856 if (FLAG_trace_elements_transitions) { | |
11857 PrintElementsTransition(stdout, object, elements_kind, old_elements, | |
11858 object->GetElementsKind(), new_elements); | |
11859 } | |
11860 | |
11861 return new_elements; | |
11862 } | |
11863 | |
11864 | |
11865 Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength( | |
11866 Handle<JSObject> object, int capacity, int length, | |
11867 SetFastElementsCapacitySmiMode smi_mode) { | |
11868 Handle<FixedArray> new_elements = | |
11869 SetFastElementsCapacity(object, capacity, smi_mode); | |
11870 if (object->IsJSArray()) { | |
11871 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length)); | |
11872 } | |
11873 return new_elements; | |
11874 } | |
11875 | |
11876 | |
11877 void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object, | |
11878 int capacity, | |
11879 int length) { | |
11880 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS); | |
11881 accessor->GrowCapacityAndConvert(object, capacity); | |
11882 if (object->IsJSArray()) { | |
11883 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length)); | |
11884 } | |
11885 } | |
11886 | |
11887 | |
11888 // static | 11808 // static |
11889 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { | 11809 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { |
11890 DCHECK(capacity >= 0); | 11810 DCHECK(capacity >= 0); |
11891 array->GetIsolate()->factory()->NewJSArrayStorage( | 11811 array->GetIsolate()->factory()->NewJSArrayStorage( |
11892 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | 11812 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); |
11893 } | 11813 } |
11894 | 11814 |
11895 | 11815 |
11896 // Returns false if the passed-in index is marked non-configurable, which will | 11816 // Returns false if the passed-in index is marked non-configurable, which will |
11897 // cause the truncation operation to halt, and thus no further old values need | 11817 // cause the truncation operation to halt, and thus no further old values need |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12431 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 12351 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
12432 return arguments->IsDictionary(); | 12352 return arguments->IsDictionary(); |
12433 } | 12353 } |
12434 | 12354 |
12435 | 12355 |
12436 void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, | 12356 void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, |
12437 Handle<Object> value) { | 12357 Handle<Object> value) { |
12438 DCHECK(object->HasFastSmiOrObjectElements() || | 12358 DCHECK(object->HasFastSmiOrObjectElements() || |
12439 object->HasFastArgumentsElements()); | 12359 object->HasFastArgumentsElements()); |
12440 | 12360 |
12441 Isolate* isolate = object->GetIsolate(); | |
12442 | |
12443 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); | 12361 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); |
12444 if (object->HasSloppyArgumentsElements()) { | 12362 if (object->HasSloppyArgumentsElements()) { |
12445 backing_store = handle(FixedArray::cast(backing_store->get(1))); | 12363 backing_store = handle(FixedArray::cast(backing_store->get(1))); |
12446 } else { | 12364 } else { |
12447 // Array optimizations rely on the prototype lookups of Array objects always | |
12448 // returning undefined. If there is a store to the initial prototype object, | |
12449 // make sure all of these optimizations are invalidated. | |
12450 isolate->UpdateArrayProtectorOnSetElement(object); | |
12451 backing_store = EnsureWritableFastElements(object); | 12365 backing_store = EnsureWritableFastElements(object); |
12452 } | 12366 } |
12453 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12367 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
12454 | 12368 |
12455 uint32_t new_capacity = capacity; | |
12456 // Check if the length property of this object needs to be updated. | 12369 // Check if the length property of this object needs to be updated. |
12457 uint32_t array_length = 0; | 12370 uint32_t array_length = 0; |
12458 bool must_update_array_length = false; | 12371 bool must_update_array_length = false; |
12459 bool introduces_holes = true; | 12372 bool introduces_holes = true; |
12460 if (object->IsJSArray()) { | 12373 if (object->IsJSArray()) { |
12461 CHECK( | 12374 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length)); |
12462 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); | |
12463 introduces_holes = index > array_length; | 12375 introduces_holes = index > array_length; |
12464 if (index >= array_length) { | 12376 if (index >= array_length) { |
12465 must_update_array_length = true; | 12377 must_update_array_length = true; |
12466 array_length = index + 1; | 12378 array_length = index + 1; |
12467 } | 12379 } |
12468 } else { | 12380 } else { |
12469 introduces_holes = index >= capacity; | 12381 introduces_holes = index >= capacity; |
12470 } | 12382 } |
12471 | 12383 |
12472 // If the array is growing, and it's not growth by a single element at the | 12384 uint32_t new_capacity = capacity; |
12473 // end, make sure that the ElementsKind is HOLEY. | |
12474 if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) { | |
12475 ElementsKind transitioned_kind = | |
12476 GetHoleyElementsKind(object->GetElementsKind()); | |
12477 TransitionElementsKind(object, transitioned_kind); | |
12478 } | |
12479 | |
12480 // Check if the capacity of the backing store needs to be increased, or if | 12385 // Check if the capacity of the backing store needs to be increased, or if |
12481 // a transition to slow elements is necessary. | 12386 // a transition to slow elements is necessary. |
12482 if (index >= capacity) { | 12387 if (index >= capacity) { |
12483 bool convert_to_slow = true; | 12388 bool convert_to_slow = true; |
12484 if ((index - capacity) < kMaxGap) { | 12389 if ((index - capacity) < kMaxGap) { |
12485 new_capacity = NewElementsCapacity(index + 1); | 12390 new_capacity = NewElementsCapacity(index + 1); |
12486 DCHECK(new_capacity > index); | 12391 DCHECK_LT(index, new_capacity); |
12487 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12392 convert_to_slow = object->ShouldConvertToSlowElements(new_capacity); |
12488 convert_to_slow = false; | |
12489 } | |
12490 } | 12393 } |
12491 if (convert_to_slow) { | 12394 if (convert_to_slow) { |
12492 NormalizeElements(object); | 12395 NormalizeElements(object); |
12493 AddDictionaryElement(object, index, value, NONE); | 12396 AddDictionaryElement(object, index, value, NONE); |
12494 return; | 12397 return; |
12495 } | 12398 } |
12496 } | 12399 } |
12497 | 12400 |
12498 if (object->HasFastSmiElements() && !value->IsSmi()) { | 12401 if (object->HasFastSmiElements() && !value->IsSmi()) { |
12499 // Convert to fast double elements if appropriate. | 12402 // Convert to fast double elements if appropriate. |
12500 if (value->IsNumber()) { | 12403 if (value->IsNumber()) { |
12501 // Consider fixing the boilerplate as well if we have one. | 12404 ElementsKind to_kind = |
12502 ElementsKind to_kind = IsHoleyElementsKind(object->GetElementsKind()) | 12405 introduces_holes ? FAST_HOLEY_DOUBLE_ELEMENTS : FAST_DOUBLE_ELEMENTS; |
12503 ? FAST_HOLEY_DOUBLE_ELEMENTS | 12406 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
12504 : FAST_DOUBLE_ELEMENTS; | 12407 accessor->GrowCapacityAndConvert(object, new_capacity); |
12505 | 12408 AddFastDoubleElement(object, index, value); |
12506 UpdateAllocationSite(object, to_kind); | |
12507 | |
12508 SetFastDoubleElementsCapacityAndLength(object, new_capacity, | |
12509 array_length); | |
12510 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); | |
12511 JSObject::ValidateElements(object); | |
12512 return; | 12409 return; |
12513 } | 12410 } |
12514 | 12411 |
12515 // Change elements kind from Smi-only to generic FAST if necessary. | 12412 // Change elements kind from Smi-only to generic FAST if necessary. |
12516 ElementsKind kind = object->HasFastHoleyElements() | 12413 ElementsKind kind = introduces_holes || object->HasFastHoleyElements() |
12517 ? FAST_HOLEY_ELEMENTS | 12414 ? FAST_HOLEY_ELEMENTS |
12518 : FAST_ELEMENTS; | 12415 : FAST_ELEMENTS; |
12519 | 12416 |
12520 UpdateAllocationSite(object, kind); | 12417 UpdateAllocationSite(object, kind); |
12521 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 12418 Handle<Map> new_map = GetElementsTransitionMap(object, kind); |
12522 JSObject::MigrateToMap(object, new_map); | 12419 JSObject::MigrateToMap(object, new_map); |
12523 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); | 12420 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); |
| 12421 } else if (introduces_holes && !object->HasFastHoleyElements()) { |
| 12422 // If the array is growing, and it's not growth by a single element at the |
| 12423 // end, make sure that the ElementsKind is HOLEY. |
| 12424 ElementsKind transitioned_kind = |
| 12425 GetHoleyElementsKind(object->GetElementsKind()); |
| 12426 TransitionElementsKind(object, transitioned_kind); |
12524 } | 12427 } |
12525 | 12428 |
12526 // Increase backing store capacity if that's been decided previously. | 12429 // Increase backing store capacity if that's been decided previously. |
12527 // Otherwise, set the new element and length. | 12430 if (capacity != new_capacity) { |
12528 if (new_capacity == capacity) { | 12431 DCHECK(!object->HasFastDoubleElements()); |
12529 DCHECK(object->elements()->IsFixedArray()); | 12432 ElementsAccessor* accessor = |
12530 backing_store->set(index, *value); | 12433 value->IsSmi() || object->HasSloppyArgumentsElements() |
12531 if (must_update_array_length) { | 12434 ? object->GetElementsAccessor() |
12532 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); | 12435 : ElementsAccessor::ForKind(FAST_ELEMENTS); |
12533 } | 12436 accessor->GrowCapacityAndConvert(object, new_capacity); |
12534 } else { | |
12535 SetFastElementsCapacitySmiMode smi_mode = | |
12536 value->IsSmi() && object->HasFastSmiElements() | |
12537 ? kAllowSmiElements | |
12538 : kDontAllowSmiElements; | |
12539 Handle<FixedArray> new_elements = | |
12540 SetFastElementsCapacityAndLength(object, new_capacity, array_length, | |
12541 smi_mode); | |
12542 new_elements->set(index, *value); | |
12543 JSObject::ValidateElements(object); | |
12544 } | 12437 } |
| 12438 |
| 12439 if (must_update_array_length) { |
| 12440 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
| 12441 } |
| 12442 |
| 12443 FixedArray* elements = FixedArray::cast(object->elements()); |
| 12444 if (object->HasSloppyArgumentsElements()) { |
| 12445 elements = FixedArray::cast(elements->get(1)); |
| 12446 } |
| 12447 elements->set(index, *value); |
12545 } | 12448 } |
12546 | 12449 |
12547 | 12450 |
12548 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, | 12451 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, |
12549 uint32_t index, | 12452 uint32_t index, |
12550 Handle<Object> value, | 12453 Handle<Object> value, |
12551 PropertyAttributes attributes) { | 12454 PropertyAttributes attributes) { |
12552 // TODO(verwaest): Handle with the elements accessor. | 12455 // TODO(verwaest): Handle with the elements accessor. |
12553 Isolate* isolate = object->GetIsolate(); | 12456 Isolate* isolate = object->GetIsolate(); |
12554 | 12457 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12694 | 12597 |
12695 // Attempt to put this object back in fast case. | 12598 // Attempt to put this object back in fast case. |
12696 if (object->ShouldConvertToFastElements()) { | 12599 if (object->ShouldConvertToFastElements()) { |
12697 uint32_t new_length = 0; | 12600 uint32_t new_length = 0; |
12698 if (object->IsJSArray()) { | 12601 if (object->IsJSArray()) { |
12699 CHECK( | 12602 CHECK( |
12700 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); | 12603 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); |
12701 } else { | 12604 } else { |
12702 new_length = dictionary->max_number_key() + 1; | 12605 new_length = dictionary->max_number_key() + 1; |
12703 } | 12606 } |
12704 bool has_smi_only_elements = false; | 12607 ElementsKind to_kind = object->BestFittingFastElementsKind(); |
12705 bool should_convert_to_fast_double_elements = | 12608 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
12706 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); | 12609 accessor->GrowCapacityAndConvert(object, new_length); |
12707 SetFastElementsCapacitySmiMode smi_mode = | |
12708 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; | |
12709 | |
12710 if (should_convert_to_fast_double_elements) { | |
12711 SetFastDoubleElementsCapacityAndLength(object, new_length, new_length); | |
12712 } else { | |
12713 SetFastElementsCapacityAndLength(object, new_length, new_length, | |
12714 smi_mode); | |
12715 } | |
12716 JSObject::ValidateElements(object); | |
12717 #ifdef DEBUG | 12610 #ifdef DEBUG |
12718 if (FLAG_trace_normalization) { | 12611 if (FLAG_trace_normalization) { |
12719 OFStream os(stdout); | 12612 OFStream os(stdout); |
12720 os << "Object elements are fast case again:\n"; | 12613 os << "Object elements are fast case again:\n"; |
12721 object->Print(os); | 12614 object->Print(os); |
12722 } | 12615 } |
12723 #endif | 12616 #endif |
12724 } | 12617 } |
12725 } | 12618 } |
12726 | 12619 |
12727 | 12620 |
12728 void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index, | 12621 void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index, |
12729 Handle<Object> value) { | 12622 Handle<Object> value) { |
12730 DCHECK(object->HasFastDoubleElements()); | 12623 DCHECK(object->HasFastDoubleElements()); |
12731 | 12624 |
12732 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); | 12625 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); |
12733 uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); | 12626 uint32_t capacity = static_cast<uint32_t>(base_elms->length()); |
12734 uint32_t length = elms_length; | |
12735 | 12627 |
| 12628 // Check if the length property of this object needs to be updated. |
| 12629 uint32_t array_length = 0; |
| 12630 bool must_update_array_length = false; |
12736 bool introduces_holes = true; | 12631 bool introduces_holes = true; |
12737 if (object->IsJSArray()) { | 12632 if (object->IsJSArray()) { |
12738 // In case of JSArray, the length does not equal the capacity. | 12633 // In case of JSArray, the length does not equal the capacity. |
12739 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); | 12634 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length)); |
12740 introduces_holes = index > length; | 12635 introduces_holes = index > array_length; |
| 12636 if (index >= array_length) { |
| 12637 must_update_array_length = true; |
| 12638 array_length = index + 1; |
| 12639 } |
12741 } else { | 12640 } else { |
12742 introduces_holes = index >= elms_length; | 12641 introduces_holes = index >= capacity; |
| 12642 } |
| 12643 |
| 12644 uint32_t new_capacity = capacity; |
| 12645 // Check if the capacity of the backing store needs to be increased, or if |
| 12646 // a transition to slow elements is necessary. |
| 12647 if (index >= capacity) { |
| 12648 bool convert_to_slow = true; |
| 12649 if ((index - capacity) < kMaxGap) { |
| 12650 new_capacity = NewElementsCapacity(index + 1); |
| 12651 DCHECK_LT(index, new_capacity); |
| 12652 convert_to_slow = object->ShouldConvertToSlowElements(new_capacity); |
| 12653 } |
| 12654 if (convert_to_slow) { |
| 12655 NormalizeElements(object); |
| 12656 AddDictionaryElement(object, index, value, NONE); |
| 12657 return; |
| 12658 } |
12743 } | 12659 } |
12744 | 12660 |
12745 // If the value object is not a heap number, switch to fast elements and try | 12661 // If the value object is not a heap number, switch to fast elements and try |
12746 // again. | 12662 // again. |
12747 if (!value->IsNumber()) { | 12663 if (!value->IsNumber()) { |
12748 SetFastElementsCapacityAndLength(object, elms_length, length, | 12664 ElementsKind to_kind = |
12749 kDontAllowSmiElements); | 12665 introduces_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
12750 AddFastElement(object, index, value); | 12666 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
12751 return; | 12667 accessor->GrowCapacityAndConvert(object, new_capacity); |
| 12668 return AddFastElement(object, index, value); |
12752 } | 12669 } |
12753 | 12670 |
12754 // If the array is growing, and it's not growth by a single element at the | 12671 // If the array is growing, and it's not growth by a single element at the |
12755 // end, make sure that the ElementsKind is HOLEY. | 12672 // end, make sure that the ElementsKind is HOLEY. |
12756 if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) { | 12673 if (introduces_holes && !object->HasFastHoleyElements()) { |
12757 ElementsKind transitioned_kind = FAST_HOLEY_DOUBLE_ELEMENTS; | 12674 ElementsKind transitioned_kind = |
| 12675 GetHoleyElementsKind(object->GetElementsKind()); |
12758 TransitionElementsKind(object, transitioned_kind); | 12676 TransitionElementsKind(object, transitioned_kind); |
12759 } | 12677 } |
12760 | 12678 |
12761 // Check whether there is extra space in the fixed array. | 12679 // Increase backing store capacity if that's been decided previously. |
12762 if (index < elms_length) { | 12680 if (capacity != new_capacity) { |
12763 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); | 12681 ElementsAccessor* accessor = object->GetElementsAccessor(); |
12764 elms->set(index, value->Number()); | 12682 accessor->GrowCapacityAndConvert(object, new_capacity); |
12765 if (object->IsJSArray()) { | |
12766 // Update the length of the array if needed. | |
12767 uint32_t array_length = 0; | |
12768 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( | |
12769 &array_length)); | |
12770 if (index >= array_length) { | |
12771 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | |
12772 } | |
12773 } | |
12774 return; | |
12775 } | 12683 } |
12776 | 12684 |
12777 // Allow gap in fast case. | 12685 if (must_update_array_length) { |
12778 if ((index - elms_length) < kMaxGap) { | 12686 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
12779 // Try allocating extra space. | |
12780 int new_capacity = NewElementsCapacity(index+1); | |
12781 if (!object->ShouldConvertToSlowElements(new_capacity)) { | |
12782 DCHECK(static_cast<uint32_t>(new_capacity) > index); | |
12783 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); | |
12784 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); | |
12785 JSObject::ValidateElements(object); | |
12786 return; | |
12787 } | |
12788 } | 12687 } |
12789 | 12688 |
12790 // Otherwise default to slow case. | 12689 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
12791 DCHECK(object->HasFastDoubleElements()); | |
12792 DCHECK(object->map()->has_fast_double_elements()); | |
12793 DCHECK(object->elements()->IsFixedDoubleArray() || | |
12794 object->elements()->length() == 0); | |
12795 | |
12796 NormalizeElements(object); | |
12797 DCHECK(object->HasDictionaryElements()); | |
12798 AddDictionaryElement(object, index, value, NONE); | |
12799 } | 12690 } |
12800 | 12691 |
12801 | 12692 |
12802 // static | 12693 // static |
12803 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 12694 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, |
12804 uint32_t index, Handle<Object> value, | 12695 uint32_t index, Handle<Object> value, |
12805 LanguageMode language_mode) { | 12696 LanguageMode language_mode) { |
12806 Isolate* isolate = object->GetIsolate(); | 12697 Isolate* isolate = object->GetIsolate(); |
12807 LookupIterator it(isolate, object, index); | 12698 LookupIterator it(isolate, object, index); |
12808 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); | 12699 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13016 | 12907 |
13017 // Walk through to the Allocation Site | 12908 // Walk through to the Allocation Site |
13018 site = handle(memento->GetAllocationSite()); | 12909 site = handle(memento->GetAllocationSite()); |
13019 } | 12910 } |
13020 AllocationSite::DigestTransitionFeedback(site, to_kind); | 12911 AllocationSite::DigestTransitionFeedback(site, to_kind); |
13021 } | 12912 } |
13022 | 12913 |
13023 | 12914 |
13024 void JSObject::TransitionElementsKind(Handle<JSObject> object, | 12915 void JSObject::TransitionElementsKind(Handle<JSObject> object, |
13025 ElementsKind to_kind) { | 12916 ElementsKind to_kind) { |
13026 ElementsKind from_kind = object->map()->elements_kind(); | 12917 ElementsKind from_kind = object->GetElementsKind(); |
13027 | 12918 |
13028 if (IsFastHoleyElementsKind(from_kind)) { | 12919 if (IsFastHoleyElementsKind(from_kind)) { |
13029 to_kind = GetHoleyElementsKind(to_kind); | 12920 to_kind = GetHoleyElementsKind(to_kind); |
13030 } | 12921 } |
13031 | 12922 |
13032 if (from_kind == to_kind) return; | 12923 if (from_kind == to_kind) return; |
13033 // Don't update the site if to_kind isn't fast | |
13034 if (IsFastElementsKind(to_kind)) { | |
13035 UpdateAllocationSite(object, to_kind); | |
13036 } | |
13037 | 12924 |
13038 Isolate* isolate = object->GetIsolate(); | 12925 // This method should never be called for any other case. |
13039 if (object->elements() == isolate->heap()->empty_fixed_array() || | 12926 DCHECK(IsFastElementsKind(from_kind)); |
13040 (IsFastSmiOrObjectElementsKind(from_kind) && | 12927 DCHECK(IsFastElementsKind(to_kind)); |
13041 IsFastSmiOrObjectElementsKind(to_kind)) || | 12928 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); |
13042 (from_kind == FAST_DOUBLE_ELEMENTS && | 12929 |
13043 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { | 12930 UpdateAllocationSite(object, to_kind); |
13044 DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND); | 12931 if (object->elements() == object->GetHeap()->empty_fixed_array() || |
| 12932 IsFastDoubleElementsKind(from_kind) == |
| 12933 IsFastDoubleElementsKind(to_kind)) { |
13045 // No change is needed to the elements() buffer, the transition | 12934 // No change is needed to the elements() buffer, the transition |
13046 // only requires a map change. | 12935 // only requires a map change. |
13047 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); | 12936 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); |
13048 MigrateToMap(object, new_map); | 12937 MigrateToMap(object, new_map); |
13049 if (FLAG_trace_elements_transitions) { | 12938 if (FLAG_trace_elements_transitions) { |
13050 Handle<FixedArrayBase> elms(object->elements()); | 12939 Handle<FixedArrayBase> elms(object->elements()); |
13051 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); | 12940 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); |
13052 } | 12941 } |
13053 return; | 12942 } else { |
| 12943 DCHECK((IsFastSmiElementsKind(from_kind) && |
| 12944 IsFastDoubleElementsKind(to_kind)) || |
| 12945 (IsFastDoubleElementsKind(from_kind) && |
| 12946 IsFastObjectElementsKind(to_kind))); |
| 12947 uint32_t c = static_cast<uint32_t>(object->elements()->length()); |
| 12948 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); |
13054 } | 12949 } |
13055 | |
13056 Handle<FixedArrayBase> elms(object->elements()); | |
13057 uint32_t capacity = static_cast<uint32_t>(elms->length()); | |
13058 uint32_t length = capacity; | |
13059 | |
13060 if (object->IsJSArray()) { | |
13061 Object* raw_length = Handle<JSArray>::cast(object)->length(); | |
13062 if (raw_length->IsUndefined()) { | |
13063 // If length is undefined, then JSArray is being initialized and has no | |
13064 // elements, assume a length of zero. | |
13065 length = 0; | |
13066 } else { | |
13067 CHECK(raw_length->ToArrayLength(&length)); | |
13068 } | |
13069 } | |
13070 | |
13071 if (IsFastSmiElementsKind(from_kind) && | |
13072 IsFastDoubleElementsKind(to_kind)) { | |
13073 SetFastDoubleElementsCapacityAndLength(object, capacity, length); | |
13074 JSObject::ValidateElements(object); | |
13075 return; | |
13076 } | |
13077 | |
13078 if (IsFastDoubleElementsKind(from_kind) && | |
13079 IsFastObjectElementsKind(to_kind)) { | |
13080 SetFastElementsCapacityAndLength(object, capacity, length, | |
13081 kDontAllowSmiElements); | |
13082 JSObject::ValidateElements(object); | |
13083 return; | |
13084 } | |
13085 | |
13086 // This method should never be called for any other case than the ones | |
13087 // handled above. | |
13088 UNREACHABLE(); | |
13089 } | 12950 } |
13090 | 12951 |
13091 | 12952 |
13092 // static | 12953 // static |
13093 bool Map::IsValidElementsTransition(ElementsKind from_kind, | 12954 bool Map::IsValidElementsTransition(ElementsKind from_kind, |
13094 ElementsKind to_kind) { | 12955 ElementsKind to_kind) { |
13095 // Transitions can't go backwards. | 12956 // Transitions can't go backwards. |
13096 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | 12957 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { |
13097 return false; | 12958 return false; |
13098 } | 12959 } |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13293 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); | 13154 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); |
13294 } else { | 13155 } else { |
13295 array_size = dictionary->max_number_key(); | 13156 array_size = dictionary->max_number_key(); |
13296 } | 13157 } |
13297 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | 13158 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
13298 SeededNumberDictionary::kEntrySize; | 13159 SeededNumberDictionary::kEntrySize; |
13299 return 2 * dictionary_size >= array_size; | 13160 return 2 * dictionary_size >= array_size; |
13300 } | 13161 } |
13301 | 13162 |
13302 | 13163 |
13303 bool JSObject::ShouldConvertToFastDoubleElements( | 13164 ElementsKind JSObject::BestFittingFastElementsKind() { |
13304 bool* has_smi_only_elements) { | 13165 if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; |
13305 *has_smi_only_elements = false; | 13166 DCHECK(HasDictionaryElements()); |
13306 if (HasSloppyArgumentsElements()) return false; | 13167 SeededNumberDictionary* dictionary = element_dictionary(); |
13307 if (FLAG_unbox_double_arrays) { | 13168 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
13308 DCHECK(HasDictionaryElements()); | 13169 for (int i = 0; i < dictionary->Capacity(); i++) { |
13309 SeededNumberDictionary* dictionary = element_dictionary(); | 13170 Object* key = dictionary->KeyAt(i); |
13310 bool found_double = false; | 13171 if (key->IsNumber()) { |
13311 for (int i = 0; i < dictionary->Capacity(); i++) { | 13172 Object* value = dictionary->ValueAt(i); |
13312 Object* key = dictionary->KeyAt(i); | 13173 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; |
13313 if (key->IsNumber()) { | 13174 if (!value->IsSmi()) { |
13314 Object* value = dictionary->ValueAt(i); | 13175 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; |
13315 if (!value->IsNumber()) return false; | 13176 kind = FAST_HOLEY_DOUBLE_ELEMENTS; |
13316 if (!value->IsSmi()) { | |
13317 found_double = true; | |
13318 } | |
13319 } | 13177 } |
13320 } | 13178 } |
13321 *has_smi_only_elements = !found_double; | |
13322 return found_double; | |
13323 } else { | |
13324 return false; | |
13325 } | 13179 } |
| 13180 return kind; |
13326 } | 13181 } |
13327 | 13182 |
13328 | 13183 |
13329 // Certain compilers request function template instantiation when they | 13184 // Certain compilers request function template instantiation when they |
13330 // see the definition of the other template functions in the | 13185 // see the definition of the other template functions in the |
13331 // class. This requires us to have the template functions put | 13186 // class. This requires us to have the template functions put |
13332 // together, so even though this function belongs in objects-debug.cc, | 13187 // together, so even though this function belongs in objects-debug.cc, |
13333 // we keep it here instead to satisfy certain compilers. | 13188 // we keep it here instead to satisfy certain compilers. |
13334 #ifdef OBJECT_PRINT | 13189 #ifdef OBJECT_PRINT |
13335 template <typename Derived, typename Shape, typename Key> | 13190 template <typename Derived, typename Shape, typename Key> |
(...skipping 3306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16642 Handle<Object> new_value) { | 16497 Handle<Object> new_value) { |
16643 if (cell->value() != *new_value) { | 16498 if (cell->value() != *new_value) { |
16644 cell->set_value(*new_value); | 16499 cell->set_value(*new_value); |
16645 Isolate* isolate = cell->GetIsolate(); | 16500 Isolate* isolate = cell->GetIsolate(); |
16646 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16501 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16647 isolate, DependentCode::kPropertyCellChangedGroup); | 16502 isolate, DependentCode::kPropertyCellChangedGroup); |
16648 } | 16503 } |
16649 } | 16504 } |
16650 } // namespace internal | 16505 } // namespace internal |
16651 } // namespace v8 | 16506 } // namespace v8 |
OLD | NEW |