Revision: 21767
Author: [email protected]
Date: Wed Jun 11 09:59:14 2014 UTC
Log: Implement LookupIterator designed to replace LookupResult
BUG=
[email protected]
Review URL: https://codereview.chromium.org/314953006
http://code.google.com/p/v8/source/detail?r=21767
Added:
/branches/bleeding_edge/src/lookup.cc
/branches/bleeding_edge/src/lookup.h
Modified:
/branches/bleeding_edge/BUILD.gn
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/arm64/stub-cache-arm64.cc
/branches/bleeding_edge/src/handles.h
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/ic.h
/branches/bleeding_edge/src/json-stringifier.h
/branches/bleeding_edge/src/mips/stub-cache-mips.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/src/x87/stub-cache-x87.cc
/branches/bleeding_edge/tools/gyp/v8.gyp
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/lookup.cc Wed Jun 11 09:59:14 2014 UTC
@@ -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<JSReceiver> LookupIterator::GetOrigin() const {
+ Handle<Object> receiver = GetReceiver();
+ if (receiver->IsJSReceiver()) return Handle<JSReceiver>::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<Map> LookupIterator::GetReceiverMap() const {
+ Handle<Object> receiver = GetReceiver();
+ if (receiver->IsNumber()) return isolate_->factory()->heap_number_map();
+ return handle(Handle<HeapObject>::cast(receiver)->map());
+}
+
+
+bool LookupIterator::NextHolder() {
+ if (holder_map_->prototype()->IsNull()) return false;
+
+ Handle<JSReceiver> 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<JSObject> 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<Object> 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<Object> LookupIterator::GetAccessors() const {
+ ASSERT(has_property_);
+ ASSERT_EQ(ACCESSORS, property_type_);
+ return FetchValue();
+}
+
+
+Handle<Object> LookupIterator::GetDataValue() const {
+ ASSERT(has_property_);
+ ASSERT_EQ(DATA, property_type_);
+ Handle<Object> 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
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/lookup.h Wed Jun 11 09:59:14 2014 UTC
@@ -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<Object> receiver,
+ Handle<Name> 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<JSReceiver> origin = GetOrigin();
+ holder_map_ = handle(origin->map());
+ maybe_holder_ = origin;
+ Next();
+ }
+
+ LookupIterator(Handle<Object> receiver,
+ Handle<Name> name,
+ Handle<JSReceiver> 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> 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<Object> GetReceiver() const {
+ return Handle<Object>::cast(maybe_receiver_.ToHandleChecked());
+ }
+ Handle<JSObject> GetHolder() const {
+ ASSERT(IsFound() && state_ != JSPROXY);
+ return Handle<JSObject>::cast(maybe_holder_.ToHandleChecked());
+ }
+ Handle<JSReceiver> 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<Object> GetAccessors() const;
+ Handle<Object> GetDataValue() const;
+
+ /* JSPROXY */
+
+ Handle<JSProxy> GetJSProxy() const {
+ return Handle<JSProxy>::cast(maybe_holder_.ToHandleChecked());
+ }
+
+ private:
+ Handle<Map> GetReceiverMap() const;
+
+ MUST_USE_RESULT bool NextHolder();
+ void LookupInHolder();
+ Handle<Object> 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> name_;
+ Handle<Map> holder_map_;
+ MaybeHandle<Object> maybe_receiver_;
+ MaybeHandle<JSReceiver> maybe_holder_;
+
+ int number_;
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_LOOKUP_H_
=======================================
--- /branches/bleeding_edge/BUILD.gn Wed Jun 11 09:42:48 2014 UTC
+++ /branches/bleeding_edge/BUILD.gn Wed Jun 11 09:59:14 2014 UTC
@@ -574,6 +574,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",
=======================================
--- /branches/bleeding_edge/src/api.cc Tue Jun 10 10:51:33 2014 UTC
+++ /branches/bleeding_edge/src/api.cc Wed Jun 11 09:59:14 2014 UTC
@@ -3518,10 +3518,9 @@
// 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<i::Object> 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<Value>());
return Utils::ToLocal(result);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Jun 10 14:01:08
2014 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jun 11 09:59:14
2014 UTC
@@ -1145,7 +1145,7 @@
this->name(), interceptor_holder);
ExternalReference ref =
-
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
isolate());
__ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength,
1);
}
=======================================
--- /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Tue Jun 10
14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Wed Jun 11
09:59:14 2014 UTC
@@ -1114,7 +1114,7 @@
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);
}
=======================================
--- /branches/bleeding_edge/src/handles.h Tue Jun 3 08:12:43 2014 UTC
+++ /branches/bleeding_edge/src/handles.h Wed Jun 11 09:59:14 2014 UTC
@@ -44,10 +44,10 @@
location_ = reinterpret_cast<T**>(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<T> ToHandleChecked()) {
+ INLINE(Handle<T> ToHandleChecked()) const {
Check();
return Handle<T>(location_);
}
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jun 10 14:01:08
2014 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jun 11 09:59:14
2014 UTC
@@ -1121,7 +1121,7 @@
__ push(scratch2()); // restore old return address
ExternalReference ref =
-
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
isolate());
__ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength,
1);
}
=======================================
--- /branches/bleeding_edge/src/ic.cc Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc Wed Jun 11 09:59:14 2014 UTC
@@ -625,17 +625,14 @@
// Update inline cache and stub cache.
if (use_ic) UpdateCaches(&lookup, object, name);
- PropertyAttributes attr;
// Get the property.
+ LookupIterator it(object, name);
Handle<Object> 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);
}
=======================================
--- /branches/bleeding_edge/src/ic.h Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/ic.h Wed Jun 11 09:59:14 2014 UTC
@@ -30,8 +30,7 @@
/* Utilities for IC stubs. */ \
ICU(StoreCallbackProperty) \
ICU(LoadPropertyWithInterceptorOnly) \
- ICU(LoadPropertyWithInterceptorForLoad) \
- ICU(LoadPropertyWithInterceptorForCall) \
+ ICU(LoadPropertyWithInterceptor) \
ICU(KeyedLoadPropertyWithInterceptor) \
ICU(StoreInterceptorProperty) \
ICU(CompareIC_Miss) \
=======================================
--- /branches/bleeding_edge/src/json-stringifier.h Tue Jun 10 14:01:08 2014
UTC
+++ /branches/bleeding_edge/src/json-stringifier.h Wed Jun 11 09:59:14 2014
UTC
@@ -338,15 +338,9 @@
MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
Handle<Object> object, Handle<Object> 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<Object> 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.
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Jun 6 15:43:19
2014 UTC
+++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Jun 11 09:59:14
2014 UTC
@@ -1137,7 +1137,7 @@
this->name(), interceptor_holder);
ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
+ IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
__ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength,
1);
}
}
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h Wed Jun 11 09:59:14 2014 UTC
@@ -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::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 @@
MaybeHandle<Object> Object::GetProperty(Handle<Object> object,
Handle<Name> name) {
- PropertyAttributes attributes;
- return GetPropertyWithReceiver(object, object, name, &attributes);
+ LookupIterator it(object, name);
+ return GetProperty(&it);
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Wed Jun 11 09:59:14 2014 UTC
@@ -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 @@
}
-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> 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 @@
}
-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 @@
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;
}
@@ -792,86 +805,6 @@
|| !HasFastProperties();
}
-
-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,
@@ -13778,62 +13711,37 @@
constructor->shared()->get_api_func_data()->indexed_property_handler();
return InterceptorInfo::cast(result);
}
-
-
-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>();
- return GetPropertyPostInterceptor(object, receiver, name, attributes);
+ 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>();
+
+ Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
+ result_internal->VerifyApiCallResultType();
+ // Rebox handle before return
+ return handle(*result_internal, isolate);
}
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Wed Jun 11 09:59:14 2014 UTC
@@ -862,6 +862,7 @@
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> class TypeImpl;
@@ -1456,11 +1457,7 @@
void Lookup(Handle<Name> name, LookupResult* result);
- MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithReceiver(
- Handle<Object> object,
- Handle<Object> receiver,
- Handle<Name> name,
- PropertyAttributes* attributes);
+ MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator*
it);
MUST_USE_RESULT static inline MaybeHandle<Object> GetPropertyOrElement(
Handle<Object> object,
Handle<Name> key);
@@ -1471,14 +1468,8 @@
MUST_USE_RESULT static inline MaybeHandle<Object> GetProperty(
Handle<Object> object,
Handle<Name> key);
- MUST_USE_RESULT static MaybeHandle<Object> GetProperty(
- Handle<Object> object,
- Handle<Object> receiver,
- LookupResult* result,
- Handle<Name> key,
- PropertyAttributes* attributes);
- MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithCallback(
+ MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithAccessor(
Handle<Object> receiver,
Handle<Name> name,
Handle<JSObject> holder,
@@ -2264,13 +2255,7 @@
MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithInterceptor(
Handle<JSObject> object,
Handle<Object> receiver,
- Handle<Name> name,
- PropertyAttributes* attributes);
- MUST_USE_RESULT static MaybeHandle<Object> GetPropertyPostInterceptor(
- Handle<JSObject> object,
- Handle<Object> receiver,
- Handle<Name> name,
- PropertyAttributes* attributes);
+ Handle<Name> 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 @@
// Used from Object::GetProperty().
MUST_USE_RESULT static MaybeHandle<Object>
GetPropertyWithFailedAccessCheck(
- Handle<JSObject> object,
- Handle<Object> receiver,
- LookupResult* result,
- Handle<Name> name,
- PropertyAttributes* attributes);
+ LookupIterator* it);
MUST_USE_RESULT static MaybeHandle<Object> GetElementWithCallback(
Handle<JSObject> object,
@@ -6649,6 +6630,10 @@
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;
}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc Wed Jun 11 09:59:14 2014 UTC
@@ -10787,7 +10787,7 @@
Handle<Object> structure(result->GetCallbackObject(), isolate);
ASSERT(!structure->IsForeign());
if (structure->IsAccessorInfo()) {
- MaybeHandle<Object> obj = JSObject::GetPropertyWithCallback(
+ MaybeHandle<Object> 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_ASSERT(obj->HasNamedInterceptor());
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
- PropertyAttributes attributes;
Handle<Object> 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;
}
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc Wed Jun 11 09:59:14 2014 UTC
@@ -544,85 +544,30 @@
HandleVector(&name_handle, 1));
return isolate->Throw(*error);
}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> LoadWithInterceptor(
- Arguments* args,
- PropertyAttributes* attrs) {
- ASSERT(args->length() == StubCache::kInterceptorArgsLength);
- Handle<Name> name_handle =
- args->at<Name>(StubCache::kInterceptorArgsNameIndex);
- Handle<InterceptorInfo> interceptor_info =
- args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
- Handle<JSObject> receiver_handle =
- args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
- Handle<JSObject> holder_handle =
- args->at<JSObject>(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<String> name = Handle<String>::cast(name_handle);
-
- Address getter_address =
v8::ToCData<Address>(interceptor_info->getter());
- v8::NamedPropertyGetterCallback getter =
- FUNCTION_CAST<v8::NamedPropertyGetterCallback>(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<v8::Value> r =
- callback_args.Call(getter, v8::Utils::ToLocal(name));
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- if (!r.IsEmpty()) {
- *attrs = NONE;
- Handle<Object> 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> name =
+ args.at<Name>(StubCache::kInterceptorArgsNameIndex);
+ Handle<JSObject> receiver =
+ args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
+ Handle<JSObject> holder =
+ args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
+
Handle<Object> result;
+ LookupIterator it(receiver, name, holder);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result, LoadWithInterceptor(&args, &attr));
+ isolate, result, JSObject::GetProperty(&it));
- // If the property is present, return it.
- if (attr != ABSENT) return *result;
- return ThrowReferenceError(isolate, Name::cast(args[0]));
-}
+ if (it.IsFound()) return *result;
-
-RUNTIME_FUNCTION(LoadPropertyWithInterceptorForCall) {
- PropertyAttributes attr;
- HandleScope scope(isolate);
- Handle<Object> 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]));
}
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Wed Jun 11 09:59:14 2014 UTC
@@ -270,8 +270,7 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Jun 10 14:01:08
2014 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jun 11 09:59:14
2014 UTC
@@ -1054,7 +1054,7 @@
__ PushReturnAddressFrom(scratch2());
ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
+ IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
__ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength,
1);
}
}
=======================================
--- /branches/bleeding_edge/src/x87/stub-cache-x87.cc Tue Jun 10 03:43:48
2014 UTC
+++ /branches/bleeding_edge/src/x87/stub-cache-x87.cc Wed Jun 11 09:59:14
2014 UTC
@@ -1120,7 +1120,7 @@
__ push(scratch2()); // restore old return address
ExternalReference ref =
-
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
isolate());
__ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength,
1);
}
=======================================
--- /branches/bleeding_edge/tools/gyp/v8.gyp Tue Jun 10 14:01:08 2014 UTC
+++ /branches/bleeding_edge/tools/gyp/v8.gyp Wed Jun 11 09:59:14 2014 UTC
@@ -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',
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.