Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 58d243bfb9561b081b8aaa1b68febc9cc3ab314c..274749d568393b95300ba9a666a57e3b4f32c08b 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -23,6 +23,7 @@ |
#include "src/hydrogen.h" |
#include "src/isolate-inl.h" |
#include "src/log.h" |
+#include "src/lookup.h" |
#include "src/objects-inl.h" |
#include "src/objects-visiting-inl.h" |
#include "src/macro-assembler.h" |
@@ -127,17 +128,40 @@ void Object::Lookup(Handle<Name> name, LookupResult* result) { |
} |
-MaybeHandle<Object> Object::GetPropertyWithReceiver( |
- Handle<Object> object, |
- Handle<Object> receiver, |
- Handle<Name> name, |
- PropertyAttributes* attributes) { |
- LookupResult lookup(name->GetIsolate()); |
- object->Lookup(name, &lookup); |
- MaybeHandle<Object> result = |
- GetProperty(object, receiver, &lookup, name, attributes); |
- ASSERT(*attributes <= ABSENT); |
- return result; |
+MaybeHandle<Object> Object::GetProperty(LookupIterator* it) { |
+ for (; it->IsFound(); it->Next()) { |
+ switch (it->state()) { |
+ case LookupIterator::NOT_FOUND: |
+ UNREACHABLE(); |
+ case LookupIterator::JSPROXY: |
+ return JSProxy::GetPropertyWithHandler( |
+ it->GetJSProxy(), it->GetReceiver(), it->name()); |
+ case LookupIterator::INTERCEPTOR: { |
+ MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithInterceptor( |
+ it->GetHolder(), it->GetReceiver(), it->name()); |
+ if (!maybe_result.is_null()) return maybe_result; |
+ if (it->isolate()->has_pending_exception()) return maybe_result; |
+ break; |
+ } |
+ case LookupIterator::ACCESS_CHECK: { |
+ if (it->HasAccess(v8::ACCESS_GET)) break; |
+ return JSObject::GetPropertyWithFailedAccessCheck(it); |
+ } |
+ case LookupIterator::PROPERTY: |
+ if (it->HasProperty()) { |
+ switch (it->property_type()) { |
+ case LookupIterator::ACCESSORS: |
+ return GetPropertyWithAccessor( |
+ it->GetReceiver(), it->name(), |
+ it->GetHolder(), it->GetAccessors()); |
+ case LookupIterator::DATA: |
+ return it->GetDataValue(); |
+ } |
+ } |
+ break; |
+ } |
+ } |
+ return it->factory()->undefined_value(); |
} |
@@ -377,7 +401,7 @@ MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy, |
} |
-MaybeHandle<Object> Object::GetPropertyWithCallback(Handle<Object> receiver, |
+MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver, |
Handle<Name> name, |
Handle<JSObject> holder, |
Handle<Object> structure) { |
@@ -542,46 +566,33 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter( |
} |
-static bool FindAllCanReadHolder(LookupResult* result, |
- Handle<Name> name, |
- bool check_prototype) { |
- if (result->IsInterceptor()) { |
- result->holder()->LookupOwnRealNamedProperty(name, result); |
- } |
- |
- while (result->IsProperty()) { |
- if (result->type() == CALLBACKS) { |
- Object* callback_obj = result->GetCallbackObject(); |
- if (callback_obj->IsAccessorInfo()) { |
- if (AccessorInfo::cast(callback_obj)->all_can_read()) return true; |
- } else if (callback_obj->IsAccessorPair()) { |
- if (AccessorPair::cast(callback_obj)->all_can_read()) return true; |
+static bool FindAllCanReadHolder(LookupIterator* it) { |
+ for (; it->IsFound(); it->Next()) { |
+ if (it->state() == LookupIterator::PROPERTY && |
+ it->HasProperty() && |
+ it->property_type() == LookupIterator::ACCESSORS) { |
+ Handle<Object> accessors = it->GetAccessors(); |
+ if (accessors->IsAccessorInfo()) { |
+ if (AccessorInfo::cast(*accessors)->all_can_read()) return true; |
+ } else if (accessors->IsAccessorPair()) { |
+ if (AccessorPair::cast(*accessors)->all_can_read()) return true; |
} |
} |
- if (!check_prototype) break; |
- result->holder()->LookupRealNamedPropertyInPrototypes(name, result); |
} |
return false; |
} |
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( |
- Handle<JSObject> object, |
- Handle<Object> receiver, |
- LookupResult* result, |
- Handle<Name> name, |
- PropertyAttributes* attributes) { |
- if (FindAllCanReadHolder(result, name, true)) { |
- *attributes = result->GetAttributes(); |
- Handle<JSObject> holder(result->holder()); |
- Handle<Object> callbacks(result->GetCallbackObject(), result->isolate()); |
- return GetPropertyWithCallback(receiver, name, holder, callbacks); |
+ LookupIterator* it) { |
+ Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); |
+ if (FindAllCanReadHolder(it)) { |
+ return GetPropertyWithAccessor( |
+ it->GetReceiver(), it->name(), it->GetHolder(), it->GetAccessors()); |
} |
- *attributes = ABSENT; |
- Isolate* isolate = result->isolate(); |
- isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- return isolate->factory()->undefined_value(); |
+ it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
+ return it->factory()->undefined_value(); |
} |
@@ -590,10 +601,12 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( |
LookupResult* result, |
Handle<Name> name, |
bool check_prototype) { |
- if (FindAllCanReadHolder(result, name, check_prototype)) { |
- return result->GetAttributes(); |
- } |
- result->isolate()->ReportFailedAccessCheck(object, v8::ACCESS_HAS); |
+ LookupIterator::Type type = check_prototype |
+ ? LookupIterator::CHECK_DERIVED |
+ : LookupIterator::CHECK_OWN_REAL; |
+ LookupIterator it(object, name, object, type); |
+ if (FindAllCanReadHolder(&it)) return it.property_details().attributes(); |
+ it.isolate()->ReportFailedAccessCheck(object, v8::ACCESS_HAS); |
// TODO(yangguo): Issue 3269, check for scheduled exception missing? |
return ABSENT; |
} |
@@ -793,86 +806,6 @@ bool JSObject::IsDirty() { |
} |
-MaybeHandle<Object> Object::GetProperty(Handle<Object> object, |
- Handle<Object> receiver, |
- LookupResult* result, |
- Handle<Name> name, |
- PropertyAttributes* attributes) { |
- Isolate* isolate = name->GetIsolate(); |
- Factory* factory = isolate->factory(); |
- |
- // Make sure that the top context does not change when doing |
- // callbacks or interceptor calls. |
- AssertNoContextChange ncc(isolate); |
- |
- // Traverse the prototype chain from the current object (this) to |
- // the holder and check for access rights. This avoids traversing the |
- // objects more than once in case of interceptors, because the |
- // 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. |
- // Proxy handlers do not use the proxy's prototype, so we can skip this. |
- if (!result->IsHandler()) { |
- ASSERT(*object != object->GetPrototype(isolate)); |
- Handle<Object> last = result->IsProperty() |
- ? handle(result->holder()->GetPrototype(), isolate) |
- : Handle<Object>::cast(factory->null_value()); |
- for (Handle<Object> current = object; |
- !current.is_identical_to(last); |
- current = Object::GetPrototype(isolate, current)) { |
- if (current->IsAccessCheckNeeded()) { |
- // Check if we're allowed to read from the current object. Note |
- // that even though we may not actually end up loading the named |
- // property from the current object, we still check that we have |
- // access to it. |
- Handle<JSObject> checked = Handle<JSObject>::cast(current); |
- if (!isolate->MayNamedAccess(checked, name, v8::ACCESS_GET)) { |
- return JSObject::GetPropertyWithFailedAccessCheck( |
- checked, receiver, result, name, attributes); |
- } |
- } |
- } |
- } |
- |
- if (!result->IsProperty()) { |
- *attributes = ABSENT; |
- return factory->undefined_value(); |
- } |
- *attributes = result->GetAttributes(); |
- |
- Handle<Object> value; |
- switch (result->type()) { |
- case NORMAL: { |
- value = JSObject::GetNormalizedProperty( |
- handle(result->holder(), isolate), result); |
- break; |
- } |
- case FIELD: |
- value = JSObject::FastPropertyAt(handle(result->holder(), isolate), |
- result->representation(), FieldIndex::ForLookupResult(result)); |
- break; |
- case CONSTANT: |
- return handle(result->GetConstant(), isolate); |
- case CALLBACKS: |
- return GetPropertyWithCallback( |
- receiver, name, handle(result->holder(), isolate), |
- handle(result->GetCallbackObject(), isolate)); |
- case HANDLER: |
- return JSProxy::GetPropertyWithHandler( |
- handle(result->proxy(), isolate), receiver, name); |
- case INTERCEPTOR: |
- return JSObject::GetPropertyWithInterceptor( |
- handle(result->holder(), isolate), receiver, name, attributes); |
- case NONEXISTENT: |
- UNREACHABLE(); |
- break; |
- } |
- ASSERT(!value->IsTheHole() || result->IsReadOnly()); |
- return value->IsTheHole() ? Handle<Object>::cast(factory->undefined_value()) |
- : value; |
-} |
- |
- |
MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
Handle<Object> object, |
Handle<Object> receiver, |
@@ -13780,60 +13713,35 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() { |
} |
-MaybeHandle<Object> JSObject::GetPropertyPostInterceptor( |
- Handle<JSObject> object, |
- Handle<Object> receiver, |
- Handle<Name> name, |
- PropertyAttributes* attributes) { |
- // Check own property in holder, ignore interceptor. |
- Isolate* isolate = object->GetIsolate(); |
- LookupResult lookup(isolate); |
- object->LookupOwnRealNamedProperty(name, &lookup); |
- if (lookup.IsFound()) { |
- return GetProperty(object, receiver, &lookup, name, attributes); |
- } else { |
- // Continue searching via the prototype chain. |
- Handle<Object> prototype(object->GetPrototype(), isolate); |
- *attributes = ABSENT; |
- if (prototype->IsNull()) return isolate->factory()->undefined_value(); |
- return GetPropertyWithReceiver(prototype, receiver, name, attributes); |
- } |
-} |
- |
- |
MaybeHandle<Object> JSObject::GetPropertyWithInterceptor( |
- Handle<JSObject> object, |
+ Handle<JSObject> holder, |
Handle<Object> receiver, |
- Handle<Name> name, |
- PropertyAttributes* attributes) { |
- Isolate* isolate = object->GetIsolate(); |
+ Handle<Name> name) { |
+ Isolate* isolate = holder->GetIsolate(); |
// TODO(rossberg): Support symbols in the API. |
if (name->IsSymbol()) return isolate->factory()->undefined_value(); |
- Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor(), isolate); |
+ Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate); |
Handle<String> name_string = Handle<String>::cast(name); |
- if (!interceptor->getter()->IsUndefined()) { |
- v8::NamedPropertyGetterCallback getter = |
- v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter()); |
- LOG(isolate, |
- ApiNamedPropertyAccess("interceptor-named-get", *object, *name)); |
- PropertyCallbackArguments |
- args(isolate, interceptor->data(), *receiver, *object); |
- v8::Handle<v8::Value> result = |
- args.Call(getter, v8::Utils::ToLocal(name_string)); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- if (!result.IsEmpty()) { |
- *attributes = NONE; |
- Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
- result_internal->VerifyApiCallResultType(); |
- // Rebox handle before return. |
- return handle(*result_internal, isolate); |
- } |
- } |
+ if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>(); |
+ |
+ v8::NamedPropertyGetterCallback getter = |
+ v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter()); |
+ LOG(isolate, |
+ ApiNamedPropertyAccess("interceptor-named-get", *holder, *name)); |
+ PropertyCallbackArguments |
+ args(isolate, interceptor->data(), *receiver, *holder); |
+ v8::Handle<v8::Value> result = |
+ args.Call(getter, v8::Utils::ToLocal(name_string)); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ if (result.IsEmpty()) return MaybeHandle<Object>(); |
- return GetPropertyPostInterceptor(object, receiver, name, attributes); |
+ Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
+ result_internal->VerifyApiCallResultType(); |
+ // Rebox handle before return |
+ return handle(*result_internal, isolate); |
} |