Use LookupIterator for CompileLoadInterceptor and delete Object::Lookup
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 15:03:13 +0000 (15:03 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 15:03:13 +0000 (15:03 +0000)
BUG=
R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/466283003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23168 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/stub-cache-arm.cc
src/arm64/stub-cache-arm64.cc
src/ia32/stub-cache-ia32.cc
src/ic.cc
src/lookup.h
src/objects.cc
src/objects.h
src/stub-cache.cc
src/stub-cache.h
src/x64/stub-cache-x64.cc

index 38f391a..b3b5674 100644 (file)
@@ -794,91 +794,76 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
 }
 
 
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg,
-                                                       LookupResult* lookup,
-                                                       Handle<Name> name) {
+void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
+    LookupIterator* it, Register holder_reg) {
   DCHECK(holder()->HasNamedInterceptor());
   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
 
-  // So far the most popular follow ups for interceptor loads are FIELD
-  // and CALLBACKS, so inline only them, other cases may be added
-  // later.
-  bool compile_followup_inline = false;
-  if (lookup->IsFound() && lookup->IsCacheable()) {
-    if (lookup->IsField()) {
-      compile_followup_inline = true;
-    } else if (lookup->type() == CALLBACKS &&
-               lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
-      Handle<ExecutableAccessorInfo> callback(
-          ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
-      compile_followup_inline =
-          callback->getter() != NULL &&
-          ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
-                                                           type());
+  // Compile the interceptor call, followed by inline code to load the
+  // property from further up the prototype chain if the call fails.
+  // Check that the maps haven't changed.
+  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
+
+  // Preserve the receiver register explicitly whenever it is different from the
+  // holder and it is needed should the interceptor return without any result.
+  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
+  // case might cause a miss during the prototype check.
+  bool must_perform_prototype_check =
+      !holder().is_identical_to(it->GetHolder<JSObject>());
+  bool must_preserve_receiver_reg =
+      !receiver().is(holder_reg) &&
+      (it->property_kind() == LookupIterator::ACCESSOR ||
+       must_perform_prototype_check);
+
+  // Save necessary data before invoking an interceptor.
+  // Requires a frame to make GC aware of pushed pointers.
+  {
+    FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
+    if (must_preserve_receiver_reg) {
+      __ Push(receiver(), holder_reg, this->name());
+    } else {
+      __ Push(holder_reg, this->name());
     }
-  }
+    // Invoke an interceptor.  Note: map checks from receiver to
+    // interceptor's holder has been compiled before (see a caller
+    // of this method.)
+    CompileCallLoadPropertyWithInterceptor(
+        masm(), receiver(), holder_reg, this->name(), holder(),
+        IC::kLoadPropertyWithInterceptorOnly);
+
+    // Check if interceptor provided a value for property.  If it's
+    // the case, return immediately.
+    Label interceptor_failed;
+    __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
+    __ cmp(r0, scratch1());
+    __ b(eq, &interceptor_failed);
+    frame_scope.GenerateLeaveFrame();
+    __ Ret();
 
-  if (compile_followup_inline) {
-    // Compile the interceptor call, followed by inline code to load the
-    // property from further up the prototype chain if the call fails.
-    // Check that the maps haven't changed.
-    DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
-    // Preserve the receiver register explicitly whenever it is different from
-    // the holder and it is needed should the interceptor return without any
-    // result. The CALLBACKS case needs the receiver to be passed into C++ code,
-    // the FIELD case might cause a miss during the prototype check.
-    bool must_perfrom_prototype_check = *holder() != lookup->holder();
-    bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
-        (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
-
-    // Save necessary data before invoking an interceptor.
-    // Requires a frame to make GC aware of pushed pointers.
-    {
-      FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
-      if (must_preserve_receiver_reg) {
-        __ Push(receiver(), holder_reg, this->name());
-      } else {
-        __ Push(holder_reg, this->name());
-      }
-      // Invoke an interceptor.  Note: map checks from receiver to
-      // interceptor's holder has been compiled before (see a caller
-      // of this method.)
-      CompileCallLoadPropertyWithInterceptor(
-          masm(), receiver(), holder_reg, this->name(), holder(),
-          IC::kLoadPropertyWithInterceptorOnly);
-
-      // Check if interceptor provided a value for property.  If it's
-      // the case, return immediately.
-      Label interceptor_failed;
-      __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
-      __ cmp(r0, scratch1());
-      __ b(eq, &interceptor_failed);
-      frame_scope.GenerateLeaveFrame();
-      __ Ret();
-
-      __ bind(&interceptor_failed);
-      __ pop(this->name());
-      __ pop(holder_reg);
-      if (must_preserve_receiver_reg) {
-        __ pop(receiver());
-      }
-      // Leave the internal frame.
+    __ bind(&interceptor_failed);
+    __ pop(this->name());
+    __ pop(holder_reg);
+    if (must_preserve_receiver_reg) {
+      __ pop(receiver());
     }
+    // Leave the internal frame.
+  }
 
-    GenerateLoadPostInterceptor(holder_reg, name, lookup);
-  } else {  // !compile_followup_inline
-    // Call the runtime system to load the interceptor.
-    // Check that the maps haven't changed.
-    PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
-                             holder());
+  GenerateLoadPostInterceptor(it, holder_reg);
+}
 
-    ExternalReference ref =
-        ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
-                          isolate());
-    __ TailCallExternalReference(
-        ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
-  }
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
+  // Call the runtime system to load the interceptor.
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
+                           holder());
+
+  ExternalReference ref = ExternalReference(
+      IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(
+      ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
 }
 
 
index b7d43a4..94609e8 100644 (file)
@@ -756,91 +756,77 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
 }
 
 
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg,
-                                                       LookupResult* lookup,
-                                                       Handle<Name> name) {
+void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
+    LookupIterator* it, Register holder_reg) {
   DCHECK(!AreAliased(receiver(), this->name(),
                      scratch1(), scratch2(), scratch3()));
   DCHECK(holder()->HasNamedInterceptor());
   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
 
-  // So far the most popular follow ups for interceptor loads are FIELD
-  // and CALLBACKS, so inline only them, other cases may be added later.
-  bool compile_followup_inline = false;
-  if (lookup->IsFound() && lookup->IsCacheable()) {
-    if (lookup->IsField()) {
-      compile_followup_inline = true;
-    } else if (lookup->type() == CALLBACKS &&
-               lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
-      Handle<ExecutableAccessorInfo> callback(
-          ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
-      compile_followup_inline =
-          callback->getter() != NULL &&
-          ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
-                                                           type());
+  // Compile the interceptor call, followed by inline code to load the
+  // property from further up the prototype chain if the call fails.
+  // Check that the maps haven't changed.
+  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
+
+  // Preserve the receiver register explicitly whenever it is different from the
+  // holder and it is needed should the interceptor return without any result.
+  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
+  // case might cause a miss during the prototype check.
+  bool must_perform_prototype_check =
+      !holder().is_identical_to(it->GetHolder<JSObject>());
+  bool must_preserve_receiver_reg =
+      !receiver().is(holder_reg) &&
+      (it->property_kind() == LookupIterator::ACCESSOR ||
+       must_perform_prototype_check);
+
+  // Save necessary data before invoking an interceptor.
+  // Requires a frame to make GC aware of pushed pointers.
+  {
+    FrameScope frame_scope(masm(), StackFrame::INTERNAL);
+    if (must_preserve_receiver_reg) {
+      __ Push(receiver(), holder_reg, this->name());
+    } else {
+      __ Push(holder_reg, this->name());
     }
-  }
+    // Invoke an interceptor.  Note: map checks from receiver to
+    // interceptor's holder has been compiled before (see a caller
+    // of this method.)
+    CompileCallLoadPropertyWithInterceptor(
+        masm(), receiver(), holder_reg, this->name(), holder(),
+        IC::kLoadPropertyWithInterceptorOnly);
+
+    // Check if interceptor provided a value for property.  If it's
+    // the case, return immediately.
+    Label interceptor_failed;
+    __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
+                  &interceptor_failed);
+    frame_scope.GenerateLeaveFrame();
+    __ Ret();
 
-  if (compile_followup_inline) {
-    // Compile the interceptor call, followed by inline code to load the
-    // property from further up the prototype chain if the call fails.
-    // Check that the maps haven't changed.
-    DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
-    // Preserve the receiver register explicitly whenever it is different from
-    // the holder and it is needed should the interceptor return without any
-    // result. The CALLBACKS case needs the receiver to be passed into C++ code,
-    // the FIELD case might cause a miss during the prototype check.
-    bool must_perfrom_prototype_check = *holder() != lookup->holder();
-    bool must_preserve_receiver_reg = !receiver().Is(holder_reg) &&
-        (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
-
-    // Save necessary data before invoking an interceptor.
-    // Requires a frame to make GC aware of pushed pointers.
-    {
-      FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-      if (must_preserve_receiver_reg) {
-        __ Push(receiver(), holder_reg, this->name());
-      } else {
-        __ Push(holder_reg, this->name());
-      }
-      // Invoke an interceptor.  Note: map checks from receiver to
-      // interceptor's holder has been compiled before (see a caller
-      // of this method.)
-      CompileCallLoadPropertyWithInterceptor(
-          masm(), receiver(), holder_reg, this->name(), holder(),
-          IC::kLoadPropertyWithInterceptorOnly);
-
-      // Check if interceptor provided a value for property.  If it's
-      // the case, return immediately.
-      Label interceptor_failed;
-      __ JumpIfRoot(x0,
-                    Heap::kNoInterceptorResultSentinelRootIndex,
-                    &interceptor_failed);
-      frame_scope.GenerateLeaveFrame();
-      __ Ret();
-
-      __ Bind(&interceptor_failed);
-      if (must_preserve_receiver_reg) {
-        __ Pop(this->name(), holder_reg, receiver());
-      } else {
-        __ Pop(this->name(), holder_reg);
-      }
-      // Leave the internal frame.
+    __ Bind(&interceptor_failed);
+    if (must_preserve_receiver_reg) {
+      __ Pop(this->name(), holder_reg, receiver());
+    } else {
+      __ Pop(this->name(), holder_reg);
     }
-    GenerateLoadPostInterceptor(holder_reg, name, lookup);
-  } else {  // !compile_followup_inline
-    // Call the runtime system to load the interceptor.
-    // Check that the maps haven't changed.
-    PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
-                             holder());
-
-    ExternalReference ref =
-        ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
-                          isolate());
-    __ TailCallExternalReference(
-        ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
+    // Leave the internal frame.
   }
+
+  GenerateLoadPostInterceptor(it, holder_reg);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
+  // Call the runtime system to load the interceptor.
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
+                           holder());
+
+  ExternalReference ref = ExternalReference(
+      IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(
+      ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
 }
 
 
index 4db2474..75ee53a 100644 (file)
@@ -779,102 +779,87 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
 }
 
 
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg,
-                                                       LookupResult* lookup,
-                                                       Handle<Name> name) {
+void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
+    LookupIterator* it, Register holder_reg) {
   DCHECK(holder()->HasNamedInterceptor());
   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
 
-  // So far the most popular follow ups for interceptor loads are FIELD
-  // and CALLBACKS, so inline only them, other cases may be added
-  // later.
-  bool compile_followup_inline = false;
-  if (lookup->IsFound() && lookup->IsCacheable()) {
-    if (lookup->IsField()) {
-      compile_followup_inline = true;
-    } else if (lookup->type() == CALLBACKS &&
-               lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
-      Handle<ExecutableAccessorInfo> callback(
-          ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
-      compile_followup_inline =
-          callback->getter() != NULL &&
-          ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
-                                                           type());
-    }
-  }
+  // Compile the interceptor call, followed by inline code to load the
+  // property from further up the prototype chain if the call fails.
+  // Check that the maps haven't changed.
+  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
+
+  // Preserve the receiver register explicitly whenever it is different from the
+  // holder and it is needed should the interceptor return without any result.
+  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
+  // case might cause a miss during the prototype check.
+  bool must_perform_prototype_check =
+      !holder().is_identical_to(it->GetHolder<JSObject>());
+  bool must_preserve_receiver_reg =
+      !receiver().is(holder_reg) &&
+      (it->property_kind() == LookupIterator::ACCESSOR ||
+       must_perform_prototype_check);
+
+  // Save necessary data before invoking an interceptor.
+  // Requires a frame to make GC aware of pushed pointers.
+  {
+    FrameScope frame_scope(masm(), StackFrame::INTERNAL);
 
-  if (compile_followup_inline) {
-    // Compile the interceptor call, followed by inline code to load the
-    // property from further up the prototype chain if the call fails.
-    // Check that the maps haven't changed.
-    DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
-    // Preserve the receiver register explicitly whenever it is different from
-    // the holder and it is needed should the interceptor return without any
-    // result. The CALLBACKS case needs the receiver to be passed into C++ code,
-    // the FIELD case might cause a miss during the prototype check.
-    bool must_perfrom_prototype_check = *holder() != lookup->holder();
-    bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
-        (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
-
-    // Save necessary data before invoking an interceptor.
-    // Requires a frame to make GC aware of pushed pointers.
-    {
-      FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-
-      if (must_preserve_receiver_reg) {
-        __ push(receiver());
-      }
-      __ push(holder_reg);
-      __ push(this->name());
-
-      // Invoke an interceptor.  Note: map checks from receiver to
-      // interceptor's holder has been compiled before (see a caller
-      // of this method.)
-      CompileCallLoadPropertyWithInterceptor(
-          masm(), receiver(), holder_reg, this->name(), holder(),
-          IC::kLoadPropertyWithInterceptorOnly);
-
-      // Check if interceptor provided a value for property.  If it's
-      // the case, return immediately.
-      Label interceptor_failed;
-      __ cmp(eax, factory()->no_interceptor_result_sentinel());
-      __ j(equal, &interceptor_failed);
-      frame_scope.GenerateLeaveFrame();
-      __ ret(0);
-
-      // Clobber registers when generating debug-code to provoke errors.
-      __ bind(&interceptor_failed);
-      if (FLAG_debug_code) {
-        __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
-        __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
-        __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
-      }
+    if (must_preserve_receiver_reg) {
+      __ push(receiver());
+    }
+    __ push(holder_reg);
+    __ push(this->name());
+
+    // Invoke an interceptor.  Note: map checks from receiver to
+    // interceptor's holder has been compiled before (see a caller
+    // of this method.)
+    CompileCallLoadPropertyWithInterceptor(
+        masm(), receiver(), holder_reg, this->name(), holder(),
+        IC::kLoadPropertyWithInterceptorOnly);
+
+    // Check if interceptor provided a value for property.  If it's
+    // the case, return immediately.
+    Label interceptor_failed;
+    __ cmp(eax, factory()->no_interceptor_result_sentinel());
+    __ j(equal, &interceptor_failed);
+    frame_scope.GenerateLeaveFrame();
+    __ ret(0);
 
-      __ pop(this->name());
-      __ pop(holder_reg);
-      if (must_preserve_receiver_reg) {
-        __ pop(receiver());
-      }
+    // Clobber registers when generating debug-code to provoke errors.
+    __ bind(&interceptor_failed);
+    if (FLAG_debug_code) {
+      __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
+      __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
+      __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
+    }
 
-      // Leave the internal frame.
+    __ pop(this->name());
+    __ pop(holder_reg);
+    if (must_preserve_receiver_reg) {
+      __ pop(receiver());
     }
 
-    GenerateLoadPostInterceptor(holder_reg, name, lookup);
-  } else {  // !compile_followup_inline
-    // Call the runtime system to load the interceptor.
-    // Check that the maps haven't changed.
-    __ pop(scratch2());  // save old return address
-    PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
-                             holder());
-    __ push(scratch2());  // restore old return address
-
-    ExternalReference ref =
-        ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
-                          isolate());
-    __ TailCallExternalReference(
-        ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
+    // Leave the internal frame.
   }
+
+  GenerateLoadPostInterceptor(it, holder_reg);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+  // Call the runtime system to load the interceptor.
+  __ pop(scratch2());  // save old return address
+  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
+                           holder());
+  __ push(scratch2());  // restore old return address
+
+  ExternalReference ref = ExternalReference(
+      IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(
+      ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
 }
 
 
index ea8c368..33c0964 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1034,7 +1034,12 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
     DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
     NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                       cache_holder);
-    return compiler.CompileLoadInterceptor(name);
+    // Perform a lookup behind the interceptor. Copy the LookupIterator since
+    // the original iterator will be used to fetch the value.
+    LookupIterator it(lookup);
+    it.Next();
+    LookupForRead(&it);
+    return compiler.CompileLoadInterceptor(&it, name);
   }
   DCHECK(lookup->state() == LookupIterator::PROPERTY);
 
index 8444771..7727ca5 100644 (file)
@@ -48,6 +48,18 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
     DESCRIPTOR
   };
 
+  explicit LookupIterator(const LookupIterator* other)
+      : configuration_(other->configuration_),
+        state_(other->state_),
+        property_kind_(other->property_kind_),
+        property_encoding_(other->property_encoding_),
+        property_details_(other->property_details_),
+        isolate_(other->isolate_),
+        name_(other->name_),
+        holder_map_(other->holder_map_),
+        maybe_receiver_(other->maybe_receiver_),
+        maybe_holder_(other->maybe_holder_) {}
+
   LookupIterator(Handle<Object> receiver, Handle<Name> name,
                  Configuration configuration = CHECK_DERIVED)
       : configuration_(ComputeConfiguration(configuration, name)),
index 3ca85c2..0318c56 100644 (file)
@@ -104,31 +104,6 @@ bool Object::IsCallable() const {
 }
 
 
-void Object::Lookup(Handle<Name> name, LookupResult* result) {
-  DisallowHeapAllocation no_gc;
-  Object* holder = NULL;
-  if (IsJSReceiver()) {
-    holder = this;
-  } else {
-    Context* native_context = result->isolate()->context()->native_context();
-    if (IsNumber()) {
-      holder = native_context->number_function()->instance_prototype();
-    } else if (IsString()) {
-      holder = native_context->string_function()->instance_prototype();
-    } else if (IsSymbol()) {
-      holder = native_context->symbol_function()->instance_prototype();
-    } else if (IsBoolean()) {
-      holder = native_context->boolean_function()->instance_prototype();
-    } else {
-      result->isolate()->PushStackTraceAndDie(
-          0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
-    }
-  }
-  DCHECK(holder != NULL);  // Cannot handle null or undefined.
-  JSReceiver::cast(holder)->Lookup(name, result);
-}
-
-
 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
index cd71c34..746f20d 100644 (file)
@@ -1473,8 +1473,6 @@ class Object {
   static MUST_USE_RESULT inline MaybeHandle<Smi> ToSmi(Isolate* isolate,
                                                        Handle<Object> object);
 
-  void Lookup(Handle<Name> name, LookupResult* result);
-
   MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator* it);
 
   // Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5.
index f959e92..d812588 100644 (file)
@@ -893,43 +893,62 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
 
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
-    Handle<Name> name) {
-  // Perform a lookup after the interceptor.
-  LookupResult lookup(isolate());
-  holder()->LookupOwnRealNamedProperty(name, &lookup);
-  if (!lookup.IsFound()) {
-    PrototypeIterator iter(holder()->GetIsolate(), holder());
-    if (!iter.IsAtEnd()) {
-      PrototypeIterator::GetCurrent(iter)->Lookup(name, &lookup);
+    LookupIterator* it, Handle<Name> name) {
+  // So far the most popular follow ups for interceptor loads are FIELD and
+  // ExecutableAccessorInfo, so inline only them. Other cases may be added
+  // later.
+  bool inline_followup = it->state() == LookupIterator::PROPERTY;
+  if (inline_followup) {
+    switch (it->property_kind()) {
+      case LookupIterator::DATA:
+        inline_followup = it->property_details().type() == FIELD;
+        break;
+      case LookupIterator::ACCESSOR: {
+        Handle<Object> accessors = it->GetAccessors();
+        inline_followup = accessors->IsExecutableAccessorInfo();
+        if (!inline_followup) break;
+        Handle<ExecutableAccessorInfo> info =
+            Handle<ExecutableAccessorInfo>::cast(accessors);
+        inline_followup = info->getter() != NULL &&
+                          ExecutableAccessorInfo::IsCompatibleReceiverType(
+                              isolate(), info, type());
+      }
     }
   }
 
   Register reg = Frontend(receiver(), name);
-  // TODO(368): Compile in the whole chain: all the interceptors in
-  // prototypes and ultimate answer.
-  GenerateLoadInterceptor(reg, &lookup, name);
+  if (inline_followup) {
+    // TODO(368): Compile in the whole chain: all the interceptors in
+    // prototypes and ultimate answer.
+    GenerateLoadInterceptorWithFollowup(it, reg);
+  } else {
+    GenerateLoadInterceptor(reg);
+  }
   return GetCode(kind(), Code::FAST, name);
 }
 
 
 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
-    Register interceptor_reg, Handle<Name> name, LookupResult* lookup) {
-  Handle<JSObject> real_named_property_holder(lookup->holder());
+    LookupIterator* it, Register interceptor_reg) {
+  Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
 
   set_type_for_object(holder());
   set_holder(real_named_property_holder);
-  Register reg = Frontend(interceptor_reg, name);
-
-  if (lookup->IsField()) {
-    __ Move(receiver(), reg);
-    LoadFieldStub stub(isolate(), lookup->GetFieldIndex());
-    GenerateTailCall(masm(), stub.GetCode());
-  } else {
-    DCHECK(lookup->type() == CALLBACKS);
-    Handle<ExecutableAccessorInfo> callback(
-        ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
-    DCHECK(callback->getter() != NULL);
-    GenerateLoadCallback(reg, callback);
+  Register reg = Frontend(interceptor_reg, it->name());
+
+  switch (it->property_kind()) {
+    case LookupIterator::DATA: {
+      DCHECK_EQ(FIELD, it->property_details().type());
+      __ Move(receiver(), reg);
+      LoadFieldStub stub(isolate(), it->GetFieldIndex());
+      GenerateTailCall(masm(), stub.GetCode());
+      break;
+    }
+    case LookupIterator::ACCESSOR:
+      Handle<ExecutableAccessorInfo> info =
+          Handle<ExecutableAccessorInfo>::cast(it->GetAccessors());
+      DCHECK_NE(NULL, info->getter());
+      GenerateLoadCallback(reg, info);
   }
 }
 
index 77bd14c..030e1dc 100644 (file)
@@ -473,7 +473,10 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
 
   Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
 
-  Handle<Code> CompileLoadInterceptor(Handle<Name> name);
+  // The LookupIterator is used to perform a lookup behind the interceptor. If
+  // the iterator points to a LookupIterator::PROPERTY, its access will be
+  // inlined.
+  Handle<Code> CompileLoadInterceptor(LookupIterator* it, Handle<Name> name);
 
   Handle<Code> CompileLoadViaGetter(Handle<Name> name,
                                     Handle<JSFunction> getter);
@@ -523,12 +526,10 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
                             Handle<ExecutableAccessorInfo> callback);
   void GenerateLoadCallback(const CallOptimization& call_optimization,
                             Handle<Map> receiver_map);
-  void GenerateLoadInterceptor(Register holder_reg,
-                               LookupResult* lookup,
-                               Handle<Name> name);
-  void GenerateLoadPostInterceptor(Register reg,
-                                   Handle<Name> name,
-                                   LookupResult* lookup);
+  void GenerateLoadInterceptor(Register holder_reg);
+  void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
+                                           Register holder_reg);
+  void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
 
   // Generates prototype loading code that uses the objects from the
   // context we were in when this function was called. If the context
index 504482d..a32b073 100644 (file)
@@ -727,94 +727,80 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
 }
 
 
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg,
-                                                       LookupResult* lookup,
-                                                       Handle<Name> name) {
+void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
+    LookupIterator* it, Register holder_reg) {
   DCHECK(holder()->HasNamedInterceptor());
   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
 
-  // So far the most popular follow ups for interceptor loads are FIELD
-  // and CALLBACKS, so inline only them, other cases may be added
-  // later.
-  bool compile_followup_inline = false;
-  if (lookup->IsFound() && lookup->IsCacheable()) {
-    if (lookup->IsField()) {
-      compile_followup_inline = true;
-    } else if (lookup->type() == CALLBACKS &&
-               lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
-      Handle<ExecutableAccessorInfo> callback(
-          ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
-      compile_followup_inline =
-          callback->getter() != NULL &&
-          ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
-                                                           type());
-    }
-  }
+  // Compile the interceptor call, followed by inline code to load the
+  // property from further up the prototype chain if the call fails.
+  // Check that the maps haven't changed.
+  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
+
+  // Preserve the receiver register explicitly whenever it is different from the
+  // holder and it is needed should the interceptor return without any result.
+  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
+  // case might cause a miss during the prototype check.
+  bool must_perform_prototype_check =
+      !holder().is_identical_to(it->GetHolder<JSObject>());
+  bool must_preserve_receiver_reg =
+      !receiver().is(holder_reg) &&
+      (it->property_kind() == LookupIterator::ACCESSOR ||
+       must_perform_prototype_check);
+
+  // Save necessary data before invoking an interceptor.
+  // Requires a frame to make GC aware of pushed pointers.
+  {
+    FrameScope frame_scope(masm(), StackFrame::INTERNAL);
 
-  if (compile_followup_inline) {
-    // Compile the interceptor call, followed by inline code to load the
-    // property from further up the prototype chain if the call fails.
-    // Check that the maps haven't changed.
-    DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
-    // Preserve the receiver register explicitly whenever it is different from
-    // the holder and it is needed should the interceptor return without any
-    // result. The CALLBACKS case needs the receiver to be passed into C++ code,
-    // the FIELD case might cause a miss during the prototype check.
-    bool must_perfrom_prototype_check = *holder() != lookup->holder();
-    bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
-        (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
-
-    // Save necessary data before invoking an interceptor.
-    // Requires a frame to make GC aware of pushed pointers.
-    {
-      FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-
-      if (must_preserve_receiver_reg) {
-        __ Push(receiver());
-      }
-      __ Push(holder_reg);
-      __ Push(this->name());
-
-      // Invoke an interceptor.  Note: map checks from receiver to
-      // interceptor's holder has been compiled before (see a caller
-      // of this method.)
-      CompileCallLoadPropertyWithInterceptor(
-          masm(), receiver(), holder_reg, this->name(), holder(),
-          IC::kLoadPropertyWithInterceptorOnly);
-
-      // Check if interceptor provided a value for property.  If it's
-      // the case, return immediately.
-      Label interceptor_failed;
-      __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
-      __ j(equal, &interceptor_failed);
-      frame_scope.GenerateLeaveFrame();
-      __ ret(0);
-
-      __ bind(&interceptor_failed);
-      __ Pop(this->name());
-      __ Pop(holder_reg);
-      if (must_preserve_receiver_reg) {
-        __ Pop(receiver());
-      }
+    if (must_preserve_receiver_reg) {
+      __ Push(receiver());
+    }
+    __ Push(holder_reg);
+    __ Push(this->name());
+
+    // Invoke an interceptor.  Note: map checks from receiver to
+    // interceptor's holder has been compiled before (see a caller
+    // of this method.)
+    CompileCallLoadPropertyWithInterceptor(
+        masm(), receiver(), holder_reg, this->name(), holder(),
+        IC::kLoadPropertyWithInterceptorOnly);
+
+    // Check if interceptor provided a value for property.  If it's
+    // the case, return immediately.
+    Label interceptor_failed;
+    __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
+    __ j(equal, &interceptor_failed);
+    frame_scope.GenerateLeaveFrame();
+    __ ret(0);
 
-      // Leave the internal frame.
+    __ bind(&interceptor_failed);
+    __ Pop(this->name());
+    __ Pop(holder_reg);
+    if (must_preserve_receiver_reg) {
+      __ Pop(receiver());
     }
 
-    GenerateLoadPostInterceptor(holder_reg, name, lookup);
-  } else {  // !compile_followup_inline
-    // Call the runtime system to load the interceptor.
-    // Check that the maps haven't changed.
-    __ PopReturnAddressTo(scratch2());
-    PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
-                             holder());
-    __ PushReturnAddressFrom(scratch2());
-
-    ExternalReference ref = ExternalReference(
-        IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
-    __ TailCallExternalReference(
-        ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
+    // Leave the internal frame.
   }
+
+  GenerateLoadPostInterceptor(it, holder_reg);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
+  // Call the runtime system to load the interceptor.
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+  __ PopReturnAddressTo(scratch2());
+  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
+                           holder());
+  __ PushReturnAddressFrom(scratch2());
+
+  ExternalReference ref = ExternalReference(
+      IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(
+      ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
 }