1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jit_x64_SharedICHelpers_x64_inl_h
8 #define jit_x64_SharedICHelpers_x64_inl_h
9 
10 #include "jit/BaselineFrame.h"
11 #include "jit/SharedICHelpers.h"
12 
13 #include "jit/MacroAssembler-inl.h"
14 
15 namespace js {
16 namespace jit {
17 
EmitBaselineTailCallVM(TrampolinePtr target,MacroAssembler & masm,uint32_t argSize)18 inline void EmitBaselineTailCallVM(TrampolinePtr target, MacroAssembler& masm,
19                                    uint32_t argSize) {
20   ScratchRegisterScope scratch(masm);
21 
22   // We an assume during this that R0 and R1 have been pushed.
23   masm.movq(BaselineFrameReg, scratch);
24   masm.addq(Imm32(BaselineFrame::FramePointerOffset), scratch);
25   masm.subq(BaselineStackReg, scratch);
26 
27 #ifdef DEBUG
28   // Store frame size without VMFunction arguments for debug assertions.
29   masm.movq(scratch, rdx);
30   masm.subq(Imm32(argSize), rdx);
31   Address frameSizeAddr(BaselineFrameReg,
32                         BaselineFrame::reverseOffsetOfDebugFrameSize());
33   masm.store32(rdx, frameSizeAddr);
34 #endif
35 
36   // Push frame descriptor and perform the tail call.
37   masm.makeFrameDescriptor(scratch, FrameType::BaselineJS,
38                            ExitFrameLayout::Size());
39   masm.push(scratch);
40   masm.push(ICTailCallReg);
41   masm.jump(target);
42 }
43 
EmitBaselineCreateStubFrameDescriptor(MacroAssembler & masm,Register reg,uint32_t headerSize)44 inline void EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm,
45                                                   Register reg,
46                                                   uint32_t headerSize) {
47   // Compute stub frame size. We have to add two pointers: the stub reg and
48   // previous frame pointer pushed by EmitEnterStubFrame.
49   masm.movq(BaselineFrameReg, reg);
50   masm.addq(Imm32(sizeof(void*) * 2), reg);
51   masm.subq(BaselineStackReg, reg);
52 
53   masm.makeFrameDescriptor(reg, FrameType::BaselineStub, headerSize);
54 }
55 
EmitBaselineCallVM(TrampolinePtr target,MacroAssembler & masm)56 inline void EmitBaselineCallVM(TrampolinePtr target, MacroAssembler& masm) {
57   ScratchRegisterScope scratch(masm);
58   EmitBaselineCreateStubFrameDescriptor(masm, scratch, ExitFrameLayout::Size());
59   masm.push(scratch);
60   masm.call(target);
61 }
62 
63 // Size of values pushed by EmitBaselineEnterStubFrame.
64 static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void*);
65 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void*);
66 
EmitBaselineEnterStubFrame(MacroAssembler & masm,Register)67 inline void EmitBaselineEnterStubFrame(MacroAssembler& masm, Register) {
68   ScratchRegisterScope scratch(masm);
69 
70   // Compute frame size. Because the return address is still on the stack,
71   // this is:
72   //
73   //   BaselineFrameReg
74   //   + BaselineFrame::FramePointerOffset
75   //   - BaselineStackReg
76   //   - sizeof(return address)
77   //
78   // The two constants cancel each other out, so we can just calculate
79   // BaselineFrameReg - BaselineStackReg.
80 
81   static_assert(
82       BaselineFrame::FramePointerOffset == sizeof(void*),
83       "FramePointerOffset must be the same as the return address size");
84 
85   masm.movq(BaselineFrameReg, scratch);
86   masm.subq(BaselineStackReg, scratch);
87 
88 #ifdef DEBUG
89   Address frameSizeAddr(BaselineFrameReg,
90                         BaselineFrame::reverseOffsetOfDebugFrameSize());
91   masm.store32(scratch, frameSizeAddr);
92 #endif
93 
94   // Note: when making changes here,  don't forget to update STUB_FRAME_SIZE
95   // if needed.
96 
97   // Push the return address that's currently on top of the stack.
98   masm.Push(Operand(BaselineStackReg, 0));
99 
100   // Replace the original return address with the frame descriptor.
101   masm.makeFrameDescriptor(scratch, FrameType::BaselineJS,
102                            BaselineStubFrameLayout::Size());
103   masm.storePtr(scratch, Address(BaselineStackReg, sizeof(uintptr_t)));
104 
105   // Save old frame pointer, stack pointer and stub reg.
106   masm.Push(ICStubReg);
107   masm.Push(BaselineFrameReg);
108   masm.mov(BaselineStackReg, BaselineFrameReg);
109 }
110 
111 }  // namespace jit
112 }  // namespace js
113 
114 #endif /* jit_x64_SharedICHelpers_x64_inl_h */
115