Removing LookupTransition from LookupRealNamedProperty and related utility functions.
Callsites now have to manually lookup transitions if required. This avoids unnecessary overhead of looking up transitions when we don't need them. This also allows us to use IsFound() in many places where IsProperty() was required previously. Review URL: https://chromiumcodereview.appspot.com/10779012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12098 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
11e5c9e281
commit
3b5a6ef2e7
@ -2175,7 +2175,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
LookupResult result(isolate());
|
||||
to->LocalLookup(descs->GetKey(i), &result);
|
||||
// If the property is already there we skip it
|
||||
if (result.IsProperty()) continue;
|
||||
if (result.IsFound()) continue;
|
||||
HandleScope inner;
|
||||
ASSERT(!to->HasFastProperties());
|
||||
// Add to dictionary.
|
||||
@ -2208,7 +2208,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
// If the property is already there we skip it.
|
||||
LookupResult result(isolate());
|
||||
to->LocalLookup(String::cast(raw_key), &result);
|
||||
if (result.IsProperty()) continue;
|
||||
if (result.IsFound()) continue;
|
||||
// Set the property.
|
||||
Handle<String> key = Handle<String>(String::cast(raw_key));
|
||||
Handle<Object> value = Handle<Object>(properties->ValueAt(i));
|
||||
|
13
src/ic.cc
13
src/ic.cc
@ -445,14 +445,14 @@ static void LookupForRead(Handle<Object> object,
|
||||
}
|
||||
|
||||
holder->LocalLookupRealNamedProperty(*name, lookup);
|
||||
if (lookup->IsProperty()) {
|
||||
if (lookup->IsFound()) {
|
||||
ASSERT(!lookup->IsInterceptor());
|
||||
return;
|
||||
}
|
||||
|
||||
Handle<Object> proto(holder->GetPrototype());
|
||||
if (proto->IsNull()) {
|
||||
lookup->NotFound();
|
||||
ASSERT(!lookup->IsFound());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
|
||||
LookupResult lookup(isolate());
|
||||
LookupForRead(object, name, &lookup);
|
||||
|
||||
if (!lookup.IsProperty()) {
|
||||
if (!lookup.IsFound()) {
|
||||
// If the object does not have the requested property, check which
|
||||
// exception we need to throw.
|
||||
return IsContextual(object)
|
||||
@ -900,7 +900,7 @@ MaybeObject* LoadIC::Load(State state,
|
||||
LookupForRead(object, name, &lookup);
|
||||
|
||||
// If we did not find a property, check if we need to throw an exception.
|
||||
if (!lookup.IsProperty()) {
|
||||
if (!lookup.IsFound()) {
|
||||
if (IsContextual(object)) {
|
||||
return ReferenceError("not_defined", name);
|
||||
}
|
||||
@ -1166,7 +1166,7 @@ MaybeObject* KeyedLoadIC::Load(State state,
|
||||
LookupForRead(object, name, &lookup);
|
||||
|
||||
// If we did not find a property, check if we need to throw an exception.
|
||||
if (!lookup.IsProperty() && IsContextual(object)) {
|
||||
if (!lookup.IsFound() && IsContextual(object)) {
|
||||
return ReferenceError("not_defined", name);
|
||||
}
|
||||
|
||||
@ -1317,6 +1317,9 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
||||
Handle<String> name,
|
||||
LookupResult* lookup) {
|
||||
receiver->LocalLookup(*name, lookup);
|
||||
if (!lookup->IsFound()) {
|
||||
receiver->map()->LookupTransition(*receiver, *name, lookup);
|
||||
}
|
||||
if (!StoreICableLookup(lookup)) {
|
||||
// 2nd chance: There can be accessors somewhere in the prototype chain. Note
|
||||
// that we explicitly exclude native accessors for now, because the stubs
|
||||
|
@ -406,13 +406,11 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
|
||||
} else {
|
||||
result->holder()->LocalLookupRealNamedProperty(name, &r);
|
||||
}
|
||||
if (r.IsProperty()) {
|
||||
return GetPropertyAttributeWithFailedAccessCheck(receiver,
|
||||
&r,
|
||||
name,
|
||||
continue_search);
|
||||
}
|
||||
break;
|
||||
if (!r.IsFound()) break;
|
||||
return GetPropertyAttributeWithFailedAccessCheck(receiver,
|
||||
&r,
|
||||
name,
|
||||
continue_search);
|
||||
}
|
||||
|
||||
case HANDLER:
|
||||
@ -1747,9 +1745,10 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
|
||||
// Check local property, ignore interceptor.
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookupRealNamedProperty(name, &result);
|
||||
if (!result.IsFound()) map()->LookupTransition(this, name, &result);
|
||||
if (result.IsFound()) {
|
||||
// An existing property, a map transition or a null descriptor was
|
||||
// found. Use set property to handle all these cases.
|
||||
// An existing property or a map transition was found. Use set property to
|
||||
// handle all these cases.
|
||||
return SetProperty(&result, name, value, attributes, strict_mode);
|
||||
}
|
||||
bool done = false;
|
||||
@ -1914,6 +1913,9 @@ MaybeObject* JSReceiver::SetProperty(String* name,
|
||||
JSReceiver::StoreFromKeyed store_mode) {
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookup(name, &result);
|
||||
if (!result.IsFound()) {
|
||||
map()->LookupTransition(JSObject::cast(this), name, &result);
|
||||
}
|
||||
return SetProperty(&result, name, value, attributes, strict_mode, store_mode);
|
||||
}
|
||||
|
||||
@ -2354,7 +2356,7 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
|
||||
}
|
||||
|
||||
if (HasFastProperties()) {
|
||||
map()->LookupTransitionOrDescriptor(this, name, result);
|
||||
map()->LookupDescriptor(this, name, result);
|
||||
// A property or a map transition was found. We return all of these result
|
||||
// types because LocalLookupRealNamedProperty is used when setting
|
||||
// properties where map transitions are handled.
|
||||
@ -2394,7 +2396,7 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
|
||||
|
||||
void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
|
||||
LocalLookupRealNamedProperty(name, result);
|
||||
if (result->IsProperty()) return;
|
||||
if (result->IsFound()) return;
|
||||
|
||||
LookupRealNamedPropertyInPrototypes(name, result);
|
||||
}
|
||||
@ -2410,8 +2412,8 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
|
||||
return result->HandlerResult(JSProxy::cast(pt));
|
||||
}
|
||||
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
|
||||
ASSERT(!(result->IsProperty() && result->type() == INTERCEPTOR));
|
||||
if (result->IsProperty()) return;
|
||||
ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
|
||||
if (result->IsFound()) return;
|
||||
}
|
||||
result->NotFound();
|
||||
}
|
||||
@ -2933,6 +2935,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
Isolate* isolate = GetIsolate();
|
||||
LookupResult result(isolate);
|
||||
LocalLookup(name, &result);
|
||||
if (!result.IsFound()) map()->LookupTransition(this, name, &result);
|
||||
// Check access rights if needed.
|
||||
if (IsAccessCheckNeeded()) {
|
||||
if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
||||
@ -3021,7 +3024,7 @@ PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
|
||||
// Check local property, ignore interceptor.
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookupRealNamedProperty(name, &result);
|
||||
if (result.IsProperty()) return result.GetAttributes();
|
||||
if (result.IsFound()) return result.GetAttributes();
|
||||
|
||||
if (continue_search) {
|
||||
// Continue searching via the prototype chain.
|
||||
@ -3114,7 +3117,7 @@ PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
|
||||
receiver, result, name, continue_search);
|
||||
}
|
||||
}
|
||||
if (result->IsProperty()) {
|
||||
if (result->IsFound()) {
|
||||
switch (result->type()) {
|
||||
case NORMAL: // fall through
|
||||
case FIELD:
|
||||
@ -3700,7 +3703,7 @@ MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
|
||||
// Check local property, ignore interceptor.
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookupRealNamedProperty(name, &result);
|
||||
if (!result.IsProperty()) return GetHeap()->true_value();
|
||||
if (!result.IsFound()) return GetHeap()->true_value();
|
||||
|
||||
// Normalize object if needed.
|
||||
Object* obj;
|
||||
@ -3849,7 +3852,7 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
|
||||
} else {
|
||||
LookupResult result(isolate);
|
||||
LocalLookup(name, &result);
|
||||
if (!result.IsProperty()) return isolate->heap()->true_value();
|
||||
if (!result.IsFound()) return isolate->heap()->true_value();
|
||||
// Ignore attributes if forcing a deletion.
|
||||
if (result.IsDontDelete() && mode != FORCE_DELETION) {
|
||||
if (mode == STRICT_DELETION) {
|
||||
@ -4199,21 +4202,22 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) {
|
||||
}
|
||||
|
||||
|
||||
void JSReceiver::Lookup(String* name, LookupResult* result) {
|
||||
void JSReceiver::Lookup(String* name,
|
||||
LookupResult* result) {
|
||||
// Ecma-262 3rd 8.6.2.4
|
||||
Heap* heap = GetHeap();
|
||||
for (Object* current = this;
|
||||
current != heap->null_value();
|
||||
current = JSObject::cast(current)->GetPrototype()) {
|
||||
JSReceiver::cast(current)->LocalLookup(name, result);
|
||||
if (result->IsProperty()) return;
|
||||
if (result->IsFound()) return;
|
||||
}
|
||||
result->NotFound();
|
||||
}
|
||||
|
||||
|
||||
// Search object and its prototype chain for callback properties.
|
||||
void JSObject::LookupCallback(String* name, LookupResult* result) {
|
||||
void JSObject::LookupCallbackProperty(String* name, LookupResult* result) {
|
||||
Heap* heap = GetHeap();
|
||||
for (Object* current = this;
|
||||
current != heap->null_value() && current->IsJSObject();
|
||||
@ -4384,8 +4388,8 @@ bool JSObject::CanSetCallback(String* name) {
|
||||
// to be overwritten because allowing overwriting could potentially
|
||||
// cause security problems.
|
||||
LookupResult callback_result(GetIsolate());
|
||||
LookupCallback(name, &callback_result);
|
||||
if (callback_result.IsProperty()) {
|
||||
LookupCallbackProperty(name, &callback_result);
|
||||
if (callback_result.IsFound()) {
|
||||
Object* obj = callback_result.GetCallbackObject();
|
||||
if (obj->IsAccessorInfo() &&
|
||||
AccessorInfo::cast(obj)->prohibits_overwriting()) {
|
||||
@ -4693,23 +4697,22 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
|
||||
break;
|
||||
}
|
||||
|
||||
{ MaybeObject* maybe_ok =
|
||||
SetElementCallback(index, info, info->property_attributes());
|
||||
if (maybe_ok->IsFailure()) return maybe_ok;
|
||||
}
|
||||
MaybeObject* maybe_ok =
|
||||
SetElementCallback(index, info, info->property_attributes());
|
||||
if (maybe_ok->IsFailure()) return maybe_ok;
|
||||
} else {
|
||||
// Lookup the name.
|
||||
LookupResult result(isolate);
|
||||
LocalLookup(name, &result);
|
||||
// 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.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
|
||||
if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
{ MaybeObject* maybe_ok =
|
||||
SetPropertyCallback(name, info, info->property_attributes());
|
||||
if (maybe_ok->IsFailure()) return maybe_ok;
|
||||
}
|
||||
|
||||
MaybeObject* maybe_ok =
|
||||
SetPropertyCallback(name, info, info->property_attributes());
|
||||
if (maybe_ok->IsFailure()) return maybe_ok;
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -4755,7 +4758,7 @@ Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
|
||||
obj = JSReceiver::cast(obj)->GetPrototype()) {
|
||||
LookupResult result(heap->isolate());
|
||||
JSReceiver::cast(obj)->LocalLookup(name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
if (result.IsReadOnly()) return heap->undefined_value();
|
||||
if (result.IsPropertyCallbacks()) {
|
||||
Object* obj = result.GetCallbackObject();
|
||||
@ -7641,7 +7644,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
|
||||
LookupResult result(heap->isolate());
|
||||
String* name = GetThisPropertyAssignmentName(i);
|
||||
receiver->LocalLookup(name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
switch (result.type()) {
|
||||
case NORMAL:
|
||||
case FIELD:
|
||||
@ -10174,7 +10177,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor(
|
||||
// Check local property in holder, ignore interceptor.
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookupRealNamedProperty(name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
return GetProperty(receiver, &result, name, attributes);
|
||||
}
|
||||
// Continue searching via the prototype chain.
|
||||
@ -10192,7 +10195,7 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
|
||||
// Check local property in holder, ignore interceptor.
|
||||
LookupResult result(GetIsolate());
|
||||
LocalLookupRealNamedProperty(name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
return GetProperty(receiver, &result, name, attributes);
|
||||
}
|
||||
return GetHeap()->undefined_value();
|
||||
@ -10251,7 +10254,7 @@ bool JSObject::HasRealNamedProperty(String* key) {
|
||||
|
||||
LookupResult result(isolate);
|
||||
LocalLookupRealNamedProperty(key, &result);
|
||||
return result.IsProperty() && !result.IsInterceptor();
|
||||
return result.IsFound() && !result.IsInterceptor();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1876,7 +1876,7 @@ class JSObject: public JSReceiver {
|
||||
void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
|
||||
MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes(
|
||||
uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode);
|
||||
void LookupCallback(String* name, LookupResult* result);
|
||||
void LookupCallbackProperty(String* name, LookupResult* result);
|
||||
|
||||
// Returns the number of properties on this object filtering out properties
|
||||
// with the specified attributes (ignoring interceptors).
|
||||
|
@ -2300,11 +2300,12 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) {
|
||||
Object* constructor_prop = NULL;
|
||||
LookupResult result(heap->isolate());
|
||||
object->LocalLookupRealNamedProperty(heap->constructor_symbol(), &result);
|
||||
if (result.IsProperty()) {
|
||||
constructor_prop = result.GetLazyValue();
|
||||
}
|
||||
if (!result.IsFound()) return object->constructor_name();
|
||||
|
||||
constructor_prop = result.GetLazyValue();
|
||||
if (constructor_prop->IsJSFunction()) {
|
||||
Object* maybe_name = JSFunction::cast(constructor_prop)->shared()->name();
|
||||
Object* maybe_name =
|
||||
JSFunction::cast(constructor_prop)->shared()->name();
|
||||
if (maybe_name->IsString()) {
|
||||
String* name = String::cast(maybe_name);
|
||||
if (name->length() > 0) return name;
|
||||
|
@ -953,13 +953,13 @@ static void GetOwnPropertyImplementation(JSObject* obj,
|
||||
LookupResult* result) {
|
||||
obj->LocalLookupRealNamedProperty(name, result);
|
||||
|
||||
if (!result->IsProperty()) {
|
||||
Object* proto = obj->GetPrototype();
|
||||
if (proto->IsJSObject() &&
|
||||
JSObject::cast(proto)->map()->is_hidden_prototype())
|
||||
GetOwnPropertyImplementation(JSObject::cast(proto),
|
||||
name, result);
|
||||
}
|
||||
if (result->IsFound()) return;
|
||||
|
||||
Object* proto = obj->GetPrototype();
|
||||
if (proto->IsJSObject() &&
|
||||
JSObject::cast(proto)->map()->is_hidden_prototype())
|
||||
GetOwnPropertyImplementation(JSObject::cast(proto),
|
||||
name, result);
|
||||
}
|
||||
|
||||
|
||||
@ -1373,14 +1373,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
Object* obj = *global;
|
||||
do {
|
||||
JSObject::cast(obj)->LocalLookup(*name, &lookup);
|
||||
if (lookup.IsProperty()) break;
|
||||
if (lookup.IsFound()) break;
|
||||
obj = obj->GetPrototype();
|
||||
} while (obj->IsJSObject() &&
|
||||
JSObject::cast(obj)->map()->is_hidden_prototype());
|
||||
} else {
|
||||
global->Lookup(*name, &lookup);
|
||||
}
|
||||
if (lookup.IsProperty()) {
|
||||
if (lookup.IsFound()) {
|
||||
// We found an existing property. Unless it was an interceptor
|
||||
// that claims the property is absent, skip this declaration.
|
||||
if (!lookup.IsInterceptor()) continue;
|
||||
@ -1416,10 +1416,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
|
||||
LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
|
||||
|
||||
if (!lookup.IsProperty() || is_function || is_module) {
|
||||
if (!lookup.IsFound() || is_function || is_module) {
|
||||
// If the local property exists, check that we can reconfigure it
|
||||
// as required for function declarations.
|
||||
if (lookup.IsProperty() && lookup.IsDontDelete()) {
|
||||
if (lookup.IsFound() && lookup.IsDontDelete()) {
|
||||
if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
|
||||
lookup.IsPropertyCallbacks()) {
|
||||
return ThrowRedeclarationError(
|
||||
@ -1634,7 +1634,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
|
||||
// We use SetLocalPropertyIgnoreAttributes instead
|
||||
LookupResult lookup(isolate);
|
||||
global->LocalLookup(*name, &lookup);
|
||||
if (!lookup.IsProperty()) {
|
||||
if (!lookup.IsFound()) {
|
||||
return global->SetLocalPropertyIgnoreAttributes(*name,
|
||||
*value,
|
||||
attributes);
|
||||
@ -4558,7 +4558,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
|
||||
// map. The current version of SetObjectProperty does not handle attributes
|
||||
// correctly in the case where a property is a field and is reset with
|
||||
// new attributes.
|
||||
if (result.IsProperty() &&
|
||||
if (result.IsFound() &&
|
||||
(attr != result.GetAttributes() || result.IsPropertyCallbacks())) {
|
||||
// New attributes - normalize to avoid writing to instance descriptor
|
||||
if (js_object->IsJSGlobalProxy()) {
|
||||
@ -10421,7 +10421,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
LookupResult result(isolate);
|
||||
jsproto->LocalLookup(*name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
// LookupResult is not GC safe as it holds raw object pointers.
|
||||
// GC can happen later in this code so put the required fields into
|
||||
// local variables using handles when required for later use.
|
||||
@ -10478,7 +10478,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
|
||||
|
||||
LookupResult result(isolate);
|
||||
obj->Lookup(*name, &result);
|
||||
if (result.IsProperty()) {
|
||||
if (result.IsFound()) {
|
||||
return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
|
@ -1361,11 +1361,8 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
LookupResult* lookup) {
|
||||
holder->LocalLookupRealNamedProperty(*name, lookup);
|
||||
if (lookup->IsProperty()) return;
|
||||
|
||||
lookup->NotFound();
|
||||
if (lookup->IsFound()) return;
|
||||
if (holder->GetPrototype()->IsNull()) return;
|
||||
|
||||
holder->GetPrototype()->Lookup(*name, lookup);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user