API call code refactoring (x64).
authorserya@chromium.org <serya@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Nov 2010 10:44:16 +0000 (10:44 +0000)
committerserya@chromium.org <serya@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Nov 2010 10:44:16 +0000 (10:44 +0000)
Review URL: http://codereview.chromium.org/5108003

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

src/x64/code-stubs-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
src/x64/stub-cache-x64.cc

index 527ae61..04173e1 100644 (file)
@@ -2582,7 +2582,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ j(zero, &failure_returned);
 
   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame(result_size_);
+  __ LeaveExitFrame();
   __ ret(0);
 
   // Handling of failure.
index dd74da0..834a6f6 100644 (file)
@@ -498,23 +498,22 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
 }
 
 
-void MacroAssembler::PrepareCallApiFunction(int stack_space,
-                                            int arg_stack_space) {
+void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
 #ifdef _WIN64
   // We need to prepare a slot for result handle on stack and put
   // a pointer to it into 1st arg register.
-  EnterApiExitFrame(stack_space, arg_stack_space + 1);
+  EnterApiExitFrame(arg_stack_space + 1);
 
   // rcx must be used to pass the pointer to the return value slot.
   lea(rcx, StackSpaceOperand(arg_stack_space));
 #else
-  EnterApiExitFrame(stack_space, arg_stack_space);
+  EnterApiExitFrame(arg_stack_space);
 #endif
 }
 
 
 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
-    ApiFunction* function) {
+    ApiFunction* function, int stack_space) {
   Label empty_result;
   Label prologue;
   Label promote_scheduled_exception;
@@ -537,7 +536,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
   // Allocate HandleScope in callee-save registers.
   Register prev_next_address_reg = r14;
   Register prev_limit_reg = rbx;
-  Register base_reg = kSmiConstantRegister;
+  Register base_reg = r12;
   movq(base_reg, next_address);
   movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
   movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
@@ -566,15 +565,14 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
   cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset));
   j(not_equal, &delete_allocated_handles);
   bind(&leave_exit_frame);
-  InitializeSmiConstantRegister();
 
   // Check if the function scheduled an exception.
   movq(rsi, scheduled_exception_address);
   Cmp(Operand(rsi, 0), Factory::the_hole_value());
   j(not_equal, &promote_scheduled_exception);
 
-  LeaveExitFrame();
-  ret(0);
+  LeaveApiExitFrame();
+  ret(stack_space * kPointerSize);
 
   bind(&promote_scheduled_exception);
   MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException,
@@ -1778,20 +1776,13 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) {
 }
 
 
-void MacroAssembler::EnterApiExitFrame(int stack_space,
-                                       int arg_stack_space) {
+void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
   EnterExitFramePrologue(false);
-
-  // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
-  // so it must be retained across the C-call.
-  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
-  lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
-
   EnterExitFrameEpilogue(arg_stack_space);
 }
 
 
-void MacroAssembler::LeaveExitFrame(int result_size) {
+void MacroAssembler::LeaveExitFrame() {
   // Registers:
   // r12 : argv
 
@@ -1803,6 +1794,22 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
   // from the caller stack.
   lea(rsp, Operand(r12, 1 * kPointerSize));
 
+  // Push the return address to get ready to return.
+  push(rcx);
+
+  LeaveExitFrameEpilogue();
+}
+
+
+void MacroAssembler::LeaveApiExitFrame() {
+  movq(rsp, rbp);
+  pop(rbp);
+
+  LeaveExitFrameEpilogue();
+}
+
+
+void MacroAssembler::LeaveExitFrameEpilogue() {
   // Restore current context from top and clear it in debug mode.
   ExternalReference context_address(Top::k_context_address);
   movq(kScratchRegister, context_address);
@@ -1811,9 +1818,6 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
   movq(Operand(kScratchRegister, 0), Immediate(0));
 #endif
 
-  // Push the return address to get ready to return.
-  push(rcx);
-
   // Clear the top frame.
   ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
   movq(kScratchRegister, c_entry_fp_address);
index c2fc830..5b082fd 100644 (file)
@@ -160,14 +160,18 @@ class MacroAssembler: public Assembler {
   // accessible via StackSpaceOperand.
   void EnterExitFrame(int arg_stack_space = 0);
 
-  void EnterApiExitFrame(int stack_space,
-                         int arg_stack_space);
+  // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
+  // memory (not GCed) on the stack accessible via StackSpaceOperand.
+  void EnterApiExitFrame(int arg_stack_space);
 
   // Leave the current exit frame. Expects/provides the return value in
   // register rax:rdx (untouched) and the pointer to the first
   // argument in register rsi.
-  void LeaveExitFrame(int result_size = 1);
+  void LeaveExitFrame();
 
+  // Leave the current exit frame. Expects/provides the return value in
+  // register rax (untouched).
+  void LeaveApiExitFrame();
 
   // ---------------------------------------------------------------------------
   // JavaScript invokes
@@ -835,23 +839,18 @@ class MacroAssembler: public Assembler {
                                           int result_size);
 
   // Prepares stack to put arguments (aligns and so on).
-  // Uses callee-saved rsi to restore stack state after call. WIN64 calling
-  // convention requires to put the pointer to the return value slot into rcx
-  // (rcx must be preserverd until TryCallApiFunctionAndReturn). argc is number
-  // of arguments to be passed in C-function. stack_space * kPointerSize bytes
-  // will be removed from stack after the call. Saves context (rsi).
-  // Clobbers rax. Allocates arg_stack_space * kPointerSize inside the exit
-  // frame (not GCed).
-  //
-  // Assumes stack_space GCed references on top of the stack and return address.
-  // After call they will be removed.
-  void PrepareCallApiFunction(int stack_space, int arg_stack_space);
+  // WIN64 calling convention requires to put the pointer to the return value
+  // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
+  // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
+  // inside the exit frame (not GCed) accessible via StackSpaceOperand.
+  void PrepareCallApiFunction(int arg_stack_space);
 
   // Calls an API function. Allocates HandleScope, extracts
   // returned value from handle and propagates exceptions.
   // Clobbers r12, r14, rbx and caller-save registers. Restores context.
+  // On return removes stack_space * kPointerSize (GCed).
   MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
-      ApiFunction* function);
+      ApiFunction* function, int stack_space);
 
   // Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
@@ -947,6 +946,8 @@ class MacroAssembler: public Assembler {
   // accessible via StackSpaceOperand.
   void EnterExitFrameEpilogue(int arg_stack_space);
 
+  void LeaveExitFrameEpilogue();
+
   // Allocation support helpers.
   // Loads the top of new-space into the result register.
   // If flags contains RESULT_CONTAINS_TOP then result_end is valid and
index 2085333..2e60dd5 100644 (file)
@@ -500,7 +500,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(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
+// Reserves space for the extra arguments to API function in the
 // caller's frame.
 //
 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
@@ -535,7 +535,7 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
 }
 
 
-// Generates call to FastHandleApiCall builtin.
+// Generates call to API function.
 static bool GenerateFastApiCall(MacroAssembler* masm,
                                 const CallOptimization& optimization,
                                 int argc,
@@ -559,7 +559,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
   __ Move(rdi, Handle<JSFunction>(function));
   __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
 
-  // Pass the additional arguments FastHandleApiCall expects.
+  // Pass the additional arguments.
   __ movq(Operand(rsp, 2 * kPointerSize), rdi);
   Object* call_data = optimization.api_call_info()->data();
   Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
@@ -589,7 +589,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
   // it's not controlled by GC.
   const int kApiStackSpace = 4;
 
-  __ PrepareCallApiFunction(argc + kFastApiCallArguments + 1, kApiStackSpace);
+  __ PrepareCallApiFunction(kApiStackSpace);
 
   __ movq(StackSpaceOperand(0), rbx);  // v8::Arguments::implicit_args_.
   __ addq(rbx, Immediate(argc * kPointerSize));
@@ -605,7 +605,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
   // garbage collection but instead return the allocation failure
   // object.
   MaybeObject* result =
-      masm->TryCallApiFunctionAndReturn(&fun);
+      masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1);
   if (result->IsFailure()) {
     *failure = Failure::cast(result);
     return false;
@@ -992,7 +992,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
 
       if (depth != kInvalidProtoDepth) {
         __ IncrementCounter(&Counters::call_const_fast_api, 1);
-        ReserveSpaceForFastApiCall(masm(), rax);
+        // Allocate space for v8::Arguments implicit values. Must be initialized
+        // before to call any runtime function.
+        __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
       }
 
       // Check that the maps haven't changed.
@@ -1071,6 +1073,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
 
   if (depth != kInvalidProtoDepth) {
     Failure* failure;
+    // Move the return address on top of the stack.
+    __ movq(rax, Operand(rsp, 3 * kPointerSize));
+    __ movq(Operand(rsp, 0 * kPointerSize), rax);
+
+    // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
+    // duplicate of return address and will be overwritten.
     bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
     if (!success) {
       return failure;
@@ -1082,7 +1090,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
   // Handle call cache miss.
   __ bind(&miss);
   if (depth != kInvalidProtoDepth) {
-    FreeSpaceForFastApiCall(masm(), rax);
+    __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
   }
 
   // Handle call cache miss.
@@ -2633,8 +2641,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   __ pop(scratch2);  // Get return address to place it below.
 
   __ push(receiver);  // receiver
-  ASSERT(!scratch3.is(reg));
-  __ movq(scratch3, rsp);
   __ push(reg);  // holder
   if (Heap::InNewSpace(callback_handle->data())) {
     __ Move(scratch1, callback_handle);
@@ -2642,7 +2648,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   } else {
     __ Push(Handle<Object>(callback_handle->data()));
   }
-  __ push(scratch3);
   __ 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.
@@ -2664,22 +2669,27 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
 
-  // 3 elements array for v8::Agruments::values_, handler for name and pointer
-  // to the values (it considered as smi in GC).
-  const int kStackSpace = 5;
-  const int kApiArgc = 2;
+  // 3 elements array for v8::Agruments::values_ and handler for name.
+  const int kStackSpace = 4;
+
+  // Allocate v8::AccessorInfo in non-GCed stack space.
+  const int kArgStackSpace = 1;
+
+  __ PrepareCallApiFunction(kArgStackSpace);
+  __ lea(rax, Operand(name_arg, 3 * kPointerSize));
 
-  __ PrepareCallApiFunction(kStackSpace, kApiArgc);
+  // v8::AccessorInfo::args_.
+  __ movq(StackSpaceOperand(0), rax);
 
   // The context register (rsi) has been saved in PrepareCallApiFunction and
   // could be used to pass arguments.
-  __ lea(accessor_info_arg, Operand(name_arg, 1 * kPointerSize));
+  __ lea(accessor_info_arg, StackSpaceOperand(0));
 
   // 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()->TryCallApiFunctionAndReturn(&fun);
+  MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
   if (result->IsFailure()) {
     *failure = Failure::cast(result);
     return false;