OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/ic/handler-compiler.h" | 10 #include "src/ic/handler-compiler.h" |
(...skipping 2140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2151 // rbx: pointer to C function (C callee-saved) | 2151 // rbx: pointer to C function (C callee-saved) |
2152 // rbp: frame pointer of calling JS frame (restored after C call) | 2152 // rbp: frame pointer of calling JS frame (restored after C call) |
2153 // rsp: stack pointer (restored after C call) | 2153 // rsp: stack pointer (restored after C call) |
2154 // rsi: current context (restored) | 2154 // rsi: current context (restored) |
2155 // | 2155 // |
2156 // If argv_in_register(): | 2156 // If argv_in_register(): |
2157 // r15: pointer to the first argument | 2157 // r15: pointer to the first argument |
2158 | 2158 |
2159 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 2159 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
2160 | 2160 |
| 2161 #ifdef _WIN64 |
| 2162 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. It requires the |
| 2163 // stack to be aligned to 16 bytes. It only allows a single-word to be |
| 2164 // returned in register rax. Larger return sizes must be written to an address |
| 2165 // passed as a hidden first argument. |
| 2166 const Register kCCallArg0 = rcx; |
| 2167 const Register kCCallArg1 = rdx; |
| 2168 const Register kCCallArg2 = r8; |
| 2169 const Register kCCallArg3 = r9; |
| 2170 const int kArgExtraStackSpace = 2; |
| 2171 const int kMaxRegisterResultSize = 1; |
| 2172 #else |
| 2173 // GCC / Clang passes arguments in rdi, rsi, rdx, rcx, r8, r9. Simple results |
| 2174 // are returned in rax, and a struct of two pointers are returned in rax+rdx. |
| 2175 // Larger return sizes must be written to an address passed as a hidden first |
| 2176 // argument. |
| 2177 const Register kCCallArg0 = rdi; |
| 2178 const Register kCCallArg1 = rsi; |
| 2179 const Register kCCallArg2 = rdx; |
| 2180 const Register kCCallArg3 = rcx; |
| 2181 const int kArgExtraStackSpace = 0; |
| 2182 const int kMaxRegisterResultSize = 2; |
| 2183 #endif // _WIN64 |
| 2184 |
2161 // Enter the exit frame that transitions from JavaScript to C++. | 2185 // Enter the exit frame that transitions from JavaScript to C++. |
2162 #ifdef _WIN64 | 2186 int arg_stack_space = |
2163 int arg_stack_space = (result_size() < 2 ? 2 : 4); | 2187 kArgExtraStackSpace + |
2164 #else // _WIN64 | 2188 (result_size() <= kMaxRegisterResultSize ? 0 : result_size()); |
2165 int arg_stack_space = 0; | |
2166 #endif // _WIN64 | |
2167 if (argv_in_register()) { | 2189 if (argv_in_register()) { |
2168 DCHECK(!save_doubles()); | 2190 DCHECK(!save_doubles()); |
2169 __ EnterApiExitFrame(arg_stack_space); | 2191 __ EnterApiExitFrame(arg_stack_space); |
2170 // Move argc into r14 (argv is already in r15). | 2192 // Move argc into r14 (argv is already in r15). |
2171 __ movp(r14, rax); | 2193 __ movp(r14, rax); |
2172 } else { | 2194 } else { |
2173 __ EnterExitFrame(arg_stack_space, save_doubles()); | 2195 __ EnterExitFrame(arg_stack_space, save_doubles()); |
2174 } | 2196 } |
2175 | 2197 |
2176 // rbx: pointer to builtin function (C callee-saved). | 2198 // rbx: pointer to builtin function (C callee-saved). |
2177 // rbp: frame pointer of exit frame (restored after C call). | 2199 // rbp: frame pointer of exit frame (restored after C call). |
2178 // rsp: stack pointer (restored after C call). | 2200 // rsp: stack pointer (restored after C call). |
2179 // r14: number of arguments including receiver (C callee-saved). | 2201 // r14: number of arguments including receiver (C callee-saved). |
2180 // r15: argv pointer (C callee-saved). | 2202 // r15: argv pointer (C callee-saved). |
2181 | 2203 |
2182 // Simple results returned in rax (both AMD64 and Win64 calling conventions). | |
2183 // Complex results must be written to address passed as first argument. | |
2184 // AMD64 calling convention: a struct of two pointers in rax+rdx | |
2185 | |
2186 // Check stack alignment. | 2204 // Check stack alignment. |
2187 if (FLAG_debug_code) { | 2205 if (FLAG_debug_code) { |
2188 __ CheckStackAlignment(); | 2206 __ CheckStackAlignment(); |
2189 } | 2207 } |
2190 | 2208 |
2191 // Call C function. | 2209 // Call C function. The arguments object will be created by stubs declared by |
2192 #ifdef _WIN64 | 2210 // DECLARE_RUNTIME_FUNCTION(). |
2193 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. | 2211 if (result_size() <= kMaxRegisterResultSize) { |
2194 // Pass argv and argc as two parameters. The arguments object will | |
2195 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). | |
2196 if (result_size() < 2) { | |
2197 // Pass a pointer to the Arguments object as the first argument. | 2212 // Pass a pointer to the Arguments object as the first argument. |
2198 // Return result in single register (rax). | 2213 // Return result in single register (rax), or a register pair (rax, rdx). |
2199 __ movp(rcx, r14); // argc. | 2214 __ movp(kCCallArg0, r14); // argc. |
2200 __ movp(rdx, r15); // argv. | 2215 __ movp(kCCallArg1, r15); // argv. |
2201 __ Move(r8, ExternalReference::isolate_address(isolate())); | 2216 __ Move(kCCallArg2, ExternalReference::isolate_address(isolate())); |
2202 } else { | 2217 } else { |
2203 DCHECK_EQ(2, result_size()); | 2218 DCHECK_LE(result_size(), 3); |
2204 // Pass a pointer to the result location as the first argument. | 2219 // Pass a pointer to the result location as the first argument. |
2205 __ leap(rcx, StackSpaceOperand(2)); | 2220 __ leap(kCCallArg0, StackSpaceOperand(kArgExtraStackSpace)); |
2206 // Pass a pointer to the Arguments object as the second argument. | 2221 // Pass a pointer to the Arguments object as the second argument. |
2207 __ movp(rdx, r14); // argc. | 2222 __ movp(kCCallArg1, r14); // argc. |
2208 __ movp(r8, r15); // argv. | 2223 __ movp(kCCallArg2, r15); // argv. |
2209 __ Move(r9, ExternalReference::isolate_address(isolate())); | 2224 __ Move(kCCallArg3, ExternalReference::isolate_address(isolate())); |
2210 } | 2225 } |
| 2226 __ call(rbx); |
2211 | 2227 |
2212 #else // _WIN64 | 2228 if (result_size() > kMaxRegisterResultSize) { |
2213 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. | |
2214 __ movp(rdi, r14); // argc. | |
2215 __ movp(rsi, r15); // argv. | |
2216 __ Move(rdx, ExternalReference::isolate_address(isolate())); | |
2217 #endif // _WIN64 | |
2218 __ call(rbx); | |
2219 // Result is in rax - do not destroy this register! | |
2220 | |
2221 #ifdef _WIN64 | |
2222 // If return value is on the stack, pop it to registers. | |
2223 if (result_size() > 1) { | |
2224 DCHECK_EQ(2, result_size()); | |
2225 // Read result values stored on stack. Result is stored | 2229 // Read result values stored on stack. Result is stored |
2226 // above the four argument mirror slots and the two | 2230 // above the the two Arguments object slots on Win64. |
2227 // Arguments object slots. | 2231 DCHECK_LE(result_size(), 3); |
2228 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); | 2232 __ movq(kReturnRegister0, StackSpaceOperand(kArgExtraStackSpace + 0)); |
2229 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); | 2233 __ movq(kReturnRegister1, StackSpaceOperand(kArgExtraStackSpace + 1)); |
| 2234 if (result_size() > 2) { |
| 2235 __ movq(kReturnRegister2, StackSpaceOperand(kArgExtraStackSpace + 2)); |
| 2236 } |
2230 } | 2237 } |
2231 #endif // _WIN64 | 2238 // Result is in rax, rdx:rax or r8:rdx:rax - do not destroy these registers! |
2232 | 2239 |
2233 // Check result for exception sentinel. | 2240 // Check result for exception sentinel. |
2234 Label exception_returned; | 2241 Label exception_returned; |
2235 __ CompareRoot(rax, Heap::kExceptionRootIndex); | 2242 __ CompareRoot(rax, Heap::kExceptionRootIndex); |
2236 __ j(equal, &exception_returned); | 2243 __ j(equal, &exception_returned); |
2237 | 2244 |
2238 // Check that there is no pending exception, otherwise we | 2245 // Check that there is no pending exception, otherwise we |
2239 // should have returned the exception sentinel. | 2246 // should have returned the exception sentinel. |
2240 if (FLAG_debug_code) { | 2247 if (FLAG_debug_code) { |
2241 Label okay; | 2248 Label okay; |
(...skipping 3174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5416 kStackSpace, nullptr, return_value_operand, NULL); | 5423 kStackSpace, nullptr, return_value_operand, NULL); |
5417 } | 5424 } |
5418 | 5425 |
5419 | 5426 |
5420 #undef __ | 5427 #undef __ |
5421 | 5428 |
5422 } // namespace internal | 5429 } // namespace internal |
5423 } // namespace v8 | 5430 } // namespace v8 |
5424 | 5431 |
5425 #endif // V8_TARGET_ARCH_X64 | 5432 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |