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_arm_BaselineHelpers_arm_h
8 #define jit_arm_BaselineHelpers_arm_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 sp to the top Value inside an IC stub (no return address on the stack on ARM).
20 static const size_t ICStackValueOffset = 0;
22 inline void
23 EmitRestoreTailCallReg(MacroAssembler &masm)
24 {
25 // No-op on ARM because link register is always holding the return address.
26 }
28 inline void
29 EmitRepushTailCallReg(MacroAssembler &masm)
30 {
31 // No-op on ARM because link register is always holding the return address.
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, ICEntry::offsetOfFirstStub()), BaselineStubReg);
44 // Load stubcode pointer from BaselineStubEntry.
45 // R2 won't be active when we call ICs, so we can use r0.
46 JS_ASSERT(R2 == ValueOperand(r1, r0));
47 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), r0);
49 // Call the stubcode via a direct branch-and-link
50 masm.ma_blx(r0);
51 }
53 inline void
54 EmitEnterTypeMonitorIC(MacroAssembler &masm,
55 size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
56 {
57 // This is expected to be called from within an IC, when BaselineStubReg
58 // is properly initialized to point to the stub.
59 masm.loadPtr(Address(BaselineStubReg, (uint32_t) monitorStubOffset), BaselineStubReg);
61 // Load stubcode pointer from BaselineStubEntry.
62 // R2 won't be active when we call ICs, so we can use r0.
63 JS_ASSERT(R2 == ValueOperand(r1, r0));
64 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), r0);
66 // Jump to the stubcode.
67 masm.branch(r0);
68 }
70 inline void
71 EmitReturnFromIC(MacroAssembler &masm)
72 {
73 masm.ma_mov(lr, pc);
74 }
76 inline void
77 EmitChangeICReturnAddress(MacroAssembler &masm, Register reg)
78 {
79 masm.ma_mov(reg, lr);
80 }
82 inline void
83 EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize)
84 {
85 // We assume during this that R0 and R1 have been pushed, and that R2 is
86 // unused.
87 JS_ASSERT(R2 == ValueOperand(r1, r0));
89 // Compute frame size.
90 masm.movePtr(BaselineFrameReg, r0);
91 masm.ma_add(Imm32(BaselineFrame::FramePointerOffset), r0);
92 masm.ma_sub(BaselineStackReg, r0);
94 // Store frame size without VMFunction arguments for GC marking.
95 masm.ma_sub(r0, Imm32(argSize), r1);
96 masm.store32(r1, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
98 // Push frame descriptor and perform the tail call.
99 // BaselineTailCallReg (lr) already contains the return address (as we keep it there through
100 // the stub calls), but the VMWrapper code being called expects the return address to also
101 // be pushed on the stack.
102 JS_ASSERT(BaselineTailCallReg == lr);
103 masm.makeFrameDescriptor(r0, JitFrame_BaselineJS);
104 masm.push(r0);
105 masm.push(lr);
106 masm.branch(target);
107 }
109 inline void
110 EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg)
111 {
112 // Compute stub frame size. We have to add two pointers: the stub reg and previous
113 // frame pointer pushed by EmitEnterStubFrame.
114 masm.mov(BaselineFrameReg, reg);
115 masm.ma_add(Imm32(sizeof(void *) * 2), reg);
116 masm.ma_sub(BaselineStackReg, reg);
118 masm.makeFrameDescriptor(reg, JitFrame_BaselineStub);
119 }
121 inline void
122 EmitCallVM(JitCode *target, MacroAssembler &masm)
123 {
124 EmitCreateStubFrameDescriptor(masm, r0);
125 masm.push(r0);
126 masm.call(target);
127 }
129 // Size of vales pushed by EmitEnterStubFrame.
130 static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void *);
131 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void *);
133 inline void
134 EmitEnterStubFrame(MacroAssembler &masm, Register scratch)
135 {
136 JS_ASSERT(scratch != BaselineTailCallReg);
138 // Compute frame size.
139 masm.mov(BaselineFrameReg, scratch);
140 masm.ma_add(Imm32(BaselineFrame::FramePointerOffset), scratch);
141 masm.ma_sub(BaselineStackReg, scratch);
143 masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
145 // Note: when making changes here, don't forget to update STUB_FRAME_SIZE
146 // if needed.
148 // Push frame descriptor and return address.
149 masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS);
150 masm.push(scratch);
151 masm.push(BaselineTailCallReg);
153 // Save old frame pointer, stack pointer and stub reg.
154 masm.push(BaselineStubReg);
155 masm.push(BaselineFrameReg);
156 masm.mov(BaselineStackReg, BaselineFrameReg);
158 // We pushed 4 words, so the stack is still aligned to 8 bytes.
159 masm.checkStackAlignment();
160 }
162 inline void
163 EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
164 {
165 // Ion frames do not save and restore the frame pointer. If we called
166 // into Ion, we have to restore the stack pointer from the frame descriptor.
167 // If we performed a VM call, the descriptor has been popped already so
168 // in that case we use the frame pointer.
169 if (calledIntoIon) {
170 masm.pop(ScratchRegister);
171 masm.ma_lsr(Imm32(FRAMESIZE_SHIFT), ScratchRegister, ScratchRegister);
172 masm.ma_add(ScratchRegister, BaselineStackReg);
173 } else {
174 masm.mov(BaselineFrameReg, BaselineStackReg);
175 }
176 }
178 inline void
179 EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
180 {
181 masm.pop(BaselineFrameReg);
182 masm.pop(BaselineStubReg);
184 // Load the return address.
185 masm.pop(BaselineTailCallReg);
187 // Discard the frame descriptor.
188 masm.pop(ScratchRegister);
189 }
191 inline void
192 EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
193 {
194 EmitLeaveStubFrameHead(masm, calledIntoIon);
195 EmitLeaveStubFrameCommonTail(masm);
196 }
198 inline void
199 EmitStowICValues(MacroAssembler &masm, int values)
200 {
201 JS_ASSERT(values >= 0 && values <= 2);
202 switch(values) {
203 case 1:
204 // Stow R0
205 masm.pushValue(R0);
206 break;
207 case 2:
208 // Stow R0 and R1
209 masm.pushValue(R0);
210 masm.pushValue(R1);
211 break;
212 }
213 }
215 inline void
216 EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
217 {
218 JS_ASSERT(values >= 0 && values <= 2);
219 switch(values) {
220 case 1:
221 // Unstow R0
222 if (discard)
223 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
224 else
225 masm.popValue(R0);
226 break;
227 case 2:
228 // Unstow R0 and R1
229 if (discard) {
230 masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
231 } else {
232 masm.popValue(R1);
233 masm.popValue(R0);
234 }
235 break;
236 }
237 }
239 inline void
240 EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset)
241 {
242 JS_ASSERT(R2 == ValueOperand(r1, r0));
244 // R0 contains the value that needs to be typechecked.
245 // The object we're updating is a boxed Value on the stack, at offset
246 // objectOffset from esp, excluding the return address.
248 // Save the current BaselineStubReg to stack, as well as the TailCallReg,
249 // since on ARM, the LR is live.
250 masm.push(BaselineStubReg);
251 masm.push(BaselineTailCallReg);
253 // This is expected to be called from within an IC, when BaselineStubReg
254 // is properly initialized to point to the stub.
255 masm.loadPtr(Address(BaselineStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()),
256 BaselineStubReg);
258 // TODO: Change r0 uses below to use masm's configurable scratch register instead.
260 // Load stubcode pointer from BaselineStubReg into BaselineTailCallReg.
261 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), r0);
263 // Call the stubcode.
264 masm.ma_blx(r0);
266 // Restore the old stub reg and tailcall reg.
267 masm.pop(BaselineTailCallReg);
268 masm.pop(BaselineStubReg);
270 // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
271 // value in R0 type-checked properly or not.
272 Label success;
273 masm.cmp32(R1.scratchReg(), Imm32(1));
274 masm.j(Assembler::Equal, &success);
276 // If the IC failed, then call the update fallback function.
277 EmitEnterStubFrame(masm, R1.scratchReg());
279 masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
281 masm.pushValue(R0);
282 masm.pushValue(R1);
283 masm.push(BaselineStubReg);
285 // Load previous frame pointer, push BaselineFrame *.
286 masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
287 masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
289 EmitCallVM(code, masm);
290 EmitLeaveStubFrame(masm);
292 // Success at end.
293 masm.bind(&success);
294 }
296 template <typename AddrType>
297 inline void
298 EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type)
299 {
300 // on ARM, lr is clobbered by patchableCallPreBarrier. Save it first.
301 masm.push(lr);
302 masm.patchableCallPreBarrier(addr, type);
303 masm.pop(lr);
304 }
306 inline void
307 EmitStubGuardFailure(MacroAssembler &masm)
308 {
309 JS_ASSERT(R2 == ValueOperand(r1, r0));
311 // NOTE: This routine assumes that the stub guard code left the stack in the
312 // same state it was in when it was entered.
314 // BaselineStubEntry points to the current stub.
316 // Load next stub into BaselineStubReg
317 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfNext()), BaselineStubReg);
319 // Load stubcode pointer from BaselineStubEntry into scratch register.
320 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), r0);
322 // Return address is already loaded, just jump to the next stubcode.
323 JS_ASSERT(BaselineTailCallReg == lr);
324 masm.branch(r0);
325 }
328 } // namespace jit
329 } // namespace js
331 #endif // JS_ION
333 #endif /* jit_arm_BaselineHelpers_arm_h */