1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x86/BaselineHelpers-x86.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,310 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_x86_BaselineHelpers_x86_h 1.11 +#define jit_x86_BaselineHelpers_x86_h 1.12 + 1.13 +#ifdef JS_ION 1.14 +#include "jit/BaselineFrame.h" 1.15 +#include "jit/BaselineIC.h" 1.16 +#include "jit/BaselineRegisters.h" 1.17 +#include "jit/IonMacroAssembler.h" 1.18 + 1.19 +namespace js { 1.20 +namespace jit { 1.21 + 1.22 +// Distance from stack top to the top Value inside an IC stub (this is the return address). 1.23 +static const size_t ICStackValueOffset = sizeof(void *); 1.24 + 1.25 +inline void 1.26 +EmitRestoreTailCallReg(MacroAssembler &masm) 1.27 +{ 1.28 + masm.pop(BaselineTailCallReg); 1.29 +} 1.30 + 1.31 +inline void 1.32 +EmitRepushTailCallReg(MacroAssembler &masm) 1.33 +{ 1.34 + masm.push(BaselineTailCallReg); 1.35 +} 1.36 + 1.37 +inline void 1.38 +EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm) 1.39 +{ 1.40 + // Move ICEntry offset into BaselineStubReg 1.41 + CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg); 1.42 + *patchOffset = offset; 1.43 + 1.44 + // Load stub pointer into BaselineStubReg 1.45 + masm.loadPtr(Address(BaselineStubReg, (int32_t) ICEntry::offsetOfFirstStub()), 1.46 + BaselineStubReg); 1.47 + 1.48 + // Load stubcode pointer from BaselineStubEntry into BaselineTailCallReg 1.49 + // BaselineTailCallReg will always be unused in the contexts where ICs are called. 1.50 + masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode())); 1.51 +} 1.52 + 1.53 +inline void 1.54 +EmitEnterTypeMonitorIC(MacroAssembler &masm, 1.55 + size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) 1.56 +{ 1.57 + // This is expected to be called from within an IC, when BaselineStubReg 1.58 + // is properly initialized to point to the stub. 1.59 + masm.loadPtr(Address(BaselineStubReg, (int32_t) monitorStubOffset), BaselineStubReg); 1.60 + 1.61 + // Jump to the stubcode. 1.62 + masm.jmp(Operand(BaselineStubReg, (int32_t) ICStub::offsetOfStubCode())); 1.63 +} 1.64 + 1.65 +inline void 1.66 +EmitReturnFromIC(MacroAssembler &masm) 1.67 +{ 1.68 + masm.ret(); 1.69 +} 1.70 + 1.71 +inline void 1.72 +EmitChangeICReturnAddress(MacroAssembler &masm, Register reg) 1.73 +{ 1.74 + masm.storePtr(reg, Address(StackPointer, 0)); 1.75 +} 1.76 + 1.77 +inline void 1.78 +EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize) 1.79 +{ 1.80 + // We assume during this that R0 and R1 have been pushed. 1.81 + 1.82 + // Compute frame size. 1.83 + masm.movl(BaselineFrameReg, eax); 1.84 + masm.addl(Imm32(BaselineFrame::FramePointerOffset), eax); 1.85 + masm.subl(BaselineStackReg, eax); 1.86 + 1.87 + // Store frame size without VMFunction arguments for GC marking. 1.88 + masm.movl(eax, ebx); 1.89 + masm.subl(Imm32(argSize), ebx); 1.90 + masm.store32(ebx, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); 1.91 + 1.92 + // Push frame descriptor and perform the tail call. 1.93 + masm.makeFrameDescriptor(eax, JitFrame_BaselineJS); 1.94 + masm.push(eax); 1.95 + masm.push(BaselineTailCallReg); 1.96 + masm.jmp(target); 1.97 +} 1.98 + 1.99 +inline void 1.100 +EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg) 1.101 +{ 1.102 + // Compute stub frame size. We have to add two pointers: the stub reg and previous 1.103 + // frame pointer pushed by EmitEnterStubFrame. 1.104 + masm.movl(BaselineFrameReg, reg); 1.105 + masm.addl(Imm32(sizeof(void *) * 2), reg); 1.106 + masm.subl(BaselineStackReg, reg); 1.107 + 1.108 + masm.makeFrameDescriptor(reg, JitFrame_BaselineStub); 1.109 +} 1.110 + 1.111 +inline void 1.112 +EmitCallVM(JitCode *target, MacroAssembler &masm) 1.113 +{ 1.114 + EmitCreateStubFrameDescriptor(masm, eax); 1.115 + masm.push(eax); 1.116 + masm.call(target); 1.117 +} 1.118 + 1.119 +// Size of vales pushed by EmitEnterStubFrame. 1.120 +static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void *); 1.121 +static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void *); 1.122 + 1.123 +inline void 1.124 +EmitEnterStubFrame(MacroAssembler &masm, Register scratch) 1.125 +{ 1.126 + JS_ASSERT(scratch != BaselineTailCallReg); 1.127 + 1.128 + EmitRestoreTailCallReg(masm); 1.129 + 1.130 + // Compute frame size. 1.131 + masm.movl(BaselineFrameReg, scratch); 1.132 + masm.addl(Imm32(BaselineFrame::FramePointerOffset), scratch); 1.133 + masm.subl(BaselineStackReg, scratch); 1.134 + 1.135 + masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); 1.136 + 1.137 + // Note: when making changes here, don't forget to update STUB_FRAME_SIZE 1.138 + // if needed. 1.139 + 1.140 + // Push frame descriptor and return address. 1.141 + masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS); 1.142 + masm.push(scratch); 1.143 + masm.push(BaselineTailCallReg); 1.144 + 1.145 + // Save old frame pointer, stack pointer and stub reg. 1.146 + masm.push(BaselineStubReg); 1.147 + masm.push(BaselineFrameReg); 1.148 + masm.mov(BaselineStackReg, BaselineFrameReg); 1.149 +} 1.150 + 1.151 +inline void 1.152 +EmitLeaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false) 1.153 +{ 1.154 + // Ion frames do not save and restore the frame pointer. If we called 1.155 + // into Ion, we have to restore the stack pointer from the frame descriptor. 1.156 + // If we performed a VM call, the descriptor has been popped already so 1.157 + // in that case we use the frame pointer. 1.158 + if (calledIntoIon) { 1.159 + Register scratch = BaselineTailCallReg; 1.160 + masm.pop(scratch); 1.161 + masm.shrl(Imm32(FRAMESIZE_SHIFT), scratch); 1.162 + masm.addl(scratch, BaselineStackReg); 1.163 + } else { 1.164 + masm.mov(BaselineFrameReg, BaselineStackReg); 1.165 + } 1.166 +} 1.167 + 1.168 +inline void 1.169 +EmitLeaveStubFrameCommonTail(MacroAssembler &masm) 1.170 +{ 1.171 + masm.pop(BaselineFrameReg); 1.172 + masm.pop(BaselineStubReg); 1.173 + 1.174 + // Pop return address. 1.175 + masm.pop(BaselineTailCallReg); 1.176 + 1.177 + // Overwrite frame descriptor with return address, so that the stack matches 1.178 + // the state before entering the stub frame. 1.179 + masm.storePtr(BaselineTailCallReg, Address(BaselineStackReg, 0)); 1.180 +} 1.181 + 1.182 +inline void 1.183 +EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false) 1.184 +{ 1.185 + EmitLeaveStubFrameHead(masm, calledIntoIon); 1.186 + EmitLeaveStubFrameCommonTail(masm); 1.187 +} 1.188 + 1.189 +inline void 1.190 +EmitStowICValues(MacroAssembler &masm, int values) 1.191 +{ 1.192 + JS_ASSERT(values >= 0 && values <= 2); 1.193 + switch(values) { 1.194 + case 1: 1.195 + // Stow R0 1.196 + masm.pop(BaselineTailCallReg); 1.197 + masm.pushValue(R0); 1.198 + masm.push(BaselineTailCallReg); 1.199 + break; 1.200 + case 2: 1.201 + // Stow R0 and R1 1.202 + masm.pop(BaselineTailCallReg); 1.203 + masm.pushValue(R0); 1.204 + masm.pushValue(R1); 1.205 + masm.push(BaselineTailCallReg); 1.206 + break; 1.207 + } 1.208 +} 1.209 + 1.210 +inline void 1.211 +EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false) 1.212 +{ 1.213 + JS_ASSERT(values >= 0 && values <= 2); 1.214 + switch(values) { 1.215 + case 1: 1.216 + // Unstow R0 1.217 + masm.pop(BaselineTailCallReg); 1.218 + if (discard) 1.219 + masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg); 1.220 + else 1.221 + masm.popValue(R0); 1.222 + masm.push(BaselineTailCallReg); 1.223 + break; 1.224 + case 2: 1.225 + // Unstow R0 and R1 1.226 + masm.pop(BaselineTailCallReg); 1.227 + if (discard) { 1.228 + masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg); 1.229 + } else { 1.230 + masm.popValue(R1); 1.231 + masm.popValue(R0); 1.232 + } 1.233 + masm.push(BaselineTailCallReg); 1.234 + break; 1.235 + } 1.236 +} 1.237 + 1.238 +inline void 1.239 +EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset) 1.240 +{ 1.241 + // R0 contains the value that needs to be typechecked. 1.242 + // The object we're updating is a boxed Value on the stack, at offset 1.243 + // objectOffset from stack top, excluding the return address. 1.244 + 1.245 + // Save the current BaselineStubReg to stack 1.246 + masm.push(BaselineStubReg); 1.247 + 1.248 + // This is expected to be called from within an IC, when BaselineStubReg 1.249 + // is properly initialized to point to the stub. 1.250 + masm.loadPtr(Address(BaselineStubReg, (int32_t) ICUpdatedStub::offsetOfFirstUpdateStub()), 1.251 + BaselineStubReg); 1.252 + 1.253 + // Call the stubcode. 1.254 + masm.call(Operand(BaselineStubReg, ICStub::offsetOfStubCode())); 1.255 + 1.256 + // Restore the old stub reg. 1.257 + masm.pop(BaselineStubReg); 1.258 + 1.259 + // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the 1.260 + // value in R0 type-checked properly or not. 1.261 + Label success; 1.262 + masm.cmp32(R1.scratchReg(), Imm32(1)); 1.263 + masm.j(Assembler::Equal, &success); 1.264 + 1.265 + // If the IC failed, then call the update fallback function. 1.266 + EmitEnterStubFrame(masm, R1.scratchReg()); 1.267 + 1.268 + masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); 1.269 + 1.270 + masm.pushValue(R0); 1.271 + masm.pushValue(R1); 1.272 + masm.push(BaselineStubReg); 1.273 + 1.274 + // Load previous frame pointer, push BaselineFrame *. 1.275 + masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); 1.276 + masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); 1.277 + 1.278 + EmitCallVM(code, masm); 1.279 + EmitLeaveStubFrame(masm); 1.280 + 1.281 + // Success at end. 1.282 + masm.bind(&success); 1.283 +} 1.284 + 1.285 +template <typename AddrType> 1.286 +inline void 1.287 +EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type) 1.288 +{ 1.289 + masm.patchableCallPreBarrier(addr, type); 1.290 +} 1.291 + 1.292 +inline void 1.293 +EmitStubGuardFailure(MacroAssembler &masm) 1.294 +{ 1.295 + // NOTE: This routine assumes that the stub guard code left the stack in the 1.296 + // same state it was in when it was entered. 1.297 + 1.298 + // BaselineStubEntry points to the current stub. 1.299 + 1.300 + // Load next stub into BaselineStubReg 1.301 + masm.loadPtr(Address(BaselineStubReg, (int32_t) ICStub::offsetOfNext()), BaselineStubReg); 1.302 + 1.303 + // Return address is already loaded, just jump to the next stubcode. 1.304 + masm.jmp(Operand(BaselineStubReg, (int32_t) ICStub::offsetOfStubCode())); 1.305 +} 1.306 + 1.307 + 1.308 +} // namespace jit 1.309 +} // namespace js 1.310 + 1.311 +#endif // JS_ION 1.312 + 1.313 +#endif /* jit_x86_BaselineHelpers_x86_h */