Index: src/x64/code-stubs-x64.cc |
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc |
index 1e14f83d9b2de1b523d3e87616cd738497bf09f6..7f976940b5a2213e505c3af0005405d9efb1dc8b 100644 |
--- a/src/x64/code-stubs-x64.cc |
+++ b/src/x64/code-stubs-x64.cc |
@@ -2158,12 +2158,34 @@ void CEntryStub::Generate(MacroAssembler* masm) { |
ProfileEntryHookStub::MaybeCallEntryHook(masm); |
- // Enter the exit frame that transitions from JavaScript to C++. |
#ifdef _WIN64 |
- int arg_stack_space = (result_size() < 2 ? 2 : 4); |
-#else // _WIN64 |
- int arg_stack_space = 0; |
+ // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. It requires the |
+ // stack to be aligned to 16 bytes. It only allows a single-word to be |
+ // returned in register rax. Larger return sizes must be written to an address |
+ // passed as a hidden first argument. |
+ const Register kCCallArg0 = rcx; |
+ const Register kCCallArg1 = rdx; |
+ const Register kCCallArg2 = r8; |
+ const Register kCCallArg3 = r9; |
+ const int kArgExtraStackSpace = 2; |
+ const int kMaxRegisterResultSize = 1; |
+#else |
+ // GCC / Clang passes arguments in rdi, rsi, rdx, rcx, r8, r9. Simple results |
+ // are returned in rax, and a struct of two pointers are returned in rax+rdx. |
+ // Larger return sizes must be written to an address passed as a hidden first |
+ // argument. |
+ const Register kCCallArg0 = rdi; |
+ const Register kCCallArg1 = rsi; |
+ const Register kCCallArg2 = rdx; |
+ const Register kCCallArg3 = rcx; |
+ const int kArgExtraStackSpace = 0; |
+ const int kMaxRegisterResultSize = 2; |
#endif // _WIN64 |
+ |
+ // Enter the exit frame that transitions from JavaScript to C++. |
+ int arg_stack_space = |
+ kArgExtraStackSpace + |
+ (result_size() <= kMaxRegisterResultSize ? 0 : result_size()); |
if (argv_in_register()) { |
DCHECK(!save_doubles()); |
__ EnterApiExitFrame(arg_stack_space); |
@@ -2179,56 +2201,41 @@ void CEntryStub::Generate(MacroAssembler* masm) { |
// r14: number of arguments including receiver (C callee-saved). |
// r15: argv pointer (C callee-saved). |
- // Simple results returned in rax (both AMD64 and Win64 calling conventions). |
- // Complex results must be written to address passed as first argument. |
- // AMD64 calling convention: a struct of two pointers in rax+rdx |
- |
// Check stack alignment. |
if (FLAG_debug_code) { |
__ CheckStackAlignment(); |
} |
- // Call C function. |
-#ifdef _WIN64 |
- // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. |
- // Pass argv and argc as two parameters. The arguments object will |
- // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). |
- if (result_size() < 2) { |
+ // Call C function. The arguments object will be created by stubs declared by |
+ // DECLARE_RUNTIME_FUNCTION(). |
+ if (result_size() <= kMaxRegisterResultSize) { |
// Pass a pointer to the Arguments object as the first argument. |
- // Return result in single register (rax). |
- __ movp(rcx, r14); // argc. |
- __ movp(rdx, r15); // argv. |
- __ Move(r8, ExternalReference::isolate_address(isolate())); |
+ // Return result in single register (rax), or a register pair (rax, rdx). |
+ __ movp(kCCallArg0, r14); // argc. |
+ __ movp(kCCallArg1, r15); // argv. |
+ __ Move(kCCallArg2, ExternalReference::isolate_address(isolate())); |
} else { |
- DCHECK_EQ(2, result_size()); |
+ DCHECK_LE(result_size(), 3); |
// Pass a pointer to the result location as the first argument. |
- __ leap(rcx, StackSpaceOperand(2)); |
+ __ leap(kCCallArg0, StackSpaceOperand(kArgExtraStackSpace)); |
// Pass a pointer to the Arguments object as the second argument. |
- __ movp(rdx, r14); // argc. |
- __ movp(r8, r15); // argv. |
- __ Move(r9, ExternalReference::isolate_address(isolate())); |
+ __ movp(kCCallArg1, r14); // argc. |
+ __ movp(kCCallArg2, r15); // argv. |
+ __ Move(kCCallArg3, ExternalReference::isolate_address(isolate())); |
} |
- |
-#else // _WIN64 |
- // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. |
- __ movp(rdi, r14); // argc. |
- __ movp(rsi, r15); // argv. |
- __ Move(rdx, ExternalReference::isolate_address(isolate())); |
-#endif // _WIN64 |
__ call(rbx); |
- // Result is in rax - do not destroy this register! |
-#ifdef _WIN64 |
- // If return value is on the stack, pop it to registers. |
- if (result_size() > 1) { |
- DCHECK_EQ(2, result_size()); |
+ if (result_size() > kMaxRegisterResultSize) { |
// Read result values stored on stack. Result is stored |
- // above the four argument mirror slots and the two |
- // Arguments object slots. |
- __ movq(rax, Operand(rsp, 6 * kRegisterSize)); |
- __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); |
+ // above the the two Arguments object slots on Win64. |
+ DCHECK_LE(result_size(), 3); |
+ __ movq(kReturnRegister0, StackSpaceOperand(kArgExtraStackSpace + 0)); |
+ __ movq(kReturnRegister1, StackSpaceOperand(kArgExtraStackSpace + 1)); |
+ if (result_size() > 2) { |
+ __ movq(kReturnRegister2, StackSpaceOperand(kArgExtraStackSpace + 2)); |
+ } |
} |
-#endif // _WIN64 |
+ // Result is in rax, rdx:rax or r8:rdx:rax - do not destroy these registers! |
// Check result for exception sentinel. |
Label exception_returned; |