Commit 806c15e4 authored by ager@chromium.org's avatar ager@chromium.org

Remove the LookupResult IsValid method because it is confusing.

Replaced IsValid by IsPropertyOrTransition and used IsProperty in most
of the places where IsValid was used before.  Most of the time when
inspecting a lookup result we really want to know if there is a real
property present.  Only for stores are we interested in transitions.

BUG=http://crbug.com/20104
TEST=cctest/test-api/NamedInterceptorMapTransitionRead
Review URL: http://codereview.chromium.org/647015

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3901 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0d6fe0a4
......@@ -2207,7 +2207,7 @@ Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup);
if (lookup.IsValid()) {
if (lookup.IsProperty()) {
PropertyAttributes attributes;
i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
&lookup,
......@@ -2226,7 +2226,7 @@ Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
self_obj->LookupRealNamedProperty(*key_obj, &lookup);
if (lookup.IsValid()) {
if (lookup.IsProperty()) {
PropertyAttributes attributes;
i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
&lookup,
......
......@@ -579,7 +579,7 @@ static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler,
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsValid() && lookup->IsCacheable()) {
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
......@@ -985,7 +985,7 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// If we call a constant function when the interceptor returns
// the no-result sentinel, generate code that optimizes this case.
if (lookup.IsValid() &&
if (lookup.IsProperty() &&
lookup.IsCacheable() &&
lookup.type() == CONSTANT_FUNCTION &&
lookup.GetConstantFunction()->is_compiled() &&
......
......@@ -723,11 +723,11 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
#ifdef DEBUG
LookupResult lookup;
result->LocalLookup(Heap::callee_symbol(), &lookup);
ASSERT(lookup.IsValid() && (lookup.type() == FIELD));
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
ASSERT(lookup.GetFieldIndex() == Heap::arguments_callee_index);
result->LocalLookup(Heap::length_symbol(), &lookup);
ASSERT(lookup.IsValid() && (lookup.type() == FIELD));
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
ASSERT(lookup.GetFieldIndex() == Heap::arguments_length_index);
ASSERT(result->map()->inobject_properties() > Heap::arguments_callee_index);
......@@ -1352,7 +1352,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
LookupResult result;
to->LocalLookup(descs->GetKey(i), &result);
// If the property is already there we skip it
if (result.IsValid()) continue;
if (result.IsProperty()) continue;
HandleScope inner;
Handle<DescriptorArray> inst_descs =
Handle<DescriptorArray>(to->map()->instance_descriptors());
......@@ -1389,7 +1389,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
// If the property is already there we skip it.
LookupResult result;
to->LocalLookup(String::cast(raw_key), &result);
if (result.IsValid()) continue;
if (result.IsProperty()) continue;
// Set the property.
Handle<String> key = Handle<String>(String::cast(raw_key));
Handle<Object> value = Handle<Object>(properties->ValueAt(i));
......
......@@ -220,7 +220,7 @@ void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
if (info()->has_global_object()) {
LookupResult lookup;
info()->global_object()->Lookup(*expr->name(), &lookup);
if (!lookup.IsValid()) {
if (!lookup.IsProperty()) {
BAILOUT("Non-existing global variable");
}
// We do not handle global variables with accessors or interceptors.
......@@ -284,7 +284,7 @@ void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsValid()) {
if (!lookup.IsProperty()) {
BAILOUT("Assigned property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment");
......@@ -322,7 +322,7 @@ void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) {
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsValid()) {
if (!lookup.IsProperty()) {
BAILOUT("Referenced property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property reference");
......@@ -586,7 +586,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
info()->global_object()->Lookup(*expr->name(), &lookup);
// We only support normal (non-accessor/interceptor) DontDelete properties
// for now.
ASSERT(lookup.IsValid());
ASSERT(lookup.IsProperty());
ASSERT_EQ(NORMAL, lookup.type());
ASSERT(lookup.IsDontDelete());
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup));
......
......@@ -323,7 +323,7 @@ static void CompileLoadInterceptor(Compiler* compiler,
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsValid() && lookup->IsCacheable()) {
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
......@@ -484,7 +484,7 @@ class CallOptimization BASE_EMBEDDED {
is_simple_api_call_(false),
expected_receiver_type_(NULL),
api_call_info_(NULL) {
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
// We only optimize constant function calls.
if (lookup->type() != CONSTANT_FUNCTION) return;
......
......@@ -330,10 +330,11 @@ static void LookupForRead(Object* object,
while (true) {
object->Lookup(name, lookup);
// Besides normal conditions (property not found or it's not
// an interceptor), bail out of lookup is not cacheable: we won't
// an interceptor), bail out if lookup is not cacheable: we won't
// be able to IC it anyway and regular lookup should work fine.
if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR ||
!lookup->IsCacheable()) {
if (!lookup->IsFound()
|| (lookup->type() != INTERCEPTOR)
|| !lookup->IsCacheable()) {
return;
}
......@@ -343,7 +344,7 @@ static void LookupForRead(Object* object,
}
holder->LocalLookupRealNamedProperty(name, lookup);
if (lookup->IsValid()) {
if (lookup->IsProperty()) {
ASSERT(lookup->type() != INTERCEPTOR);
return;
}
......@@ -422,7 +423,7 @@ Object* CallIC::LoadFunction(State state,
LookupResult lookup;
LookupForRead(*object, *name, &lookup);
if (!lookup.IsValid()) {
if (!lookup.IsProperty()) {
// If the object does not have the requested property, check which
// exception we need to throw.
if (IsContextual(object)) {
......@@ -493,7 +494,7 @@ void CallIC::UpdateCaches(LookupResult* lookup,
Handle<String> name) {
ASSERT(lookup->IsLoaded());
// Bail out if we didn't find a result.
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
// Compute the number of arguments.
int argc = target()->arguments_count();
......@@ -642,8 +643,8 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
LookupResult lookup;
LookupForRead(*object, *name, &lookup);
// If lookup is invalid, check if we need to throw an exception.
if (!lookup.IsValid()) {
// If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty()) {
if (FLAG_strict || IsContextual(object)) {
return ReferenceError("not_defined", name);
}
......@@ -653,7 +654,7 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
bool can_be_inlined =
FLAG_use_ic &&
state == PREMONOMORPHIC &&
lookup.IsValid() &&
lookup.IsProperty() &&
lookup.IsLoaded() &&
lookup.IsCacheable() &&
lookup.holder() == *object &&
......@@ -681,7 +682,7 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
}
PropertyAttributes attr;
if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
// Get the property.
Object* result = object->GetProperty(*object, &lookup, *name, &attr);
if (result->IsFailure()) return result;
......@@ -704,7 +705,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
Handle<String> name) {
ASSERT(lookup->IsLoaded());
// Bail out if we didn't find a result.
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
// Loading properties from values is not common, so don't try to
// deal with non-JS objects here.
......@@ -857,8 +858,8 @@ Object* KeyedLoadIC::Load(State state,
LookupResult lookup;
LookupForRead(*object, *name, &lookup);
// If lookup is invalid, check if we need to throw an exception.
if (!lookup.IsValid()) {
// If we did not find a property, check if we need to throw an exception.
if (!lookup.IsProperty()) {
if (FLAG_strict || IsContextual(object)) {
return ReferenceError("not_defined", name);
}
......@@ -869,7 +870,7 @@ Object* KeyedLoadIC::Load(State state,
}
PropertyAttributes attr;
if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
// Get the property.
Object* result = object->GetProperty(*object, &lookup, *name, &attr);
if (result->IsFailure()) return result;
......@@ -921,7 +922,7 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
Handle<Object> object, Handle<String> name) {
ASSERT(lookup->IsLoaded());
// Bail out if we didn't find a result.
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
if (!object->IsJSObject()) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
......@@ -994,7 +995,7 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
static bool StoreICableLookup(LookupResult* lookup) {
// Bail out if we didn't find a result.
if (!lookup->IsValid() || !lookup->IsCacheable()) return false;
if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false;
// If the property is read-only, we leave the IC in its current
// state.
......@@ -1214,7 +1215,7 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
if (receiver->IsJSGlobalProxy()) return;
// Bail out if we didn't find a result.
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return;
// If the property is read-only, we leave the IC in its current
// state.
......
......@@ -219,7 +219,7 @@ Object* JSObject::GetPropertyWithFailedAccessCheck(
LookupResult* result,
String* name,
PropertyAttributes* attributes) {
if (result->IsValid()) {
if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
// Only allow API accessors.
......@@ -242,7 +242,7 @@ Object* JSObject::GetPropertyWithFailedAccessCheck(
// Search ALL_CAN_READ accessors in prototype chain.
LookupResult r;
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsValid()) {
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
&r,
name,
......@@ -255,16 +255,15 @@ Object* JSObject::GetPropertyWithFailedAccessCheck(
// No access check in GetPropertyAttributeWithInterceptor.
LookupResult r;
result->holder()->LookupRealNamedProperty(name, &r);
if (r.IsValid()) {
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
&r,
name,
attributes);
}
}
default: {
break;
}
default:
UNREACHABLE();
}
}
......@@ -280,7 +279,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
LookupResult* result,
String* name,
bool continue_search) {
if (result->IsValid()) {
if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
// Only allow API accessors.
......@@ -301,7 +300,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
// Search ALL_CAN_READ accessors in prototype chain.
LookupResult r;
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsValid()) {
if (r.IsProperty()) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
&r,
name,
......@@ -319,7 +318,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
} else {
result->holder()->LocalLookupRealNamedProperty(name, &r);
}
if (r.IsValid()) {
if (r.IsProperty()) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
&r,
name,
......@@ -328,9 +327,8 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
break;
}
default: {
break;
}
default:
UNREACHABLE();
}
}
......@@ -505,7 +503,7 @@ Object* Object::GetProperty(Object* receiver,
// holder will always be the interceptor holder and the search may
// only continue with a current object just after the interceptor
// holder in the prototype chain.
Object* last = result->IsValid() ? result->holder() : Heap::null_value();
Object* last = result->IsProperty() ? result->holder() : Heap::null_value();
for (Object* current = this; true; current = current->GetPrototype()) {
if (current->IsAccessCheckNeeded()) {
// Check if we're allowed to read from the current object. Note
......@@ -1463,8 +1461,12 @@ Object* JSObject::SetPropertyPostInterceptor(String* name,
// Check local property, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsValid()) return SetProperty(&result, name, value, attributes);
// Add real property.
if (result.IsFound()) {
// An existing property, a map transition or a null descriptor was
// found. Use set property to handle all these cases.
return SetProperty(&result, name, value, attributes);
}
// Add a new real property.
return AddProperty(name, value, attributes);
}
......@@ -1696,8 +1698,8 @@ void JSObject::LookupCallbackSetterInPrototypes(String* name,
pt != Heap::null_value();
pt = pt->GetPrototype()) {
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsValid()) {
if (!result->IsTransitionType() && result->IsReadOnly()) {
if (result->IsProperty()) {
if (result->IsReadOnly()) {
result->NotFound();
return;
}
......@@ -1758,7 +1760,11 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
if (HasFastProperties()) {
LookupInDescriptor(name, result);
if (result->IsValid()) {
if (result->IsFound()) {
// A property, a map transition or a null descriptor was found.
// We return all of these result types because
// LocalLookupRealNamedProperty is used when setting properties
// where map transitions and null descriptors are handled.
ASSERT(result->holder() == this && result->type() != NORMAL);
// Disallow caching for uninitialized constants. These can only
// occur as fields.
......@@ -1808,16 +1814,7 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
pt != Heap::null_value();
pt = JSObject::cast(pt)->GetPrototype()) {
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsValid()) {
switch (result->type()) {
case NORMAL:
case FIELD:
case CONSTANT_FUNCTION:
case CALLBACKS:
return;
default: break;
}
}
if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
}
result->NotFound();
}
......@@ -1903,14 +1900,15 @@ Object* JSObject::SetProperty(LookupResult* result,
// accessor that wants to handle the property.
LookupResult accessor_result;
LookupCallbackSetterInPrototypes(name, &accessor_result);
if (accessor_result.IsValid()) {
if (accessor_result.IsProperty()) {
return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
name,
value,
accessor_result.holder());
}
}
if (result->IsNotFound()) {
if (!result->IsFound()) {
// Neither properties nor transitions found.
return AddProperty(name, value, attributes);
}
if (!result->IsLoaded()) {
......@@ -1972,15 +1970,12 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
// ADDED TO CLONE
LookupResult result_struct;
LocalLookup(name, &result_struct);
LookupResult* result = &result_struct;
// END ADDED TO CLONE
LookupResult result;
LocalLookup(name, &result);
// Check access rights if needed.
if (IsAccessCheckNeeded()
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value);
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(&result, name, value);
}
if (IsJSGlobalProxy()) {
......@@ -1994,33 +1989,34 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
}
// Check for accessor in prototype chain removed here in clone.
if (result->IsNotFound()) {
if (!result.IsFound()) {
// Neither properties nor transitions found.
return AddProperty(name, value, attributes);
}
if (!result->IsLoaded()) {
return SetLazyProperty(result, name, value, attributes);
if (!result.IsLoaded()) {
return SetLazyProperty(&result, name, value, attributes);
}
PropertyDetails details = PropertyDetails(attributes, NORMAL);
// Check of IsReadOnly removed from here in clone.
switch (result->type()) {
switch (result.type()) {
case NORMAL:
return SetNormalizedProperty(name, value, details);
case FIELD:
return FastPropertyAtPut(result->GetFieldIndex(), value);
return FastPropertyAtPut(result.GetFieldIndex(), value);
case MAP_TRANSITION:
if (attributes == result->GetAttributes()) {
if (attributes == result.GetAttributes()) {
// Only use map transition if the attributes match.
return AddFastPropertyUsingMap(result->GetTransitionMap(),
return AddFastPropertyUsingMap(result.GetTransitionMap(),
name,
value);
}
return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_FUNCTION:
// Only replace the function if necessary.
if (value == result->GetConstantFunction()) return value;
if (value == result.GetConstantFunction()) return value;
// Preserve the attributes of this existing property.
attributes = result->GetAttributes();
attributes = result.GetAttributes();
return ConvertDescriptorToField(name, value, attributes);
case CALLBACKS:
case INTERCEPTOR:
......@@ -2136,7 +2132,7 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
name,
continue_search);
}
if (result->IsValid()) {
if (result->IsProperty()) {
switch (result->type()) {
case NORMAL: // fall through
case FIELD:
......@@ -2146,13 +2142,8 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
case INTERCEPTOR:
return result->holder()->
GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return ABSENT;
default:
UNREACHABLE();
break;
}
}
return ABSENT;
......@@ -2325,7 +2316,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) {
// Check local property, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (!result.IsValid()) return Heap::true_value();
if (!result.IsProperty()) return Heap::true_value();
// Normalize object if needed.
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
......@@ -2509,7 +2500,7 @@ Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
} else {
LookupResult result;
LocalLookup(name, &result);
if (!result.IsValid()) return Heap::true_value();
if (!result.IsProperty()) return Heap::true_value();
// Ignore attributes if forcing a deletion.
if (result.IsDontDelete() && mode != FORCE_DELETION) {
return Heap::false_value();
......@@ -2744,7 +2735,7 @@ void JSObject::Lookup(String* name, LookupResult* result) {
current != Heap::null_value();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookup(name, result);
if (result->IsValid() && !result->IsTransitionType()) return;
if (result->IsProperty()) return;
}
result->NotFound();
}
......@@ -2756,7 +2747,7 @@ void JSObject::LookupCallback(String* name, LookupResult* result) {
current != Heap::null_value();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
if (result->IsValid() && result->type() == CALLBACKS) return;
if (result->IsProperty() && result->type() == CALLBACKS) return;
}
result->NotFound();
}
......@@ -2786,7 +2777,7 @@ Object* JSObject::DefineGetterSetter(String* name,
// cause security problems.
LookupResult callback_result;
LookupCallback(name, &callback_result);
if (callback_result.IsValid()) {
if (callback_result.IsFound()) {
Object* obj = callback_result.GetCallbackObject();
if (obj->IsAccessorInfo() &&
AccessorInfo::cast(obj)->prohibits_overwriting()) {
......@@ -2837,7 +2828,7 @@ Object* JSObject::DefineGetterSetter(String* name,
// Lookup the name.
LookupResult result;
LocalLookup(name, &result);
if (result.IsValid()) {
if (result.IsProperty()) {
if (result.IsReadOnly()) return Heap::undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
......@@ -2959,7 +2950,7 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
obj = JSObject::cast(obj)->GetPrototype()) {
LookupResult result;
JSObject::cast(obj)->LocalLookup(name, &result);
if (result.IsValid()) {
if (result.IsProperty()) {
if (result.IsReadOnly()) return Heap::undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
......@@ -4851,7 +4842,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
LookupResult result;
String* name = GetThisPropertyAssignmentName(i);
js_object->LocalLookupRealNamedProperty(name, &result);
if (result.IsValid() && result.type() == CALLBACKS) {
if (result.IsProperty() && result.type() == CALLBACKS) {
return false;
}
}
......@@ -6252,7 +6243,9 @@ Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
// Check local property in holder, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsValid()) return GetProperty(receiver, &result, name, attributes);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
}
// Continue searching via the prototype chain.
Object* pt = GetPrototype();
*attributes = ABSENT;
......@@ -6268,8 +6261,10 @@ Object* JSObject::GetLocalPropertyPostInterceptor(
// Check local property in holder, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (!result.IsValid()) return Heap::undefined_value();
return GetProperty(receiver, &result, name, attributes);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
}
return Heap::undefined_value();
}
......@@ -6321,24 +6316,7 @@ bool JSObject::HasRealNamedProperty(String* key) {
LookupResult result;
LocalLookupRealNamedProperty(key, &result);
if (result.IsValid()) {
switch (result.type()) {
case NORMAL: // fall through.
case FIELD: // fall through.
case CALLBACKS: // fall through.
case CONSTANT_FUNCTION:
return true;
case INTERCEPTOR:
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return false;
default:
UNREACHABLE();
}
}
return false;
return result.IsProperty() && (result.type() != INTERCEPTOR);
}
......@@ -6400,7 +6378,7 @@ bool JSObject::HasRealNamedCallbackProperty(String* key) {
LookupResult result;
LocalLookupRealNamedProperty(key, &result);
return result.IsValid() && (result.type() == CALLBACKS);
return result.IsProperty() && (result.type() == CALLBACKS);
}
......
......@@ -33,7 +33,7 @@ namespace internal {
#ifdef DEBUG
void LookupResult::Print() {
if (!IsValid()) {
if (!IsFound()) {
PrintF("Not Found\n");
return;
}
......
......@@ -201,23 +201,17 @@ class LookupResult BASE_EMBEDDED {
}
JSObject* holder() {
ASSERT(IsValid());
ASSERT(IsFound());
return holder_;
}
PropertyType type() {
ASSERT(IsValid());
ASSERT(IsFound());
return details_.type();
}
bool IsTransitionType() {
PropertyType t = type();
if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
return false;
}
PropertyAttributes GetAttributes() {
ASSERT(IsValid());
ASSERT(IsFound());
return details_.attributes();
}
......@@ -229,14 +223,17 @@ class LookupResult BASE_EMBEDDED {
bool IsDontDelete() { return details_.IsDontDelete(); }
bool IsDontEnum() { return details_.IsDontEnum(); }
bool IsDeleted() { return details_.IsDeleted(); }
bool IsFound() { return lookup_type_ != NOT_FOUND; }
bool IsValid() { return lookup_type_ != NOT_FOUND; }
bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
// Tells whether the result is a property.
// Excluding transitions and the null descriptor.
// Is the result is a property excluding transitions and the null
// descriptor?
bool IsProperty() {
return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE;
return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE);
}
// Is the result a property or a transition?
bool IsPropertyOrTransition() {
return IsFound() && (type() != NULL_DESCRIPTOR);
}
bool IsCacheable() { return cacheable_; }
......
......@@ -2895,7 +2895,7 @@ static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
// If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
// delete it to avoid running into trouble in DefineAccessor, which
// handles this incorrectly if the property is readonly (does nothing)
if (result.IsValid() &&
if (result.IsProperty() &&
(result.type() == FIELD || result.type() == NORMAL
|| result.type() == CONSTANT_FUNCTION)) {
obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
......
......@@ -1070,11 +1070,13 @@ Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
}
void StubCompiler::LookupPostInterceptor(JSObject* holder,
String* name,
LookupResult* lookup) {
holder->LocalLookupRealNamedProperty(name, lookup);
if (lookup->IsNotFound()) {
if (!lookup->IsProperty()) {
lookup->NotFound();
Object* proto = holder->GetPrototype();
if (proto != Heap::null_value()) {
proto->Lookup(name, lookup);
......
......@@ -399,7 +399,7 @@ static void CompileLoadInterceptor(Compiler* compiler,
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
if (lookup->IsValid() && lookup->IsCacheable()) {
if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
......
......@@ -2528,6 +2528,33 @@ THREADED_TEST(NamedInterceptorPropertyRead) {
}
static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
const AccessorInfo& info) {
// Set x on the prototype object and do not handle the get request.
v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
return v8::Handle<Value>();
}
// This is a regression test for http://crbug.com/20104. Map
// transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead) {
v8::HandleScope scope;
Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
Local<v8::ObjectTemplate> instance_template
= function_template->InstanceTemplate();
instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
LocalContext context;
context->Global()->Set(v8_str("F"), function_template->GetFunction());
// Create an instance of F and introduce a map transition for x.
CompileRun("var o = new F(); o.x = 23;");
// Create an instance of F and invoke the getter. The result should be 23.
Local<Value> result = CompileRun("o = new F(); o.x");
CHECK_EQ(result->Int32Value(), 23);
}
static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment