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

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

Powered by Google App Engine
This is Rietveld 408576698