| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 29af1d83373193db4face20c934c39f939a276be..d4a5d3a90e591e13967cb3bdef1708250dac588b 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -575,8 +575,6 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
|
|
|
|
|
| static bool FindAllCanReadHolder(LookupIterator* it) {
|
| - it->skip_interceptor();
|
| - it->skip_access_check();
|
| for (; it->IsFound(); it->Next()) {
|
| if (it->state() == LookupIterator::PROPERTY &&
|
| it->HasProperty() &&
|
| @@ -618,8 +616,6 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
|
|
|
|
|
| static bool FindAllCanWriteHolder(LookupIterator* it) {
|
| - it->skip_interceptor();
|
| - it->skip_access_check();
|
| for (; it->IsFound(); it->Next()) {
|
| if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
|
| it->property_kind() == LookupIterator::ACCESSOR) {
|
| @@ -675,21 +671,6 @@ Handle<Object> JSObject::GetNormalizedProperty(Handle<JSObject> object,
|
|
|
|
|
| void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
| - const LookupResult* result,
|
| - Handle<Object> value) {
|
| - DCHECK(!object->HasFastProperties());
|
| - NameDictionary* property_dictionary = object->property_dictionary();
|
| - if (object->IsGlobalObject()) {
|
| - Handle<PropertyCell> cell(PropertyCell::cast(
|
| - property_dictionary->ValueAt(result->GetDictionaryEntry())));
|
| - PropertyCell::SetValueInferType(cell, value);
|
| - } else {
|
| - property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
|
| - }
|
| -}
|
| -
|
| -
|
| -void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
| Handle<Name> name,
|
| Handle<Object> value,
|
| PropertyDetails details) {
|
| @@ -1823,37 +1804,6 @@ MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
|
| }
|
|
|
|
|
| -void JSObject::AddFastProperty(Handle<JSObject> object,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - PropertyAttributes attributes,
|
| - StoreFromKeyed store_mode,
|
| - TransitionFlag flag) {
|
| - DCHECK(!object->IsJSGlobalProxy());
|
| -
|
| - MaybeHandle<Map> maybe_map;
|
| - if (value->IsJSFunction()) {
|
| - maybe_map = Map::CopyWithConstant(
|
| - handle(object->map()), name, value, attributes, flag);
|
| - } else if (!object->map()->TooManyFastProperties(store_mode)) {
|
| - Isolate* isolate = object->GetIsolate();
|
| - Representation representation = value->OptimalRepresentation();
|
| - maybe_map = Map::CopyWithField(
|
| - handle(object->map(), isolate), name,
|
| - value->OptimalType(isolate, representation),
|
| - attributes, representation, flag);
|
| - }
|
| -
|
| - Handle<Map> new_map;
|
| - if (!maybe_map.ToHandle(&new_map)) {
|
| - NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| - return;
|
| - }
|
| -
|
| - JSObject::MigrateToNewProperty(object, new_map, value);
|
| -}
|
| -
|
| -
|
| void JSObject::AddSlowProperty(Handle<JSObject> object,
|
| Handle<Name> name,
|
| Handle<Object> value,
|
| @@ -1886,45 +1836,6 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
|
| }
|
|
|
|
|
| -MaybeHandle<Object> JSObject::AddPropertyInternal(
|
| - Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
|
| - PropertyAttributes attributes, JSReceiver::StoreFromKeyed store_mode,
|
| - ExtensibilityCheck extensibility_check, TransitionFlag transition_flag) {
|
| - DCHECK(!object->IsJSGlobalProxy());
|
| - Isolate* isolate = object->GetIsolate();
|
| -
|
| - if (!name->IsUniqueName()) {
|
| - name = isolate->factory()->InternalizeString(
|
| - Handle<String>::cast(name));
|
| - }
|
| -
|
| - if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
|
| - !object->map()->is_extensible()) {
|
| - Handle<Object> args[1] = {name};
|
| - Handle<Object> error = isolate->factory()->NewTypeError(
|
| - "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
|
| - return isolate->Throw<Object>(error);
|
| - }
|
| -
|
| - if (object->HasFastProperties()) {
|
| - AddFastProperty(object, name, value, attributes, store_mode,
|
| - transition_flag);
|
| - }
|
| -
|
| - if (!object->HasFastProperties()) {
|
| - AddSlowProperty(object, name, value, attributes);
|
| - }
|
| -
|
| - if (object->map()->is_observed() &&
|
| - *name != isolate->heap()->hidden_string()) {
|
| - Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - EnqueueChangeRecord(object, "add", name, old_value);
|
| - }
|
| -
|
| - return value;
|
| -}
|
| -
|
| -
|
| Context* JSObject::GetCreationContext() {
|
| Object* constructor = this->map()->constructor();
|
| JSFunction* function;
|
| @@ -1959,23 +1870,6 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
|
| }
|
|
|
|
|
| -static void ReplaceSlowProperty(Handle<JSObject> object,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| - NameDictionary* dictionary = object->property_dictionary();
|
| - int old_index = dictionary->FindEntry(name);
|
| - int new_enumeration_index = 0; // 0 means "Use the next available index."
|
| - if (old_index != -1) {
|
| - // All calls to ReplaceSlowProperty have had all transitions removed.
|
| - new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
|
| - }
|
| -
|
| - PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
|
| - JSObject::SetNormalizedProperty(object, name, value, new_details);
|
| -}
|
| -
|
| -
|
| const char* Representation::Mnemonic() const {
|
| switch (kind_) {
|
| case kNone: return "v";
|
| @@ -3029,7 +2923,8 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
|
| if (done) break;
|
| }
|
|
|
| - return AddDataProperty(it, value, NONE, strict_mode, store_mode);
|
| + return AddDataProperty(it, value, NONE, strict_mode, store_mode,
|
| + PERFORM_EXTENSIBILITY_CHECK);
|
| }
|
|
|
|
|
| @@ -3084,7 +2979,8 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
|
| Handle<Object> value,
|
| PropertyAttributes attributes,
|
| StrictMode strict_mode,
|
| - StoreFromKeyed store_mode) {
|
| + StoreFromKeyed store_mode,
|
| + ExtensibilityCheck check) {
|
| DCHECK(!it->GetReceiver()->IsJSProxy());
|
| if (!it->GetReceiver()->IsJSObject()) {
|
| // TODO(verwaest): Throw a TypeError with a more specific message.
|
| @@ -3102,7 +2998,8 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
|
| Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| }
|
|
|
| - if (!receiver->map()->is_extensible()) {
|
| + if (check == PERFORM_EXTENSIBILITY_CHECK &&
|
| + !receiver->map()->is_extensible()) {
|
| if (strict_mode == SLOPPY) return value;
|
|
|
| Handle<Object> args[1] = {it->name()};
|
| @@ -3943,45 +3840,6 @@ bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
|
| }
|
|
|
|
|
| -MaybeHandle<Object> JSObject::SetPropertyUsingTransition(
|
| - Handle<JSObject> object,
|
| - LookupResult* lookup,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| - Handle<Map> transition_map(lookup->GetTransitionTarget());
|
| - int descriptor = transition_map->LastAdded();
|
| -
|
| - Handle<DescriptorArray> descriptors(transition_map->instance_descriptors());
|
| - PropertyDetails details = descriptors->GetDetails(descriptor);
|
| -
|
| - if (details.type() == CALLBACKS || attributes != details.attributes()) {
|
| - // AddPropertyInternal will either normalize the object, or create a new
|
| - // fast copy of the map. If we get a fast copy of the map, all field
|
| - // representations will be tagged since the transition is omitted.
|
| - return JSObject::AddPropertyInternal(
|
| - object, name, value, attributes,
|
| - JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
|
| - JSReceiver::OMIT_EXTENSIBILITY_CHECK, OMIT_TRANSITION);
|
| - }
|
| -
|
| - // Keep the target CONSTANT if the same value is stored.
|
| - // TODO(verwaest): Also support keeping the placeholder
|
| - // (value->IsUninitialized) as constant.
|
| - if (!lookup->CanHoldValue(value)) {
|
| - Representation field_representation = value->OptimalRepresentation();
|
| - Handle<HeapType> field_type = value->OptimalType(
|
| - lookup->isolate(), field_representation);
|
| - transition_map = Map::GeneralizeRepresentation(
|
| - transition_map, descriptor,
|
| - field_representation, field_type, FORCE_FIELD);
|
| - }
|
| -
|
| - JSObject::MigrateToNewProperty(object, transition_map, value);
|
| - return value;
|
| -}
|
| -
|
| -
|
| void JSObject::MigrateToNewProperty(Handle<JSObject> object,
|
| Handle<Map> map,
|
| Handle<Object> value) {
|
| @@ -4012,65 +3870,6 @@ void JSObject::WriteToField(int descriptor, Object* value) {
|
| }
|
|
|
|
|
| -void JSObject::SetPropertyToField(LookupResult* lookup, Handle<Object> value) {
|
| - if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) {
|
| - Representation field_representation = value->OptimalRepresentation();
|
| - Handle<HeapType> field_type = value->OptimalType(
|
| - lookup->isolate(), field_representation);
|
| - JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
|
| - lookup->GetDescriptorIndex(),
|
| - field_representation, field_type);
|
| - }
|
| - lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value);
|
| -}
|
| -
|
| -
|
| -void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| - Handle<JSObject> object(lookup->holder());
|
| - if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) {
|
| - JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| - } else if (object->map()->is_prototype_map()) {
|
| - JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
|
| - }
|
| -
|
| - if (!object->HasFastProperties()) {
|
| - ReplaceSlowProperty(object, name, value, attributes);
|
| - ReoptimizeIfPrototype(object);
|
| - return;
|
| - }
|
| -
|
| - int descriptor_index = lookup->GetDescriptorIndex();
|
| - if (lookup->GetAttributes() == attributes) {
|
| - JSObject::GeneralizeFieldRepresentation(object, descriptor_index,
|
| - Representation::Tagged(),
|
| - HeapType::Any(lookup->isolate()));
|
| - } else {
|
| - Handle<Map> old_map(object->map());
|
| - Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
|
| - descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
|
| - JSObject::MigrateToMap(object, new_map);
|
| - }
|
| -
|
| - object->WriteToField(descriptor_index, *value);
|
| -}
|
| -
|
| -
|
| -void JSObject::SetPropertyToFieldWithAttributes(LookupResult* lookup,
|
| - Handle<Name> name,
|
| - Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| - if (lookup->GetAttributes() == attributes) {
|
| - if (value->IsUninitialized()) return;
|
| - SetPropertyToField(lookup, value);
|
| - } else {
|
| - ConvertAndSetOwnProperty(lookup, name, value, attributes);
|
| - }
|
| -}
|
| -
|
| -
|
| void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
|
| Handle<Object> value,
|
| PropertyAttributes attributes) {
|
| @@ -4100,156 +3899,123 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| StoreFromKeyed store_from_keyed,
|
| ExecutableAccessorInfoHandling handling) {
|
| DCHECK(!value->IsTheHole());
|
| - Isolate* isolate = object->GetIsolate();
|
| -
|
| - // Make sure that the top context does not change when doing callbacks or
|
| - // interceptor calls.
|
| - AssertNoContextChange ncc(isolate);
|
| + LookupIterator it(object, name, LookupIterator::CHECK_HIDDEN_ACCESS);
|
| + bool is_observed = object->map()->is_observed() &&
|
| + *name != it.isolate()->heap()->hidden_string();
|
| + for (; it.IsFound(); it.Next()) {
|
| + switch (it.state()) {
|
| + case LookupIterator::NOT_FOUND:
|
| + case LookupIterator::JSPROXY:
|
| + case LookupIterator::INTERCEPTOR:
|
| + UNREACHABLE();
|
|
|
| - LookupResult lookup(isolate);
|
| - object->LookupOwn(name, &lookup, true);
|
| - if (!lookup.IsFound()) {
|
| - object->map()->LookupTransition(*object, *name, &lookup);
|
| - }
|
| + case LookupIterator::ACCESS_CHECK:
|
| + if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
|
| + return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
|
| + }
|
| + break;
|
|
|
| - // Check access rights if needed.
|
| - if (object->IsAccessCheckNeeded()) {
|
| - if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
|
| - LookupIterator it(object, name, LookupIterator::CHECK_OWN);
|
| - return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
|
| - }
|
| - }
|
| + case LookupIterator::PROPERTY: {
|
| + if (!it.HasProperty()) break;
|
| + if (it.HolderIsNonGlobalHiddenPrototype()) break;
|
| + PropertyDetails details = it.property_details();
|
| + Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
| + switch (it.property_kind()) {
|
| + case LookupIterator::ACCESSOR: {
|
| + // Ensure the context isn't changed after calling into accessors.
|
| + AssertNoContextChange ncc(it.isolate());
|
|
|
| - if (object->IsJSGlobalProxy()) {
|
| - PrototypeIterator iter(isolate, object);
|
| - if (iter.IsAtEnd()) return value;
|
| - DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
|
| - return SetOwnPropertyIgnoreAttributes(
|
| - Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
|
| - value, attributes, extensibility_check);
|
| - }
|
| + Handle<Object> accessors = it.GetAccessors();
|
|
|
| - if (lookup.IsInterceptor() ||
|
| - (lookup.IsDescriptorOrDictionary() && lookup.type() == CALLBACKS)) {
|
| - object->LookupOwnRealNamedProperty(name, &lookup);
|
| - }
|
| + if (is_observed && accessors->IsAccessorInfo()) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + it.isolate(), old_value,
|
| + GetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
| + it.GetHolder<JSObject>(), accessors),
|
| + Object);
|
| + }
|
|
|
| - // Check for accessor in prototype chain removed here in clone.
|
| - if (!lookup.IsFound()) {
|
| - object->map()->LookupTransition(*object, *name, &lookup);
|
| - TransitionFlag flag = lookup.IsFound()
|
| - ? OMIT_TRANSITION : INSERT_TRANSITION;
|
| - // Neither properties nor transitions found.
|
| - return AddPropertyInternal(object, name, value, attributes,
|
| - store_from_keyed, extensibility_check, flag);
|
| - }
|
| + // Special handling for ExecutableAccessorInfo, which behaves like a
|
| + // data property.
|
| + if (handling == DONT_FORCE_FIELD &&
|
| + accessors->IsExecutableAccessorInfo()) {
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + it.isolate(), result,
|
| + JSObject::SetPropertyWithAccessor(
|
| + it.GetReceiver(), it.name(), value,
|
| + it.GetHolder<JSObject>(), accessors, STRICT),
|
| + Object);
|
| + DCHECK(result->SameValue(*value));
|
| +
|
| + if (details.attributes() == attributes) {
|
| + // Regular property update if the attributes match.
|
| + if (is_observed && !old_value->SameValue(*value)) {
|
| + // If we are setting the prototype of a function and are
|
| + // observed, don't send change records because the prototype
|
| + // handles that itself.
|
| + if (!object->IsJSFunction() ||
|
| + !Name::Equals(it.isolate()->factory()->prototype_string(),
|
| + name) ||
|
| + !Handle<JSFunction>::cast(object)
|
| + ->should_have_prototype()) {
|
| + EnqueueChangeRecord(object, "update", name, old_value);
|
| + }
|
| + }
|
| + return value;
|
| + }
|
|
|
| - Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - PropertyAttributes old_attributes = ABSENT;
|
| - bool is_observed = object->map()->is_observed() &&
|
| - *name != isolate->heap()->hidden_string();
|
| - if (is_observed && lookup.IsProperty()) {
|
| - if (lookup.IsDataProperty()) {
|
| - old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
|
| - }
|
| - old_attributes = lookup.GetAttributes();
|
| - }
|
| + // Reconfigure the accessor if attributes mismatch.
|
| + Handle<ExecutableAccessorInfo> new_data =
|
| + Accessors::CloneAccessor(
|
| + it.isolate(),
|
| + Handle<ExecutableAccessorInfo>::cast(accessors));
|
| + new_data->set_property_attributes(attributes);
|
| + // By clearing the setter we don't have to introduce a lookup to
|
| + // the setter, simply make it unavailable to reflect the
|
| + // attributes.
|
| + if (attributes & READ_ONLY) new_data->clear_setter();
|
| + SetPropertyCallback(object, name, new_data, attributes);
|
| + if (is_observed) {
|
| + if (old_value->SameValue(*value)) {
|
| + old_value = it.isolate()->factory()->the_hole_value();
|
| + }
|
| + EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| + }
|
| + return value;
|
| + }
|
|
|
| - bool executed_set_prototype = false;
|
| + // Regular accessor. Reconfigure to data property.
|
| + break;
|
| + }
|
|
|
| - // Check of IsReadOnly removed from here in clone.
|
| - if (lookup.IsTransition()) {
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, result,
|
| - SetPropertyUsingTransition(
|
| - handle(lookup.holder()), &lookup, name, value, attributes),
|
| - Object);
|
| - } else {
|
| - switch (lookup.type()) {
|
| - case NORMAL:
|
| - ReplaceSlowProperty(object, name, value, attributes);
|
| - break;
|
| - case FIELD:
|
| - SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
|
| - break;
|
| - case CONSTANT:
|
| - // Only replace the constant if necessary.
|
| - if (lookup.GetAttributes() != attributes ||
|
| - *value != lookup.GetConstant()) {
|
| - SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
|
| - }
|
| - break;
|
| - case CALLBACKS:
|
| - {
|
| - Handle<Object> callback(lookup.GetCallbackObject(), isolate);
|
| - if (callback->IsExecutableAccessorInfo() &&
|
| - handling == DONT_FORCE_FIELD) {
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, result, JSObject::SetPropertyWithAccessor(
|
| - object, name, value, handle(lookup.holder()),
|
| - callback, STRICT),
|
| - Object);
|
| -
|
| - if (attributes != lookup.GetAttributes()) {
|
| - Handle<ExecutableAccessorInfo> new_data =
|
| - Accessors::CloneAccessor(
|
| - isolate, Handle<ExecutableAccessorInfo>::cast(callback));
|
| - new_data->set_property_attributes(attributes);
|
| - if (attributes & READ_ONLY) {
|
| - // This way we don't have to introduce a lookup to the setter,
|
| - // simply make it unavailable to reflect the attributes.
|
| - new_data->clear_setter();
|
| + case LookupIterator::DATA:
|
| + // Regular property update if the attributes match.
|
| + if (details.attributes() == attributes) {
|
| + return SetDataProperty(&it, value);
|
| }
|
| + // Reconfigure the data property if the attributes mismatch.
|
| + if (is_observed) old_value = it.GetDataValue();
|
| + }
|
|
|
| - SetPropertyCallback(object, name, new_data, attributes);
|
| - }
|
| - if (is_observed) {
|
| - // If we are setting the prototype of a function and are observed,
|
| - // don't send change records because the prototype handles that
|
| - // itself.
|
| - executed_set_prototype = object->IsJSFunction() &&
|
| - String::Equals(isolate->factory()->prototype_string(),
|
| - Handle<String>::cast(name)) &&
|
| - Handle<JSFunction>::cast(object)->should_have_prototype();
|
| + it.ReconfigureDataProperty(value, attributes);
|
| + it.PrepareForDataProperty(value);
|
| + it.WriteDataValue(value);
|
| +
|
| + if (is_observed) {
|
| + if (old_value->SameValue(*value)) {
|
| + old_value = it.isolate()->factory()->the_hole_value();
|
| }
|
| - } else {
|
| - ConvertAndSetOwnProperty(&lookup, name, value, attributes);
|
| + EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| }
|
| - break;
|
| - }
|
| - case NONEXISTENT:
|
| - case HANDLER:
|
| - case INTERCEPTOR:
|
| - UNREACHABLE();
|
| - }
|
| - }
|
|
|
| - if (is_observed && !executed_set_prototype) {
|
| - if (lookup.IsTransition()) {
|
| - EnqueueChangeRecord(object, "add", name, old_value);
|
| - } else if (old_value->IsTheHole()) {
|
| - EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| - } else {
|
| - LookupResult new_lookup(isolate);
|
| - object->LookupOwn(name, &new_lookup, true);
|
| - bool value_changed = false;
|
| - if (new_lookup.IsDataProperty()) {
|
| - Handle<Object> new_value =
|
| - Object::GetPropertyOrElement(object, name).ToHandleChecked();
|
| - value_changed = !old_value->SameValue(*new_value);
|
| - }
|
| - if (new_lookup.GetAttributes() != old_attributes) {
|
| - if (!value_changed) old_value = isolate->factory()->the_hole_value();
|
| - EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| - } else if (value_changed) {
|
| - EnqueueChangeRecord(object, "update", name, old_value);
|
| + return value;
|
| }
|
| }
|
| }
|
|
|
| - return value;
|
| + return AddDataProperty(&it, value, attributes, STRICT, store_from_keyed,
|
| + extensibility_check);
|
| }
|
|
|
|
|
| @@ -7394,6 +7160,18 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
|
| }
|
|
|
|
|
| +Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
|
| + PropertyAttributes attributes) {
|
| + // Dictionaries have to be reconfigured in-place.
|
| + DCHECK(!map->is_dictionary_map());
|
| +
|
| + // For now, give up on transitioning and just create a unique map.
|
| + // TODO(verwaest/ishell): Cache transitions with different attributes.
|
| + return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
|
| + attributes, "attributes mismatch");
|
| +}
|
| +
|
| +
|
| Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
|
| Descriptor* descriptor,
|
| TransitionFlag flag) {
|
|
|