let load and store api callbacks use global proxy as receiver
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 3 Feb 2014 15:19:38 +0000 (15:19 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 3 Feb 2014 15:19:38 +0000 (15:19 +0000)
R=verwaest@chromium.org

BUG=

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

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

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

index 9951659..ca63052 100644 (file)
@@ -782,11 +782,23 @@ static void CompileCallLoadPropertyWithInterceptor(
 }
 
 
-static void GenerateFastApiCallBody(MacroAssembler* masm,
-                                    const CallOptimization& optimization,
-                                    int argc,
-                                    Register holder_in,
-                                    bool restore_context) {
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+                                const CallOptimization& optimization,
+                                Handle<Map> receiver_map,
+                                Register receiver,
+                                Register scratch_in,
+                                int argc,
+                                Register* values) {
+  ASSERT(!receiver.is(scratch_in));
+  __ push(receiver);
+  // Write the arguments to stack frame.
+  for (int i = 0; i < argc; i++) {
+    Register arg = values[argc-1-i];
+    ASSERT(!receiver.is(arg));
+    ASSERT(!scratch_in.is(arg));
+    __ push(arg);
+  }
   ASSERT(optimization.is_simple_api_call());
 
   // Abi for CallApiFunctionStub.
@@ -796,7 +808,21 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
   Register api_function_address = r1;
 
   // Put holder in place.
-  __ Move(holder, holder_in);
+  CallOptimization::HolderLookup holder_lookup;
+  Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
+      receiver_map,
+      &holder_lookup);
+  switch (holder_lookup) {
+    case CallOptimization::kHolderIsReceiver:
+      __ Move(holder, receiver);
+      break;
+    case CallOptimization::kHolderFound:
+      __ Move(holder, api_holder);
+     break;
+    case CallOptimization::kHolderNotFound:
+      UNREACHABLE();
+      break;
+  }
 
   Isolate* isolate = masm->isolate();
   Handle<JSFunction> function = optimization.constant_function();
@@ -828,36 +854,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
   __ mov(api_function_address, Operand(ref));
 
   // Jump to stub.
-  CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
+  CallApiFunctionStub stub(true, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
 
 
-// Generate call to api function.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                Register receiver,
-                                Register scratch,
-                                int argc,
-                                Register* values) {
-  ASSERT(!receiver.is(scratch));
-  __ push(receiver);
-  // Write the arguments to stack frame.
-  for (int i = 0; i < argc; i++) {
-    Register arg = values[argc-1-i];
-    ASSERT(!receiver.is(arg));
-    ASSERT(!scratch.is(arg));
-    __ push(arg);
-  }
-  // Stack now matches JSFunction abi.
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          receiver,
-                          true);
-}
-
-
 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
   __ Jump(code, RelocInfo::CODE_TARGET);
 }
@@ -1075,9 +1076,11 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
 
 
 void LoadStubCompiler::GenerateLoadCallback(
-    const CallOptimization& call_optimization) {
+    const CallOptimization& call_optimization,
+    Handle<Map> receiver_map) {
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(), scratch3(), 0, NULL);
+      masm(), call_optimization, receiver_map,
+      receiver(), scratch3(), 0, NULL);
 }
 
 
@@ -1267,7 +1270,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
 
   Register values[] = { value() };
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(), scratch3(), 1, values);
+      masm(), call_optimization, handle(object->map()),
+      receiver(), scratch3(), 1, values);
 
   // Return the generated code.
   return GetCode(kind(), Code::FAST, name);
index d12e682..f91cee2 100644 (file)
@@ -418,11 +418,30 @@ static void CompileCallLoadPropertyWithInterceptor(
 }
 
 
-static void GenerateFastApiCallBody(MacroAssembler* masm,
-                                    const CallOptimization& optimization,
-                                    int argc,
-                                    Register holder_in,
-                                    bool restore_context) {
+// Generate call to api function.
+// This function uses push() to generate smaller, faster code than
+// the version above. It is an optimization that should will be removed
+// when api call ICs are generated in hydrogen.
+static void GenerateFastApiCall(MacroAssembler* masm,
+                                const CallOptimization& optimization,
+                                Handle<Map> receiver_map,
+                                Register receiver,
+                                Register scratch_in,
+                                int argc,
+                                Register* values) {
+  // Copy return value.
+  __ pop(scratch_in);
+  // receiver
+  __ push(receiver);
+  // Write the arguments to stack frame.
+  for (int i = 0; i < argc; i++) {
+    Register arg = values[argc-1-i];
+    ASSERT(!receiver.is(arg));
+    ASSERT(!scratch_in.is(arg));
+    __ push(arg);
+  }
+  __ push(scratch_in);
+  // Stack now matches JSFunction abi.
   ASSERT(optimization.is_simple_api_call());
 
   // Abi for CallApiFunctionStub.
@@ -430,11 +449,24 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
   Register call_data = ebx;
   Register holder = ecx;
   Register api_function_address = edx;
+  Register scratch = edi;  // scratch_in is no longer valid.
 
   // Put holder in place.
-  __ Move(holder, holder_in);
-
-  Register scratch = edi;
+  CallOptimization::HolderLookup holder_lookup;
+  Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
+      receiver_map,
+      &holder_lookup);
+  switch (holder_lookup) {
+    case CallOptimization::kHolderIsReceiver:
+      __ Move(holder, receiver);
+      break;
+    case CallOptimization::kHolderFound:
+      __ LoadHeapObject(holder, api_holder);
+     break;
+    case CallOptimization::kHolderNotFound:
+      UNREACHABLE();
+      break;
+  }
 
   Isolate* isolate = masm->isolate();
   Handle<JSFunction> function = optimization.constant_function();
@@ -461,42 +493,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
   __ mov(api_function_address, Immediate(function_address));
 
   // Jump to stub.
-  CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
+  CallApiFunctionStub stub(true, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
 
 
-// Generate call to api function.
-// This function uses push() to generate smaller, faster code than
-// the version above. It is an optimization that should will be removed
-// when api call ICs are generated in hydrogen.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                Register receiver,
-                                Register scratch1,
-                                int argc,
-                                Register* values) {
-  // Copy return value.
-  __ pop(scratch1);
-  // receiver
-  __ push(receiver);
-  // Write the arguments to stack frame.
-  for (int i = 0; i < argc; i++) {
-    Register arg = values[argc-1-i];
-    ASSERT(!receiver.is(arg));
-    ASSERT(!scratch1.is(arg));
-    __ push(arg);
-  }
-  __ push(scratch1);
-  // Stack now matches JSFunction abi.
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          receiver,
-                          true);
-}
-
-
 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
                                             Label* label,
                                             Handle<Name> name) {
@@ -1065,10 +1066,11 @@ void LoadStubCompiler::GenerateLoadField(Register reg,
 
 
 void LoadStubCompiler::GenerateLoadCallback(
-    const CallOptimization& call_optimization) {
+    const CallOptimization& call_optimization,
+    Handle<Map> receiver_map) {
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(),
-      scratch1(), 0, NULL);
+      masm(), call_optimization, receiver_map,
+      receiver(), scratch1(), 0, NULL);
 }
 
 
@@ -1271,8 +1273,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
 
   Register values[] = { value() };
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(),
-      scratch1(), 1, values);
+      masm(), call_optimization, handle(object->map()),
+      receiver(), scratch1(), 1, values);
 
   // Return the generated code.
   return GetCode(kind(), Code::FAST, name);
index c79ea2c..9e9aa93 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -938,7 +938,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
         }
         CallOptimization call_optimization(function);
         if (call_optimization.is_simple_api_call() &&
-            call_optimization.IsCompatibleReceiver(*object)) {
+            call_optimization.IsCompatibleReceiver(object, holder)) {
           return compiler.CompileLoadCallback(
               type, holder, name, call_optimization);
         }
@@ -1364,7 +1364,7 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
         Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
         CallOptimization call_optimization(function);
         if (call_optimization.is_simple_api_call() &&
-            call_optimization.IsCompatibleReceiver(*receiver)) {
+            call_optimization.IsCompatibleReceiver(receiver, holder)) {
           return compiler.CompileStoreCallback(
               receiver, holder, name, call_optimization);
         }
index b83a5e1..4cf85c3 100644 (file)
@@ -951,7 +951,7 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
   ASSERT(call_optimization.is_simple_api_call());
   Handle<JSFunction> callback = call_optimization.constant_function();
   CallbackHandlerFrontend(type, receiver(), holder, name, callback);
-  GenerateLoadCallback(call_optimization);
+  GenerateLoadCallback(call_optimization, IC::TypeToMap(*type, isolate()));
 
   // Return the generated code.
   return GetCode(kind(), Code::FAST, name);
@@ -1357,7 +1357,6 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
     Handle<Map> object_map,
     HolderLookup* holder_lookup) const {
   ASSERT(is_simple_api_call());
-  ASSERT_EQ(kHolderNotFound, *holder_lookup);
   if (!object_map->IsJSObjectMap()) {
     *holder_lookup = kHolderNotFound;
     return Handle<JSObject>::null();
@@ -1382,6 +1381,38 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
 }
 
 
+bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
+                                            Handle<JSObject> holder) const {
+  ASSERT(is_simple_api_call());
+  if (!receiver->IsJSObject()) return false;
+  Handle<Map> map(JSObject::cast(*receiver)->map());
+  HolderLookup holder_lookup;
+  Handle<JSObject> api_holder =
+      LookupHolderOfExpectedType(map, &holder_lookup);
+  switch (holder_lookup) {
+    case kHolderNotFound:
+      return false;
+    case kHolderIsReceiver:
+      return true;
+    case kHolderFound:
+      if (api_holder.is_identical_to(holder)) return true;
+      // Check if holder is in prototype chain of api_holder.
+      {
+        JSObject* object = *api_holder;
+        while (true) {
+          Object* prototype = object->map()->prototype();
+          if (!prototype->IsJSObject()) return false;
+          if (prototype == *holder) return true;
+          object = JSObject::cast(prototype);
+        }
+      }
+      break;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
 void CallOptimization::Initialize(Handle<JSFunction> function) {
   constant_function_ = Handle<JSFunction>::null();
   is_simple_api_call_ = false;
index daa1e6e..d893349 100644 (file)
@@ -611,7 +611,8 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
   void GenerateLoadConstant(Handle<Object> value);
   void GenerateLoadCallback(Register reg,
                             Handle<ExecutableAccessorInfo> callback);
-  void GenerateLoadCallback(const CallOptimization& call_optimization);
+  void GenerateLoadCallback(const CallOptimization& call_optimization,
+                            Handle<Map> receiver_map);
   void GenerateLoadInterceptor(Register holder_reg,
                                Handle<Object> object,
                                Handle<JSObject> holder,
@@ -827,11 +828,9 @@ class CallOptimization BASE_EMBEDDED {
       Handle<Map> receiver_map,
       HolderLookup* holder_lookup) const;
 
-  bool IsCompatibleReceiver(Object* receiver) {
-    ASSERT(is_simple_api_call());
-    if (expected_receiver_type_.is_null()) return true;
-    return expected_receiver_type_->IsTemplateFor(receiver);
-  }
+  // Check if the api holder is between the receiver and the holder.
+  bool IsCompatibleReceiver(Handle<Object> receiver,
+                            Handle<JSObject> holder) const;
 
  private:
   void Initialize(Handle<JSFunction> function);
index b7e7b48..3e06865 100644 (file)
@@ -392,23 +392,52 @@ static void CompileCallLoadPropertyWithInterceptor(
 }
 
 
-static void GenerateFastApiCallBody(MacroAssembler* masm,
-                                    const CallOptimization& optimization,
-                                    int argc,
-                                    Register holder_in,
-                                    bool restore_context) {
+// Generate call to api function.
+static void GenerateFastApiCall(MacroAssembler* masm,
+                                const CallOptimization& optimization,
+                                Handle<Map> receiver_map,
+                                Register receiver,
+                                Register scratch_in,
+                                int argc,
+                                Register* values) {
   ASSERT(optimization.is_simple_api_call());
 
+  __ PopReturnAddressTo(scratch_in);
+  // receiver
+  __ push(receiver);
+  // Write the arguments to stack frame.
+  for (int i = 0; i < argc; i++) {
+    Register arg = values[argc-1-i];
+    ASSERT(!receiver.is(arg));
+    ASSERT(!scratch_in.is(arg));
+    __ push(arg);
+  }
+  __ PushReturnAddressFrom(scratch_in);
+  // Stack now matches JSFunction abi.
+
   // Abi for CallApiFunctionStub.
   Register callee = rax;
   Register call_data = rbx;
   Register holder = rcx;
   Register api_function_address = rdx;
+  Register scratch = rdi;  // scratch_in is no longer valid.
 
   // Put holder in place.
-  __ Move(holder, holder_in);
-
-  Register scratch = rdi;
+  CallOptimization::HolderLookup holder_lookup;
+  Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
+      receiver_map,
+      &holder_lookup);
+  switch (holder_lookup) {
+    case CallOptimization::kHolderIsReceiver:
+      __ Move(holder, receiver);
+      break;
+    case CallOptimization::kHolderFound:
+      __ Move(holder, api_holder);
+     break;
+    case CallOptimization::kHolderNotFound:
+      UNREACHABLE();
+      break;
+  }
 
   Isolate* isolate = masm->isolate();
   Handle<JSFunction> function = optimization.constant_function();
@@ -436,38 +465,11 @@ static void GenerateFastApiCallBody(MacroAssembler* masm,
       api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE);
 
   // Jump to stub.
-  CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
+  CallApiFunctionStub stub(true, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
 
 
-// Generate call to api function.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                Register receiver,
-                                Register scratch1,
-                                int argc,
-                                Register* values) {
-  __ PopReturnAddressTo(scratch1);
-  // receiver
-  __ push(receiver);
-  // Write the arguments to stack frame.
-  for (int i = 0; i < argc; i++) {
-    Register arg = values[argc-1-i];
-    ASSERT(!receiver.is(arg));
-    ASSERT(!scratch1.is(arg));
-    __ push(arg);
-  }
-  __ PushReturnAddressFrom(scratch1);
-  // Stack now matches JSFunction abi.
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          receiver,
-                          true);
-}
-
-
 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
                                             Label* label,
                                             Handle<Name> name) {
@@ -968,10 +970,11 @@ void LoadStubCompiler::GenerateLoadField(Register reg,
 
 
 void LoadStubCompiler::GenerateLoadCallback(
-    const CallOptimization& call_optimization) {
+    const CallOptimization& call_optimization,
+    Handle<Map> receiver_map) {
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(),
-      scratch1(), 0, NULL);
+      masm(), call_optimization, receiver_map,
+      receiver(), scratch1(), 0, NULL);
 }
 
 
@@ -1165,8 +1168,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
 
   Register values[] = { value() };
   GenerateFastApiCall(
-      masm(), call_optimization, receiver(),
-      scratch1(), 1, values);
+      masm(), call_optimization, handle(object->map()),
+      receiver(), scratch1(), 1, values);
 
   // Return the generated code.
   return GetCode(kind(), Code::FAST, name);