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.

Reply via email to