Revision: 2577
Author: [email protected]
Date: Wed Jul 29 05:34:21 2009
Log: Compile precanned answers for the case of failed interceptor for some  
combinations.

Review URL: http://codereview.chromium.org/140069
http://code.google.com/p/v8/source/detail?r=2577

Modified:
  /branches/bleeding_edge/src/arm/stub-cache-arm.cc
  /branches/bleeding_edge/src/heap.cc
  /branches/bleeding_edge/src/heap.h
  /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
  /branches/bleeding_edge/src/ic.h
  /branches/bleeding_edge/src/objects-debug.cc
  /branches/bleeding_edge/src/objects-inl.h
  /branches/bleeding_edge/src/objects.h
  /branches/bleeding_edge/src/stub-cache.cc
  /branches/bleeding_edge/src/stub-cache.h

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc   Tue Jul 28 07:46:06  
2009
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc   Wed Jul 29 05:34:21  
2009
@@ -483,7 +483,7 @@

  void StubCompiler::GenerateLoadInterceptor(JSObject* object,
                                             JSObject* holder,
-                                           Smi* lookup_hint,
+                                           LookupResult* lookup,
                                             Register receiver,
                                             Register name_reg,
                                             Register scratch1,
@@ -502,8 +502,6 @@
    __ push(receiver);  // receiver
    __ push(reg);  // holder
    __ push(name_reg);  // name
-  __ mov(scratch1, Operand(lookup_hint));
-  __ push(scratch1);

    InterceptorInfo* interceptor = holder->GetNamedInterceptor();
    ASSERT(!Heap::InNewSpace(interceptor));
@@ -514,8 +512,8 @@

    // Do tail-call to the runtime system.
    ExternalReference load_ic_property =
-      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
-  __ TailCallRuntime(load_ic_property, 6);
+       
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+  __ TailCallRuntime(load_ic_property, 5);
  }


@@ -1059,9 +1057,11 @@

    __ ldr(r0, MemOperand(sp, 0));

+  LookupResult lookup;
+  holder->LocalLookupRealNamedProperty(name, &lookup);
    GenerateLoadInterceptor(object,
                            holder,
-                          holder->InterceptorPropertyLookupHint(name),
+                          &lookup,
                            r0,
                            r2,
                            r3,
@@ -1218,9 +1218,11 @@
    __ cmp(r2, Operand(Handle<String>(name)));
    __ b(ne, &miss);

+  LookupResult lookup;
+  holder->LocalLookupRealNamedProperty(name, &lookup);
    GenerateLoadInterceptor(receiver,
                            holder,
-                          Smi::FromInt(JSObject::kLookupInHolder),
+                          &lookup,
                            r0,
                            r2,
                            r3,
=======================================
--- /branches/bleeding_edge/src/heap.cc Wed Jul 29 01:10:19 2009
+++ /branches/bleeding_edge/src/heap.cc Wed Jul 29 05:34:21 2009
@@ -1411,6 +1411,12 @@
    if (obj->IsFailure()) return false;
    set_the_hole_value(obj);

+  obj = CreateOddball(
+      oddball_map(), "no_interceptor_result_sentinel", Smi::FromInt(-2));
+  if (obj->IsFailure()) return false;
+  set_no_interceptor_result_sentinel(obj);
+
+
    // Allocate the empty string.
    obj = AllocateRawAsciiString(0, TENURED);
    if (obj->IsFailure()) return false;
=======================================
--- /branches/bleeding_edge/src/heap.h  Tue Jul 28 01:43:51 2009
+++ /branches/bleeding_edge/src/heap.h  Wed Jul 29 05:34:21 2009
@@ -110,6 +110,7 @@
    V(Map, two_pointer_filler_map,  
TwoPointerFillerMap)                          \
    V(Object, nan_value,  
NanValue)                                               \
    V(Object, undefined_value,  
UndefinedValue)                                   \
+  V(Object, no_interceptor_result_sentinel,  
NoInterceptorResultSentinel)       \
    V(Object, minus_zero_value,  
MinusZeroValue)                                  \
    V(Object, null_value,  
NullValue)                                             \
    V(Object, true_value,  
TrueValue)                                             \
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jul 28 07:46:06  
2009
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 29 05:34:21  
2009
@@ -157,15 +157,10 @@
                                       Register receiver,
                                       Register holder,
                                       Pushable name,
-                                     JSObject* holder_obj,
-                                     Smi* lookup_hint) {
+                                     JSObject* holder_obj) {
    __ push(receiver);
    __ push(holder);
    __ push(name);
-  // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
-  // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
-  __ push(Immediate(lookup_hint));
-
    InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
    __ mov(receiver, Immediate(Handle<Object>(interceptor)));
    __ push(receiver);
@@ -292,6 +287,322 @@
      __ mov(dst, FieldOperand(dst, offset));
    }
  }
+
+
+template <class Pushable>
+static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
+                                                   Register receiver,
+                                                   Register holder,
+                                                   Pushable name,
+                                                   JSObject* holder_obj) {
+  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
+
+  ExternalReference ref =
+      ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
+  __ mov(eax, Immediate(5));
+  __ mov(ebx, Immediate(ref));
+
+  CEntryStub stub;
+  __ CallStub(&stub);
+}
+
+
+template <class Compiler>
+static void CompileLoadInterceptor(Compiler* compiler,
+                                   StubCompiler* stub_compiler,
+                                   MacroAssembler* masm,
+                                   JSObject* object,
+                                   JSObject* holder,
+                                   String* name,
+                                   LookupResult* lookup,
+                                   Register receiver,
+                                   Register scratch1,
+                                   Register scratch2,
+                                   Label* miss) {
+  ASSERT(holder->HasNamedInterceptor());
+  ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
+
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      stub_compiler->CheckPrototypes(object, receiver, holder,
+                                     scratch1, scratch2, name, miss);
+
+  if (lookup->IsValid() && lookup->IsCacheable()) {
+    compiler->CompileCacheable(masm,
+                               stub_compiler,
+                               receiver,
+                               reg,
+                               scratch1,
+                               scratch2,
+                               holder,
+                               lookup,
+                               name,
+                               miss);
+  } else {
+    compiler->CompileRegular(masm,
+                             receiver,
+                             reg,
+                             scratch2,
+                             holder,
+                             miss);
+  }
+}
+
+
+static void LookupPostInterceptor(JSObject* holder,
+                                  String* name,
+                                  LookupResult* lookup) {
+  holder->LocalLookupRealNamedProperty(name, lookup);
+  if (lookup->IsNotFound()) {
+    Object* proto = holder->GetPrototype();
+    if (proto != Heap::null_value()) {
+      proto->Lookup(name, lookup);
+    }
+  }
+}
+
+
+class LoadInterceptorCompiler BASE_EMBEDDED {
+ public:
+  explicit LoadInterceptorCompiler(Register name) : name_(name) {}
+
+  void CompileCacheable(MacroAssembler* masm,
+                        StubCompiler* stub_compiler,
+                        Register receiver,
+                        Register holder,
+                        Register scratch1,
+                        Register scratch2,
+                        JSObject* holder_obj,
+                        LookupResult* lookup,
+                        String* name,
+                        Label* miss_label) {
+    AccessorInfo* callback = 0;
+    bool optimize = false;
+    // So far the most popular follow ups for interceptor loads are FIELD
+    // and CALLBACKS, so inline only them, other cases may be added
+    // later.
+    if (lookup->type() == FIELD) {
+      optimize = true;
+    } else if (lookup->type() == CALLBACKS) {
+      Object* callback_object = lookup->GetCallbackObject();
+      if (callback_object->IsAccessorInfo()) {
+        callback = AccessorInfo::cast(callback_object);
+        optimize = callback->getter() != NULL;
+      }
+    }
+
+    if (!optimize) {
+      CompileRegular(masm, receiver, holder, scratch2, holder_obj,  
miss_label);
+      return;
+    }
+
+    // Note: starting a frame here makes GC aware of pointers pushed below.
+    __ EnterInternalFrame();
+
+    if (lookup->type() == CALLBACKS) {
+      __ push(receiver);
+    }
+    __ push(holder);
+    __ push(name_);
+
+    CompileCallLoadPropertyWithInterceptor(masm,
+                                           receiver,
+                                           holder,
+                                           name_,
+                                           holder_obj);
+
+    Label interceptor_failed;
+    __ cmp(eax, Factory::no_interceptor_result_sentinel());
+    __ j(equal, &interceptor_failed);
+    __ LeaveInternalFrame();
+    __ ret(0);
+
+    __ bind(&interceptor_failed);
+    __ pop(name_);
+    __ pop(holder);
+    if (lookup->type() == CALLBACKS) {
+      __ pop(receiver);
+    }
+
+    __ LeaveInternalFrame();
+
+    if (lookup->type() == FIELD) {
+      holder = stub_compiler->CheckPrototypes(holder_obj, holder,
+                                              lookup->holder(), scratch1,
+                                              scratch2,
+                                              name,
+                                              miss_label);
+      stub_compiler->GenerateFastPropertyLoad(masm, eax,
+                                              holder, lookup->holder(),
+                                              lookup->GetFieldIndex());
+      __ ret(0);
+    } else {
+      ASSERT(lookup->type() == CALLBACKS);
+      ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
+      ASSERT(callback != NULL);
+      ASSERT(callback->getter() != NULL);
+
+      Label cleanup;
+      __ pop(scratch2);
+      __ push(receiver);
+      __ push(scratch2);
+
+      holder = stub_compiler->CheckPrototypes(holder_obj, holder,
+                                              lookup->holder(), scratch1,
+                                              scratch2,
+                                              name,
+                                              &cleanup);
+
+      __ pop(scratch2);  // save old return address
+      __ push(holder);
+      __ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
+      __ push(holder);
+      __ push(FieldOperand(holder, AccessorInfo::kDataOffset));
+      __ push(name_);
+      __ push(scratch2);  // restore old return address
+
+      ExternalReference ref =
+          ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+      __ TailCallRuntime(ref, 5);
+
+      __ bind(&cleanup);
+      __ pop(scratch1);
+      __ pop(scratch2);
+      __ push(scratch1);
+    }
+  }
+
+
+  void CompileRegular(MacroAssembler* masm,
+                      Register receiver,
+                      Register holder,
+                      Register scratch,
+                      JSObject* holder_obj,
+                      Label* miss_label) {
+    __ pop(scratch);  // save old return address
+    PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
+    __ push(scratch);  // restore old return address
+
+    ExternalReference ref = ExternalReference(
+        IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+    __ TailCallRuntime(ref, 5);
+  }
+
+ private:
+  Register name_;
+};
+
+
+class CallInterceptorCompiler BASE_EMBEDDED {
+ public:
+  explicit CallInterceptorCompiler(const ParameterCount& arguments)
+      : arguments_(arguments), argc_(arguments.immediate()) {}
+
+  void CompileCacheable(MacroAssembler* masm,
+                        StubCompiler* stub_compiler,
+                        Register receiver,
+                        Register holder,
+                        Register scratch1,
+                        Register scratch2,
+                        JSObject* holder_obj,
+                        LookupResult* lookup,
+                        String* name,
+                        Label* miss_label) {
+    JSFunction* function = 0;
+    bool optimize = false;
+    // So far the most popular case for failed interceptor is
+    // CONSTANT_FUNCTION sitting below.
+    if (lookup->type() == CONSTANT_FUNCTION) {
+      function = lookup->GetConstantFunction();
+      // JSArray holder is a special case for call constant function
+      // (see the corresponding code).
+      if (function->is_compiled() && !holder_obj->IsJSArray()) {
+        optimize = true;
+      }
+    }
+
+    if (!optimize) {
+      CompileRegular(masm, receiver, holder, scratch2, holder_obj,  
miss_label);
+      return;
+    }
+
+    __ EnterInternalFrame();
+    __ push(holder);  // save the holder
+
+    CompileCallLoadPropertyWithInterceptor(
+        masm,
+        receiver,
+        holder,
+        // Under EnterInternalFrame this refers to name.
+        Operand(ebp, (argc_ + 3) * kPointerSize),
+        holder_obj);
+
+    __ pop(receiver);  // restore holder
+    __ LeaveInternalFrame();
+
+    __ cmp(eax, Factory::no_interceptor_result_sentinel());
+    Label invoke;
+    __ j(not_equal, &invoke);
+
+    stub_compiler->CheckPrototypes(holder_obj, receiver,
+                                   lookup->holder(), scratch1,
+                                   scratch2,
+                                   name,
+                                   miss_label);
+    if (lookup->holder()->IsGlobalObject()) {
+      __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize));
+      __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+      __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx);
+    }
+
+    ASSERT(function->is_compiled());
+    // Get the function and setup the context.
+    __ mov(edi, Immediate(Handle<JSFunction>(function)));
+    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+    // Jump to the cached code (tail call).
+    ASSERT(function->is_compiled());
+    Handle<Code> code(function->code());
+    ParameterCount expected(function->shared()->formal_parameter_count());
+    __ InvokeCode(code, expected, arguments_,
+                  RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+    __ bind(&invoke);
+  }
+
+  void CompileRegular(MacroAssembler* masm,
+                      Register receiver,
+                      Register holder,
+                      Register scratch,
+                      JSObject* holder_obj,
+                      Label* miss_label) {
+    __ EnterInternalFrame();
+
+    PushInterceptorArguments(masm,
+                             receiver,
+                             holder,
+                             Operand(ebp, (argc_ + 3) * kPointerSize),
+                             holder_obj);
+
+    ExternalReference ref = ExternalReference(
+        IC_Utility(IC::kLoadPropertyWithInterceptorForCall));
+    __ mov(eax, Immediate(5));
+    __ mov(ebx, Immediate(ref));
+
+    CEntryStub stub;
+    __ CallStub(&stub);
+
+    __ LeaveInternalFrame();
+  }
+
+ private:
+  const ParameterCount& arguments_;
+  int argc_;
+};


  void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind)  
{
@@ -507,36 +818,25 @@

  void StubCompiler::GenerateLoadInterceptor(JSObject* object,
                                             JSObject* holder,
-                                           Smi* lookup_hint,
+                                           LookupResult* lookup,
                                             Register receiver,
                                             Register name_reg,
                                             Register scratch1,
                                             Register scratch2,
                                             String* name,
                                             Label* miss) {
-  // Check that the receiver isn't a smi.
-  __ test(receiver, Immediate(kSmiTagMask));
-  __ j(zero, miss, not_taken);
-
-  // Check that the maps haven't changed.
-  Register reg =
-      CheckPrototypes(object, receiver, holder,
-                      scratch1, scratch2, name, miss);
-
-  // Push the arguments on the JS stack of the caller.
-  __ pop(scratch2);  // remove return address
-  PushInterceptorArguments(masm(),
-                           receiver,
-                           reg,
-                           name_reg,
-                           holder,
-                           lookup_hint);
-  __ push(scratch2);  // restore return address
-
-  // Do tail-call to the runtime system.
-  ExternalReference load_ic_property =
-      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
-  __ TailCallRuntime(load_ic_property, 6);
+  LoadInterceptorCompiler compiler(name_reg);
+  CompileLoadInterceptor(&compiler,
+                         this,
+                         masm(),
+                         object,
+                         holder,
+                         name,
+                         lookup,
+                         receiver,
+                         scratch1,
+                         scratch2,
+                         miss);
  }


@@ -749,49 +1049,32 @@
    // Get the number of arguments.
    const int argc = arguments().immediate();

+  LookupResult lookup;
+  LookupPostInterceptor(holder, name, &lookup);
+
    // Get the receiver from the stack.
    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));

-  // Check that the receiver isn't a smi.
-  __ test(edx, Immediate(kSmiTagMask));
-  __ j(zero, &miss, not_taken);
-
-  // Check that maps have not changed and compute the holder register.
-  Register reg =
-      CheckPrototypes(JSObject::cast(object), edx, holder,
-                      ebx, ecx, name, &miss);
-
-  // Enter an internal frame.
-  __ EnterInternalFrame();
-
-  // Push arguments on the expression stack.
-  PushInterceptorArguments(masm(),
-                           edx,
-                           reg,
-                           Operand(ebp, (argc + 3) * kPointerSize),
-                           holder,
-                           holder->InterceptorPropertyLookupHint(name));
-
-  // Perform call.
-  ExternalReference load_interceptor =
-      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
-  __ mov(eax, Immediate(6));
-  __ mov(ebx, Immediate(load_interceptor));
-
-  CEntryStub stub;
-  __ CallStub(&stub);
-
-  // Move result to edi and restore receiver.
-  __ mov(edi, eax);
-  __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize));  // receiver
-
-  // Exit frame.
-  __ LeaveInternalFrame();
+  CallInterceptorCompiler compiler(arguments());
+  CompileLoadInterceptor(&compiler,
+                         this,
+                         masm(),
+                         JSObject::cast(object),
+                         holder,
+                         name,
+                         &lookup,
+                         edx,
+                         ebx,
+                         ecx,
+                         &miss);
+
+  // Restore receiver.
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));

    // Check that the function really is a function.
-  __ test(edi, Immediate(kSmiTagMask));
+  __ test(eax, Immediate(kSmiTagMask));
    __ j(zero, &miss, not_taken);
-  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
+  __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
    __ j(not_equal, &miss, not_taken);

    // Patch the receiver on the stack with the global proxy if
@@ -802,6 +1085,7 @@
    }

    // Invoke the function.
+  __ mov(edi, eax);
    __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);

    // Handle load cache miss.
@@ -1173,12 +1457,15 @@
    // -----------------------------------
    Label miss;

+  LookupResult lookup;
+  LookupPostInterceptor(holder, name, &lookup);
+
    __ mov(eax, Operand(esp, kPointerSize));
    // TODO(368): Compile in the whole chain: all the interceptors in
    // prototypes and ultimate answer.
    GenerateLoadInterceptor(receiver,
                            holder,
-                          holder->InterceptorPropertyLookupHint(name),
+                          &lookup,
                            eax,
                            ecx,
                            edx,
@@ -1353,9 +1640,11 @@
    __ cmp(Operand(eax), Immediate(Handle<String>(name)));
    __ j(not_equal, &miss, not_taken);

+  LookupResult lookup;
+  LookupPostInterceptor(holder, name, &lookup);
    GenerateLoadInterceptor(receiver,
                            holder,
-                          Smi::FromInt(JSObject::kLookupInHolder),
+                          &lookup,
                            ecx,
                            eax,
                            edx,
=======================================
--- /branches/bleeding_edge/src/ic.h    Thu Jul 16 01:38:52 2009
+++ /branches/bleeding_edge/src/ic.h    Wed Jul 29 05:34:21 2009
@@ -35,17 +35,19 @@

  // IC_UTIL_LIST defines all utility functions called from generated
  // inline caching code. The argument for the macro, ICU, is the function  
name.
-#define IC_UTIL_LIST(ICU)          \
-  ICU(LoadIC_Miss)                 \
-  ICU(KeyedLoadIC_Miss)            \
-  ICU(CallIC_Miss)                 \
-  ICU(StoreIC_Miss)                \
-  ICU(SharedStoreIC_ExtendStorage) \
-  ICU(KeyedStoreIC_Miss)           \
-  /* Utilities for IC stubs. */    \
-  ICU(LoadCallbackProperty)        \
-  ICU(StoreCallbackProperty)       \
-  ICU(LoadInterceptorProperty)     \
+#define IC_UTIL_LIST(ICU)                             \
+  ICU(LoadIC_Miss)                                    \
+  ICU(KeyedLoadIC_Miss)                               \
+  ICU(CallIC_Miss)                                    \
+  ICU(StoreIC_Miss)                                   \
+  ICU(SharedStoreIC_ExtendStorage)                    \
+  ICU(KeyedStoreIC_Miss)                              \
+  /* Utilities for IC stubs. */                       \
+  ICU(LoadCallbackProperty)                           \
+  ICU(StoreCallbackProperty)                          \
+  ICU(LoadPropertyWithInterceptorOnly)                \
+  ICU(LoadPropertyWithInterceptorForLoad)             \
+  ICU(LoadPropertyWithInterceptorForCall)             \
    ICU(StoreInterceptorProperty)

  //
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc        Tue Jul 28 01:43:51 2009
+++ /branches/bleeding_edge/src/objects-debug.cc        Wed Jul 29 05:34:21 2009
@@ -698,7 +698,7 @@
    } else {
      ASSERT(number->IsSmi());
      int value = Smi::cast(number)->value();
-    ASSERT(value == 0 || value == 1 || value == -1);
+    ASSERT(value == 0 || value == 1 || value == -1 || value == -2);
    }
  }

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed Jul 29 02:51:41 2009
+++ /branches/bleeding_edge/src/objects-inl.h   Wed Jul 29 05:34:21 2009
@@ -2727,24 +2727,6 @@
  bool JSObject::HasElement(uint32_t index) {
    return HasElementWithReceiver(this, index);
  }
-
-
-Smi* JSObject::InterceptorPropertyLookupHint(String* name) {
-  // TODO(antonm): Do we want to do any shortcuts for global object?
-  if (HasFastProperties()) {
-    LookupResult lookup;
-    LocalLookupRealNamedProperty(name, &lookup);
-    if (lookup.IsValid()) {
-      if (lookup.type() == FIELD && lookup.IsCacheable()) {
-        return Smi::FromInt(lookup.GetFieldIndex());
-      }
-    } else {
-      return Smi::FromInt(kLookupInPrototype);
-    }
-  }
-
-  return Smi::FromInt(kLookupInHolder);
-}


  bool AccessorInfo::all_can_read() {
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jul 29 02:51:41 2009
+++ /branches/bleeding_edge/src/objects.h       Wed Jul 29 05:34:21 2009
@@ -1507,10 +1507,6 @@
    Object* LookupCallbackSetterInPrototypes(uint32_t index);
    void LookupCallback(String* name, LookupResult* result);

-  inline Smi* InterceptorPropertyLookupHint(String* name);
-  static const int kLookupInHolder = -1;
-  static const int kLookupInPrototype = -2;
-
    // Returns the number of properties on this object filtering out  
properties
    // with the specified attributes (ignoring interceptors).
    int NumberOfLocalProperties(PropertyAttributes filter);
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Tue Jul 28 07:46:06 2009
+++ /branches/bleeding_edge/src/stub-cache.cc   Wed Jul 29 05:34:21 2009
@@ -787,23 +787,25 @@
    return *value;
  }

-
-Object* LoadInterceptorProperty(Arguments args) {
+/**
+ * Attempts to load a property with an interceptor (which must be present),
+ * but doesn't search the prototype chain.
+ *
+ * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
+ * provide any value for the given name.
+ */
+Object* LoadPropertyWithInterceptorOnly(Arguments args) {
    Handle<JSObject> receiver_handle = args.at<JSObject>(0);
    Handle<JSObject> holder_handle = args.at<JSObject>(1);
    Handle<String> name_handle = args.at<String>(2);
-  Smi* lookup_hint = Smi::cast(args[3]);
-  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(4);
-  Handle<Object> data_handle = args.at<Object>(5);
+  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(3);
+  Handle<Object> data_handle = args.at<Object>(4);

    Address getter_address =  
v8::ToCData<Address>(interceptor_info->getter());
    v8::NamedPropertyGetter getter =
        FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
    ASSERT(getter != NULL);

-  PropertyAttributes attributes = ABSENT;
-  Object* result = Heap::undefined_value();
-
    {
      // Use the interceptor getter.
      v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
@@ -822,65 +824,92 @@
      }
    }

-  int property_index = lookup_hint->value();
-  if (property_index >= 0) {
-    result = holder_handle->FastPropertyAt(property_index);
-  } else {
-    switch (property_index) {
-      case JSObject::kLookupInPrototype: {
-          Object* pt = holder_handle->GetPrototype();
-          if (pt == Heap::null_value()) return Heap::undefined_value();
-          result = pt->GetPropertyWithReceiver(
-              *receiver_handle,
-              *name_handle,
-              &attributes);
-          RETURN_IF_SCHEDULED_EXCEPTION();
-        }
-        break;
-
-      case JSObject::kLookupInHolder:
-        result = holder_handle->GetPropertyPostInterceptor(
-            *receiver_handle,
-            *name_handle,
-            &attributes);
-        RETURN_IF_SCHEDULED_EXCEPTION();
-        break;
-
-      default:
-        UNREACHABLE();
-    }
-  }
-
-  if (result->IsFailure()) return result;
-  if (attributes != ABSENT) return result;
-
-  // If the top frame is an internal frame, this is really a 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.
-  StackFrameIterator it;
-  it.Advance();  // skip exit frame
-  if (it.frame()->is_internal()) return result;
-
+  return Heap::no_interceptor_result_sentinel();
+}
+
+
+static Object* ThrowReferenceError(String* name) {
    // If the load is non-contextual, just return the undefined result.
    // Note that both keyed and non-keyed loads may end up here, so we
    // can't use either LoadIC or KeyedLoadIC constructors.
    IC ic(IC::NO_EXTRA_FRAME);
    ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
-  if (!ic.is_contextual()) return result;
+  if (!ic.is_contextual()) return Heap::undefined_value();

    // Throw a reference error.
-  {
+  HandleScope scope;
+  Handle<String> name_handle(name);
+  Handle<Object> error =
+      Factory::NewReferenceError("not_defined",
+                                  HandleVector(&name_handle, 1));
+  return Top::Throw(*error);
+}
+
+
+static Object* LoadWithInterceptor(Arguments* args,
+                                   PropertyAttributes* attrs) {
+  Handle<JSObject> receiver_handle = args->at<JSObject>(0);
+  Handle<JSObject> holder_handle = args->at<JSObject>(1);
+  Handle<String> name_handle = args->at<String>(2);
+  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(3);
+  Handle<Object> data_handle = args->at<Object>(4);
+
+  Address getter_address =  
v8::ToCData<Address>(interceptor_info->getter());
+  v8::NamedPropertyGetter getter =
+      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
+  ASSERT(getter != NULL);
+
+  {
+    // Use the interceptor getter.
+    v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(holder_handle));
      HandleScope scope;
-    // We cannot use the raw name pointer here since getting the
-    // property might cause a GC.  However, we can get the name from
-    // the stack using the arguments object.
-    Handle<String> name_handle = args.at<String>(2);
-    Handle<Object> error =
-        Factory::NewReferenceError("not_defined",
-                                   HandleVector(&name_handle, 1));
-    return Top::Throw(*error);
-  }
+    v8::Handle<v8::Value> r;
+    {
+      // Leaving JavaScript.
+      VMState state(EXTERNAL);
+      r = getter(v8::Utils::ToLocal(name_handle), info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!r.IsEmpty()) {
+      *attrs = NONE;
+      return *v8::Utils::OpenHandle(*r);
+    }
+  }
+
+  Object* result = holder_handle->GetPropertyPostInterceptor(
+      *receiver_handle,
+      *name_handle,
+      attrs);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return result;
+}
+
+
+/**
+ * Loads a property with an interceptor performing post interceptor
+ * lookup if interceptor failed.
+ */
+Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
+  PropertyAttributes attr = NONE;
+  Object* result = LoadWithInterceptor(&args, &attr);
+  if (result->IsFailure()) return result;
+
+  // If the property is present, return it.
+  if (attr != ABSENT) return result;
+  return ThrowReferenceError(String::cast(args[2]));
+}
+
+
+Object* LoadPropertyWithInterceptorForCall(Arguments args) {
+  PropertyAttributes attr;
+  Object* result = LoadWithInterceptor(&args, &attr);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  // 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;
  }


=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Tue Jul 21 06:30:46 2009
+++ /branches/bleeding_edge/src/stub-cache.h    Wed Jul 29 05:34:21 2009
@@ -307,7 +307,9 @@


  // Support functions for IC stubs for interceptors.
-Object* LoadInterceptorProperty(Arguments args);
+Object* LoadPropertyWithInterceptorOnly(Arguments args);
+Object* LoadPropertyWithInterceptorForLoad(Arguments args);
+Object* LoadPropertyWithInterceptorForCall(Arguments args);
  Object* StoreInterceptorProperty(Arguments args);
  Object* CallInterceptorProperty(Arguments args);

@@ -376,13 +378,6 @@
                                   Register scratch,
                                   Label* miss_label);
    static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
-
- protected:
-  Object* GetCodeWithFlags(Code::Flags flags, const char* name);
-  Object* GetCodeWithFlags(Code::Flags flags, String* name);
-
-  MacroAssembler* masm() { return &masm_; }
-  void set_failure(Failure* failure) { failure_ = failure; }

    // Check the integrity of the prototype chain to make sure that the
    // current IC is still valid.
@@ -393,6 +388,13 @@
                             Register scratch,
                             String* name,
                             Label* miss);
+
+ protected:
+  Object* GetCodeWithFlags(Code::Flags flags, const char* name);
+  Object* GetCodeWithFlags(Code::Flags flags, String* name);
+
+  MacroAssembler* masm() { return &masm_; }
+  void set_failure(Failure* failure) { failure_ = failure; }

    void GenerateLoadField(JSObject* object,
                           JSObject* holder,
@@ -424,7 +426,7 @@

    void GenerateLoadInterceptor(JSObject* object,
                                 JSObject* holder,
-                               Smi* lookup_hint,
+                               LookupResult* lookup,
                                 Register receiver,
                                 Register name_reg,
                                 Register scratch1,

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to