Direct call API functions (ia32 implementation).
authorserya@chromium.org <serya@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 9 Nov 2010 14:01:23 +0000 (14:01 +0000)
committerserya@chromium.org <serya@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 9 Nov 2010 14:01:23 +0000 (14:01 +0000)
Review URL: http://codereview.chromium.org/4456002

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

src/code-stubs.h
src/codegen.cc
src/ia32/assembler-ia32.h
src/ia32/code-stubs-ia32.cc
src/ia32/macro-assembler-ia32.h
src/ia32/stub-cache-ia32.cc
src/objects-debug.cc
src/objects-inl.h
src/objects.h

index c0a8d30..ec64353 100644 (file)
@@ -542,7 +542,7 @@ class ApiGetterEntryStub : public CodeStub {
   ApiFunction* fun() { return fun_; }
   Major MajorKey() { return NoCache; }
   int MinorKey() { return 0; }
-  const char* GetName() { return "ApiEntryStub"; }
+  const char* GetName() { return "ApiGetterEntryStub"; }
   // The accessor info associated with the function.
   Handle<AccessorInfo> info_;
   // The function to be called.
@@ -550,6 +550,32 @@ class ApiGetterEntryStub : public CodeStub {
 };
 
 
+class ApiCallEntryStub : public CodeStub {
+ public:
+  ApiCallEntryStub(Handle<CallHandlerInfo> info,
+                   ApiFunction* fun)
+      : info_(info),
+        fun_(fun) { }
+  void Generate(MacroAssembler* masm);
+  virtual bool has_custom_cache() { return true; }
+  virtual bool GetCustomCache(Code** code_out);
+  virtual void SetCustomCache(Code* value);
+
+  static const int kStackSpace = 0;
+  static const int kArgc = 5;
+ private:
+  Handle<CallHandlerInfo> info() { return info_; }
+  ApiFunction* fun() { return fun_; }
+  Major MajorKey() { return NoCache; }
+  int MinorKey() { return 0; }
+  const char* GetName() { return "ApiCallEntryStub"; }
+  // The call handler info associated with the function.
+  Handle<CallHandlerInfo> info_;
+  // The function to be called.
+  ApiFunction* fun_;
+};
+
+
 class JSEntryStub : public CodeStub {
  public:
   JSEntryStub() { }
index 2e32418..e954dd6 100644 (file)
@@ -482,8 +482,8 @@ int CEntryStub::MinorKey() {
 }
 
 
-bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
-  Object* cache = info()->load_stub_cache();
+// Implementation of CodeStub::GetCustomCache.
+static bool GetCustomCacheHelper(Object* cache, Code** code_out) {
   if (cache->IsUndefined()) {
     return false;
   } else {
@@ -493,9 +493,24 @@ bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
 }
 
 
+bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
+  return GetCustomCacheHelper(info()->load_stub_cache(), code_out);
+}
+
+
 void ApiGetterEntryStub::SetCustomCache(Code* value) {
   info()->set_load_stub_cache(value);
 }
 
 
+bool ApiCallEntryStub::GetCustomCache(Code** code_out) {
+  return GetCustomCacheHelper(info()->call_stub_cache(), code_out);
+}
+
+
+void ApiCallEntryStub::SetCustomCache(Code* value) {
+  info()->set_call_stub_cache(value);
+}
+
+
 } }  // namespace v8::internal
index 624be0c..79637a1 100644 (file)
@@ -521,7 +521,6 @@ class Assembler : public Malloced {
   void push(const Immediate& x);
   void push(Register src);
   void push(const Operand& src);
-  void push(Label* label, RelocInfo::Mode relocation_mode);
 
   void pop(Register dst);
   void pop(const Operand& dst);
index b2b7392..a7d658b 100644 (file)
@@ -3067,6 +3067,26 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
 }
 
 
+void ApiCallEntryStub::Generate(MacroAssembler* masm) {
+  __ PrepareCallApiFunction(kStackSpace, kArgc);
+  STATIC_ASSERT(kArgc == 5);
+
+  // Allocate the v8::Arguments structure in the arguments' space since
+  // it's not controlled by GC.
+  __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
+  __ mov(ApiParameterOperand(2), ebx);  // v8::Arguments::values_.
+  __ mov(ApiParameterOperand(3), edx);  // v8::Arguments::length_.
+  // v8::Arguments::is_construct_call_.
+  __ mov(ApiParameterOperand(4), Immediate(0));
+
+  // v8::InvocationCallback's argument.
+  __ lea(eax, ApiParameterOperand(1));
+  __ mov(ApiParameterOperand(0), eax);
+
+  __ CallApiFunctionAndReturn(fun(), kArgc);
+}
+
+
 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
index 7b9b843..d65eebb 100644 (file)
@@ -488,7 +488,7 @@ class MacroAssembler: public Assembler {
   // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
   void PrepareCallApiFunction(int stack_space, int argc);
 
-  // Tail call an API function (jump). Allocates HandleScope, extracts
+  // Calls an API function. Allocates HandleScope, extracts
   // returned value from handle and propagates exceptions.
   // Clobbers ebx, esi, edi and caller-save registers.
   void CallApiFunctionAndReturn(ApiFunction* function, int argc);
index 042335a..f59928f 100644 (file)
@@ -413,6 +413,10 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
 }
 
 
+// Number of pointers to be reserved on stack for fast API call.
+static const int kFastApiCallArguments = 3;
+
+
 // Reserves space for the extra arguments to FastHandleApiCall in the
 // caller's frame.
 //
@@ -423,10 +427,9 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   //  -- esp[4] : last argument in the internal frame of the caller
   // -----------------------------------
   __ pop(scratch);
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
+  for (int i = 0; i < kFastApiCallArguments; i++) {
+    __ push(Immediate(Smi::FromInt(0)));
+  }
   __ push(scratch);
 }
 
@@ -434,75 +437,81 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
 // Undoes the effects of ReserveSpaceForFastApiCall.
 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   // ----------- S t a t e -------------
-  //  -- esp[0]  : return address
-  //  -- esp[4]  : last fast api call extra argument
+  //  -- esp[0]  : return address.
+  //  -- esp[4]  : last fast api call extra argument.
   //  -- ...
-  //  -- esp[16] : first fast api call extra argument
-  //  -- esp[20] : last argument in the internal frame
+  //  -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
+  //  -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
+  //                                          frame.
   // -----------------------------------
   __ pop(scratch);
-  __ add(Operand(esp), Immediate(kPointerSize * 4));
+  __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
   __ push(scratch);
 }
 
 
 // Generates call to FastHandleApiCall builtin.
-static void GenerateFastApiCall(MacroAssembler* masm,
+static bool GenerateFastApiCall(MacroAssembler* masm,
                                 const CallOptimization& optimization,
-                                int argc) {
+                                int argc,
+                                Failure** failure) {
   // ----------- S t a t e -------------
   //  -- esp[0]              : return address
   //  -- esp[4]              : object passing the type check
   //                           (last fast api call extra argument,
   //                            set by CheckPrototypes)
-  //  -- esp[8]              : api call data
-  //  -- esp[12]             : api callback
-  //  -- esp[16]             : api function
+  //  -- esp[8]              : api function
   //                           (first fast api call extra argument)
-  //  -- esp[20]             : last argument
+  //  -- esp[12]             : api call data
+  //  -- esp[16]             : last argument
   //  -- ...
-  //  -- esp[(argc + 5) * 4] : first argument
-  //  -- esp[(argc + 6) * 4] : receiver
+  //  -- esp[(argc + 3) * 4] : first argument
+  //  -- esp[(argc + 4) * 4] : receiver
   // -----------------------------------
-
   // Get the function and setup the context.
   JSFunction* function = optimization.constant_function();
   __ mov(edi, Immediate(Handle<JSFunction>(function)));
   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 
   // Pass the additional arguments FastHandleApiCall expects.
-  __ mov(Operand(esp, 4 * kPointerSize), edi);
-  bool info_loaded = false;
-  Object* callback = optimization.api_call_info()->callback();
-  if (Heap::InNewSpace(callback)) {
-    info_loaded = true;
-    __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
-    __ mov(Operand(esp, 3 * kPointerSize), ebx);
-  } else {
-    __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
-  }
+  __ mov(Operand(esp, 2 * kPointerSize), edi);
   Object* call_data = optimization.api_call_info()->data();
+  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
   if (Heap::InNewSpace(call_data)) {
-    if (!info_loaded) {
-      __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    }
+    __ mov(ecx, api_call_info_handle);
     __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
-    __ mov(Operand(esp, 2 * kPointerSize), ebx);
+    __ mov(Operand(esp, 3 * kPointerSize), ebx);
   } else {
-    __ mov(Operand(esp, 2 * kPointerSize),
+    __ mov(Operand(esp, 3 * kPointerSize),
            Immediate(Handle<Object>(call_data)));
   }
 
-  // Set the number of arguments.
-  __ mov(eax, Immediate(argc + 4));
+  // Prepare arguments for ApiCallEntryStub.
+  __ lea(eax, Operand(esp, 3 * kPointerSize));
+  __ lea(ebx, Operand(esp, (argc + 3) * kPointerSize));
+  __ Set(edx, Immediate(argc));
 
-  // Jump to the fast api call builtin (tail call).
-  Handle<Code> code = Handle<Code>(
-      Builtins::builtin(Builtins::FastHandleApiCall));
-  ParameterCount expected(0);
-  __ InvokeCode(code, expected, expected,
-                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+  Object* callback = optimization.api_call_info()->callback();
+  Address api_function_address = v8::ToCData<Address>(callback);
+  ApiFunction fun(api_function_address);
+
+  ApiCallEntryStub stub(api_call_info_handle, &fun);
+
+  __ EnterInternalFrame();
+
+  // Emitting a stub call may try to allocate (if the code is not
+  // already generated).  Do not allow the assembler to perform a
+  // garbage collection but instead return the allocation failure
+  // object.
+  MaybeObject* result = masm->TryCallStub(&stub);
+  if (result->IsFailure()) {
+    *failure = Failure::cast(result);
+    return false;
+  }
+
+  __ LeaveInternalFrame();
+  __ ret((argc + 4) * kPointerSize);
+  return true;
 }
 
 
@@ -515,7 +524,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
         arguments_(arguments),
         name_(name) {}
 
-  void Compile(MacroAssembler* masm,
+  bool Compile(MacroAssembler* masm,
                JSObject* object,
                JSObject* holder,
                String* name,
@@ -524,7 +533,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                Register scratch1,
                Register scratch2,
                Register scratch3,
-               Label* miss) {
+               Label* miss,
+               Failure** failure) {
     ASSERT(holder->HasNamedInterceptor());
     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
 
@@ -535,17 +545,18 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     CallOptimization optimization(lookup);
 
     if (optimization.is_constant_call()) {
-      CompileCacheable(masm,
-                       object,
-                       receiver,
-                       scratch1,
-                       scratch2,
-                       scratch3,
-                       holder,
-                       lookup,
-                       name,
-                       optimization,
-                       miss);
+      return CompileCacheable(masm,
+                              object,
+                              receiver,
+                              scratch1,
+                              scratch2,
+                              scratch3,
+                              holder,
+                              lookup,
+                              name,
+                              optimization,
+                              miss,
+                              failure);
     } else {
       CompileRegular(masm,
                      object,
@@ -556,11 +567,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                      name,
                      holder,
                      miss);
+      return true;
     }
   }
 
  private:
-  void CompileCacheable(MacroAssembler* masm,
+  bool CompileCacheable(MacroAssembler* masm,
                         JSObject* object,
                         Register receiver,
                         Register scratch1,
@@ -570,7 +582,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                         LookupResult* lookup,
                         String* name,
                         const CallOptimization& optimization,
-                        Label* miss_label) {
+                        Label* miss_label,
+                        Failure** failure) {
     ASSERT(optimization.is_constant_call());
     ASSERT(!lookup->holder()->IsGlobalObject());
 
@@ -632,7 +645,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 
     // Invoke function.
     if (can_do_fast_api_call) {
-      GenerateFastApiCall(masm, optimization, arguments_.immediate());
+      bool success = GenerateFastApiCall(masm, optimization,
+                                         arguments_.immediate(), failure);
+      if (!success) {
+        return false;
+      }
     } else {
       __ InvokeFunction(optimization.constant_function(), arguments_,
                         JUMP_FUNCTION);
@@ -650,6 +667,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     if (can_do_fast_api_call) {
       FreeSpaceForFastApiCall(masm, scratch1);
     }
+
+    return true;
   }
 
   void CompileRegular(MacroAssembler* masm,
@@ -1046,8 +1065,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
 
   __ EnterInternalFrame();
   // Push the stack address where the list of arguments ends.
-  __ mov(scratch2, esp);
-  __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
+  __ lea(scratch2, Operand(esp, -2 * kPointerSize));
   __ push(scratch2);
   __ push(receiver);  // receiver
   __ push(reg);  // holder
@@ -1061,12 +1079,11 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   __ push(name_reg);  // name
   // Save a pointer to where we pushed the arguments pointer.
   // This will be passed as the const AccessorInfo& to the C++ callback.
-  __ mov(eax, esp);
-  __ add(Operand(eax), Immediate(4 * kPointerSize));
+  STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5);
+  __ lea(eax, Operand(esp, 4 * kPointerSize));
   __ mov(ebx, esp);
 
   // Do call through the api.
-  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
   ApiGetterEntryStub stub(callback_handle, &fun);
@@ -2208,7 +2225,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
   }
 
   if (depth != kInvalidProtoDepth) {
-    GenerateFastApiCall(masm(), optimization, argc);
+    Failure* failure;
+    bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
+    if (!success) {
+      return failure;
+    }
   } else {
     __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   }
@@ -2253,16 +2274,21 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
   CallInterceptorCompiler compiler(this, arguments(), ecx);
-  compiler.Compile(masm(),
-                   object,
-                   holder,
-                   name,
-                   &lookup,
-                   edx,
-                   ebx,
-                   edi,
-                   eax,
-                   &miss);
+  Failure* failure;
+  bool success = compiler.Compile(masm(),
+                                  object,
+                                  holder,
+                                  name,
+                                  &lookup,
+                                  edx,
+                                  ebx,
+                                  edi,
+                                  eax,
+                                  &miss,
+                                  &failure);
+  if (!success) {
+    return false;
+  }
 
   // Restore receiver.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
index c0e5610..2b79016 100644 (file)
@@ -997,6 +997,8 @@ void AccessorInfo::AccessorInfoPrint() {
   data()->ShortPrint();
   PrintF("\n - flag: ");
   flag()->ShortPrint();
+  PrintF("\n - load_stub_cache: ");
+  load_stub_cache()->ShortPrint();
 }
 
 void AccessCheckInfo::AccessCheckInfoVerify() {
@@ -1046,6 +1048,7 @@ void CallHandlerInfo::CallHandlerInfoVerify() {
   CHECK(IsCallHandlerInfo());
   VerifyPointer(callback());
   VerifyPointer(data());
+  VerifyPointer(call_stub_cache());
 }
 
 void CallHandlerInfo::CallHandlerInfoPrint() {
@@ -1054,6 +1057,8 @@ void CallHandlerInfo::CallHandlerInfoPrint() {
   callback()->ShortPrint();
   PrintF("\n - data: ");
   data()->ShortPrint();
+  PrintF("\n - call_stub_cache: ");
+  call_stub_cache()->ShortPrint();
 }
 
 void TemplateInfo::TemplateInfoVerify() {
index 399ef35..79d70e1 100644 (file)
@@ -2557,6 +2557,7 @@ ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
 
 ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
 ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
+ACCESSORS(CallHandlerInfo, call_stub_cache, Object, kCallStubCacheOffset)
 
 ACCESSORS(TemplateInfo, tag, Object, kTagOffset)
 ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset)
index 6029ad5..9d975ec 100644 (file)
@@ -5423,6 +5423,7 @@ class CallHandlerInfo: public Struct {
  public:
   DECL_ACCESSORS(callback, Object)
   DECL_ACCESSORS(data, Object)
+  DECL_ACCESSORS(call_stub_cache, Object)
 
   static inline CallHandlerInfo* cast(Object* obj);
 
@@ -5433,7 +5434,8 @@ class CallHandlerInfo: public Struct {
 
   static const int kCallbackOffset = HeapObject::kHeaderSize;
   static const int kDataOffset = kCallbackOffset + kPointerSize;
-  static const int kSize = kDataOffset + kPointerSize;
+  static const int kCallStubCacheOffset = kDataOffset + kPointerSize;
+  static const int kSize = kCallStubCacheOffset + kPointerSize;
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo);