Revision: 5836
Author: [email protected]
Date: Wed Nov 17 02:44:16 2010
Log: API call code refactoring (x64).
Review URL: http://codereview.chromium.org/5108003
http://code.google.com/p/v8/source/detail?r=5836
Modified:
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.h
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Nov 16 08:08:57
2010
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Nov 17 02:44:16
2010
@@ -2582,7 +2582,7 @@
__ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame.
- __ LeaveExitFrame(result_size_);
+ __ LeaveExitFrame();
__ ret(0);
// Handling of failure.
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Nov 16
08:08:57 2010
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Nov 17
02:44:16 2010
@@ -498,23 +498,22 @@
}
-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 @@
// 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 @@
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::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 @@
// 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 @@
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);
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Nov 16
08:08:57 2010
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Nov 17
02:44:16 2010
@@ -160,14 +160,18 @@
// 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 @@
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 @@
// 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
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Nov 16 08:08:57
2010
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Nov 17 02:44:16
2010
@@ -500,7 +500,7 @@
// 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 @@
}
-// Generates call to FastHandleApiCall builtin.
+// Generates call to API function.
static bool GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
@@ -559,7 +559,7 @@
__ 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
__ 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 @@
} 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 @@
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;
-
- __ PrepareCallApiFunction(kStackSpace, kApiArgc);
+ // 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));
+
+ // 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;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev