Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
7 #ifndef jit_x64_BaselineHelpers_x64_h
8 #define jit_x64_BaselineHelpers_x64_h
10 #ifdef JS_ION
11 #include "jit/BaselineFrame.h"
12 #include "jit/BaselineIC.h"
13 #include "jit/BaselineRegisters.h"
14 #include "jit/IonMacroAssembler.h"
16 namespace js {
17 namespace jit {
19 // Distance from Stack top to the top Value inside an IC stub (this is the return address).
20 static const size_t ICStackValueOffset = sizeof(void *);
22 inline void
23 EmitRestoreTailCallReg(MacroAssembler &masm)
24 {
25 masm.pop(BaselineTailCallReg);
26 }
28 inline void
29 EmitRepushTailCallReg(MacroAssembler &masm)
30 {
31 masm.push(BaselineTailCallReg);
32 }
34 inline void
35 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
36 {
37 // Move ICEntry offset into BaselineStubReg
38 CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
39 *patchOffset = offset;
41 // Load stub pointer into BaselineStubReg
42 masm.loadPtr(Address(BaselineStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
43 BaselineStubReg);
45 // Call the stubcode.
46 masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode()));
47 }
49 inline void
50 EmitEnterTypeMonitorIC(MacroAssembler &masm,
51 size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
52 {
53 // This is expected to be called from within an IC, when BaselineStubReg
54 // is properly initialized to point to the stub.
55 masm.loadPtr(Address(BaselineStubReg, (int32_t) monitorStubOffset), BaselineStubReg);
57 // Jump to the stubcode.
58 masm.jmp(Operand(BaselineStubReg, (int32_t) ICStub::offsetOfStubCode()));
59 }
61 inline void
62 EmitReturnFromIC(MacroAssembler &masm)
63 {
64 masm.ret();
65 }
67 inline void
68 EmitChangeICReturnAddress(MacroAssembler &masm, Register reg)
69 {
70 masm.storePtr(reg, Address(StackPointer, 0));
71 }
73 inline void
74 EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize)
75 {
76 // We an assume during this that R0 and R1 have been pushed.
77 masm.movq(BaselineFrameReg, ScratchReg);
78 masm.addq(Imm32(BaselineFrame::FramePointerOffset), ScratchReg);
79 masm.subq(BaselineStackReg, ScratchReg);
81 // Store frame size without VMFunction arguments for GC marking.
82 masm.movq(ScratchReg, rdx);
83 masm.subq(Imm32(argSize), rdx);
84 masm.store32(rdx, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
86 // Push frame descriptor and perform the tail call.
87 masm.makeFrameDescriptor(ScratchReg, JitFrame_BaselineJS);
88 masm.push(ScratchReg);
89 masm.push(BaselineTailCallReg);
90 masm.jmp(target);
91 }
93 inline void
94 EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg)
95 {
96 // Compute stub frame size. We have to add two pointers: the stub reg and previous
97 // frame pointer pushed by EmitEnterStubFrame.
98 masm.movq(BaselineFrameReg, reg);
99 masm.addq(Imm32(sizeof(void *) * 2), reg);
100 masm.subq(BaselineStackReg, reg);
102 masm.makeFrameDescriptor(reg, JitFrame_BaselineStub);
103 }
105 inline void
106 EmitCallVM(JitCode *target, MacroAssembler &masm)
107 {
108 EmitCreateStubFrameDescriptor(masm, ScratchReg);
109 masm.push(ScratchReg);
110 masm.call(target);
111 }
113 // Size of vales pushed by EmitEnterStubFrame.
114 static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void *);
115 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void *);
117 inline void
118 EmitEnterStubFrame(MacroAssembler &masm, Register)
119 {
120 EmitRestoreTailCallReg(masm);
122 // Compute frame size.
123 masm.movq(BaselineFrameReg, ScratchReg);
124 masm.addq(Imm32(BaselineFrame::FramePointerOffset), ScratchReg);
125 masm.subq(BaselineStackReg, ScratchReg);
127 masm.store32(ScratchReg, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
129 // Note: when making changes here, don't forget to update STUB_FRAME_SIZE
130 // if needed.
132 // Push frame descriptor and return address.
133 masm.makeFrameDescriptor(ScratchReg, JitFrame_BaselineJS);
134 masm.push(ScratchReg);
135 masm.push(BaselineTailCallReg);
137 // Save old frame pointer, stack pointer and stub reg.
138 masm.push(BaselineStubReg);
139 masm.push(BaselineFrameReg);
140 masm.mov(BaselineStackReg, BaselineFrameReg);
141 }
143 inline void
144 EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
145 {
146 // Ion frames do not save and restore the frame pointer. If we called
147 // into Ion, we have to restore the stack pointer from the frame descriptor.
148 // If we performed a VM call, the descriptor has been popped already so
149 // in that case we use the frame pointer.
150 if (calledIntoIon) {
151 masm.pop(ScratchReg);
152 masm.shrq(Imm32(FRAMESIZE_SHIFT), ScratchReg);
153 masm.addq(ScratchReg, BaselineStackReg);
154 } else {
155 masm.mov(BaselineFrameReg, BaselineStackReg);
156 }
157 }
159 inline void
160 EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
161 {
162 masm.pop(BaselineFrameReg);
163 masm.pop(BaselineStubReg);
165 // Pop return address.
166 masm.pop(BaselineTailCallReg);
168 // Overwrite frame descriptor with return address, so that the stack matches
169 // the state before entering the stub frame.
170 masm.storePtr(BaselineTailCallReg, Address(BaselineStackReg, 0));
171 }
173 inline void
174 EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
175 {
176 EmitLeaveStubFrameHead(masm, calledIntoIon);
177 EmitLeaveStubFrameCommonTail(masm);
178 }
180 inline void
181 EmitStowICValues(MacroAssembler &masm, int values)
182 {
183 JS_ASSERT(values >= 0 && values <= 2);
184 switch(values) {
185 case 1:
186 // Stow R0
187 masm.pop(BaselineTailCallReg);
188 masm.pushValue(R0);
189 masm.push(BaselineTailCallReg);
190 break;
191 case 2:
192 // Stow R0 and R1
193 masm.pop(BaselineTailCallReg);
194 masm.pushValue(R0);
195 masm.pushValue(R1);
196 masm.push(BaselineTailCallReg);
197 break;
198 }
199 }
201 inline void
202 EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
203 {
204 JS_ASSERT(values >= 0 && values <= 2);
205 switch(values) {
206 case 1:
207 // Unstow R0
208 masm.pop(BaselineTailCallReg);
209 if (discard)
210 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
211 else
212 masm.popValue(R0);
213 masm.push(BaselineTailCallReg);
214 break;
215 case 2:
216 // Unstow R0 and R1
217 masm.pop(BaselineTailCallReg);
218 if (discard) {
219 masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
220 } else {
221 masm.popValue(R1);
222 masm.popValue(R0);
223 }
224 masm.push(BaselineTailCallReg);
225 break;
226 }
227 }
229 inline void
230 EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset)
231 {
232 // R0 contains the value that needs to be typechecked.
233 // The object we're updating is a boxed Value on the stack, at offset
234 // objectOffset from stack top, excluding the return address.
236 // Save the current BaselineStubReg to stack
237 masm.push(BaselineStubReg);
239 // This is expected to be called from within an IC, when BaselineStubReg
240 // is properly initialized to point to the stub.
241 masm.loadPtr(Address(BaselineStubReg, (int32_t) ICUpdatedStub::offsetOfFirstUpdateStub()),
242 BaselineStubReg);
244 // Call the stubcode.
245 masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode()));
247 // Restore the old stub reg.
248 masm.pop(BaselineStubReg);
250 // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
251 // value in R0 type-checked properly or not.
252 Label success;
253 masm.cmp32(R1.scratchReg(), Imm32(1));
254 masm.j(Assembler::Equal, &success);
256 // If the IC failed, then call the update fallback function.
257 EmitEnterStubFrame(masm, R1.scratchReg());
259 masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
261 masm.pushValue(R0);
262 masm.pushValue(R1);
263 masm.push(BaselineStubReg);
265 // Load previous frame pointer, push BaselineFrame *.
266 masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
267 masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
269 EmitCallVM(code, masm);
270 EmitLeaveStubFrame(masm);
272 // Success at end.
273 masm.bind(&success);
274 }
276 template <typename AddrType>
277 inline void
278 EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type)
279 {
280 masm.patchableCallPreBarrier(addr, type);
281 }
283 inline void
284 EmitStubGuardFailure(MacroAssembler &masm)
285 {
286 // NOTE: This routine assumes that the stub guard code left the stack in the
287 // same state it was in when it was entered.
289 // BaselineStubEntry points to the current stub.
291 // Load next stub into BaselineStubReg
292 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfNext()), BaselineStubReg);
294 // Return address is already loaded, just jump to the next stubcode.
295 masm.jmp(Operand(BaselineStubReg, ICStub::offsetOfStubCode()));
296 }
299 } // namespace jit
300 } // namespace js
302 #endif // JS_ION
304 #endif /* jit_x64_BaselineHelpers_x64_h */