From 0f6d0d28dd3aa97f3c292f1922245537e3154280 Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Tue, 20 Nov 2012 12:32:29 +0000 Subject: [PATCH] Fix and clean up treatment of hidden prototypes. R=mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/11413068 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13012 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/objects.cc | 34 ++++++++++++++++++++++------------ src/objects.h | 3 ++- src/runtime.cc | 43 +++++++++++++++---------------------------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/objects.cc b/src/objects.cc index 85b43ba..efc4868 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1966,7 +1966,7 @@ MaybeObject* JSReceiver::SetProperty(String* name, StrictModeFlag strict_mode, JSReceiver::StoreFromKeyed store_mode) { LookupResult result(GetIsolate()); - LocalLookup(name, &result); + LocalLookup(name, &result, true); if (!result.IsFound()) { map()->LookupTransition(JSObject::cast(this), name, &result); } @@ -3020,7 +3020,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, EnqueueChangeRecord(self, "new", name, old_value); } else { LookupResult new_lookup(isolate); - self->LocalLookup(*name, &new_lookup); + self->LocalLookup(*name, &new_lookup, true); ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); if (!new_lookup.GetLazyValue()->SameValue(*old_value)) { EnqueueChangeRecord(self, "updated", name, old_value); @@ -3062,7 +3062,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( AssertNoContextChange ncc; Isolate* isolate = GetIsolate(); LookupResult lookup(isolate); - LocalLookup(name_raw, &lookup); + LocalLookup(name_raw, &lookup, true); if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup); // Check access rights if needed. if (IsAccessCheckNeeded()) { @@ -3169,7 +3169,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( EnqueueChangeRecord(self, "new", name, old_value); } else { LookupResult new_lookup(isolate); - self->LocalLookup(*name, &new_lookup); + self->LocalLookup(*name, &new_lookup, true); ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); if (old_value->IsTheHole() || new_lookup.GetAttributes() != old_attributes) { @@ -3316,7 +3316,7 @@ PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { } // Named property. LookupResult lookup(GetIsolate()); - LocalLookup(name, &lookup); + LocalLookup(name, &lookup, true); return GetPropertyAttributeForResult(this, &lookup, name, false); } @@ -4218,7 +4218,7 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { } LookupResult lookup(isolate); - LocalLookup(name, &lookup); + LocalLookup(name, &lookup, true); if (!lookup.IsFound()) return isolate->heap()->true_value(); // Ignore attributes if forcing a deletion. if (lookup.IsDontDelete() && mode != FORCE_DELETION) { @@ -4548,7 +4548,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { } -void JSReceiver::LocalLookup(String* name, LookupResult* result) { +void JSReceiver::LocalLookup( + String* name, LookupResult* result, bool search_hidden_prototypes) { ASSERT(name->IsString()); Heap* heap = GetHeap(); @@ -4557,7 +4558,8 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) { Object* proto = GetPrototype(); if (proto->IsNull()) return result->NotFound(); ASSERT(proto->IsJSGlobalObject()); - return JSReceiver::cast(proto)->LocalLookup(name, result); + return JSReceiver::cast(proto)->LocalLookup( + name, result, search_hidden_prototypes); } if (IsJSProxy()) { @@ -4587,6 +4589,14 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) { } js_object->LocalLookupRealNamedProperty(name, result); + if (result->IsFound() || !search_hidden_prototypes) return; + + Object* proto = js_object->GetPrototype(); + if (!proto->IsJSReceiver()) return; + JSReceiver* receiver = JSReceiver::cast(proto); + if (receiver->map()->is_hidden_prototype()) { + receiver->LocalLookup(name, result, search_hidden_prototypes); + } } @@ -4596,7 +4606,7 @@ void JSReceiver::Lookup(String* name, LookupResult* result) { for (Object* current = this; current != heap->null_value(); current = JSObject::cast(current)->GetPrototype()) { - JSReceiver::cast(current)->LocalLookup(name, result); + JSReceiver::cast(current)->LocalLookup(name, result, false); if (result->IsFound()) return; } result->NotFound(); @@ -4918,7 +4928,7 @@ MaybeObject* JSObject::DefineAccessor(String* name_raw, } } else { LookupResult lookup(isolate); - LocalLookup(*name, &lookup); + LocalLookup(*name, &lookup, true); preexists = lookup.IsProperty(); if (preexists) old_value = handle(lookup.GetLazyValue(), isolate); } @@ -5116,7 +5126,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { } else { // Lookup the name. LookupResult result(isolate); - LocalLookup(name, &result); + LocalLookup(name, &result, true); // ES5 forbids turning a property into an accessor if it's not // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) { @@ -9630,7 +9640,7 @@ PropertyType JSObject::GetLocalPropertyType(String* name) { return GetLocalElementType(index); } LookupResult lookup(GetIsolate()); - LocalLookup(name, &lookup); + LocalLookup(name, &lookup, true); return lookup.type(); } diff --git a/src/objects.h b/src/objects.h index dbee6f3..e5cd7f5 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1516,7 +1516,8 @@ class JSReceiver: public HeapObject { // Lookup a property. If found, the result is valid and has // detailed information. - void LocalLookup(String* name, LookupResult* result); + void LocalLookup(String* name, LookupResult* result, + bool search_hidden_prototypes = false); void Lookup(String* name, LookupResult* result); protected: diff --git a/src/runtime.cc b/src/runtime.cc index 0b91d99..838681f 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1034,7 +1034,7 @@ static AccessCheckResult CheckPropertyAccess( } LookupResult lookup(obj->GetIsolate()); - obj->LocalLookup(name, &lookup); + obj->LocalLookup(name, &lookup, true); if (!lookup.IsProperty()) return ACCESS_ABSENT; if (CheckGenericAccess( @@ -1290,13 +1290,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { // Do the lookup locally only, see ES5 erratum. LookupResult lookup(isolate); if (FLAG_es52_globals) { - Object* obj = *global; - do { - JSObject::cast(obj)->LocalLookup(*name, &lookup); - if (lookup.IsFound()) break; - obj = obj->GetPrototype(); - } while (obj->IsJSObject() && - JSObject::cast(obj)->map()->is_hidden_prototype()); + global->LocalLookup(*name, &lookup, true); } else { global->Lookup(*name, &lookup); } @@ -1320,7 +1314,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { } LookupResult lookup(isolate); - global->LocalLookup(*name, &lookup); + global->LocalLookup(*name, &lookup, true); // Compute the property attributes. According to ECMA-262, // the property must be non-configurable except in eval. @@ -1499,27 +1493,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { // the whole chain of hidden prototypes to do a 'local' lookup. Object* object = global; LookupResult lookup(isolate); - while (object->IsJSObject() && - JSObject::cast(object)->map()->is_hidden_prototype()) { - JSObject* raw_holder = JSObject::cast(object); - raw_holder->LocalLookup(*name, &lookup); - if (lookup.IsInterceptor()) { - HandleScope handle_scope(isolate); - Handle holder(raw_holder); - PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); - // Update the raw pointer in case it's changed due to GC. - raw_holder = *holder; - if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { - // Found an interceptor that's not read only. - if (assign) { - return raw_holder->SetProperty( - &lookup, *name, args[2], attributes, strict_mode_flag); - } else { - return isolate->heap()->undefined_value(); - } + JSObject::cast(object)->LocalLookup(*name, &lookup, true); + if (lookup.IsInterceptor()) { + HandleScope handle_scope(isolate); + PropertyAttributes intercepted = + lookup.holder()->GetPropertyAttribute(*name); + if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { + // Found an interceptor that's not read only. + if (assign) { + return lookup.holder()->SetProperty( + &lookup, *name, args[2], attributes, strict_mode_flag); + } else { + return isolate->heap()->undefined_value(); } } - object = raw_holder->GetPrototype(); } // Reload global in case the loop above performed a GC. -- 2.7.4