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); |
} |