| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 008058894833b5114da05b9cdd3f181ba7216ebe..fd2f023ea18786f9f5d1172f75ce43e097ba3f01 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -11790,7 +11790,10 @@ Handle<FixedArray> JSObject::SetFastElementsCapacity(
|
| ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
|
| accessor->CopyElements(object, new_elements, elements_kind);
|
|
|
| - if (elements_kind != SLOPPY_ARGUMENTS_ELEMENTS) {
|
| + if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
|
| + Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
|
| + parameter_map->set(1, *new_elements);
|
| + } else {
|
| Handle<Map> new_map = (new_elements_kind != elements_kind)
|
| ? GetElementsTransitionMap(object, new_elements_kind)
|
| : handle(object->map());
|
| @@ -11799,9 +11802,6 @@ Handle<FixedArray> JSObject::SetFastElementsCapacity(
|
|
|
| // Transition through the allocation site as well if present.
|
| JSObject::UpdateAllocationSite(object, new_elements_kind);
|
| - } else {
|
| - Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
|
| - parameter_map->set(1, *new_elements);
|
| }
|
|
|
| if (FLAG_trace_elements_transitions) {
|
| @@ -12427,22 +12427,21 @@ bool JSObject::HasDictionaryArgumentsElements() {
|
| }
|
|
|
|
|
| -void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
| +void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index,
|
| Handle<Object> value) {
|
| DCHECK(object->HasFastSmiOrObjectElements() ||
|
| object->HasFastArgumentsElements());
|
|
|
| Isolate* isolate = object->GetIsolate();
|
|
|
| - // Array optimizations rely on the prototype lookups of Array objects always
|
| - // returning undefined. If there is a store to the initial prototype object,
|
| - // make sure all of these optimizations are invalidated.
|
| - isolate->UpdateArrayProtectorOnSetElement(object);
|
| -
|
| Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
|
| if (object->HasSloppyArgumentsElements()) {
|
| backing_store = handle(FixedArray::cast(backing_store->get(1)));
|
| } else {
|
| + // Array optimizations rely on the prototype lookups of Array objects always
|
| + // returning undefined. If there is a store to the initial prototype object,
|
| + // make sure all of these optimizations are invalidated.
|
| + isolate->UpdateArrayProtectorOnSetElement(object);
|
| backing_store = EnsureWritableFastElements(object);
|
| }
|
| uint32_t capacity = static_cast<uint32_t>(backing_store->length());
|
| @@ -12466,11 +12465,9 @@ void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
|
|
| // If the array is growing, and it's not growth by a single element at the
|
| // end, make sure that the ElementsKind is HOLEY.
|
| - ElementsKind elements_kind = object->GetElementsKind();
|
| - if (introduces_holes &&
|
| - IsFastElementsKind(elements_kind) &&
|
| - !IsFastHoleyElementsKind(elements_kind)) {
|
| - ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
|
| + if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) {
|
| + ElementsKind transitioned_kind =
|
| + GetHoleyElementsKind(object->GetElementsKind());
|
| TransitionElementsKind(object, transitioned_kind);
|
| }
|
|
|
| @@ -12487,16 +12484,17 @@ void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
| }
|
| if (convert_to_slow) {
|
| NormalizeElements(object);
|
| - SetDictionaryElement(object, index, value, NONE);
|
| + AddDictionaryElement(object, index, value, NONE);
|
| return;
|
| }
|
| }
|
| +
|
| // Convert to fast double elements if appropriate.
|
| if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
|
| // Consider fixing the boilerplate as well if we have one.
|
| - ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
|
| - ? FAST_HOLEY_DOUBLE_ELEMENTS
|
| - : FAST_DOUBLE_ELEMENTS;
|
| + ElementsKind to_kind = IsHoleyElementsKind(object->GetElementsKind())
|
| + ? FAST_HOLEY_DOUBLE_ELEMENTS
|
| + : FAST_DOUBLE_ELEMENTS;
|
|
|
| UpdateAllocationSite(object, to_kind);
|
|
|
| @@ -12505,6 +12503,7 @@ void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
| JSObject::ValidateElements(object);
|
| return;
|
| }
|
| +
|
| // Change elements kind from Smi-only to generic FAST if necessary.
|
| if (object->HasFastSmiElements() && !value->IsSmi()) {
|
| ElementsKind kind = object->HasFastHoleyElements()
|
| @@ -12516,6 +12515,7 @@ void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
| JSObject::MigrateToMap(object, new_map);
|
| DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
|
| }
|
| +
|
| // Increase backing store capacity if that's been decided previously.
|
| if (new_capacity != capacity) {
|
| SetFastElementsCapacitySmiMode smi_mode =
|
| @@ -12539,42 +12539,62 @@ void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index,
|
| }
|
|
|
|
|
| -void JSObject::SetSloppyArgumentsElement(Handle<JSObject> object,
|
| - uint32_t index, Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| +void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object,
|
| + uint32_t index,
|
| + Handle<Object> value,
|
| + PropertyAttributes attributes) {
|
| // TODO(verwaest): Handle with the elements accessor.
|
| Isolate* isolate = object->GetIsolate();
|
|
|
| - DCHECK(object->HasSloppyArgumentsElements());
|
| + DCHECK(object->HasDictionaryArgumentsElements());
|
|
|
| Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
|
| uint32_t length = parameter_map->length();
|
| Handle<Object> probe =
|
| index < length - 2
|
| - ? Handle<Object>(parameter_map->get(index + 2), isolate)
|
| - : Handle<Object>();
|
| - if (!probe.is_null() && !probe->IsTheHole()) {
|
| + ? handle(parameter_map->get(index + 2), isolate)
|
| + : Handle<Object>::cast(isolate->factory()->the_hole_value());
|
| + if (!probe->IsTheHole()) {
|
| Handle<Context> context(Context::cast(parameter_map->get(0)));
|
| int context_index = Handle<Smi>::cast(probe)->value();
|
| DCHECK(!context->get(context_index)->IsTheHole());
|
| context->set(context_index, *value);
|
|
|
| - if (attributes == NONE) return;
|
| + DCHECK_NE(NONE, attributes);
|
|
|
| // Redefining attributes of an aliased element destroys fast aliasing.
|
| parameter_map->set_the_hole(index + 2);
|
| // For elements that are still writable we re-establish slow aliasing.
|
| if ((attributes & READ_ONLY) == 0) {
|
| - value = Handle<Object>::cast(
|
| - isolate->factory()->NewAliasedArgumentsEntry(context_index));
|
| + value = isolate->factory()->NewAliasedArgumentsEntry(context_index);
|
| }
|
| + AddDictionaryElement(object, index, value, attributes);
|
| + } else {
|
| + SetDictionaryElement(object, index, value, attributes);
|
| }
|
| +}
|
|
|
| - Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
|
| - if (arguments->IsDictionary()) {
|
| - SetDictionaryElement(object, index, value, attributes);
|
| +
|
| +void JSObject::AddSloppyArgumentsElement(Handle<JSObject> object,
|
| + uint32_t index, Handle<Object> value,
|
| + PropertyAttributes attributes) {
|
| + DCHECK(object->HasSloppyArgumentsElements());
|
| +
|
| + // TODO(verwaest): Handle with the elements accessor.
|
| + FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| +
|
| +#ifdef DEBUG
|
| + uint32_t length = parameter_map->length();
|
| + if (index < length - 2) {
|
| + Object* probe = parameter_map->get(index + 2);
|
| + DCHECK(probe->IsTheHole());
|
| + }
|
| +#endif
|
| +
|
| + if (parameter_map->get(1)->IsDictionary()) {
|
| + AddDictionaryElement(object, index, value, attributes);
|
| } else {
|
| - SetFastElement(object, index, value);
|
| + AddFastElement(object, index, value);
|
| }
|
| }
|
|
|
| @@ -12598,19 +12618,17 @@ void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| : SeededNumberDictionary::cast(*elements));
|
|
|
| int entry = dictionary->FindEntry(index);
|
| - if (entry != SeededNumberDictionary::kNotFound) {
|
| - Handle<Object> element(dictionary->ValueAt(entry), isolate);
|
| - PropertyDetails details = dictionary->DetailsAt(entry);
|
| - DCHECK(details.IsConfigurable() || !details.IsReadOnly() ||
|
| - element->IsTheHole());
|
| - dictionary->UpdateMaxNumberKey(index);
|
| + DCHECK_NE(SeededNumberDictionary::kNotFound, entry);
|
|
|
| - details = PropertyDetails(attributes, DATA, details.dictionary_index(),
|
| - PropertyCellType::kNoCell);
|
| - dictionary->DetailsAtPut(entry, details);
|
| + PropertyDetails details = dictionary->DetailsAt(entry);
|
| + details = PropertyDetails(attributes, DATA, details.dictionary_index(),
|
| + PropertyCellType::kNoCell);
|
| + dictionary->DetailsAtPut(entry, details);
|
|
|
| - // Elements of the arguments object in slow mode might be slow aliases.
|
| - if (is_arguments && element->IsAliasedArgumentsEntry()) {
|
| + // Elements of the arguments object in slow mode might be slow aliases.
|
| + if (is_arguments) {
|
| + Handle<Object> element(dictionary->ValueAt(entry), isolate);
|
| + if (element->IsAliasedArgumentsEntry()) {
|
| Handle<AliasedArgumentsEntry> entry =
|
| Handle<AliasedArgumentsEntry>::cast(element);
|
| Handle<Context> context(Context::cast(elements->get(0)));
|
| @@ -12620,21 +12638,46 @@ void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| // For elements that are still writable we keep slow aliasing.
|
| if (!details.IsReadOnly()) value = element;
|
| }
|
| - dictionary->ValueAtPut(entry, *value);
|
| - } else {
|
| - DCHECK(object->map()->is_extensible());
|
| - 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;
|
| + }
|
| +
|
| + dictionary->ValueAtPut(entry, *value);
|
| +}
|
| +
|
| +
|
| +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());
|
| +
|
| + Handle<SeededNumberDictionary> dictionary(
|
| + is_arguments ? SeededNumberDictionary::cast(elements->get(1))
|
| + : SeededNumberDictionary::cast(*elements));
|
| +
|
| +#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.
|
| @@ -12675,7 +12718,8 @@ void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| }
|
| }
|
|
|
| -void JSObject::SetFastDoubleElement(Handle<JSObject> object, uint32_t index,
|
| +
|
| +void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index,
|
| Handle<Object> value) {
|
| DCHECK(object->HasFastDoubleElements());
|
|
|
| @@ -12697,15 +12741,14 @@ void JSObject::SetFastDoubleElement(Handle<JSObject> object, uint32_t index,
|
| if (!value->IsNumber()) {
|
| SetFastElementsCapacityAndLength(object, elms_length, length,
|
| kDontAllowSmiElements);
|
| - SetFastElement(object, index, value);
|
| + AddFastElement(object, index, value);
|
| return;
|
| }
|
|
|
| // If the array is growing, and it's not growth by a single element at the
|
| // end, make sure that the ElementsKind is HOLEY.
|
| - ElementsKind elements_kind = object->GetElementsKind();
|
| - if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
|
| - ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
|
| + if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) {
|
| + ElementsKind transitioned_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
|
| TransitionElementsKind(object, transitioned_kind);
|
| }
|
|
|
| @@ -12746,7 +12789,7 @@ void JSObject::SetFastDoubleElement(Handle<JSObject> object, uint32_t index,
|
|
|
| NormalizeElements(object);
|
| DCHECK(object->HasDictionaryElements());
|
| - SetDictionaryElement(object, index, value, NONE);
|
| + AddDictionaryElement(object, index, value, NONE);
|
| }
|
|
|
|
|
| @@ -12788,18 +12831,18 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver,
|
| case FAST_ELEMENTS:
|
| case FAST_HOLEY_SMI_ELEMENTS:
|
| case FAST_HOLEY_ELEMENTS:
|
| - SetFastElement(receiver, index, value);
|
| + AddFastElement(receiver, index, value);
|
| break;
|
| case FAST_DOUBLE_ELEMENTS:
|
| case FAST_HOLEY_DOUBLE_ELEMENTS:
|
| - SetFastDoubleElement(receiver, index, value);
|
| + AddFastDoubleElement(receiver, index, value);
|
| break;
|
|
|
| case DICTIONARY_ELEMENTS:
|
| - SetDictionaryElement(receiver, index, value, attributes);
|
| + AddDictionaryElement(receiver, index, value, attributes);
|
| break;
|
| case SLOPPY_ARGUMENTS_ELEMENTS:
|
| - SetSloppyArgumentsElement(receiver, index, value, attributes);
|
| + AddSloppyArgumentsElement(receiver, index, value, attributes);
|
| break;
|
|
|
| // Elements cannot be added to typed arrays.
|
|
|