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 12429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12440 context->set(context_index, *value); | 12440 context->set(context_index, *value); |
12441 // For elements that are still writable we keep slow aliasing. | 12441 // For elements that are still writable we keep slow aliasing. |
12442 if (!details.IsReadOnly()) value = element; | 12442 if (!details.IsReadOnly()) value = element; |
12443 } | 12443 } |
12444 } | 12444 } |
12445 | 12445 |
12446 dictionary->ValueAtPut(entry, *value); | 12446 dictionary->ValueAtPut(entry, *value); |
12447 } | 12447 } |
12448 | 12448 |
12449 | 12449 |
| 12450 static bool ShouldConvertToFastElements(SeededNumberDictionary* dictionary, |
| 12451 uint32_t array_size) { |
| 12452 // If properties with non-standard attributes or accessors were added, we |
| 12453 // cannot go back to fast elements. |
| 12454 if (dictionary->requires_slow_elements()) return false; |
| 12455 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
| 12456 SeededNumberDictionary::kEntrySize; |
| 12457 return 2 * dictionary_size >= array_size; |
| 12458 } |
| 12459 |
| 12460 |
12450 void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index, | 12461 void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index, |
12451 Handle<Object> value, | 12462 Handle<Object> value, |
12452 PropertyAttributes attributes) { | 12463 PropertyAttributes attributes) { |
12453 // TODO(verwaest): Handle with the elements accessor. | 12464 // TODO(verwaest): Handle with the elements accessor. |
12454 Isolate* isolate = object->GetIsolate(); | |
12455 | |
12456 // Insert element in the dictionary. | 12465 // Insert element in the dictionary. |
12457 Handle<FixedArray> elements(FixedArray::cast(object->elements())); | |
12458 bool is_arguments = | |
12459 (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); | |
12460 | |
12461 DCHECK(object->HasDictionaryElements() || | 12466 DCHECK(object->HasDictionaryElements() || |
12462 object->HasDictionaryArgumentsElements()); | 12467 object->HasDictionaryArgumentsElements()); |
| 12468 DCHECK(object->map()->is_extensible()); |
12463 | 12469 |
| 12470 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
| 12471 bool is_arguments = object->HasSloppyArgumentsElements(); |
12464 Handle<SeededNumberDictionary> dictionary( | 12472 Handle<SeededNumberDictionary> dictionary( |
12465 is_arguments ? SeededNumberDictionary::cast(elements->get(1)) | 12473 is_arguments ? SeededNumberDictionary::cast(elements->get(1)) |
12466 : SeededNumberDictionary::cast(*elements)); | 12474 : SeededNumberDictionary::cast(*elements)); |
12467 | 12475 |
12468 #ifdef DEBUG | 12476 #ifdef DEBUG |
12469 int entry = dictionary->FindEntry(index); | 12477 int entry = dictionary->FindEntry(index); |
12470 DCHECK_EQ(SeededNumberDictionary::kNotFound, entry); | 12478 DCHECK_EQ(SeededNumberDictionary::kNotFound, entry); |
12471 DCHECK(object->map()->is_extensible()); | |
12472 #endif | 12479 #endif |
12473 | 12480 |
12474 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 12481 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
12475 Handle<SeededNumberDictionary> new_dictionary = | 12482 Handle<SeededNumberDictionary> new_dictionary = |
12476 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, details); | 12483 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, details); |
| 12484 |
12477 if (*dictionary != *new_dictionary) { | 12485 if (*dictionary != *new_dictionary) { |
12478 if (is_arguments) { | 12486 if (is_arguments) { |
12479 elements->set(1, *new_dictionary); | 12487 elements->set(1, *new_dictionary); |
12480 } else { | 12488 } else { |
12481 object->set_elements(*new_dictionary); | 12489 object->set_elements(*new_dictionary); |
12482 } | 12490 } |
12483 dictionary = new_dictionary; | |
12484 } | 12491 } |
12485 | 12492 |
12486 // Update the array length if this JSObject is an array. | 12493 uint32_t length = 0; |
12487 if (object->IsJSArray()) { | 12494 if (object->IsJSArray()) { |
12488 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index, | 12495 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&length)); |
12489 value); | 12496 if (index >= length) { |
| 12497 length = index + 1; |
| 12498 Isolate* isolate = object->GetIsolate(); |
| 12499 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length); |
| 12500 JSArray::cast(*object)->set_length(*length_obj); |
| 12501 } |
| 12502 } else if (!new_dictionary->requires_slow_elements()) { |
| 12503 length = new_dictionary->max_number_key() + 1; |
12490 } | 12504 } |
12491 | 12505 |
12492 // Attempt to put this object back in fast case. | 12506 // Attempt to put this object back in fast case. |
12493 if (object->ShouldConvertToFastElements()) { | 12507 if (object->HasDenseElements() && |
12494 uint32_t new_length = 0; | 12508 ShouldConvertToFastElements(*new_dictionary, length)) { |
12495 if (object->IsJSArray()) { | |
12496 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&new_length)); | |
12497 } else { | |
12498 new_length = dictionary->max_number_key() + 1; | |
12499 } | |
12500 ElementsKind to_kind = object->BestFittingFastElementsKind(); | 12509 ElementsKind to_kind = object->BestFittingFastElementsKind(); |
12501 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); | 12510 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
12502 accessor->GrowCapacityAndConvert(object, new_length); | 12511 accessor->GrowCapacityAndConvert(object, length); |
12503 #ifdef DEBUG | 12512 #ifdef DEBUG |
12504 if (FLAG_trace_normalization) { | 12513 if (FLAG_trace_normalization) { |
12505 OFStream os(stdout); | 12514 OFStream os(stdout); |
12506 os << "Object elements are fast case again:\n"; | 12515 os << "Object elements are fast case again:\n"; |
12507 object->Print(os); | 12516 object->Print(os); |
12508 } | 12517 } |
12509 #endif | 12518 #endif |
12510 } | 12519 } |
12511 } | 12520 } |
12512 | 12521 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12567 | 12576 |
12568 Isolate* isolate = object->GetIsolate(); | 12577 Isolate* isolate = object->GetIsolate(); |
12569 | 12578 |
12570 // TODO(verwaest): Use ElementAccessor. | 12579 // TODO(verwaest): Use ElementAccessor. |
12571 Handle<Object> old_length_handle; | 12580 Handle<Object> old_length_handle; |
12572 if (object->IsJSArray() && object->map()->is_observed()) { | 12581 if (object->IsJSArray() && object->map()->is_observed()) { |
12573 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); | 12582 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); |
12574 } | 12583 } |
12575 | 12584 |
12576 ElementsKind kind = object->GetElementsKind(); | 12585 ElementsKind kind = object->GetElementsKind(); |
12577 bool handle_slow = false; | 12586 bool handle_slow = IsDictionaryElementsKind(kind); |
12578 uint32_t capacity = 0; | 12587 uint32_t capacity = 0; |
12579 uint32_t new_capacity = 0; | 12588 uint32_t new_capacity = 0; |
12580 if (IsFastElementsKind(kind) || object->HasFastArgumentsElements()) { | 12589 if (attributes != NONE) { |
12581 if (attributes != NONE) { | 12590 // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements. |
12582 // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements. | 12591 NormalizeElements(object)->set_requires_slow_elements(); |
12583 NormalizeElements(object)->set_requires_slow_elements(); | 12592 handle_slow = true; |
| 12593 } else if (IsSloppyArgumentsElements(kind)) { |
| 12594 FixedArray* parameter_map = FixedArray::cast(object->elements()); |
| 12595 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 12596 if (arguments->IsDictionary()) { |
12584 handle_slow = true; | 12597 handle_slow = true; |
12585 } else { | 12598 } else { |
12586 if (IsSloppyArgumentsElements(kind)) { | 12599 capacity = static_cast<uint32_t>(arguments->length()); |
12587 FixedArray* parameter_map = FixedArray::cast(object->elements()); | 12600 handle_slow = |
12588 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 12601 object->ShouldConvertToSlowElements(capacity, index, &new_capacity); |
12589 capacity = static_cast<uint32_t>(arguments->length()); | 12602 if (handle_slow) NormalizeElements(object); |
12590 } else { | |
12591 if (IsFastSmiOrObjectElementsKind(kind)) { | |
12592 EnsureWritableFastElements(object); | |
12593 } | |
12594 capacity = static_cast<uint32_t>(object->elements()->length()); | |
12595 } | |
12596 | |
12597 new_capacity = capacity; | |
12598 // Check if the capacity of the backing store needs to be increased, or if | |
12599 // a transition to slow elements is necessary. | |
12600 if (index >= capacity) { | |
12601 handle_slow = true; | |
12602 if ((index - capacity) < kMaxGap) { | |
12603 new_capacity = NewElementsCapacity(index + 1); | |
12604 DCHECK_LT(index, new_capacity); | |
12605 handle_slow = object->ShouldConvertToSlowElements(new_capacity); | |
12606 } | |
12607 if (handle_slow) NormalizeElements(object); | |
12608 } | |
12609 } | 12603 } |
12610 } else { | 12604 } else if (!handle_slow) { |
12611 handle_slow = true; | 12605 capacity = static_cast<uint32_t>(object->elements()->length()); |
| 12606 handle_slow = |
| 12607 object->ShouldConvertToSlowElements(capacity, index, &new_capacity); |
| 12608 if (handle_slow) { |
| 12609 NormalizeElements(object); |
| 12610 } else if (IsFastSmiOrObjectElementsKind(kind)) { |
| 12611 EnsureWritableFastElements(object); |
| 12612 } |
12612 } | 12613 } |
12613 | 12614 |
12614 if (handle_slow) { | 12615 if (handle_slow) { |
12615 DCHECK(object->HasDictionaryElements() || | 12616 DCHECK(object->HasDictionaryElements() || |
12616 object->HasDictionaryArgumentsElements()); | 12617 object->HasDictionaryArgumentsElements()); |
12617 AddDictionaryElement(object, index, value, attributes); | 12618 AddDictionaryElement(object, index, value, attributes); |
12618 } else { | 12619 } else { |
12619 AddFastElement(object, index, value, kind, capacity, new_capacity); | 12620 AddFastElement(object, index, value, kind, capacity, new_capacity); |
12620 } | 12621 } |
12621 | 12622 |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12821 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | 12822 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { |
12822 return false; | 12823 return false; |
12823 } | 12824 } |
12824 | 12825 |
12825 // Transitions from HOLEY -> PACKED are not allowed. | 12826 // Transitions from HOLEY -> PACKED are not allowed. |
12826 return !IsFastHoleyElementsKind(from_kind) || | 12827 return !IsFastHoleyElementsKind(from_kind) || |
12827 IsFastHoleyElementsKind(to_kind); | 12828 IsFastHoleyElementsKind(to_kind); |
12828 } | 12829 } |
12829 | 12830 |
12830 | 12831 |
12831 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array, | |
12832 uint32_t index, | |
12833 Handle<Object> value) { | |
12834 uint32_t old_len = 0; | |
12835 CHECK(array->length()->ToArrayLength(&old_len)); | |
12836 // Check to see if we need to update the length. For now, we make | |
12837 // sure that the length stays within 32-bits (unsigned). | |
12838 if (index >= old_len && index != 0xffffffff) { | |
12839 Handle<Object> len = array->GetIsolate()->factory()->NewNumber( | |
12840 static_cast<double>(index) + 1); | |
12841 array->set_length(*len); | |
12842 } | |
12843 } | |
12844 | |
12845 | |
12846 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { | 12832 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { |
12847 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), | 12833 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), |
12848 LookupIterator::OWN_SKIP_INTERCEPTOR); | 12834 LookupIterator::OWN_SKIP_INTERCEPTOR); |
12849 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); | 12835 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); |
12850 CHECK(it.IsFound()); | 12836 CHECK(it.IsFound()); |
12851 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); | 12837 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); |
12852 return it.IsReadOnly(); | 12838 return it.IsReadOnly(); |
12853 } | 12839 } |
12854 | 12840 |
12855 | 12841 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12952 break; | 12938 break; |
12953 } | 12939 } |
12954 } | 12940 } |
12955 } | 12941 } |
12956 | 12942 |
12957 | 12943 |
12958 bool JSObject::WouldConvertToSlowElements(uint32_t index) { | 12944 bool JSObject::WouldConvertToSlowElements(uint32_t index) { |
12959 if (HasFastElements()) { | 12945 if (HasFastElements()) { |
12960 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); | 12946 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); |
12961 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12947 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
12962 if (index >= capacity) { | 12948 uint32_t new_capacity; |
12963 if ((index - capacity) >= kMaxGap) return true; | 12949 return ShouldConvertToSlowElements(capacity, index, &new_capacity); |
12964 uint32_t new_capacity = NewElementsCapacity(index + 1); | |
12965 return ShouldConvertToSlowElements(new_capacity); | |
12966 } | |
12967 } | 12950 } |
12968 return false; | 12951 return false; |
12969 } | 12952 } |
12970 | 12953 |
12971 | 12954 |
12972 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 12955 bool JSObject::ShouldConvertToSlowElements(uint32_t capacity, uint32_t index, |
| 12956 uint32_t* new_capacity) { |
12973 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <= | 12957 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <= |
12974 kMaxUncheckedFastElementsLength); | 12958 kMaxUncheckedFastElementsLength); |
12975 if (new_capacity <= kMaxUncheckedOldFastElementsLength || | 12959 if (index < capacity) { |
12976 (new_capacity <= kMaxUncheckedFastElementsLength && | 12960 *new_capacity = capacity; |
| 12961 return false; |
| 12962 } |
| 12963 if (index - capacity >= kMaxGap) return true; |
| 12964 *new_capacity = NewElementsCapacity(index + 1); |
| 12965 DCHECK_LT(index, *new_capacity); |
| 12966 if (*new_capacity <= kMaxUncheckedOldFastElementsLength || |
| 12967 (*new_capacity <= kMaxUncheckedFastElementsLength && |
12977 GetHeap()->InNewSpace(this))) { | 12968 GetHeap()->InNewSpace(this))) { |
12978 return false; | 12969 return false; |
12979 } | 12970 } |
12980 // If the fast-case backing storage takes up roughly three times as | 12971 // If the fast-case backing storage takes up roughly three times as |
12981 // much space (in machine words) as a dictionary backing storage | 12972 // much space (in machine words) as a dictionary backing storage |
12982 // would, the object should have slow elements. | 12973 // would, the object should have slow elements. |
12983 int old_capacity = 0; | 12974 int old_capacity = 0; |
12984 int used_elements = 0; | 12975 int used_elements = 0; |
12985 GetElementsCapacityAndUsage(&old_capacity, &used_elements); | 12976 GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
12986 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * | 12977 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * |
12987 SeededNumberDictionary::kEntrySize; | 12978 SeededNumberDictionary::kEntrySize; |
12988 return 3 * dictionary_size <= new_capacity; | 12979 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; |
12989 } | 12980 } |
12990 | 12981 |
12991 | 12982 |
12992 bool JSObject::ShouldConvertToFastElements() { | |
12993 DCHECK(HasDictionaryElements() || HasDictionaryArgumentsElements()); | |
12994 // If the elements are sparse, we should not go back to fast case. | |
12995 if (!HasDenseElements()) return false; | |
12996 // An object requiring access checks is never allowed to have fast | |
12997 // elements. If it had fast elements we would skip security checks. | |
12998 if (IsAccessCheckNeeded()) return false; | |
12999 // Observed objects may not go to fast mode because they rely on map checks, | |
13000 // and for fast element accesses we sometimes check element kinds only. | |
13001 if (map()->is_observed()) return false; | |
13002 | |
13003 FixedArray* elements = FixedArray::cast(this->elements()); | |
13004 SeededNumberDictionary* dictionary = NULL; | |
13005 if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) { | |
13006 dictionary = SeededNumberDictionary::cast(elements->get(1)); | |
13007 } else { | |
13008 dictionary = SeededNumberDictionary::cast(elements); | |
13009 } | |
13010 // If an element has been added at a very high index in the elements | |
13011 // dictionary, we cannot go back to fast case. | |
13012 if (dictionary->requires_slow_elements()) return false; | |
13013 // If the dictionary backing storage takes up roughly half as much | |
13014 // space (in machine words) as a fast-case backing storage would, | |
13015 // the object should have fast elements. | |
13016 uint32_t array_size = 0; | |
13017 if (IsJSArray()) { | |
13018 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); | |
13019 } else { | |
13020 array_size = dictionary->max_number_key(); | |
13021 } | |
13022 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | |
13023 SeededNumberDictionary::kEntrySize; | |
13024 return 2 * dictionary_size >= array_size; | |
13025 } | |
13026 | |
13027 | |
13028 ElementsKind JSObject::BestFittingFastElementsKind() { | 12983 ElementsKind JSObject::BestFittingFastElementsKind() { |
13029 if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; | 12984 if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; |
13030 DCHECK(HasDictionaryElements()); | 12985 DCHECK(HasDictionaryElements()); |
13031 SeededNumberDictionary* dictionary = element_dictionary(); | 12986 SeededNumberDictionary* dictionary = element_dictionary(); |
13032 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; | 12987 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
13033 for (int i = 0; i < dictionary->Capacity(); i++) { | 12988 for (int i = 0; i < dictionary->Capacity(); i++) { |
13034 Object* key = dictionary->KeyAt(i); | 12989 Object* key = dictionary->KeyAt(i); |
13035 if (key->IsNumber()) { | 12990 if (key->IsNumber()) { |
13036 Object* value = dictionary->ValueAt(i); | 12991 Object* value = dictionary->ValueAt(i); |
13037 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; | 12992 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; |
(...skipping 3323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16361 Handle<Object> new_value) { | 16316 Handle<Object> new_value) { |
16362 if (cell->value() != *new_value) { | 16317 if (cell->value() != *new_value) { |
16363 cell->set_value(*new_value); | 16318 cell->set_value(*new_value); |
16364 Isolate* isolate = cell->GetIsolate(); | 16319 Isolate* isolate = cell->GetIsolate(); |
16365 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16320 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16366 isolate, DependentCode::kPropertyCellChangedGroup); | 16321 isolate, DependentCode::kPropertyCellChangedGroup); |
16367 } | 16322 } |
16368 } | 16323 } |
16369 } // namespace internal | 16324 } // namespace internal |
16370 } // namespace v8 | 16325 } // namespace v8 |
OLD | NEW |