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_mips_BaselineHelpers_mips_h
8 #define jit_mips_BaselineHelpers_mips_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
20 // the stack on MIPS).
21 static const size_t ICStackValueOffset = 0;
23 inline void
24 EmitRestoreTailCallReg(MacroAssembler &masm)
25 {
26 // No-op on MIPS because ra register is always holding the return address.
27 }
29 inline void
30 EmitRepushTailCallReg(MacroAssembler &masm)
31 {
32 // No-op on MIPS because ra register is always holding the return address.
33 }
35 inline void
36 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
37 {
38 // Move ICEntry offset into BaselineStubReg.
39 CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
40 *patchOffset = offset;
42 // Load stub pointer into BaselineStubReg.
43 masm.loadPtr(Address(BaselineStubReg, ICEntry::offsetOfFirstStub()), BaselineStubReg);
45 // Load stubcode pointer from BaselineStubEntry.
46 // R2 won't be active when we call ICs, so we can use it as scratch.
47 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
49 // Call the stubcode via a direct jump-and-link
50 masm.call(R2.scratchReg());
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 it.
63 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
65 // Jump to the stubcode.
66 masm.branch(R2.scratchReg());
67 }
69 inline void
70 EmitReturnFromIC(MacroAssembler &masm)
71 {
72 masm.branch(ra);
73 }
75 inline void
76 EmitChangeICReturnAddress(MacroAssembler &masm, Register reg)
77 {
78 masm.movePtr(reg, ra);
79 }
81 inline void
82 EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize)
83 {
84 // We assume during this that R0 and R1 have been pushed, and that R2 is
85 // unused.
86 MOZ_ASSERT(R2 == ValueOperand(t7, t6));
88 // Compute frame size.
89 masm.movePtr(BaselineFrameReg, t6);
90 masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), t6);
91 masm.subPtr(BaselineStackReg, t6);
93 // Store frame size without VMFunction arguments for GC marking.
94 masm.ma_subu(t7, t6, Imm32(argSize));
95 masm.storePtr(t7, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
97 // Push frame descriptor and perform the tail call.
98 // BaselineTailCallReg (ra) already contains the return address (as we
99 // keep it there through the stub calls), but the VMWrapper code being
100 // called expects the return address to also be pushed on the stack.
101 MOZ_ASSERT(BaselineTailCallReg == ra);
102 masm.makeFrameDescriptor(t6, JitFrame_BaselineJS);
103 masm.subPtr(Imm32(sizeof(IonCommonFrameLayout)), StackPointer);
104 masm.storePtr(t6, Address(StackPointer, IonCommonFrameLayout::offsetOfDescriptor()));
105 masm.storePtr(ra, Address(StackPointer, IonCommonFrameLayout::offsetOfReturnAddress()));
107 masm.branch(target);
108 }
110 inline void
111 EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg)
112 {
113 // Compute stub frame size. We have to add two pointers: the stub reg and
114 // previous frame pointer pushed by EmitEnterStubFrame.
115 masm.movePtr(BaselineFrameReg, reg);
116 masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg);
117 masm.subPtr(BaselineStackReg, reg);
119 masm.makeFrameDescriptor(reg, JitFrame_BaselineStub);
120 }
122 inline void
123 EmitCallVM(JitCode *target, MacroAssembler &masm)
124 {
125 EmitCreateStubFrameDescriptor(masm, t6);
126 masm.push(t6);
127 masm.call(target);
128 }
130 struct BaselineStubFrame {
131 uintptr_t savedFrame;
132 uintptr_t savedStub;
133 uintptr_t returnAddress;
134 uintptr_t descriptor;
135 };
137 static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame);
138 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub);
140 inline void
141 EmitEnterStubFrame(MacroAssembler &masm, Register scratch)
142 {
143 MOZ_ASSERT(scratch != BaselineTailCallReg);
145 // Compute frame size.
146 masm.movePtr(BaselineFrameReg, scratch);
147 masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch);
148 masm.subPtr(BaselineStackReg, scratch);
150 masm.storePtr(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
152 // Note: when making changes here, don't forget to update
153 // BaselineStubFrame if needed.
155 // Push frame descriptor and return address.
156 masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS);
157 masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
158 masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor)));
159 masm.storePtr(BaselineTailCallReg, Address(StackPointer,
160 offsetof(BaselineStubFrame, returnAddress)));
162 // Save old frame pointer, stack pointer and stub reg.
163 masm.storePtr(BaselineStubReg, Address(StackPointer,
164 offsetof(BaselineStubFrame, savedStub)));
165 masm.storePtr(BaselineFrameReg, Address(StackPointer,
166 offsetof(BaselineStubFrame, savedFrame)));
167 masm.movePtr(BaselineStackReg, BaselineFrameReg);
169 // We pushed 4 words, so the stack is still aligned to 8 bytes.
170 masm.checkStackAlignment();
171 }
173 inline void
174 EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
175 {
176 // Ion frames do not save and restore the frame pointer. If we called
177 // into Ion, we have to restore the stack pointer from the frame descriptor.
178 // If we performed a VM call, the descriptor has been popped already so
179 // in that case we use the frame pointer.
180 if (calledIntoIon) {
181 masm.pop(ScratchRegister);
182 masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), ScratchRegister);
183 masm.addPtr(ScratchRegister, BaselineStackReg);
184 } else {
185 masm.movePtr(BaselineFrameReg, BaselineStackReg);
186 }
188 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)),
189 BaselineFrameReg);
190 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedStub)),
191 BaselineStubReg);
193 // Load the return address.
194 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, returnAddress)),
195 BaselineTailCallReg);
197 // Discard the frame descriptor.
198 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, descriptor)), ScratchRegister);
199 masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
200 }
202 inline void
203 EmitStowICValues(MacroAssembler &masm, int values)
204 {
205 MOZ_ASSERT(values >= 0 && values <= 2);
206 switch(values) {
207 case 1:
208 // Stow R0
209 masm.pushValue(R0);
210 break;
211 case 2:
212 // Stow R0 and R1
213 masm.pushValue(R0);
214 masm.pushValue(R1);
215 break;
216 }
217 }
219 inline void
220 EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
221 {
222 MOZ_ASSERT(values >= 0 && values <= 2);
223 switch(values) {
224 case 1:
225 // Unstow R0.
226 if (discard)
227 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
228 else
229 masm.popValue(R0);
230 break;
231 case 2:
232 // Unstow R0 and R1.
233 if (discard) {
234 masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
235 } else {
236 masm.popValue(R1);
237 masm.popValue(R0);
238 }
239 break;
240 }
241 }
243 inline void
244 EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset)
245 {
246 // R0 contains the value that needs to be typechecked.
247 // The object we're updating is a boxed Value on the stack, at offset
248 // objectOffset from $sp, excluding the return address.
250 // Save the current BaselineStubReg to stack, as well as the TailCallReg,
251 // since on mips, the $ra is live.
252 masm.subPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
253 masm.storePtr(BaselineStubReg, Address(StackPointer, sizeof(intptr_t)));
254 masm.storePtr(BaselineTailCallReg, Address(StackPointer, 0));
256 // This is expected to be called from within an IC, when BaselineStubReg
257 // is properly initialized to point to the stub.
258 masm.loadPtr(Address(BaselineStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()),
259 BaselineStubReg);
261 // Load stubcode pointer from BaselineStubReg into BaselineTailCallReg.
262 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
264 // Call the stubcode.
265 masm.call(R2.scratchReg());
267 // Restore the old stub reg and tailcall reg.
268 masm.loadPtr(Address(StackPointer, 0), BaselineTailCallReg);
269 masm.loadPtr(Address(StackPointer, sizeof(intptr_t)), BaselineStubReg);
270 masm.addPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
272 // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
273 // value in R0 type-checked properly or not.
274 Label success;
275 masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump);
277 // If the IC failed, then call the update fallback function.
278 EmitEnterStubFrame(masm, R1.scratchReg());
280 masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
282 masm.pushValue(R0);
283 masm.pushValue(R1);
284 masm.push(BaselineStubReg);
286 // Load previous frame pointer, push BaselineFrame *.
287 masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
288 masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
290 EmitCallVM(code, masm);
291 EmitLeaveStubFrame(masm);
293 // Success at end.
294 masm.bind(&success);
295 }
297 template <typename AddrType>
298 inline void
299 EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type)
300 {
301 // On MIPS, $ra is clobbered by patchableCallPreBarrier. Save it first.
302 masm.push(ra);
303 masm.patchableCallPreBarrier(addr, type);
304 masm.pop(ra);
305 }
307 inline void
308 EmitStubGuardFailure(MacroAssembler &masm)
309 {
310 // NOTE: This routine assumes that the stub guard code left the stack in
311 // the same state it was in when it was entered.
313 // BaselineStubEntry points to the current stub.
315 // Load next stub into BaselineStubReg
316 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfNext()), BaselineStubReg);
318 // Load stubcode pointer from BaselineStubEntry into scratch register.
319 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
321 // Return address is already loaded, just jump to the next stubcode.
322 MOZ_ASSERT(BaselineTailCallReg == ra);
323 masm.branch(R2.scratchReg());
324 }
327 } // namespace jit
328 } // namespace js
330 #endif // JS_ION
332 #endif /* jit_mips_BaselineHelpers_mips_h */