| // Copyright 2013 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #if V8_TARGET_ARCH_X64 |
| |
| #include "src/api-arguments-inl.h" |
| #include "src/bootstrapper.h" |
| #include "src/code-stubs.h" |
| #include "src/counters.h" |
| #include "src/double.h" |
| #include "src/frame-constants.h" |
| #include "src/frames.h" |
| #include "src/ic/ic.h" |
| #include "src/ic/stub-cache.h" |
| #include "src/isolate.h" |
| #include "src/macro-assembler.h" |
| #include "src/objects-inl.h" |
| #include "src/objects/api-callbacks.h" |
| #include "src/objects/regexp-match-info.h" |
| #include "src/regexp/jsregexp.h" |
| #include "src/regexp/regexp-macro-assembler.h" |
| #include "src/runtime/runtime.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #define __ ACCESS_MASM(masm) |
| |
| // Called with the native C calling convention. The corresponding function |
| // signature is: |
| // |
| // using JSEntryFunction = GeneratedCode<Object*( |
| // Object * new_target, Object * target, Object * receiver, int argc, |
| // Object*** args, Address root_register_value)>; |
| void JSEntryStub::Generate(MacroAssembler* masm) { |
| Label invoke, handler_entry, exit; |
| Label not_outermost_js, not_outermost_js_2; |
| |
| { // NOLINT. Scope block confuses linter. |
| NoRootArrayScope uninitialized_root_register(masm); |
| // Set up frame. |
| __ pushq(rbp); |
| __ movp(rbp, rsp); |
| |
| // Push the stack frame type. |
| __ Push(Immediate(StackFrame::TypeToMarker(type()))); // context slot |
| ExternalReference context_address = |
| ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()); |
| __ Load(kScratchRegister, context_address); |
| __ Push(kScratchRegister); // context |
| // Save callee-saved registers (X64/X32/Win64 calling conventions). |
| __ pushq(r12); |
| __ pushq(r13); |
| __ pushq(r14); |
| __ pushq(r15); |
| #ifdef _WIN64 |
| __ pushq(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI. |
| __ pushq(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI. |
| #endif |
| __ pushq(rbx); |
| |
| #ifdef _WIN64 |
| // On Win64 XMM6-XMM15 are callee-save. |
| __ subp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize)); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0), xmm6); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1), xmm7); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2), xmm8); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3), xmm9); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4), xmm10); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5), xmm11); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6), xmm12); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7), xmm13); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8), xmm14); |
| __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9), xmm15); |
| STATIC_ASSERT(EntryFrameConstants::kCalleeSaveXMMRegisters == 10); |
| STATIC_ASSERT(EntryFrameConstants::kXMMRegistersBlockSize == |
| EntryFrameConstants::kXMMRegisterSize * |
| EntryFrameConstants::kCalleeSaveXMMRegisters); |
| #endif |
| |
| #ifdef _WIN64 |
| // Initialize the root register. |
| // C calling convention. The sixth argument is passed on the stack. |
| __ movp(kRootRegister, |
| Operand(rbp, EntryFrameConstants::kRootRegisterValueOffset)); |
| #else |
| // Initialize the root register. |
| // C calling convention. The sixth argument is passed in r9. |
| __ movp(kRootRegister, r9); |
| #endif |
| } |
| |
| // Save copies of the top frame descriptor on the stack. |
| ExternalReference c_entry_fp = |
| ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate()); |
| { |
| Operand c_entry_fp_operand = masm->ExternalReferenceAsOperand(c_entry_fp); |
| __ Push(c_entry_fp_operand); |
| } |
| |
| // If this is the outermost JS call, set js_entry_sp value. |
| ExternalReference js_entry_sp = |
| ExternalReference::Create(IsolateAddressId::kJSEntrySPAddress, isolate()); |
| __ Load(rax, js_entry_sp); |
| __ testp(rax, rax); |
| __ j(not_zero, ¬_outermost_js); |
| __ Push(Immediate(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| __ movp(rax, rbp); |
| __ Store(js_entry_sp, rax); |
| Label cont; |
| __ jmp(&cont); |
| __ bind(¬_outermost_js); |
| __ Push(Immediate(StackFrame::INNER_JSENTRY_FRAME)); |
| __ bind(&cont); |
| |
| // Jump to a faked try block that does the invoke, with a faked catch |
| // block that sets the pending exception. |
| __ jmp(&invoke); |
| __ bind(&handler_entry); |
| handler_offset_ = handler_entry.pos(); |
| // Caught exception: Store result (exception) in the pending exception |
| // field in the JSEnv and return a failure sentinel. |
| ExternalReference pending_exception = ExternalReference::Create( |
| IsolateAddressId::kPendingExceptionAddress, isolate()); |
| __ Store(pending_exception, rax); |
| __ LoadRoot(rax, RootIndex::kException); |
| __ jmp(&exit); |
| |
| // Invoke: Link this frame into the handler chain. |
| __ bind(&invoke); |
| __ PushStackHandler(); |
| |
| // Invoke the function by calling through JS entry trampoline builtin and |
| // pop the faked function when we return. We load the address from an |
| // external reference instead of inlining the call target address directly |
| // in the code, because the builtin stubs may not have been generated yet |
| // at the time this code is generated. |
| __ Call(EntryTrampoline(), RelocInfo::CODE_TARGET); |
| |
| // Unlink this frame from the handler chain. |
| __ PopStackHandler(); |
| |
| __ bind(&exit); |
| // Check if the current stack frame is marked as the outermost JS frame. |
| __ Pop(rbx); |
| __ cmpp(rbx, Immediate(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| __ j(not_equal, ¬_outermost_js_2); |
| __ Move(kScratchRegister, js_entry_sp); |
| __ movp(Operand(kScratchRegister, 0), Immediate(0)); |
| __ bind(¬_outermost_js_2); |
| |
| // Restore the top frame descriptor from the stack. |
| { |
| Operand c_entry_fp_operand = masm->ExternalReferenceAsOperand(c_entry_fp); |
| __ Pop(c_entry_fp_operand); |
| } |
| |
| // Restore callee-saved registers (X64 conventions). |
| #ifdef _WIN64 |
| // On Win64 XMM6-XMM15 are callee-save |
| __ movdqu(xmm6, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0)); |
| __ movdqu(xmm7, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1)); |
| __ movdqu(xmm8, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2)); |
| __ movdqu(xmm9, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3)); |
| __ movdqu(xmm10, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4)); |
| __ movdqu(xmm11, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5)); |
| __ movdqu(xmm12, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6)); |
| __ movdqu(xmm13, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7)); |
| __ movdqu(xmm14, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8)); |
| __ movdqu(xmm15, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9)); |
| __ addp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize)); |
| #endif |
| |
| __ popq(rbx); |
| #ifdef _WIN64 |
| // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. |
| __ popq(rsi); |
| __ popq(rdi); |
| #endif |
| __ popq(r15); |
| __ popq(r14); |
| __ popq(r13); |
| __ popq(r12); |
| __ addp(rsp, Immediate(2 * kPointerSize)); // remove markers |
| |
| // Restore frame pointer and return. |
| __ popq(rbp); |
| __ ret(0); |
| } |
| |
| #undef __ |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_TARGET_ARCH_X64 |