Chromium Code Reviews| 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 11784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 11795 | 11795 | 
| 11796 os << "RelocInfo (size = " << relocation_size() << ")\n"; | 11796 os << "RelocInfo (size = " << relocation_size() << ")\n"; | 
| 11797 for (RelocIterator it(this); !it.done(); it.next()) { | 11797 for (RelocIterator it(this); !it.done(); it.next()) { | 
| 11798 it.rinfo()->Print(GetIsolate(), os); | 11798 it.rinfo()->Print(GetIsolate(), os); | 
| 11799 } | 11799 } | 
| 11800 os << "\n"; | 11800 os << "\n"; | 
| 11801 } | 11801 } | 
| 11802 #endif // ENABLE_DISASSEMBLER | 11802 #endif // ENABLE_DISASSEMBLER | 
| 11803 | 11803 | 
| 11804 | 11804 | 
| 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 | 11805 // static | 
| 11889 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { | 11806 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { | 
| 11890 DCHECK(capacity >= 0); | 11807 DCHECK(capacity >= 0); | 
| 11891 array->GetIsolate()->factory()->NewJSArrayStorage( | 11808 array->GetIsolate()->factory()->NewJSArrayStorage( | 
| 11892 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | 11809 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | 
| 11893 } | 11810 } | 
| 11894 | 11811 | 
| 11895 | 11812 | 
| 11896 // Returns false if the passed-in index is marked non-configurable, which will | 11813 // 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 | 11814 // 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)); | 12348 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 
| 12432 return arguments->IsDictionary(); | 12349 return arguments->IsDictionary(); | 
| 12433 } | 12350 } | 
| 12434 | 12351 | 
| 12435 | 12352 | 
| 12436 void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, | 12353 void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, | 
| 12437 Handle<Object> value) { | 12354 Handle<Object> value) { | 
| 12438 DCHECK(object->HasFastSmiOrObjectElements() || | 12355 DCHECK(object->HasFastSmiOrObjectElements() || | 
| 12439 object->HasFastArgumentsElements()); | 12356 object->HasFastArgumentsElements()); | 
| 12440 | 12357 | 
| 12441 Isolate* isolate = object->GetIsolate(); | |
| 12442 | |
| 12443 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); | 12358 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); | 
| 12444 if (object->HasSloppyArgumentsElements()) { | 12359 if (object->HasSloppyArgumentsElements()) { | 
| 12445 backing_store = handle(FixedArray::cast(backing_store->get(1))); | 12360 backing_store = handle(FixedArray::cast(backing_store->get(1))); | 
| 12446 } else { | 12361 } 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); | 12362 backing_store = EnsureWritableFastElements(object); | 
| 12452 } | 12363 } | 
| 12453 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12364 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 
| 12454 | 12365 | 
| 12455 uint32_t new_capacity = capacity; | |
| 12456 // Check if the length property of this object needs to be updated. | 12366 // Check if the length property of this object needs to be updated. | 
| 12457 uint32_t array_length = 0; | 12367 uint32_t array_length = 0; | 
| 12458 bool must_update_array_length = false; | 12368 bool must_update_array_length = false; | 
| 12459 bool introduces_holes = true; | 12369 bool introduces_holes = true; | 
| 12460 if (object->IsJSArray()) { | 12370 if (object->IsJSArray()) { | 
| 12461 CHECK( | 12371 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length)); | 
| 12462 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); | |
| 12463 introduces_holes = index > array_length; | 12372 introduces_holes = index > array_length; | 
| 12464 if (index >= array_length) { | 12373 if (index >= array_length) { | 
| 12465 must_update_array_length = true; | 12374 must_update_array_length = true; | 
| 12466 array_length = index + 1; | 12375 array_length = index + 1; | 
| 12467 } | 12376 } | 
| 12468 } else { | 12377 } else { | 
| 12469 introduces_holes = index >= capacity; | 12378 introduces_holes = index >= capacity; | 
| 12470 } | 12379 } | 
| 12471 | 12380 | 
| 12472 // If the array is growing, and it's not growth by a single element at the | 12381 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 | 12382 // Check if the capacity of the backing store needs to be increased, or if | 
| 12481 // a transition to slow elements is necessary. | 12383 // a transition to slow elements is necessary. | 
| 12482 if (index >= capacity) { | 12384 if (index >= capacity) { | 
| 12483 bool convert_to_slow = true; | 12385 bool convert_to_slow = true; | 
| 12484 if ((index - capacity) < kMaxGap) { | 12386 if ((index - capacity) < kMaxGap) { | 
| 12485 new_capacity = NewElementsCapacity(index + 1); | 12387 new_capacity = NewElementsCapacity(index + 1); | 
| 12486 DCHECK(new_capacity > index); | 12388 DCHECK_LT(index, new_capacity); | 
| 12487 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12389 convert_to_slow = object->ShouldConvertToSlowElements(new_capacity); | 
| 12488 convert_to_slow = false; | |
| 12489 } | |
| 12490 } | 12390 } | 
| 12491 if (convert_to_slow) { | 12391 if (convert_to_slow) { | 
| 12492 NormalizeElements(object); | 12392 NormalizeElements(object); | 
| 12493 AddDictionaryElement(object, index, value, NONE); | 12393 AddDictionaryElement(object, index, value, NONE); | 
| 12494 return; | 12394 return; | 
| 12495 } | 12395 } | 
| 12496 } | 12396 } | 
| 12497 | 12397 | 
| 12498 if (object->HasFastSmiElements() && !value->IsSmi()) { | 12398 if (object->HasFastSmiElements() && !value->IsSmi()) { | 
| 12499 // Convert to fast double elements if appropriate. | 12399 // Convert to fast double elements if appropriate. | 
| 12500 if (value->IsNumber()) { | 12400 if (value->IsNumber()) { | 
| 12501 // Consider fixing the boilerplate as well if we have one. | 12401 ElementsKind to_kind = | 
| 12502 ElementsKind to_kind = IsHoleyElementsKind(object->GetElementsKind()) | 12402 introduces_holes ? FAST_HOLEY_DOUBLE_ELEMENTS : FAST_DOUBLE_ELEMENTS; | 
| 12503 ? FAST_HOLEY_DOUBLE_ELEMENTS | 12403 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); | 
| 12504 : FAST_DOUBLE_ELEMENTS; | 12404 accessor->GrowCapacityAndConvert(object, new_capacity); | 
| 12505 | 12405 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; | 12406 return; | 
| 12513 } | 12407 } | 
| 12514 | 12408 | 
| 12515 // Change elements kind from Smi-only to generic FAST if necessary. | 12409 // Change elements kind from Smi-only to generic FAST if necessary. | 
| 12516 ElementsKind kind = object->HasFastHoleyElements() | 12410 ElementsKind kind = introduces_holes || object->HasFastHoleyElements() | 
| 12517 ? FAST_HOLEY_ELEMENTS | 12411 ? FAST_HOLEY_ELEMENTS | 
| 12518 : FAST_ELEMENTS; | 12412 : FAST_ELEMENTS; | 
| 12519 | 12413 | 
| 12520 UpdateAllocationSite(object, kind); | 12414 UpdateAllocationSite(object, kind); | 
| 12521 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 12415 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 
| 12522 JSObject::MigrateToMap(object, new_map); | 12416 JSObject::MigrateToMap(object, new_map); | 
| 12523 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); | 12417 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); | 
| 12418 } else if (introduces_holes && !object->HasFastHoleyElements()) { | |
| 12419 // If the array is growing, and it's not growth by a single element at the | |
| 12420 // end, make sure that the ElementsKind is HOLEY. | |
| 12421 ElementsKind transitioned_kind = | |
| 12422 GetHoleyElementsKind(object->GetElementsKind()); | |
| 12423 TransitionElementsKind(object, transitioned_kind); | |
| 12524 } | 12424 } | 
| 12525 | 12425 | 
| 12526 // Increase backing store capacity if that's been decided previously. | 12426 // Increase backing store capacity if that's been decided previously. | 
| 12527 // Otherwise, set the new element and length. | 12427 if (capacity != new_capacity) { | 
| 12528 if (new_capacity == capacity) { | 12428 DCHECK(!(value->IsSmi() && object->HasFastDoubleElements())); | 
| 
 
Jakob Kummerow
2015/06/22 17:03:02
AFAICS you can DCHECK(!object->HasFastDoubleElemen
 
Toon Verwaest
2015/06/22 18:31:01
Done.
 
 | |
| 12529 DCHECK(object->elements()->IsFixedArray()); | 12429 ElementsAccessor* accessor = | 
| 12530 backing_store->set(index, *value); | 12430 value->IsSmi() || object->HasSloppyArgumentsElements() | 
| 12531 if (must_update_array_length) { | 12431 ? object->GetElementsAccessor() | 
| 12532 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); | 12432 : ElementsAccessor::ForKind(FAST_ELEMENTS); | 
| 12533 } | 12433 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 } | 12434 } | 
| 12435 | |
| 12436 if (must_update_array_length) { | |
| 12437 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); | |
| 12438 } | |
| 12439 | |
| 12440 FixedArray* elements = FixedArray::cast(object->elements()); | |
| 12441 if (object->HasSloppyArgumentsElements()) { | |
| 12442 elements = FixedArray::cast(elements->get(1)); | |
| 12443 } | |
| 12444 elements->set(index, *value); | |
| 12445 | |
| 12446 JSObject::ValidateElements(object); | |
| 12545 } | 12447 } | 
| 12546 | 12448 | 
| 12547 | 12449 | 
| 12548 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, | 12450 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, | 
| 12549 uint32_t index, | 12451 uint32_t index, | 
| 12550 Handle<Object> value, | 12452 Handle<Object> value, | 
| 12551 PropertyAttributes attributes) { | 12453 PropertyAttributes attributes) { | 
| 12552 // TODO(verwaest): Handle with the elements accessor. | 12454 // TODO(verwaest): Handle with the elements accessor. | 
| 12553 Isolate* isolate = object->GetIsolate(); | 12455 Isolate* isolate = object->GetIsolate(); | 
| 12554 | 12456 | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 12694 | 12596 | 
| 12695 // Attempt to put this object back in fast case. | 12597 // Attempt to put this object back in fast case. | 
| 12696 if (object->ShouldConvertToFastElements()) { | 12598 if (object->ShouldConvertToFastElements()) { | 
| 12697 uint32_t new_length = 0; | 12599 uint32_t new_length = 0; | 
| 12698 if (object->IsJSArray()) { | 12600 if (object->IsJSArray()) { | 
| 12699 CHECK( | 12601 CHECK( | 
| 12700 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); | 12602 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); | 
| 12701 } else { | 12603 } else { | 
| 12702 new_length = dictionary->max_number_key() + 1; | 12604 new_length = dictionary->max_number_key() + 1; | 
| 12703 } | 12605 } | 
| 12704 bool has_smi_only_elements = false; | 12606 ElementsKind to_kind = object->BestFittingFastElementsKind(); | 
| 12705 bool should_convert_to_fast_double_elements = | 12607 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); | 
| 12706 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); | 12608 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); | 12609 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()) { | 
| 
 
Jakob Kummerow
2015/06/22 17:03:02
I think you want to keep the '!'.
 
Toon Verwaest
2015/06/22 18:31:01
Done.
 
 | |
| 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()); | 12690 JSObject::ValidateElements(object); | 
| 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 } | 12691 } | 
| 12800 | 12692 | 
| 12801 | 12693 | 
| 12802 // static | 12694 // static | 
| 12803 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 12695 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 
| 12804 uint32_t index, Handle<Object> value, | 12696 uint32_t index, Handle<Object> value, | 
| 12805 LanguageMode language_mode) { | 12697 LanguageMode language_mode) { | 
| 12806 Isolate* isolate = object->GetIsolate(); | 12698 Isolate* isolate = object->GetIsolate(); | 
| 12807 LookupIterator it(isolate, object, index); | 12699 LookupIterator it(isolate, object, index); | 
| 12808 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); | 12700 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 | 12908 | 
| 13017 // Walk through to the Allocation Site | 12909 // Walk through to the Allocation Site | 
| 13018 site = handle(memento->GetAllocationSite()); | 12910 site = handle(memento->GetAllocationSite()); | 
| 13019 } | 12911 } | 
| 13020 AllocationSite::DigestTransitionFeedback(site, to_kind); | 12912 AllocationSite::DigestTransitionFeedback(site, to_kind); | 
| 13021 } | 12913 } | 
| 13022 | 12914 | 
| 13023 | 12915 | 
| 13024 void JSObject::TransitionElementsKind(Handle<JSObject> object, | 12916 void JSObject::TransitionElementsKind(Handle<JSObject> object, | 
| 13025 ElementsKind to_kind) { | 12917 ElementsKind to_kind) { | 
| 13026 ElementsKind from_kind = object->map()->elements_kind(); | 12918 ElementsKind from_kind = object->GetElementsKind(); | 
| 13027 | 12919 | 
| 13028 if (IsFastHoleyElementsKind(from_kind)) { | 12920 if (IsFastHoleyElementsKind(from_kind)) { | 
| 13029 to_kind = GetHoleyElementsKind(to_kind); | 12921 to_kind = GetHoleyElementsKind(to_kind); | 
| 13030 } | 12922 } | 
| 13031 | 12923 | 
| 13032 if (from_kind == to_kind) return; | 12924 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 | 12925 | 
| 13038 Isolate* isolate = object->GetIsolate(); | 12926 // This method should never be called for any other case. | 
| 13039 if (object->elements() == isolate->heap()->empty_fixed_array() || | 12927 DCHECK(IsFastElementsKind(from_kind)); | 
| 13040 (IsFastSmiOrObjectElementsKind(from_kind) && | 12928 DCHECK(IsFastElementsKind(to_kind)); | 
| 13041 IsFastSmiOrObjectElementsKind(to_kind)) || | 12929 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); | 
| 13042 (from_kind == FAST_DOUBLE_ELEMENTS && | 12930 | 
| 13043 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { | 12931 UpdateAllocationSite(object, to_kind); | 
| 13044 DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND); | 12932 if (object->elements() == object->GetHeap()->empty_fixed_array() || | 
| 12933 IsFastDoubleElementsKind(from_kind) == | |
| 12934 IsFastDoubleElementsKind(to_kind)) { | |
| 13045 // No change is needed to the elements() buffer, the transition | 12935 // No change is needed to the elements() buffer, the transition | 
| 13046 // only requires a map change. | 12936 // only requires a map change. | 
| 13047 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); | 12937 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); | 
| 13048 MigrateToMap(object, new_map); | 12938 MigrateToMap(object, new_map); | 
| 13049 if (FLAG_trace_elements_transitions) { | 12939 if (FLAG_trace_elements_transitions) { | 
| 13050 Handle<FixedArrayBase> elms(object->elements()); | 12940 Handle<FixedArrayBase> elms(object->elements()); | 
| 13051 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); | 12941 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); | 
| 13052 } | 12942 } | 
| 13053 return; | 12943 } else { | 
| 12944 DCHECK((IsFastSmiElementsKind(from_kind) && | |
| 12945 IsFastDoubleElementsKind(to_kind)) || | |
| 12946 (IsFastDoubleElementsKind(from_kind) && | |
| 12947 IsFastObjectElementsKind(to_kind))); | |
| 12948 uint32_t c = static_cast<uint32_t>(object->elements()->length()); | |
| 12949 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); | |
| 13054 } | 12950 } | 
| 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 } | 12951 } | 
| 13090 | 12952 | 
| 13091 | 12953 | 
| 13092 // static | 12954 // static | 
| 13093 bool Map::IsValidElementsTransition(ElementsKind from_kind, | 12955 bool Map::IsValidElementsTransition(ElementsKind from_kind, | 
| 13094 ElementsKind to_kind) { | 12956 ElementsKind to_kind) { | 
| 13095 // Transitions can't go backwards. | 12957 // Transitions can't go backwards. | 
| 13096 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | 12958 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | 
| 13097 return false; | 12959 return false; | 
| 13098 } | 12960 } | 
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13293 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); | 13155 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); | 
| 13294 } else { | 13156 } else { | 
| 13295 array_size = dictionary->max_number_key(); | 13157 array_size = dictionary->max_number_key(); | 
| 13296 } | 13158 } | 
| 13297 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | 13159 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | 
| 13298 SeededNumberDictionary::kEntrySize; | 13160 SeededNumberDictionary::kEntrySize; | 
| 13299 return 2 * dictionary_size >= array_size; | 13161 return 2 * dictionary_size >= array_size; | 
| 13300 } | 13162 } | 
| 13301 | 13163 | 
| 13302 | 13164 | 
| 13303 bool JSObject::ShouldConvertToFastDoubleElements( | 13165 ElementsKind JSObject::BestFittingFastElementsKind() { | 
| 13304 bool* has_smi_only_elements) { | 13166 if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; | 
| 13305 *has_smi_only_elements = false; | 13167 DCHECK(HasDictionaryElements()); | 
| 13306 if (HasSloppyArgumentsElements()) return false; | 13168 SeededNumberDictionary* dictionary = element_dictionary(); | 
| 13307 if (FLAG_unbox_double_arrays) { | 13169 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; | 
| 13308 DCHECK(HasDictionaryElements()); | 13170 for (int i = 0; i < dictionary->Capacity(); i++) { | 
| 13309 SeededNumberDictionary* dictionary = element_dictionary(); | 13171 Object* key = dictionary->KeyAt(i); | 
| 13310 bool found_double = false; | 13172 if (key->IsNumber()) { | 
| 13311 for (int i = 0; i < dictionary->Capacity(); i++) { | 13173 Object* value = dictionary->ValueAt(i); | 
| 13312 Object* key = dictionary->KeyAt(i); | 13174 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; | 
| 13313 if (key->IsNumber()) { | 13175 if (!value->IsSmi()) { | 
| 13314 Object* value = dictionary->ValueAt(i); | 13176 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; | 
| 13315 if (!value->IsNumber()) return false; | 13177 kind = FAST_HOLEY_DOUBLE_ELEMENTS; | 
| 13316 if (!value->IsSmi()) { | |
| 13317 found_double = true; | |
| 13318 } | |
| 13319 } | 13178 } | 
| 13320 } | 13179 } | 
| 13321 *has_smi_only_elements = !found_double; | |
| 13322 return found_double; | |
| 13323 } else { | |
| 13324 return false; | |
| 13325 } | 13180 } | 
| 13181 return kind; | |
| 13326 } | 13182 } | 
| 13327 | 13183 | 
| 13328 | 13184 | 
| 13329 // Certain compilers request function template instantiation when they | 13185 // Certain compilers request function template instantiation when they | 
| 13330 // see the definition of the other template functions in the | 13186 // see the definition of the other template functions in the | 
| 13331 // class. This requires us to have the template functions put | 13187 // class. This requires us to have the template functions put | 
| 13332 // together, so even though this function belongs in objects-debug.cc, | 13188 // together, so even though this function belongs in objects-debug.cc, | 
| 13333 // we keep it here instead to satisfy certain compilers. | 13189 // we keep it here instead to satisfy certain compilers. | 
| 13334 #ifdef OBJECT_PRINT | 13190 #ifdef OBJECT_PRINT | 
| 13335 template <typename Derived, typename Shape, typename Key> | 13191 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) { | 16498 Handle<Object> new_value) { | 
| 16643 if (cell->value() != *new_value) { | 16499 if (cell->value() != *new_value) { | 
| 16644 cell->set_value(*new_value); | 16500 cell->set_value(*new_value); | 
| 16645 Isolate* isolate = cell->GetIsolate(); | 16501 Isolate* isolate = cell->GetIsolate(); | 
| 16646 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16502 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 
| 16647 isolate, DependentCode::kPropertyCellChangedGroup); | 16503 isolate, DependentCode::kPropertyCellChangedGroup); | 
| 16648 } | 16504 } | 
| 16649 } | 16505 } | 
| 16650 } // namespace internal | 16506 } // namespace internal | 
| 16651 } // namespace v8 | 16507 } // namespace v8 | 
| OLD | NEW |