From bb2b08b194336abe293ed127e21c3dea2b748643 Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Wed, 11 Jun 2014 09:59:14 +0000 Subject: [PATCH] Implement LookupIterator designed to replace LookupResult BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/314953006 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21767 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- BUILD.gn | 2 + src/api.cc | 5 +- src/arm/stub-cache-arm.cc | 2 +- src/arm64/stub-cache-arm64.cc | 2 +- src/handles.h | 6 +- src/ia32/stub-cache-ia32.cc | 2 +- src/ic.cc | 9 +- src/ic.h | 3 +- src/json-stringifier.h | 10 +- src/lookup.cc | 202 +++++++++++++++++++++++++++++++++ src/lookup.h | 167 ++++++++++++++++++++++++++++ src/mips/stub-cache-mips.cc | 2 +- src/objects-inl.h | 8 +- src/objects.cc | 252 ++++++++++++++---------------------------- src/objects.h | 33 ++---- src/runtime.cc | 7 +- src/stub-cache.cc | 81 +++----------- src/stub-cache.h | 3 +- src/x64/stub-cache-x64.cc | 2 +- src/x87/stub-cache-x87.cc | 2 +- tools/gyp/v8.gyp | 2 + 21 files changed, 500 insertions(+), 302 deletions(-) create mode 100644 src/lookup.cc create mode 100644 src/lookup.h diff --git a/BUILD.gn b/BUILD.gn index a281a91..00ad3cc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -574,6 +574,8 @@ source_set("v8_base") { "src/log-utils.h", "src/log.cc", "src/log.h", + "src/lookup.cc", + "src/lookup.h", "src/macro-assembler.h", "src/mark-compact.cc", "src/mark-compact.h", diff --git a/src/api.cc b/src/api.cc index 0f04cd1..91c2856 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3518,10 +3518,9 @@ static Local GetPropertyByLookup(i::Isolate* isolate, // If the property being looked up is a callback, it can throw // an exception. EXCEPTION_PREAMBLE(isolate); - PropertyAttributes ignored; + i::LookupIterator it(receiver, name); i::Handle result; - has_pending_exception = !i::Object::GetProperty( - receiver, receiver, lookup, name, &ignored).ToHandle(&result); + has_pending_exception = !i::Object::GetProperty(&it).ToHandle(&result); EXCEPTION_BAILOUT_CHECK(isolate, Local()); return Utils::ToLocal(result); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 5f17c9f..edc6953 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1145,7 +1145,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( this->name(), interceptor_holder); ExternalReference ref = - ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } diff --git a/src/arm64/stub-cache-arm64.cc b/src/arm64/stub-cache-arm64.cc index b933f65..b0f58fd 100644 --- a/src/arm64/stub-cache-arm64.cc +++ b/src/arm64/stub-cache-arm64.cc @@ -1114,7 +1114,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( masm(), receiver(), holder_reg, this->name(), interceptor_holder); ExternalReference ref = - ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } diff --git a/src/handles.h b/src/handles.h index 19e023b..3bd82e5 100644 --- a/src/handles.h +++ b/src/handles.h @@ -44,10 +44,10 @@ class MaybeHandle { location_ = reinterpret_cast(maybe_handle.location_); } - INLINE(void Assert()) { ASSERT(location_ != NULL); } - INLINE(void Check()) { CHECK(location_ != NULL); } + INLINE(void Assert() const) { ASSERT(location_ != NULL); } + INLINE(void Check() const) { CHECK(location_ != NULL); } - INLINE(Handle ToHandleChecked()) { + INLINE(Handle ToHandleChecked()) const { Check(); return Handle(location_); } diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 9eb113c..4927019 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -1121,7 +1121,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( __ push(scratch2()); // restore old return address ExternalReference ref = - ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } diff --git a/src/ic.cc b/src/ic.cc index 0544a5b..f09af32 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -625,17 +625,14 @@ MaybeHandle LoadIC::Load(Handle object, Handle name) { // Update inline cache and stub cache. if (use_ic) UpdateCaches(&lookup, object, name); - PropertyAttributes attr; // Get the property. + LookupIterator it(object, name); Handle result; ASSIGN_RETURN_ON_EXCEPTION( - isolate(), - result, - Object::GetProperty(object, object, &lookup, name, &attr), - Object); + isolate(), result, Object::GetProperty(&it), Object); // If the property is not present, check if we need to throw an exception. if ((lookup.IsInterceptor() || lookup.IsHandler()) && - attr == ABSENT && IsUndeclaredGlobal(object)) { + !it.IsFound() && IsUndeclaredGlobal(object)) { return ReferenceError("not_defined", name); } diff --git a/src/ic.h b/src/ic.h index f3e2418..ae8e5c3 100644 --- a/src/ic.h +++ b/src/ic.h @@ -30,8 +30,7 @@ const int kMaxKeyedPolymorphism = 4; /* Utilities for IC stubs. */ \ ICU(StoreCallbackProperty) \ ICU(LoadPropertyWithInterceptorOnly) \ - ICU(LoadPropertyWithInterceptorForLoad) \ - ICU(LoadPropertyWithInterceptorForCall) \ + ICU(LoadPropertyWithInterceptor) \ ICU(KeyedLoadPropertyWithInterceptor) \ ICU(StoreInterceptorProperty) \ ICU(CompareIC_Miss) \ diff --git a/src/json-stringifier.h b/src/json-stringifier.h index 23927b1..03461d7 100644 --- a/src/json-stringifier.h +++ b/src/json-stringifier.h @@ -338,15 +338,9 @@ void BasicJsonStringifier::Append_(const Char* chars) { MaybeHandle BasicJsonStringifier::ApplyToJsonFunction( Handle object, Handle key) { - LookupResult lookup(isolate_); - JSObject::cast(*object)->LookupRealNamedProperty(tojson_string_, &lookup); - if (!lookup.IsProperty()) return object; - PropertyAttributes attr; + LookupIterator it(object, tojson_string_, LookupIterator::SKIP_INTERCEPTOR); Handle fun; - ASSIGN_RETURN_ON_EXCEPTION( - isolate_, fun, - Object::GetProperty(object, object, &lookup, tojson_string_, &attr), - Object); + ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); if (!fun->IsJSFunction()) return object; // Call toJSON function. diff --git a/src/lookup.cc b/src/lookup.cc new file mode 100644 index 0000000..17a8ed0 --- /dev/null +++ b/src/lookup.cc @@ -0,0 +1,202 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#include "src/bootstrapper.h" +#include "src/lookup.h" + +namespace v8 { +namespace internal { + + +void LookupIterator::Next() { + has_property_ = false; + do { + LookupInHolder(); + } while (!IsFound() && NextHolder()); +} + + +Handle LookupIterator::GetOrigin() const { + Handle receiver = GetReceiver(); + if (receiver->IsJSReceiver()) return Handle::cast(receiver); + Context* native_context = isolate_->context()->native_context(); + JSFunction* function; + if (receiver->IsNumber()) { + function = native_context->number_function(); + } else if (receiver->IsString()) { + function = native_context->string_function(); + } else if (receiver->IsSymbol()) { + function = native_context->symbol_function(); + } else if (receiver->IsBoolean()) { + function = native_context->boolean_function(); + } else { + UNREACHABLE(); + function = NULL; + } + return handle(JSReceiver::cast(function->instance_prototype())); +} + + +Handle LookupIterator::GetReceiverMap() const { + Handle receiver = GetReceiver(); + if (receiver->IsNumber()) return isolate_->factory()->heap_number_map(); + return handle(Handle::cast(receiver)->map()); +} + + +bool LookupIterator::NextHolder() { + if (holder_map_->prototype()->IsNull()) return false; + + Handle next(JSReceiver::cast(holder_map_->prototype())); + + if (!check_derived() && + // TODO(verwaest): Check if this is actually necessary currently. If it + // is, this should be handled by setting is_hidden_prototype on the + // global object behind the proxy. + !holder_map_->IsJSGlobalProxyMap() && + !next->map()->is_hidden_prototype()) { + return false; + } + + holder_map_ = handle(next->map()); + maybe_holder_ = next; + return true; +} + + +void LookupIterator::LookupInHolder() { + State old_state = state_; + state_ = NOT_FOUND; + switch (old_state) { + case NOT_FOUND: + if (holder_map_->IsJSProxyMap()) { + state_ = JSPROXY; + return; + } + if (check_access_check() && holder_map_->is_access_check_needed()) { + state_ = ACCESS_CHECK; + return; + } + case ACCESS_CHECK: + if (check_interceptor() && holder_map_->has_named_interceptor()) { + state_ = INTERCEPTOR; + return; + } + case INTERCEPTOR: + if (holder_map_->is_dictionary_map()) { + property_encoding_ = DICTIONARY; + } else { + DescriptorArray* descriptors = holder_map_->instance_descriptors(); + number_ = descriptors->SearchWithCache(*name_, *holder_map_); + if (number_ == DescriptorArray::kNotFound) return; + property_encoding_ = DESCRIPTOR; + } + state_ = PROPERTY; + case PROPERTY: + return; + case JSPROXY: + UNREACHABLE(); + } +} + + +bool LookupIterator::IsBootstrapping() const { + return isolate_->bootstrapper()->IsActive(); +} + + +bool LookupIterator::HasAccess(v8::AccessType access_type) const { + ASSERT_EQ(ACCESS_CHECK, state_); + ASSERT(is_guaranteed_to_have_holder()); + return isolate_->MayNamedAccess(GetHolder(), name_, access_type); +} + + +bool LookupIterator::HasProperty() { + ASSERT_EQ(PROPERTY, state_); + ASSERT(is_guaranteed_to_have_holder()); + + if (property_encoding_ == DICTIONARY) { + Handle holder = GetHolder(); + number_ = holder->property_dictionary()->FindEntry(name_); + if (number_ == NameDictionary::kNotFound) return false; + + property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_); + // Holes in dictionary cells are absent values unless marked as read-only. + if (holder->IsGlobalObject() && + (property_details_.IsDeleted() || + (!property_details_.IsReadOnly() && FetchValue()->IsTheHole()))) { + return false; + } + } else { + property_details_ = holder_map_->instance_descriptors()->GetDetails( + number_); + } + + switch (property_details_.type()) { + case v8::internal::FIELD: + case v8::internal::NORMAL: + case v8::internal::CONSTANT: + property_type_ = DATA; + break; + case v8::internal::CALLBACKS: + property_type_ = ACCESSORS; + break; + case v8::internal::HANDLER: + case v8::internal::NONEXISTENT: + case v8::internal::INTERCEPTOR: + UNREACHABLE(); + } + + has_property_ = true; + return true; +} + + +Handle LookupIterator::FetchValue() const { + Object* result = NULL; + switch (property_encoding_) { + case DICTIONARY: + result = GetHolder()->property_dictionary()->ValueAt(number_); + if (GetHolder()->IsGlobalObject()) { + result = PropertyCell::cast(result)->value(); + } + break; + case DESCRIPTOR: + if (property_details_.type() == v8::internal::FIELD) { + FieldIndex field_index = FieldIndex::ForDescriptor( + *holder_map_, number_); + return JSObject::FastPropertyAt( + GetHolder(), property_details_.representation(), field_index); + } + result = holder_map_->instance_descriptors()->GetValue(number_); + } + return handle(result, isolate_); +} + + +Handle LookupIterator::GetAccessors() const { + ASSERT(has_property_); + ASSERT_EQ(ACCESSORS, property_type_); + return FetchValue(); +} + + +Handle LookupIterator::GetDataValue() const { + ASSERT(has_property_); + ASSERT_EQ(DATA, property_type_); + Handle value = FetchValue(); + if (value->IsTheHole()) { + ASSERT_EQ(DICTIONARY, property_encoding_); + ASSERT(GetHolder()->IsGlobalObject()); + ASSERT(property_details_.IsReadOnly()); + return factory()->undefined_value(); + } + return value; +} + + +} } // namespace v8::internal diff --git a/src/lookup.h b/src/lookup.h new file mode 100644 index 0000000..fb91b4e --- /dev/null +++ b/src/lookup.h @@ -0,0 +1,167 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_LOOKUP_H_ +#define V8_LOOKUP_H_ + +#include "src/factory.h" +#include "src/isolate.h" +#include "src/objects.h" + +namespace v8 { +namespace internal { + +class LookupIterator V8_FINAL BASE_EMBEDDED { + public: + enum Type { + CHECK_DERIVED = 1 << 0, + CHECK_INTERCEPTOR = 1 << 1, + CHECK_ACCESS_CHECK = 1 << 2, + CHECK_OWN_REAL = 0, + CHECK_ALL = CHECK_DERIVED | CHECK_INTERCEPTOR | CHECK_ACCESS_CHECK, + SKIP_INTERCEPTOR = CHECK_ALL ^ CHECK_INTERCEPTOR + }; + + enum State { + NOT_FOUND, + PROPERTY, + INTERCEPTOR, + ACCESS_CHECK, + JSPROXY + }; + + enum PropertyType { + DATA, + ACCESSORS + }; + + enum PropertyEncoding { + DICTIONARY, + DESCRIPTOR + }; + + LookupIterator(Handle receiver, + Handle name, + Type type = CHECK_ALL) + : type_(type), + state_(NOT_FOUND), + property_type_(DATA), + property_encoding_(DESCRIPTOR), + property_details_(NONE, NONEXISTENT, Representation::None()), + isolate_(name->GetIsolate()), + name_(name), + maybe_receiver_(receiver), + number_(DescriptorArray::kNotFound) { + Handle origin = GetOrigin(); + holder_map_ = handle(origin->map()); + maybe_holder_ = origin; + Next(); + } + + LookupIterator(Handle receiver, + Handle name, + Handle holder, + Type type = CHECK_ALL) + : type_(type), + state_(NOT_FOUND), + property_type_(DATA), + property_encoding_(DESCRIPTOR), + property_details_(NONE, NONEXISTENT, Representation::None()), + isolate_(name->GetIsolate()), + name_(name), + holder_map_(holder->map()), + maybe_receiver_(receiver), + maybe_holder_(holder), + number_(DescriptorArray::kNotFound) { + Next(); + } + + Isolate* isolate() const { return isolate_; } + State state() const { return state_; } + Handle name() const { return name_; } + + bool IsFound() const { return state_ != NOT_FOUND; } + void Next(); + + Heap* heap() const { return isolate_->heap(); } + Factory* factory() const { return isolate_->factory(); } + Handle GetReceiver() const { + return Handle::cast(maybe_receiver_.ToHandleChecked()); + } + Handle GetHolder() const { + ASSERT(IsFound() && state_ != JSPROXY); + return Handle::cast(maybe_holder_.ToHandleChecked()); + } + Handle GetOrigin() const; + + /* ACCESS_CHECK */ + bool HasAccess(v8::AccessType access_type) const; + + /* PROPERTY */ + // HasProperty needs to be called before any of the other PROPERTY methods + // below can be used. It ensures that we are able to provide a definite + // answer, and loads extra information about the property. + bool HasProperty(); + PropertyType property_type() const { + ASSERT(has_property_); + return property_type_; + } + PropertyDetails property_details() const { + ASSERT(has_property_); + return property_details_; + } + Handle GetAccessors() const; + Handle GetDataValue() const; + + /* JSPROXY */ + + Handle GetJSProxy() const { + return Handle::cast(maybe_holder_.ToHandleChecked()); + } + + private: + Handle GetReceiverMap() const; + + MUST_USE_RESULT bool NextHolder(); + void LookupInHolder(); + Handle FetchValue() const; + + bool IsBootstrapping() const; + + // Methods that fetch data from the holder ensure they always have a holder. + // This means the receiver needs to be present as opposed to just the receiver + // map. Other objects in the prototype chain are transitively guaranteed to be + // present via the receiver map. + bool is_guaranteed_to_have_holder() const { + return !maybe_receiver_.is_null(); + } + bool check_interceptor() const { + return !IsBootstrapping() && (type_ & CHECK_INTERCEPTOR) != 0; + } + bool check_derived() const { + return (type_ & CHECK_DERIVED) != 0; + } + bool check_access_check() const { + return (type_ & CHECK_ACCESS_CHECK) != 0; + } + + Type type_; + State state_; + bool has_property_; + PropertyType property_type_; + PropertyEncoding property_encoding_; + PropertyDetails property_details_; + Isolate* isolate_; + Handle name_; + Handle holder_map_; + MaybeHandle maybe_receiver_; + MaybeHandle maybe_holder_; + + int number_; +}; + + +} } // namespace v8::internal + +#endif // V8_LOOKUP_H_ diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc index 3b66382..13e7e4b 100644 --- a/src/mips/stub-cache-mips.cc +++ b/src/mips/stub-cache-mips.cc @@ -1137,7 +1137,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( this->name(), interceptor_holder); ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } } diff --git a/src/objects-inl.h b/src/objects-inl.h index cd61ab5..2bca797 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -29,6 +29,7 @@ #include "src/incremental-marking.h" #include "src/transitions-inl.h" #include "src/objects-visiting.h" +#include "src/lookup.h" namespace v8 { namespace internal { @@ -664,8 +665,7 @@ bool Object::IsJSObject() { bool Object::IsJSProxy() { if (!Object::IsHeapObject()) return false; - InstanceType type = HeapObject::cast(this)->map()->instance_type(); - return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE; + return HeapObject::cast(this)->map()->IsJSProxyMap(); } @@ -1053,8 +1053,8 @@ bool Object::HasSpecificClassOf(String* name) { MaybeHandle Object::GetProperty(Handle object, Handle name) { - PropertyAttributes attributes; - return GetPropertyWithReceiver(object, object, name, &attributes); + LookupIterator it(object, name); + return GetProperty(&it); } diff --git a/src/objects.cc b/src/objects.cc index 58d243b..274749d 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, LookupResult* result) { } -MaybeHandle Object::GetPropertyWithReceiver( - Handle object, - Handle receiver, - Handle name, - PropertyAttributes* attributes) { - LookupResult lookup(name->GetIsolate()); - object->Lookup(name, &lookup); - MaybeHandle result = - GetProperty(object, receiver, &lookup, name, attributes); - ASSERT(*attributes <= ABSENT); - return result; +MaybeHandle 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 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 JSProxy::GetPropertyWithHandler(Handle proxy, } -MaybeHandle Object::GetPropertyWithCallback(Handle receiver, +MaybeHandle Object::GetPropertyWithAccessor(Handle receiver, Handle name, Handle holder, Handle structure) { @@ -542,46 +566,33 @@ MaybeHandle Object::SetPropertyWithDefinedSetter( } -static bool FindAllCanReadHolder(LookupResult* result, - Handle 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 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 JSObject::GetPropertyWithFailedAccessCheck( - Handle object, - Handle receiver, - LookupResult* result, - Handle name, - PropertyAttributes* attributes) { - if (FindAllCanReadHolder(result, name, true)) { - *attributes = result->GetAttributes(); - Handle holder(result->holder()); - Handle callbacks(result->GetCallbackObject(), result->isolate()); - return GetPropertyWithCallback(receiver, name, holder, callbacks); + LookupIterator* it) { + Handle checked = Handle::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, 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::GetProperty(Handle object, - Handle receiver, - LookupResult* result, - Handle 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 last = result->IsProperty() - ? handle(result->holder()->GetPrototype(), isolate) - : Handle::cast(factory->null_value()); - for (Handle 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 checked = Handle::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 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::cast(factory->undefined_value()) - : value; -} - - MaybeHandle Object::GetElementWithReceiver(Isolate* isolate, Handle object, Handle receiver, @@ -13780,60 +13713,35 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() { } -MaybeHandle JSObject::GetPropertyPostInterceptor( - Handle object, - Handle receiver, - Handle 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 prototype(object->GetPrototype(), isolate); - *attributes = ABSENT; - if (prototype->IsNull()) return isolate->factory()->undefined_value(); - return GetPropertyWithReceiver(prototype, receiver, name, attributes); - } -} - - MaybeHandle JSObject::GetPropertyWithInterceptor( - Handle object, + Handle holder, Handle receiver, - Handle name, - PropertyAttributes* attributes) { - Isolate* isolate = object->GetIsolate(); + Handle name) { + Isolate* isolate = holder->GetIsolate(); // TODO(rossberg): Support symbols in the API. if (name->IsSymbol()) return isolate->factory()->undefined_value(); - Handle interceptor(object->GetNamedInterceptor(), isolate); + Handle interceptor(holder->GetNamedInterceptor(), isolate); Handle name_string = Handle::cast(name); - if (!interceptor->getter()->IsUndefined()) { - v8::NamedPropertyGetterCallback getter = - v8::ToCData(interceptor->getter()); - LOG(isolate, - ApiNamedPropertyAccess("interceptor-named-get", *object, *name)); - PropertyCallbackArguments - args(isolate, interceptor->data(), *receiver, *object); - v8::Handle result = - args.Call(getter, v8::Utils::ToLocal(name_string)); - RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); - if (!result.IsEmpty()) { - *attributes = NONE; - Handle result_internal = v8::Utils::OpenHandle(*result); - result_internal->VerifyApiCallResultType(); - // Rebox handle before return. - return handle(*result_internal, isolate); - } - } + if (interceptor->getter()->IsUndefined()) return MaybeHandle(); + + v8::NamedPropertyGetterCallback getter = + v8::ToCData(interceptor->getter()); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-get", *holder, *name)); + PropertyCallbackArguments + args(isolate, interceptor->data(), *receiver, *holder); + v8::Handle result = + args.Call(getter, v8::Utils::ToLocal(name_string)); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); + if (result.IsEmpty()) return MaybeHandle(); - return GetPropertyPostInterceptor(object, receiver, name, attributes); + Handle result_internal = v8::Utils::OpenHandle(*result); + result_internal->VerifyApiCallResultType(); + // Rebox handle before return + return handle(*result_internal, isolate); } diff --git a/src/objects.h b/src/objects.h index ef55761..2ed6157 100644 --- a/src/objects.h +++ b/src/objects.h @@ -862,6 +862,7 @@ class ElementsAccessor; class FixedArrayBase; class GlobalObject; class ObjectVisitor; +class LookupIterator; class StringStream; // We cannot just say "class HeapType;" if it is created from a template... =8-? template class TypeImpl; @@ -1456,11 +1457,7 @@ class Object { void Lookup(Handle name, LookupResult* result); - MUST_USE_RESULT static MaybeHandle GetPropertyWithReceiver( - Handle object, - Handle receiver, - Handle name, - PropertyAttributes* attributes); + MUST_USE_RESULT static MaybeHandle GetProperty(LookupIterator* it); MUST_USE_RESULT static inline MaybeHandle GetPropertyOrElement( Handle object, Handle key); @@ -1471,14 +1468,8 @@ class Object { MUST_USE_RESULT static inline MaybeHandle GetProperty( Handle object, Handle key); - MUST_USE_RESULT static MaybeHandle GetProperty( - Handle object, - Handle receiver, - LookupResult* result, - Handle key, - PropertyAttributes* attributes); - MUST_USE_RESULT static MaybeHandle GetPropertyWithCallback( + MUST_USE_RESULT static MaybeHandle GetPropertyWithAccessor( Handle receiver, Handle name, Handle holder, @@ -2264,13 +2255,7 @@ class JSObject: public JSReceiver { MUST_USE_RESULT static MaybeHandle GetPropertyWithInterceptor( Handle object, Handle receiver, - Handle name, - PropertyAttributes* attributes); - MUST_USE_RESULT static MaybeHandle GetPropertyPostInterceptor( - Handle object, - Handle receiver, - Handle name, - PropertyAttributes* attributes); + Handle name); // Returns true if this is an instance of an api function and has // been modified since it was created. May give false positives. @@ -2681,11 +2666,7 @@ class JSObject: public JSReceiver { // Used from Object::GetProperty(). MUST_USE_RESULT static MaybeHandle GetPropertyWithFailedAccessCheck( - Handle object, - Handle receiver, - LookupResult* result, - Handle name, - PropertyAttributes* attributes); + LookupIterator* it); MUST_USE_RESULT static MaybeHandle GetElementWithCallback( Handle object, @@ -6649,6 +6630,10 @@ class Map: public HeapObject { bool IsJSObjectMap() { return instance_type() >= FIRST_JS_OBJECT_TYPE; } + bool IsJSProxyMap() { + InstanceType type = instance_type(); + return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE; + } bool IsJSGlobalProxyMap() { return instance_type() == JS_GLOBAL_PROXY_TYPE; } diff --git a/src/runtime.cc b/src/runtime.cc index 07987e2..7eb753a 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -10787,7 +10787,7 @@ static Handle DebugLookupResultValue(Isolate* isolate, Handle structure(result->GetCallbackObject(), isolate); ASSERT(!structure->IsForeign()); if (structure->IsAccessorInfo()) { - MaybeHandle obj = JSObject::GetPropertyWithCallback( + MaybeHandle obj = JSObject::GetPropertyWithAccessor( receiver, name, handle(result->holder(), isolate), structure); if (!obj.ToHandle(&value)) { value = handle(isolate->pending_exception(), isolate); @@ -10968,11 +10968,10 @@ RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { RUNTIME_ASSERT(obj->HasNamedInterceptor()); CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); - PropertyAttributes attributes; Handle result; + LookupIterator it(obj, name, obj); ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, - JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes)); + isolate, result, JSObject::GetProperty(&it)); return *result; } diff --git a/src/stub-cache.cc b/src/stub-cache.cc index ef9270f..c15038e 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -546,83 +546,28 @@ static Object* ThrowReferenceError(Isolate* isolate, Name* name) { } -MUST_USE_RESULT static MaybeHandle LoadWithInterceptor( - Arguments* args, - PropertyAttributes* attrs) { - ASSERT(args->length() == StubCache::kInterceptorArgsLength); - Handle name_handle = - args->at(StubCache::kInterceptorArgsNameIndex); - Handle interceptor_info = - args->at(StubCache::kInterceptorArgsInfoIndex); - Handle receiver_handle = - args->at(StubCache::kInterceptorArgsThisIndex); - Handle holder_handle = - args->at(StubCache::kInterceptorArgsHolderIndex); - - Isolate* isolate = receiver_handle->GetIsolate(); - - // TODO(rossberg): Support symbols in the API. - if (name_handle->IsSymbol()) { - return JSObject::GetPropertyPostInterceptor( - holder_handle, receiver_handle, name_handle, attrs); - } - Handle name = Handle::cast(name_handle); - - Address getter_address = v8::ToCData
(interceptor_info->getter()); - v8::NamedPropertyGetterCallback getter = - FUNCTION_CAST(getter_address); - ASSERT(getter != NULL); - - PropertyCallbackArguments callback_args(isolate, - interceptor_info->data(), - *receiver_handle, - *holder_handle); - { - HandleScope scope(isolate); - // Use the interceptor getter. - v8::Handle r = - callback_args.Call(getter, v8::Utils::ToLocal(name)); - RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); - if (!r.IsEmpty()) { - *attrs = NONE; - Handle result = v8::Utils::OpenHandle(*r); - result->VerifyApiCallResultType(); - return scope.CloseAndEscape(result); - } - } - - return JSObject::GetPropertyPostInterceptor( - holder_handle, receiver_handle, name_handle, attrs); -} - - /** * Loads a property with an interceptor performing post interceptor * lookup if interceptor failed. */ -RUNTIME_FUNCTION(LoadPropertyWithInterceptorForLoad) { - PropertyAttributes attr = NONE; +RUNTIME_FUNCTION(LoadPropertyWithInterceptor) { HandleScope scope(isolate); + ASSERT(args.length() == StubCache::kInterceptorArgsLength); + Handle name = + args.at(StubCache::kInterceptorArgsNameIndex); + Handle receiver = + args.at(StubCache::kInterceptorArgsThisIndex); + Handle holder = + args.at(StubCache::kInterceptorArgsHolderIndex); + Handle result; + LookupIterator it(receiver, name, holder); ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, LoadWithInterceptor(&args, &attr)); - - // If the property is present, return it. - if (attr != ABSENT) return *result; - return ThrowReferenceError(isolate, Name::cast(args[0])); -} + isolate, result, JSObject::GetProperty(&it)); + if (it.IsFound()) return *result; -RUNTIME_FUNCTION(LoadPropertyWithInterceptorForCall) { - PropertyAttributes attr; - HandleScope scope(isolate); - Handle result; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, LoadWithInterceptor(&args, &attr)); - // This is call IC. In this case, we simply return the undefined result which - // will lead to an exception when trying to invoke the result as a - // function. - return *result; + return ThrowReferenceError(isolate, Name::cast(args[0])); } diff --git a/src/stub-cache.h b/src/stub-cache.h index 7ab7bed..9f2a87b 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -270,8 +270,7 @@ DECLARE_RUNTIME_FUNCTION(StoreCallbackProperty); // Support functions for IC stubs for interceptors. DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly); -DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorForLoad); -DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorForCall); +DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptor); DECLARE_RUNTIME_FUNCTION(StoreInterceptorProperty); DECLARE_RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor); diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index b0aa310..422ef2e 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -1054,7 +1054,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( __ PushReturnAddressFrom(scratch2()); ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } } diff --git a/src/x87/stub-cache-x87.cc b/src/x87/stub-cache-x87.cc index fee4871..f480b51 100644 --- a/src/x87/stub-cache-x87.cc +++ b/src/x87/stub-cache-x87.cc @@ -1120,7 +1120,7 @@ void LoadStubCompiler::GenerateLoadInterceptor( __ push(scratch2()); // restore old return address ExternalReference ref = - ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 174243c..1df1169 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -472,6 +472,8 @@ '../../src/log-utils.h', '../../src/log.cc', '../../src/log.h', + '../../src/lookup.cc', + '../../src/lookup.h', '../../src/macro-assembler.h', '../../src/mark-compact.cc', '../../src/mark-compact.h', -- 2.7.4