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_x86_BaselineHelpers_x86_h
8 #define jit_x86_BaselineHelpers_x86_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 // Load stubcode pointer from BaselineStubEntry into BaselineTailCallReg
46 // BaselineTailCallReg will always be unused in the contexts where ICs are called.
47 masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode()));
48 }
50 inline void
51 EmitEnterTypeMonitorIC(MacroAssembler &masm,
52 size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
53 {
54 // This is expected to be called from within an IC, when BaselineStubReg
55 // is properly initialized to point to the stub.
56 masm.loadPtr(Address(BaselineStubReg, (int32_t) monitorStubOffset), BaselineStubReg);
58 // Jump to the stubcode.
59 masm.jmp(Operand(BaselineStubReg, (int32_t) ICStub::offsetOfStubCode()));
60 }
62 inline void
63 EmitReturnFromIC(MacroAssembler &masm)
64 {
65 masm.ret();
66 }
68 inline void
69 EmitChangeICReturnAddress(MacroAssembler &masm, Register reg)
70 {
71 masm.storePtr(reg, Address(StackPointer, 0));
72 }
74 inline void
75 EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize)
76 {
77 // We assume during this that R0 and R1 have been pushed.
79 // Compute frame size.
80 masm.movl(BaselineFrameReg, eax);
81 masm.addl(Imm32(BaselineFrame::FramePointerOffset), eax);
82 masm.subl(BaselineStackReg, eax);
84 // Store frame size without VMFunction arguments for GC marking.
85 masm.movl(eax, ebx);
86 masm.subl(Imm32(argSize), ebx);
87 masm.store32(ebx, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
89 // Push frame descriptor and perform the tail call.
90 masm.makeFrameDescriptor(eax, JitFrame_BaselineJS);
91 masm.push(eax);
92 masm.push(BaselineTailCallReg);
93 masm.jmp(target);
94 }
96 inline void
97 EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg)
98 {
99 // Compute stub frame size. We have to add two pointers: the stub reg and previous
100 // frame pointer pushed by EmitEnterStubFrame.
101 masm.movl(BaselineFrameReg, reg);
102 masm.addl(Imm32(sizeof(void *) * 2), reg);
103 masm.subl(BaselineStackReg, reg);
105 masm.makeFrameDescriptor(reg, JitFrame_BaselineStub);
106 }
108 inline void
109 EmitCallVM(JitCode *target, MacroAssembler &masm)
110 {
111 EmitCreateStubFrameDescriptor(masm, eax);
112 masm.push(eax);
113 masm.call(target);
114 }
116 // Size of vales pushed by EmitEnterStubFrame.
117 static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void *);
118 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void *);
120 inline void
121 EmitEnterStubFrame(MacroAssembler &masm, Register scratch)
122 {
123 JS_ASSERT(scratch != BaselineTailCallReg);
125 EmitRestoreTailCallReg(masm);
127 // Compute frame size.
128 masm.movl(BaselineFrameReg, scratch);
129 masm.addl(Imm32(BaselineFrame::FramePointerOffset), scratch);
130 masm.subl(BaselineStackReg, scratch);
132 masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
134 // Note: when making changes here, don't forget to update STUB_FRAME_SIZE
135 // if needed.
137 // Push frame descriptor and return address.
138 masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS);
139 masm.push(scratch);
140 masm.push(BaselineTailCallReg);
142 // Save old frame pointer, stack pointer and stub reg.
143 masm.push(BaselineStubReg);
144 masm.push(BaselineFrameReg);
145 masm.mov(BaselineStackReg, BaselineFrameReg);
146 }
148 inline void
149 EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false)
150 {
151 // Ion frames do not save and restore the frame pointer. If we called
152 // into Ion, we have to restore the stack pointer from the frame descriptor.
153 // If we performed a VM call, the descriptor has been popped already so
154 // in that case we use the frame pointer.
155 if (calledIntoIon) {
156 Register scratch = BaselineTailCallReg;
157 masm.pop(scratch);
158 masm.shrl(Imm32(FRAMESIZE_SHIFT), scratch);
159 masm.addl(scratch, BaselineStackReg);
160 } else {
161 masm.mov(BaselineFrameReg, BaselineStackReg);
162 }
163 }
165 inline void
166 EmitLeaveStubFrameCommonTail(MacroAssembler &masm)
167 {
168 masm.pop(BaselineFrameReg);
169 masm.pop(BaselineStubReg);
171 // Pop return address.
172 masm.pop(BaselineTailCallReg);
174 // Overwrite frame descriptor with return address, so that the stack matches
175 // the state before entering the stub frame.
176 masm.storePtr(BaselineTailCallReg, Address(BaselineStackReg, 0));
177 }
179 inline void
180 EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
181 {
182 EmitLeaveStubFrameHead(masm, calledIntoIon);
183 EmitLeaveStubFrameCommonTail(masm);
184 }
186 inline void
187 EmitStowICValues(MacroAssembler &masm, int values)
188 {
189 JS_ASSERT(values >= 0 && values <= 2);
190 switch(values) {
191 case 1:
192 // Stow R0
193 masm.pop(BaselineTailCallReg);
194 masm.pushValue(R0);
195 masm.push(BaselineTailCallReg);
196 break;
197 case 2:
198 // Stow R0 and R1
199 masm.pop(BaselineTailCallReg);
200 masm.pushValue(R0);
201 masm.pushValue(R1);
202 masm.push(BaselineTailCallReg);
203 break;
204 }
205 }
207 inline void
208 EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
209 {
210 JS_ASSERT(values >= 0 && values <= 2);
211 switch(values) {
212 case 1:
213 // Unstow R0
214 masm.pop(BaselineTailCallReg);
215 if (discard)
216 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
217 else
218 masm.popValue(R0);
219 masm.push(BaselineTailCallReg);
220 break;
221 case 2:
222 // Unstow R0 and R1
223 masm.pop(BaselineTailCallReg);
224 if (discard) {
225 masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
226 } else {
227 masm.popValue(R1);
228 masm.popValue(R0);
229 }
230 masm.push(BaselineTailCallReg);
231 break;
232 }
233 }
235 inline void
236 EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset)
237 {
238 // R0 contains the value that needs to be typechecked.
239 // The object we're updating is a boxed Value on the stack, at offset
240 // objectOffset from stack top, excluding the return address.
242 // Save the current BaselineStubReg to stack
243 masm.push(BaselineStubReg);
245 // This is expected to be called from within an IC, when BaselineStubReg
246 // is properly initialized to point to the stub.
247 masm.loadPtr(Address(BaselineStubReg, (int32_t) ICUpdatedStub::offsetOfFirstUpdateStub()),
248 BaselineStubReg);
250 // Call the stubcode.
251 masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode()));
253 // Restore the old stub reg.
254 masm.pop(BaselineStubReg);
256 // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
257 // value in R0 type-checked properly or not.
258 Label success;
259 masm.cmp32(R1.scratchReg(), Imm32(1));
260 masm.j(Assembler::Equal, &success);
262 // If the IC failed, then call the update fallback function.
263 EmitEnterStubFrame(masm, R1.scratchReg());
265 masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
267 masm.pushValue(R0);
268 masm.pushValue(R1);
269 masm.push(BaselineStubReg);
271 // Load previous frame pointer, push BaselineFrame *.
272 masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
273 masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
275 EmitCallVM(code, masm);
276 EmitLeaveStubFrame(masm);
278 // Success at end.
279 masm.bind(&success);
280 }
282 template <typename AddrType>
283 inline void
284 EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type)
285 {
286 masm.patchableCallPreBarrier(addr, type);
287 }
289 inline void
290 EmitStubGuardFailure(MacroAssembler &masm)
291 {
292 // NOTE: This routine assumes that the stub guard code left the stack in the
293 // same state it was in when it was entered.
295 // BaselineStubEntry points to the current stub.
297 // Load next stub into BaselineStubReg
298 masm.loadPtr(Address(BaselineStubReg, (int32_t) ICStub::offsetOfNext()), BaselineStubReg);
300 // Return address is already loaded, just jump to the next stubcode.
301 masm.jmp(Operand(BaselineStubReg, (int32_t) ICStub::offsetOfStubCode()));
302 }
305 } // namespace jit
306 } // namespace js
308 #endif // JS_ION
310 #endif /* jit_x86_BaselineHelpers_x86_h */