[runtime] Make sure that LookupIterator::OWN always performs a HIDDEN lookup as well.
Hidden prototypes are merely an implementation detail. Properties on an object + hidden prototype should look like properties on the object. Hence we should always perform a hidden prototype lookup. This CL removes the option to ignore hidden prototypes to avoid bugs that leak this implementation detail. Also, the only previously valid cases were either places were we knew we didn't have a hidden prototype; or because we knew we (in the optimizing compiler) would only handle properties from the non-hidden object.The first case is already handled by directly tagging whether a receiver has a hidden prototype. In the second case we can just filter out properties from hidden prototypes. Review-Url: https://codereview.chromium.org/1975763002 Cr-Commit-Position: refs/heads/master@{#36235}
This commit is contained in:
parent
fff4301f8a
commit
c9a83150e0
@ -146,6 +146,7 @@ MUST_USE_RESULT MaybeHandle<Object> ReplaceAccessorWithDataProperty(
|
||||
CHECK(it.HasAccess());
|
||||
it.Next();
|
||||
}
|
||||
DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
|
||||
CHECK_EQ(LookupIterator::ACCESSOR, it.state());
|
||||
it.ReconfigureDataProperty(value, it.property_attributes());
|
||||
return value;
|
||||
|
@ -4137,7 +4137,7 @@ BUILTIN(FunctionPrototypeBind) {
|
||||
isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
|
||||
|
||||
LookupIterator length_lookup(target, isolate->factory()->length_string(),
|
||||
target, LookupIterator::HIDDEN);
|
||||
target, LookupIterator::OWN);
|
||||
// Setup the "length" property based on the "length" of the {target}.
|
||||
// If the targets length is the default JSFunction accessor, we can keep the
|
||||
// accessor that's installed by default on the JSBoundFunction. It lazily
|
||||
@ -4170,7 +4170,7 @@ BUILTIN(FunctionPrototypeBind) {
|
||||
// accessor that's installed by default on the JSBoundFunction. It lazily
|
||||
// computes the value from the underlying internal name.
|
||||
LookupIterator name_lookup(target, isolate->factory()->name_string(), target,
|
||||
LookupIterator::HIDDEN);
|
||||
LookupIterator::OWN);
|
||||
if (!target->IsJSFunction() ||
|
||||
name_lookup.state() != LookupIterator::ACCESSOR ||
|
||||
!name_lookup.GetAccessors()->IsAccessorInfo()) {
|
||||
|
@ -74,6 +74,7 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
// properties of the global object here (represented as PropertyCell).
|
||||
LookupIterator it(global_object, name, LookupIterator::OWN);
|
||||
if (it.state() != LookupIterator::DATA) return NoChange();
|
||||
if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
|
||||
Handle<PropertyCell> property_cell = it.GetPropertyCell();
|
||||
PropertyDetails property_details = property_cell->property_details();
|
||||
Handle<Object> property_cell_value(property_cell->value(), isolate());
|
||||
@ -154,6 +155,7 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
// properties of the global object here (represented as PropertyCell).
|
||||
LookupIterator it(global_object, name, LookupIterator::OWN);
|
||||
if (it.state() != LookupIterator::DATA) return NoChange();
|
||||
if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
|
||||
Handle<PropertyCell> property_cell = it.GetPropertyCell();
|
||||
PropertyDetails property_details = property_cell->property_details();
|
||||
Handle<Object> property_cell_value(property_cell->value(), isolate());
|
||||
|
@ -5771,6 +5771,7 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
|
||||
return kUseGeneric;
|
||||
case LookupIterator::DATA:
|
||||
if (access_type == STORE && it->IsReadOnly()) return kUseGeneric;
|
||||
if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return kUseGeneric;
|
||||
return kUseCell;
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::TRANSITION:
|
||||
|
@ -280,6 +280,7 @@ bool IC::ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name) {
|
||||
LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
if (it.state() == LookupIterator::ACCESS_CHECK) return false;
|
||||
if (!it.IsFound()) return false;
|
||||
if (!it.GetHolder<JSReceiver>()->IsJSGlobalObject()) return false;
|
||||
return it.property_details().cell_type() == PropertyCellType::kConstant;
|
||||
}
|
||||
|
||||
|
@ -637,17 +637,7 @@ bool LookupIterator::SkipInterceptor(JSObject* holder) {
|
||||
JSReceiver* LookupIterator::NextHolder(Map* map) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (map->prototype() == heap()->null_value()) return NULL;
|
||||
|
||||
DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype());
|
||||
|
||||
if (!check_prototype_chain() &&
|
||||
!(check_hidden() && map->has_hidden_prototype()) &&
|
||||
// Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
|
||||
// when not checking other hidden prototypes.
|
||||
!map->IsJSGlobalProxyMap()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!check_prototype_chain() && !map->has_hidden_prototype()) return NULL;
|
||||
return JSReceiver::cast(map->prototype());
|
||||
}
|
||||
|
||||
|
19
src/lookup.h
19
src/lookup.h
@ -16,17 +16,14 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
public:
|
||||
enum Configuration {
|
||||
// Configuration bits.
|
||||
kHidden = 1 << 0,
|
||||
kInterceptor = 1 << 1,
|
||||
kPrototypeChain = 1 << 2,
|
||||
kInterceptor = 1 << 0,
|
||||
kPrototypeChain = 1 << 1,
|
||||
|
||||
// Convience combinations of bits.
|
||||
OWN_SKIP_INTERCEPTOR = 0,
|
||||
OWN = kInterceptor,
|
||||
HIDDEN_SKIP_INTERCEPTOR = kHidden,
|
||||
HIDDEN = kHidden | kInterceptor,
|
||||
PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain,
|
||||
PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor,
|
||||
PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
|
||||
PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
|
||||
DEFAULT = PROTOTYPE_CHAIN
|
||||
};
|
||||
|
||||
@ -316,7 +313,6 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
: holder->GetNamedInterceptor();
|
||||
}
|
||||
|
||||
bool check_hidden() const { return (configuration_ & kHidden) != 0; }
|
||||
bool check_interceptor() const {
|
||||
return (configuration_ & kInterceptor) != 0;
|
||||
}
|
||||
@ -335,12 +331,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
|
||||
static Configuration ComputeConfiguration(
|
||||
Configuration configuration, Handle<Name> name) {
|
||||
if (name->IsPrivate()) {
|
||||
return static_cast<Configuration>(configuration &
|
||||
HIDDEN_SKIP_INTERCEPTOR);
|
||||
} else {
|
||||
return configuration;
|
||||
}
|
||||
return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration;
|
||||
}
|
||||
|
||||
static Handle<JSReceiver> GetRootForNonJSReceiver(
|
||||
|
@ -7113,7 +7113,7 @@ Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
|
||||
Handle<Name> name) {
|
||||
if (object->IsJSObject()) { // Shortcut
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
object->GetIsolate(), object, name, object, LookupIterator::HIDDEN);
|
||||
object->GetIsolate(), object, name, object, LookupIterator::OWN);
|
||||
return HasProperty(&it);
|
||||
}
|
||||
|
||||
@ -7135,7 +7135,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
||||
Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
|
||||
Handle<JSReceiver> object, Handle<Name> name) {
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
name->GetIsolate(), object, name, object, LookupIterator::HIDDEN);
|
||||
name->GetIsolate(), object, name, object, LookupIterator::OWN);
|
||||
return GetPropertyAttributes(&it);
|
||||
}
|
||||
|
||||
@ -7157,7 +7157,7 @@ Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
|
||||
Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
|
||||
Handle<JSReceiver> object, uint32_t index) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
LookupIterator it(isolate, object, index, object, LookupIterator::HIDDEN);
|
||||
LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
|
||||
return GetPropertyAttributes(&it);
|
||||
}
|
||||
|
||||
|
@ -4289,7 +4289,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
}
|
||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
|
||||
|
||||
LookupIterator::Configuration c = LookupIterator::HIDDEN;
|
||||
LookupIterator::Configuration c = LookupIterator::OWN;
|
||||
LookupIterator own_lookup =
|
||||
it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
|
||||
: LookupIterator(receiver, it->name(), c);
|
||||
@ -5988,7 +5988,7 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
|
||||
Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
|
||||
LanguageMode language_mode) {
|
||||
LookupIterator it(object->GetIsolate(), object, index, object,
|
||||
LookupIterator::HIDDEN);
|
||||
LookupIterator::OWN);
|
||||
return DeleteProperty(&it, language_mode);
|
||||
}
|
||||
|
||||
@ -5996,7 +5996,7 @@ Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
|
||||
Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
|
||||
Handle<Name> name,
|
||||
LanguageMode language_mode) {
|
||||
LookupIterator it(object, name, object, LookupIterator::HIDDEN);
|
||||
LookupIterator it(object, name, object, LookupIterator::OWN);
|
||||
return DeleteProperty(&it, language_mode);
|
||||
}
|
||||
|
||||
@ -6005,7 +6005,7 @@ Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
|
||||
Handle<Name> name,
|
||||
LanguageMode language_mode) {
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
name->GetIsolate(), object, name, object, LookupIterator::HIDDEN);
|
||||
name->GetIsolate(), object, name, object, LookupIterator::OWN);
|
||||
return DeleteProperty(&it, language_mode);
|
||||
}
|
||||
|
||||
@ -6106,7 +6106,7 @@ MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
|
||||
// 7b. ReturnIfAbrupt(propDesc).
|
||||
bool success = false;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, props, next_key, &success, LookupIterator::HIDDEN);
|
||||
isolate, props, next_key, &success, LookupIterator::OWN);
|
||||
DCHECK(success);
|
||||
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
||||
if (!maybe.IsJust()) return MaybeHandle<Object>();
|
||||
@ -6181,7 +6181,7 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
|
||||
bool success = false;
|
||||
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, object, key, &success, LookupIterator::HIDDEN);
|
||||
isolate, object, key, &success, LookupIterator::OWN);
|
||||
DCHECK(success); // ...so creating a LookupIterator can't fail.
|
||||
|
||||
// Deal with access checks first.
|
||||
@ -6908,7 +6908,7 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
|
||||
bool success = false;
|
||||
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, object, key, &success, LookupIterator::HIDDEN);
|
||||
isolate, object, key, &success, LookupIterator::OWN);
|
||||
DCHECK(success); // ...so creating a LookupIterator can't fail.
|
||||
return GetOwnPropertyDescriptor(&it, desc);
|
||||
}
|
||||
@ -8283,7 +8283,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
return DefineAccessor(&it, getter, setter, attributes);
|
||||
}
|
||||
|
||||
@ -8327,7 +8327,7 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
|
||||
Handle<Name> name(Name::cast(info->name()), isolate);
|
||||
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
|
||||
// Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
|
||||
// the FailedAccessCheckCallbackFunction doesn't throw an exception.
|
||||
@ -13954,7 +13954,6 @@ void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
|
||||
array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
||||
}
|
||||
|
||||
|
||||
void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
|
||||
// We should never end in here with a pixel or external array.
|
||||
DCHECK(array->AllowsSetLength());
|
||||
|
@ -358,7 +358,7 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
|
||||
return *isolate->factory()->NewJSArrayWithElements(details);
|
||||
}
|
||||
|
||||
LookupIterator it(obj, name, LookupIterator::HIDDEN);
|
||||
LookupIterator it(obj, name, LookupIterator::OWN);
|
||||
bool has_caught = false;
|
||||
Handle<Object> value = DebugGetProperty(&it, &has_caught);
|
||||
if (!it.IsFound()) return isolate->heap()->undefined_value();
|
||||
|
@ -120,7 +120,7 @@ Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
|
||||
LanguageMode language_mode) {
|
||||
bool success = false;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, receiver, key, &success, LookupIterator::HIDDEN);
|
||||
isolate, receiver, key, &success, LookupIterator::OWN);
|
||||
if (!success) return Nothing<bool>();
|
||||
|
||||
return JSReceiver::DeleteProperty(&it, language_mode);
|
||||
@ -169,7 +169,7 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
|
||||
}
|
||||
|
||||
// Slow case.
|
||||
LookupIterator::Configuration c = LookupIterator::HIDDEN;
|
||||
LookupIterator::Configuration c = LookupIterator::OWN;
|
||||
LookupIterator it = key_is_array_index
|
||||
? LookupIterator(isolate, js_obj, index, js_obj, c)
|
||||
: LookupIterator(js_obj, key, js_obj, c);
|
||||
@ -300,7 +300,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalViaContext) {
|
||||
Handle<Name> name(scope_info->ContextSlotName(slot), isolate);
|
||||
Handle<JSGlobalObject> global_object(script_context->global_object(),
|
||||
isolate);
|
||||
LookupIterator it(global_object, name, global_object, LookupIterator::HIDDEN);
|
||||
LookupIterator it(global_object, name, global_object, LookupIterator::OWN);
|
||||
|
||||
// Switch to fast mode only if there is a data property and it's not on
|
||||
// a hidden prototype.
|
||||
@ -335,7 +335,7 @@ Object* StoreGlobalViaContext(Isolate* isolate, int slot, Handle<Object> value,
|
||||
Handle<Name> name(scope_info->ContextSlotName(slot), isolate);
|
||||
Handle<JSGlobalObject> global_object(script_context->global_object(),
|
||||
isolate);
|
||||
LookupIterator it(global_object, name, global_object, LookupIterator::HIDDEN);
|
||||
LookupIterator it(global_object, name, global_object, LookupIterator::OWN);
|
||||
|
||||
// Switch to fast mode only if there is a data property and it's not on
|
||||
// a hidden prototype.
|
||||
@ -1116,7 +1116,7 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
||||
bool success;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, o, key, &success, LookupIterator::HIDDEN);
|
||||
isolate, o, key, &success, LookupIterator::OWN);
|
||||
if (!success) return isolate->heap()->exception();
|
||||
MAYBE_RETURN(
|
||||
JSReceiver::CreateDataProperty(&it, value, Object::THROW_ON_ERROR),
|
||||
|
@ -44,8 +44,7 @@ static Object* DeclareGlobals(Isolate* isolate, Handle<JSGlobalObject> global,
|
||||
}
|
||||
|
||||
// Do the lookup own properties only, see ES5 erratum.
|
||||
LookupIterator it(global, name, global,
|
||||
LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
LookupIterator it(global, name, global, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
||||
if (!maybe.IsJust()) return isolate->heap()->exception();
|
||||
|
||||
@ -182,8 +181,7 @@ RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
|
||||
Handle<JSGlobalObject> global = isolate->global_object();
|
||||
|
||||
// Lookup the property as own on the global object.
|
||||
LookupIterator it(global, name, global,
|
||||
LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
LookupIterator it(global, name, global, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
||||
DCHECK(maybe.IsJust());
|
||||
PropertyAttributes old_attributes = maybe.FromJust();
|
||||
@ -622,7 +620,7 @@ static Object* FindNameClash(Handle<ScopeInfo> scope_info,
|
||||
|
||||
if (IsLexicalVariableMode(mode)) {
|
||||
LookupIterator it(global_object, name, global_object,
|
||||
LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
||||
if (!maybe.IsJust()) return isolate->heap()->exception();
|
||||
if ((maybe.FromJust() & DONT_DELETE) != 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user