| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 5f07c02f8116496c3382187b16a6acd03cd18f3c..3ace4228b849ab0722cc559f9eb6a598e161caba 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -12447,20 +12447,28 @@ void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| }
|
|
|
|
|
| +static bool ShouldConvertToFastElements(SeededNumberDictionary* dictionary,
|
| + uint32_t array_size) {
|
| + // If properties with non-standard attributes or accessors were added, we
|
| + // cannot go back to fast elements.
|
| + if (dictionary->requires_slow_elements()) return false;
|
| + uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
|
| + SeededNumberDictionary::kEntrySize;
|
| + return 2 * dictionary_size >= array_size;
|
| +}
|
| +
|
| +
|
| void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| Handle<Object> value,
|
| PropertyAttributes attributes) {
|
| // TODO(verwaest): Handle with the elements accessor.
|
| - Isolate* isolate = object->GetIsolate();
|
| -
|
| // Insert element in the dictionary.
|
| - Handle<FixedArray> elements(FixedArray::cast(object->elements()));
|
| - bool is_arguments =
|
| - (elements->map() == isolate->heap()->sloppy_arguments_elements_map());
|
| -
|
| DCHECK(object->HasDictionaryElements() ||
|
| object->HasDictionaryArgumentsElements());
|
| + DCHECK(object->map()->is_extensible());
|
|
|
| + Handle<FixedArray> elements(FixedArray::cast(object->elements()));
|
| + bool is_arguments = object->HasSloppyArgumentsElements();
|
| Handle<SeededNumberDictionary> dictionary(
|
| is_arguments ? SeededNumberDictionary::cast(elements->get(1))
|
| : SeededNumberDictionary::cast(*elements));
|
| @@ -12468,38 +12476,39 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| #ifdef DEBUG
|
| int entry = dictionary->FindEntry(index);
|
| DCHECK_EQ(SeededNumberDictionary::kNotFound, entry);
|
| - DCHECK(object->map()->is_extensible());
|
| #endif
|
|
|
| PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
|
| Handle<SeededNumberDictionary> new_dictionary =
|
| SeededNumberDictionary::AddNumberEntry(dictionary, index, value, details);
|
| +
|
| if (*dictionary != *new_dictionary) {
|
| if (is_arguments) {
|
| elements->set(1, *new_dictionary);
|
| } else {
|
| object->set_elements(*new_dictionary);
|
| }
|
| - dictionary = new_dictionary;
|
| }
|
|
|
| - // Update the array length if this JSObject is an array.
|
| + uint32_t length = 0;
|
| if (object->IsJSArray()) {
|
| - JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
|
| - value);
|
| + CHECK(JSArray::cast(*object)->length()->ToArrayLength(&length));
|
| + if (index >= length) {
|
| + length = index + 1;
|
| + Isolate* isolate = object->GetIsolate();
|
| + Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
|
| + JSArray::cast(*object)->set_length(*length_obj);
|
| + }
|
| + } else if (!new_dictionary->requires_slow_elements()) {
|
| + length = new_dictionary->max_number_key() + 1;
|
| }
|
|
|
| // Attempt to put this object back in fast case.
|
| - if (object->ShouldConvertToFastElements()) {
|
| - uint32_t new_length = 0;
|
| - if (object->IsJSArray()) {
|
| - CHECK(JSArray::cast(*object)->length()->ToArrayLength(&new_length));
|
| - } else {
|
| - new_length = dictionary->max_number_key() + 1;
|
| - }
|
| + if (object->HasDenseElements() &&
|
| + ShouldConvertToFastElements(*new_dictionary, length)) {
|
| ElementsKind to_kind = object->BestFittingFastElementsKind();
|
| ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
|
| - accessor->GrowCapacityAndConvert(object, new_length);
|
| + accessor->GrowCapacityAndConvert(object, length);
|
| #ifdef DEBUG
|
| if (FLAG_trace_normalization) {
|
| OFStream os(stdout);
|
| @@ -12574,41 +12583,33 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
|
| }
|
|
|
| ElementsKind kind = object->GetElementsKind();
|
| - bool handle_slow = false;
|
| + bool handle_slow = IsDictionaryElementsKind(kind);
|
| uint32_t capacity = 0;
|
| uint32_t new_capacity = 0;
|
| - if (IsFastElementsKind(kind) || object->HasFastArgumentsElements()) {
|
| - if (attributes != NONE) {
|
| - // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements.
|
| - NormalizeElements(object)->set_requires_slow_elements();
|
| + if (attributes != NONE) {
|
| + // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements.
|
| + NormalizeElements(object)->set_requires_slow_elements();
|
| + handle_slow = true;
|
| + } else if (IsSloppyArgumentsElements(kind)) {
|
| + FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| + FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
| + if (arguments->IsDictionary()) {
|
| handle_slow = true;
|
| } else {
|
| - if (IsSloppyArgumentsElements(kind)) {
|
| - FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| - FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
| - capacity = static_cast<uint32_t>(arguments->length());
|
| - } else {
|
| - if (IsFastSmiOrObjectElementsKind(kind)) {
|
| - EnsureWritableFastElements(object);
|
| - }
|
| - capacity = static_cast<uint32_t>(object->elements()->length());
|
| - }
|
| -
|
| - new_capacity = capacity;
|
| - // Check if the capacity of the backing store needs to be increased, or if
|
| - // a transition to slow elements is necessary.
|
| - if (index >= capacity) {
|
| - handle_slow = true;
|
| - if ((index - capacity) < kMaxGap) {
|
| - new_capacity = NewElementsCapacity(index + 1);
|
| - DCHECK_LT(index, new_capacity);
|
| - handle_slow = object->ShouldConvertToSlowElements(new_capacity);
|
| - }
|
| - if (handle_slow) NormalizeElements(object);
|
| - }
|
| + capacity = static_cast<uint32_t>(arguments->length());
|
| + handle_slow =
|
| + object->ShouldConvertToSlowElements(capacity, index, &new_capacity);
|
| + if (handle_slow) NormalizeElements(object);
|
| + }
|
| + } else if (!handle_slow) {
|
| + capacity = static_cast<uint32_t>(object->elements()->length());
|
| + handle_slow =
|
| + object->ShouldConvertToSlowElements(capacity, index, &new_capacity);
|
| + if (handle_slow) {
|
| + NormalizeElements(object);
|
| + } else if (IsFastSmiOrObjectElementsKind(kind)) {
|
| + EnsureWritableFastElements(object);
|
| }
|
| - } else {
|
| - handle_slow = true;
|
| }
|
|
|
| if (handle_slow) {
|
| @@ -12828,21 +12829,6 @@ bool Map::IsValidElementsTransition(ElementsKind from_kind,
|
| }
|
|
|
|
|
| -void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
|
| - uint32_t index,
|
| - Handle<Object> value) {
|
| - uint32_t old_len = 0;
|
| - CHECK(array->length()->ToArrayLength(&old_len));
|
| - // Check to see if we need to update the length. For now, we make
|
| - // sure that the length stays within 32-bits (unsigned).
|
| - if (index >= old_len && index != 0xffffffff) {
|
| - Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
|
| - static_cast<double>(index) + 1);
|
| - array->set_length(*len);
|
| - }
|
| -}
|
| -
|
| -
|
| bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
|
| LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
|
| LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| @@ -12959,21 +12945,26 @@ bool JSObject::WouldConvertToSlowElements(uint32_t index) {
|
| if (HasFastElements()) {
|
| Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
|
| uint32_t capacity = static_cast<uint32_t>(backing_store->length());
|
| - if (index >= capacity) {
|
| - if ((index - capacity) >= kMaxGap) return true;
|
| - uint32_t new_capacity = NewElementsCapacity(index + 1);
|
| - return ShouldConvertToSlowElements(new_capacity);
|
| - }
|
| + uint32_t new_capacity;
|
| + return ShouldConvertToSlowElements(capacity, index, &new_capacity);
|
| }
|
| return false;
|
| }
|
|
|
|
|
| -bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
|
| +bool JSObject::ShouldConvertToSlowElements(uint32_t capacity, uint32_t index,
|
| + uint32_t* new_capacity) {
|
| STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
|
| kMaxUncheckedFastElementsLength);
|
| - if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
|
| - (new_capacity <= kMaxUncheckedFastElementsLength &&
|
| + if (index < capacity) {
|
| + *new_capacity = capacity;
|
| + return false;
|
| + }
|
| + if (index - capacity >= kMaxGap) return true;
|
| + *new_capacity = NewElementsCapacity(index + 1);
|
| + DCHECK_LT(index, *new_capacity);
|
| + if (*new_capacity <= kMaxUncheckedOldFastElementsLength ||
|
| + (*new_capacity <= kMaxUncheckedFastElementsLength &&
|
| GetHeap()->InNewSpace(this))) {
|
| return false;
|
| }
|
| @@ -12985,43 +12976,7 @@ bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
|
| GetElementsCapacityAndUsage(&old_capacity, &used_elements);
|
| int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
|
| SeededNumberDictionary::kEntrySize;
|
| - return 3 * dictionary_size <= new_capacity;
|
| -}
|
| -
|
| -
|
| -bool JSObject::ShouldConvertToFastElements() {
|
| - DCHECK(HasDictionaryElements() || HasDictionaryArgumentsElements());
|
| - // If the elements are sparse, we should not go back to fast case.
|
| - if (!HasDenseElements()) return false;
|
| - // An object requiring access checks is never allowed to have fast
|
| - // elements. If it had fast elements we would skip security checks.
|
| - if (IsAccessCheckNeeded()) return false;
|
| - // Observed objects may not go to fast mode because they rely on map checks,
|
| - // and for fast element accesses we sometimes check element kinds only.
|
| - if (map()->is_observed()) return false;
|
| -
|
| - FixedArray* elements = FixedArray::cast(this->elements());
|
| - SeededNumberDictionary* dictionary = NULL;
|
| - if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) {
|
| - dictionary = SeededNumberDictionary::cast(elements->get(1));
|
| - } else {
|
| - dictionary = SeededNumberDictionary::cast(elements);
|
| - }
|
| - // If an element has been added at a very high index in the elements
|
| - // dictionary, we cannot go back to fast case.
|
| - if (dictionary->requires_slow_elements()) return false;
|
| - // If the dictionary backing storage takes up roughly half as much
|
| - // space (in machine words) as a fast-case backing storage would,
|
| - // the object should have fast elements.
|
| - uint32_t array_size = 0;
|
| - if (IsJSArray()) {
|
| - CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size));
|
| - } else {
|
| - array_size = dictionary->max_number_key();
|
| - }
|
| - uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
|
| - SeededNumberDictionary::kEntrySize;
|
| - return 2 * dictionary_size >= array_size;
|
| + return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity;
|
| }
|
|
|
|
|
|
|