| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 498479d8114a935846192e30d27c06a8c73fa307..7db464e8c901207c569be2ef6daf8929f924371b 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -4219,7 +4219,8 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| ValueType value_type,
|
| StoreMode mode,
|
| ExtensibilityCheck extensibility_check,
|
| - StoreFromKeyed store_from_keyed) {
|
| + StoreFromKeyed store_from_keyed,
|
| + ExecutableAccessorInfoHandling handling) {
|
| Isolate* isolate = object->GetIsolate();
|
|
|
| // Make sure that the top context does not change when doing callbacks or
|
| @@ -4274,6 +4275,8 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| old_attributes = lookup.GetAttributes();
|
| }
|
|
|
| + bool executed_set_prototype = false;
|
| +
|
| // Check of IsReadOnly removed from here in clone.
|
| if (lookup.IsTransition()) {
|
| Handle<Object> result;
|
| @@ -4297,9 +4300,11 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
|
| }
|
| break;
|
| - case CALLBACKS: {
|
| + case CALLBACKS:
|
| + {
|
| Handle<Object> callback(lookup.GetCallbackObject(), isolate);
|
| - if (callback->IsExecutableAccessorInfo()) {
|
| + if (callback->IsExecutableAccessorInfo() &&
|
| + handling == DONT_FORCE_FIELD) {
|
| Handle<Object> result;
|
| ASSIGN_RETURN_ON_EXCEPTION(
|
| isolate, result,
|
| @@ -4311,29 +4316,31 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| STRICT),
|
| Object);
|
|
|
| - if (attributes == lookup.GetAttributes()) return result;
|
| -
|
| - Handle<ExecutableAccessorInfo> new_data =
|
| - Accessors::CloneAccessor(
|
| - isolate, Handle<ExecutableAccessorInfo>::cast(callback));
|
| - new_data->set_property_attributes(attributes);
|
| - // This way 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 (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();
|
| + }
|
|
|
| + SetPropertyCallback(object, name, new_data, attributes);
|
| + }
|
| if (is_observed) {
|
| - Handle<Object> new_value =
|
| - Object::GetPropertyOrElement(object, name).ToHandleChecked();
|
| - if (old_value->SameValue(*new_value)) {
|
| - old_value = isolate->factory()->the_hole_value();
|
| - }
|
| - EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| + // 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();
|
| }
|
| -
|
| - return result;
|
| + } else {
|
| + ConvertAndSetOwnProperty(&lookup, name, value, attributes);
|
| }
|
| - ConvertAndSetOwnProperty(&lookup, name, value, attributes);
|
| break;
|
| }
|
| case NONEXISTENT:
|
| @@ -4343,7 +4350,7 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| }
|
| }
|
|
|
| - if (is_observed) {
|
| + if (is_observed && !executed_set_prototype) {
|
| if (lookup.IsTransition()) {
|
| EnqueueChangeRecord(object, "add", name, old_value);
|
| } else if (old_value->IsTheHole()) {
|
|
|