1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/mips/BaselineHelpers-mips.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,333 @@ 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_mips_BaselineHelpers_mips_h 1.11 +#define jit_mips_BaselineHelpers_mips_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 sp to the top Value inside an IC stub (no return address on 1.23 +// the stack on MIPS). 1.24 +static const size_t ICStackValueOffset = 0; 1.25 + 1.26 +inline void 1.27 +EmitRestoreTailCallReg(MacroAssembler &masm) 1.28 +{ 1.29 + // No-op on MIPS because ra register is always holding the return address. 1.30 +} 1.31 + 1.32 +inline void 1.33 +EmitRepushTailCallReg(MacroAssembler &masm) 1.34 +{ 1.35 + // No-op on MIPS because ra register is always holding the return address. 1.36 +} 1.37 + 1.38 +inline void 1.39 +EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm) 1.40 +{ 1.41 + // Move ICEntry offset into BaselineStubReg. 1.42 + CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg); 1.43 + *patchOffset = offset; 1.44 + 1.45 + // Load stub pointer into BaselineStubReg. 1.46 + masm.loadPtr(Address(BaselineStubReg, ICEntry::offsetOfFirstStub()), BaselineStubReg); 1.47 + 1.48 + // Load stubcode pointer from BaselineStubEntry. 1.49 + // R2 won't be active when we call ICs, so we can use it as scratch. 1.50 + masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); 1.51 + 1.52 + // Call the stubcode via a direct jump-and-link 1.53 + masm.call(R2.scratchReg()); 1.54 +} 1.55 + 1.56 +inline void 1.57 +EmitEnterTypeMonitorIC(MacroAssembler &masm, 1.58 + size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) 1.59 +{ 1.60 + // This is expected to be called from within an IC, when BaselineStubReg 1.61 + // is properly initialized to point to the stub. 1.62 + masm.loadPtr(Address(BaselineStubReg, (uint32_t) monitorStubOffset), BaselineStubReg); 1.63 + 1.64 + // Load stubcode pointer from BaselineStubEntry. 1.65 + // R2 won't be active when we call ICs, so we can use it. 1.66 + masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); 1.67 + 1.68 + // Jump to the stubcode. 1.69 + masm.branch(R2.scratchReg()); 1.70 +} 1.71 + 1.72 +inline void 1.73 +EmitReturnFromIC(MacroAssembler &masm) 1.74 +{ 1.75 + masm.branch(ra); 1.76 +} 1.77 + 1.78 +inline void 1.79 +EmitChangeICReturnAddress(MacroAssembler &masm, Register reg) 1.80 +{ 1.81 + masm.movePtr(reg, ra); 1.82 +} 1.83 + 1.84 +inline void 1.85 +EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize) 1.86 +{ 1.87 + // We assume during this that R0 and R1 have been pushed, and that R2 is 1.88 + // unused. 1.89 + MOZ_ASSERT(R2 == ValueOperand(t7, t6)); 1.90 + 1.91 + // Compute frame size. 1.92 + masm.movePtr(BaselineFrameReg, t6); 1.93 + masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), t6); 1.94 + masm.subPtr(BaselineStackReg, t6); 1.95 + 1.96 + // Store frame size without VMFunction arguments for GC marking. 1.97 + masm.ma_subu(t7, t6, Imm32(argSize)); 1.98 + masm.storePtr(t7, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); 1.99 + 1.100 + // Push frame descriptor and perform the tail call. 1.101 + // BaselineTailCallReg (ra) already contains the return address (as we 1.102 + // keep it there through the stub calls), but the VMWrapper code being 1.103 + // called expects the return address to also be pushed on the stack. 1.104 + MOZ_ASSERT(BaselineTailCallReg == ra); 1.105 + masm.makeFrameDescriptor(t6, JitFrame_BaselineJS); 1.106 + masm.subPtr(Imm32(sizeof(IonCommonFrameLayout)), StackPointer); 1.107 + masm.storePtr(t6, Address(StackPointer, IonCommonFrameLayout::offsetOfDescriptor())); 1.108 + masm.storePtr(ra, Address(StackPointer, IonCommonFrameLayout::offsetOfReturnAddress())); 1.109 + 1.110 + masm.branch(target); 1.111 +} 1.112 + 1.113 +inline void 1.114 +EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg) 1.115 +{ 1.116 + // Compute stub frame size. We have to add two pointers: the stub reg and 1.117 + // previous frame pointer pushed by EmitEnterStubFrame. 1.118 + masm.movePtr(BaselineFrameReg, reg); 1.119 + masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg); 1.120 + masm.subPtr(BaselineStackReg, reg); 1.121 + 1.122 + masm.makeFrameDescriptor(reg, JitFrame_BaselineStub); 1.123 +} 1.124 + 1.125 +inline void 1.126 +EmitCallVM(JitCode *target, MacroAssembler &masm) 1.127 +{ 1.128 + EmitCreateStubFrameDescriptor(masm, t6); 1.129 + masm.push(t6); 1.130 + masm.call(target); 1.131 +} 1.132 + 1.133 +struct BaselineStubFrame { 1.134 + uintptr_t savedFrame; 1.135 + uintptr_t savedStub; 1.136 + uintptr_t returnAddress; 1.137 + uintptr_t descriptor; 1.138 +}; 1.139 + 1.140 +static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame); 1.141 +static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub); 1.142 + 1.143 +inline void 1.144 +EmitEnterStubFrame(MacroAssembler &masm, Register scratch) 1.145 +{ 1.146 + MOZ_ASSERT(scratch != BaselineTailCallReg); 1.147 + 1.148 + // Compute frame size. 1.149 + masm.movePtr(BaselineFrameReg, scratch); 1.150 + masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch); 1.151 + masm.subPtr(BaselineStackReg, scratch); 1.152 + 1.153 + masm.storePtr(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize())); 1.154 + 1.155 + // Note: when making changes here, don't forget to update 1.156 + // BaselineStubFrame if needed. 1.157 + 1.158 + // Push frame descriptor and return address. 1.159 + masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS); 1.160 + masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer); 1.161 + masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor))); 1.162 + masm.storePtr(BaselineTailCallReg, Address(StackPointer, 1.163 + offsetof(BaselineStubFrame, returnAddress))); 1.164 + 1.165 + // Save old frame pointer, stack pointer and stub reg. 1.166 + masm.storePtr(BaselineStubReg, Address(StackPointer, 1.167 + offsetof(BaselineStubFrame, savedStub))); 1.168 + masm.storePtr(BaselineFrameReg, Address(StackPointer, 1.169 + offsetof(BaselineStubFrame, savedFrame))); 1.170 + masm.movePtr(BaselineStackReg, BaselineFrameReg); 1.171 + 1.172 + // We pushed 4 words, so the stack is still aligned to 8 bytes. 1.173 + masm.checkStackAlignment(); 1.174 +} 1.175 + 1.176 +inline void 1.177 +EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false) 1.178 +{ 1.179 + // Ion frames do not save and restore the frame pointer. If we called 1.180 + // into Ion, we have to restore the stack pointer from the frame descriptor. 1.181 + // If we performed a VM call, the descriptor has been popped already so 1.182 + // in that case we use the frame pointer. 1.183 + if (calledIntoIon) { 1.184 + masm.pop(ScratchRegister); 1.185 + masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), ScratchRegister); 1.186 + masm.addPtr(ScratchRegister, BaselineStackReg); 1.187 + } else { 1.188 + masm.movePtr(BaselineFrameReg, BaselineStackReg); 1.189 + } 1.190 + 1.191 + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)), 1.192 + BaselineFrameReg); 1.193 + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedStub)), 1.194 + BaselineStubReg); 1.195 + 1.196 + // Load the return address. 1.197 + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, returnAddress)), 1.198 + BaselineTailCallReg); 1.199 + 1.200 + // Discard the frame descriptor. 1.201 + masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, descriptor)), ScratchRegister); 1.202 + masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer); 1.203 +} 1.204 + 1.205 +inline void 1.206 +EmitStowICValues(MacroAssembler &masm, int values) 1.207 +{ 1.208 + MOZ_ASSERT(values >= 0 && values <= 2); 1.209 + switch(values) { 1.210 + case 1: 1.211 + // Stow R0 1.212 + masm.pushValue(R0); 1.213 + break; 1.214 + case 2: 1.215 + // Stow R0 and R1 1.216 + masm.pushValue(R0); 1.217 + masm.pushValue(R1); 1.218 + break; 1.219 + } 1.220 +} 1.221 + 1.222 +inline void 1.223 +EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false) 1.224 +{ 1.225 + MOZ_ASSERT(values >= 0 && values <= 2); 1.226 + switch(values) { 1.227 + case 1: 1.228 + // Unstow R0. 1.229 + if (discard) 1.230 + masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg); 1.231 + else 1.232 + masm.popValue(R0); 1.233 + break; 1.234 + case 2: 1.235 + // Unstow R0 and R1. 1.236 + if (discard) { 1.237 + masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg); 1.238 + } else { 1.239 + masm.popValue(R1); 1.240 + masm.popValue(R0); 1.241 + } 1.242 + break; 1.243 + } 1.244 +} 1.245 + 1.246 +inline void 1.247 +EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset) 1.248 +{ 1.249 + // R0 contains the value that needs to be typechecked. 1.250 + // The object we're updating is a boxed Value on the stack, at offset 1.251 + // objectOffset from $sp, excluding the return address. 1.252 + 1.253 + // Save the current BaselineStubReg to stack, as well as the TailCallReg, 1.254 + // since on mips, the $ra is live. 1.255 + masm.subPtr(Imm32(2 * sizeof(intptr_t)), StackPointer); 1.256 + masm.storePtr(BaselineStubReg, Address(StackPointer, sizeof(intptr_t))); 1.257 + masm.storePtr(BaselineTailCallReg, Address(StackPointer, 0)); 1.258 + 1.259 + // This is expected to be called from within an IC, when BaselineStubReg 1.260 + // is properly initialized to point to the stub. 1.261 + masm.loadPtr(Address(BaselineStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()), 1.262 + BaselineStubReg); 1.263 + 1.264 + // Load stubcode pointer from BaselineStubReg into BaselineTailCallReg. 1.265 + masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); 1.266 + 1.267 + // Call the stubcode. 1.268 + masm.call(R2.scratchReg()); 1.269 + 1.270 + // Restore the old stub reg and tailcall reg. 1.271 + masm.loadPtr(Address(StackPointer, 0), BaselineTailCallReg); 1.272 + masm.loadPtr(Address(StackPointer, sizeof(intptr_t)), BaselineStubReg); 1.273 + masm.addPtr(Imm32(2 * sizeof(intptr_t)), StackPointer); 1.274 + 1.275 + // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the 1.276 + // value in R0 type-checked properly or not. 1.277 + Label success; 1.278 + masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump); 1.279 + 1.280 + // If the IC failed, then call the update fallback function. 1.281 + EmitEnterStubFrame(masm, R1.scratchReg()); 1.282 + 1.283 + masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); 1.284 + 1.285 + masm.pushValue(R0); 1.286 + masm.pushValue(R1); 1.287 + masm.push(BaselineStubReg); 1.288 + 1.289 + // Load previous frame pointer, push BaselineFrame *. 1.290 + masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); 1.291 + masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); 1.292 + 1.293 + EmitCallVM(code, masm); 1.294 + EmitLeaveStubFrame(masm); 1.295 + 1.296 + // Success at end. 1.297 + masm.bind(&success); 1.298 +} 1.299 + 1.300 +template <typename AddrType> 1.301 +inline void 1.302 +EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type) 1.303 +{ 1.304 + // On MIPS, $ra is clobbered by patchableCallPreBarrier. Save it first. 1.305 + masm.push(ra); 1.306 + masm.patchableCallPreBarrier(addr, type); 1.307 + masm.pop(ra); 1.308 +} 1.309 + 1.310 +inline void 1.311 +EmitStubGuardFailure(MacroAssembler &masm) 1.312 +{ 1.313 + // NOTE: This routine assumes that the stub guard code left the stack in 1.314 + // the same state it was in when it was entered. 1.315 + 1.316 + // BaselineStubEntry points to the current stub. 1.317 + 1.318 + // Load next stub into BaselineStubReg 1.319 + masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfNext()), BaselineStubReg); 1.320 + 1.321 + // Load stubcode pointer from BaselineStubEntry into scratch register. 1.322 + masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); 1.323 + 1.324 + // Return address is already loaded, just jump to the next stubcode. 1.325 + MOZ_ASSERT(BaselineTailCallReg == ra); 1.326 + masm.branch(R2.scratchReg()); 1.327 +} 1.328 + 1.329 + 1.330 +} // namespace jit 1.331 +} // namespace js 1.332 + 1.333 +#endif // JS_ION 1.334 + 1.335 +#endif /* jit_mips_BaselineHelpers_mips_h */ 1.336 +