| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index ea9052ab07734e22606efe56aeb550b6b2e869ab..d3c8b625c9cb52f17727b7a2a0e870a81b6cfb9d 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -110,6 +110,7 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
|
| switch (it->state()) {
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
| case LookupIterator::JSPROXY:
|
| return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
|
| @@ -124,18 +125,12 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
|
| case LookupIterator::ACCESS_CHECK:
|
| if (it->HasAccess(v8::ACCESS_GET)) break;
|
| return JSObject::GetPropertyWithFailedAccessCheck(it);
|
| - case LookupIterator::PROPERTY:
|
| - if (it->HasProperty()) {
|
| - switch (it->property_kind()) {
|
| - case LookupIterator::ACCESSOR:
|
| - return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
| - it->GetHolder<JSObject>(),
|
| - it->GetAccessors());
|
| - case LookupIterator::DATA:
|
| - return it->GetDataValue();
|
| - }
|
| - }
|
| - break;
|
| + case LookupIterator::ACCESSOR:
|
| + return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
| + it->GetHolder<JSObject>(),
|
| + it->GetAccessors());
|
| + case LookupIterator::DATA:
|
| + return it->GetDataValue();
|
| }
|
| }
|
| return it->factory()->undefined_value();
|
| @@ -156,6 +151,7 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
|
| case LookupIterator::INTERCEPTOR:
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
| case LookupIterator::ACCESS_CHECK:
|
| if (it->HasAccess(v8::ACCESS_GET)) continue;
|
| @@ -163,18 +159,14 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
|
| case LookupIterator::JSPROXY:
|
| it->NotFound();
|
| return it->isolate()->factory()->undefined_value();
|
| - case LookupIterator::PROPERTY:
|
| - if (!it->HasProperty()) continue;
|
| - switch (it->property_kind()) {
|
| - case LookupIterator::DATA:
|
| - return it->GetDataValue();
|
| - case LookupIterator::ACCESSOR:
|
| - // TODO(verwaest): For now this doesn't call into
|
| - // ExecutableAccessorInfo, since clients don't need it. Update once
|
| - // relevant.
|
| - it->NotFound();
|
| - return it->isolate()->factory()->undefined_value();
|
| - }
|
| + case LookupIterator::ACCESSOR:
|
| + // TODO(verwaest): For now this doesn't call into
|
| + // ExecutableAccessorInfo, since clients don't need it. Update once
|
| + // relevant.
|
| + it->NotFound();
|
| + return it->isolate()->factory()->undefined_value();
|
| + case LookupIterator::DATA:
|
| + return it->GetDataValue();
|
| }
|
| }
|
| return it->isolate()->factory()->undefined_value();
|
| @@ -582,9 +574,7 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
|
|
|
| static bool FindAllCanReadHolder(LookupIterator* it) {
|
| for (; it->IsFound(); it->Next()) {
|
| - if (it->state() == LookupIterator::PROPERTY &&
|
| - it->HasProperty() &&
|
| - it->property_kind() == LookupIterator::ACCESSOR) {
|
| + if (it->state() == LookupIterator::ACCESSOR) {
|
| Handle<Object> accessors = it->GetAccessors();
|
| if (accessors->IsAccessorInfo()) {
|
| if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
|
| @@ -623,8 +613,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
|
|
|
| static bool FindAllCanWriteHolder(LookupIterator* it) {
|
| for (; it->IsFound(); it->Next()) {
|
| - if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
|
| - it->property_kind() == LookupIterator::ACCESSOR) {
|
| + if (it->state() == LookupIterator::ACCESSOR) {
|
| Handle<Object> accessors = it->GetAccessors();
|
| if (accessors->IsAccessorInfo()) {
|
| if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
|
| @@ -2830,6 +2819,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
|
| for (; it->IsFound(); it->Next()) {
|
| switch (it->state()) {
|
| case LookupIterator::NOT_FOUND:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
|
|
| case LookupIterator::ACCESS_CHECK:
|
| @@ -2875,24 +2865,25 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
|
| }
|
| break;
|
|
|
| - case LookupIterator::PROPERTY:
|
| - if (!it->HasProperty()) break;
|
| + case LookupIterator::ACCESSOR:
|
| if (it->property_details().IsReadOnly()) {
|
| return WriteToReadOnlyProperty(it, value, strict_mode);
|
| }
|
| - switch (it->property_kind()) {
|
| - case LookupIterator::ACCESSOR:
|
| - if (it->HolderIsReceiverOrHiddenPrototype() ||
|
| - !it->GetAccessors()->IsDeclaredAccessorInfo()) {
|
| - return SetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
| - value, it->GetHolder<JSObject>(),
|
| - it->GetAccessors(), strict_mode);
|
| - }
|
| - break;
|
| - case LookupIterator::DATA:
|
| - if (it->HolderIsReceiverOrHiddenPrototype()) {
|
| - return SetDataProperty(it, value);
|
| - }
|
| + if (it->HolderIsReceiverOrHiddenPrototype() ||
|
| + !it->GetAccessors()->IsDeclaredAccessorInfo()) {
|
| + return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
|
| + it->GetHolder<JSObject>(),
|
| + it->GetAccessors(), strict_mode);
|
| + }
|
| + done = true;
|
| + break;
|
| +
|
| + case LookupIterator::DATA:
|
| + if (it->property_details().IsReadOnly()) {
|
| + return WriteToReadOnlyProperty(it, value, strict_mode);
|
| + }
|
| + if (it->HolderIsReceiverOrHiddenPrototype()) {
|
| + return SetDataProperty(it, value);
|
| }
|
| done = true;
|
| break;
|
| @@ -3825,6 +3816,7 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| case LookupIterator::JSPROXY:
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
|
|
| case LookupIterator::ACCESS_CHECK:
|
| @@ -3833,87 +3825,92 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| }
|
| break;
|
|
|
| - case LookupIterator::PROPERTY: {
|
| - if (!it.HasProperty()) break;
|
| + case LookupIterator::ACCESSOR: {
|
| 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());
|
| + // Ensure the context isn't changed after calling into accessors.
|
| + AssertNoContextChange ncc(it.isolate());
|
|
|
| - Handle<Object> accessors = it.GetAccessors();
|
| + Handle<Object> accessors = it.GetAccessors();
|
|
|
| - if (is_observed && accessors->IsAccessorInfo()) {
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - it.isolate(), old_value,
|
| - GetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
| - it.GetHolder<JSObject>(), accessors),
|
| - Object);
|
| - }
|
| + if (is_observed && accessors->IsAccessorInfo()) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + it.isolate(), old_value,
|
| + GetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
| + it.GetHolder<JSObject>(), accessors),
|
| + Object);
|
| + }
|
|
|
| - // 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;
|
| + // 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;
|
| + }
|
|
|
| - // 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;
|
| + // 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;
|
| + }
|
|
|
| - // Regular accessor. Reconfigure to data property.
|
| - break;
|
| + 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();
|
| }
|
| + EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
| + }
|
|
|
| - 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();
|
| + return value;
|
| + }
|
| +
|
| + case LookupIterator::DATA: {
|
| + PropertyDetails details = it.property_details();
|
| + Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
| + // 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();
|
|
|
| it.ReconfigureDataProperty(value, attributes);
|
| it.PrepareForDataProperty(value);
|
| @@ -3996,6 +3993,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
| for (; it->IsFound(); it->Next()) {
|
| switch (it->state()) {
|
| case LookupIterator::NOT_FOUND:
|
| + case LookupIterator::UNKNOWN:
|
| case LookupIterator::TRANSITION:
|
| UNREACHABLE();
|
| case LookupIterator::JSPROXY:
|
| @@ -4012,11 +4010,9 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
| case LookupIterator::ACCESS_CHECK:
|
| if (it->HasAccess(v8::ACCESS_HAS)) break;
|
| return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
|
| - case LookupIterator::PROPERTY:
|
| - if (it->HasProperty()) {
|
| - return maybe(it->property_details().attributes());
|
| - }
|
| - break;
|
| + case LookupIterator::ACCESSOR:
|
| + case LookupIterator::DATA:
|
| + return maybe(it->property_details().attributes());
|
| }
|
| }
|
| return maybe(ABSENT);
|
| @@ -4693,7 +4689,7 @@ bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
|
| Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
|
| LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
| - return it.IsFound() && it.HasProperty();
|
| + return it.IsFound();
|
| }
|
|
|
|
|
| @@ -4726,10 +4722,10 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
|
| LookupIterator it(handle(this), isolate->factory()->hidden_string(),
|
| LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
| - if (it.IsFound() && it.HasProperty()) {
|
| - DCHECK_EQ(LookupIterator::DATA, it.property_kind());
|
| + if (it.state() == LookupIterator::DATA) {
|
| return *it.GetDataValue();
|
| }
|
| + DCHECK(!it.IsFound());
|
| return GetHeap()->undefined_value();
|
| }
|
| }
|
| @@ -4926,12 +4922,14 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
|
|
| bool is_observed = object->map()->is_observed() &&
|
| *name != it.isolate()->heap()->hidden_string();
|
| + Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
|
|
| for (; it.IsFound(); it.Next()) {
|
| switch (it.state()) {
|
| case LookupIterator::JSPROXY:
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
| case LookupIterator::ACCESS_CHECK:
|
| if (it.HasAccess(v8::ACCESS_DELETE)) break;
|
| @@ -4949,8 +4947,12 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| if (it.isolate()->has_pending_exception()) return maybe_result;
|
| break;
|
| }
|
| - case LookupIterator::PROPERTY: {
|
| - if (!it.HasProperty()) continue;
|
| + case LookupIterator::DATA:
|
| + if (is_observed) {
|
| + old_value = it.GetDataValue();
|
| + }
|
| + // Fall through.
|
| + case LookupIterator::ACCESSOR: {
|
| if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
|
| // Fail if the property is not configurable.
|
| if (delete_mode == STRICT_DELETION) {
|
| @@ -4963,17 +4965,6 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| return it.isolate()->factory()->false_value();
|
| }
|
|
|
| - Handle<Object> old_value;
|
| - if (is_observed) {
|
| - switch (it.property_kind()) {
|
| - case LookupIterator::ACCESSOR:
|
| - old_value = it.isolate()->factory()->the_hole_value();
|
| - break;
|
| - case LookupIterator::DATA:
|
| - old_value = it.GetDataValue();
|
| - }
|
| - }
|
| -
|
| PropertyNormalizationMode mode = object->map()->is_prototype_map()
|
| ? KEEP_INOBJECT_PROPERTIES
|
| : CLEAR_INOBJECT_PROPERTIES;
|
| @@ -6150,7 +6141,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
| LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
| CHECK(GetPropertyAttributes(&it).has_value);
|
| preexists = it.IsFound();
|
| - if (preexists && (it.property_kind() == LookupIterator::DATA ||
|
| + if (preexists && (it.state() == LookupIterator::DATA ||
|
| it.GetAccessors()->IsAccessorInfo())) {
|
| old_value = GetProperty(&it).ToHandleChecked();
|
| }
|
| @@ -6314,6 +6305,7 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
| case LookupIterator::INTERCEPTOR:
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| + case LookupIterator::UNKNOWN:
|
| UNREACHABLE();
|
|
|
| case LookupIterator::ACCESS_CHECK:
|
| @@ -6326,20 +6318,16 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
| case LookupIterator::JSPROXY:
|
| return isolate->factory()->undefined_value();
|
|
|
| - case LookupIterator::PROPERTY:
|
| - if (!it.HasProperty()) continue;
|
| - switch (it.property_kind()) {
|
| - case LookupIterator::DATA:
|
| - continue;
|
| - case LookupIterator::ACCESSOR: {
|
| - Handle<Object> maybe_pair = it.GetAccessors();
|
| - if (maybe_pair->IsAccessorPair()) {
|
| - return handle(
|
| - AccessorPair::cast(*maybe_pair)->GetComponent(component),
|
| - isolate);
|
| - }
|
| - }
|
| + case LookupIterator::DATA:
|
| + continue;
|
| + case LookupIterator::ACCESSOR: {
|
| + Handle<Object> maybe_pair = it.GetAccessors();
|
| + if (maybe_pair->IsAccessorPair()) {
|
| + return handle(
|
| + AccessorPair::cast(*maybe_pair)->GetComponent(component),
|
| + isolate);
|
| }
|
| + }
|
| }
|
| }
|
| }
|
| @@ -12849,7 +12837,7 @@ bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
|
| LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
| CHECK(it.IsFound());
|
| - CHECK(it.HasProperty());
|
| + CHECK_EQ(LookupIterator::ACCESSOR, it.state());
|
| return it.IsReadOnly();
|
| }
|
| return false;
|
| @@ -13275,7 +13263,7 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
|
| LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
|
| if (!maybe_result.has_value) return Maybe<bool>();
|
| - return maybe(it.IsFound() && it.property_kind() == LookupIterator::ACCESSOR);
|
| + return maybe(it.state() == LookupIterator::ACCESSOR);
|
| }
|
|
|
|
|
|
|