Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: src/objects.cc

Issue 1196163005: Cleanup adding elements and in particular dictionary elements (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698