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,
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,
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,
// 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() &&
#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);
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());
// 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));
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.
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");
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");
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));
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,
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;
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;
}
}
holder->LocalLookupRealNamedProperty(name, lookup);
- if (lookup->IsValid()) {
+ if (lookup->IsProperty()) {
ASSERT(lookup->type() != INTERCEPTOR);
return;
}
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)) {
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();
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);
}
bool can_be_inlined =
FLAG_use_ic &&
state == PREMONOMORPHIC &&
- lookup.IsValid() &&
+ lookup.IsProperty() &&
lookup.IsLoaded() &&
lookup.IsCacheable() &&
lookup.holder() == *object &&
}
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;
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.
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);
}
}
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;
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);
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.
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.
LookupResult* result,
String* name,
PropertyAttributes* attributes) {
- if (result->IsValid()) {
+ if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
// Only allow API accessors.
// 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,
// 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();
}
}
LookupResult* result,
String* name,
bool continue_search) {
- if (result->IsValid()) {
+ if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
// Only allow API accessors.
// 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,
} else {
result->holder()->LocalLookupRealNamedProperty(name, &r);
}
- if (r.IsValid()) {
+ if (r.IsProperty()) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
&r,
name,
break;
}
- default: {
- break;
- }
+ default:
+ UNREACHABLE();
}
}
// 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
// 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);
}
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;
}
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.
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();
}
// 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()) {
// 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()) {
}
// 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:
name,
continue_search);
}
- if (result->IsValid()) {
+ if (result->IsProperty()) {
switch (result->type()) {
case NORMAL: // fall through
case FIELD:
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;
// 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);
} 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();
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();
}
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();
}
// 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()) {
// 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();
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();
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;
}
}
// 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;
// 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();
}
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);
}
LookupResult result;
LocalLookupRealNamedProperty(key, &result);
- return result.IsValid() && (result.type() == CALLBACKS);
+ return result.IsProperty() && (result.type() == CALLBACKS);
}
#ifdef DEBUG
void LookupResult::Print() {
- if (!IsValid()) {
+ if (!IsFound()) {
PrintF("Not Found\n");
return;
}
}
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();
}
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_; }
// 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);
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);
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,
}
+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();