js/src/jit/mips/BaselineHelpers-mips.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jit_mips_BaselineHelpers_mips_h
michael@0 8 #define jit_mips_BaselineHelpers_mips_h
michael@0 9
michael@0 10 #ifdef JS_ION
michael@0 11 #include "jit/BaselineFrame.h"
michael@0 12 #include "jit/BaselineIC.h"
michael@0 13 #include "jit/BaselineRegisters.h"
michael@0 14 #include "jit/IonMacroAssembler.h"
michael@0 15
michael@0 16 namespace js {
michael@0 17 namespace jit {
michael@0 18
michael@0 19 // Distance from sp to the top Value inside an IC stub (no return address on
michael@0 20 // the stack on MIPS).
michael@0 21 static const size_t ICStackValueOffset = 0;
michael@0 22
michael@0 23 inline void
michael@0 24 EmitRestoreTailCallReg(MacroAssembler &masm)
michael@0 25 {
michael@0 26 // No-op on MIPS because ra register is always holding the return address.
michael@0 27 }
michael@0 28
michael@0 29 inline void
michael@0 30 EmitRepushTailCallReg(MacroAssembler &masm)
michael@0 31 {
michael@0 32 // No-op on MIPS because ra register is always holding the return address.
michael@0 33 }
michael@0 34
michael@0 35 inline void
michael@0 36 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
michael@0 37 {
michael@0 38 // Move ICEntry offset into BaselineStubReg.
michael@0 39 CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
michael@0 40 *patchOffset = offset;
michael@0 41
michael@0 42 // Load stub pointer into BaselineStubReg.
michael@0 43 masm.loadPtr(Address(BaselineStubReg, ICEntry::offsetOfFirstStub()), BaselineStubReg);
michael@0 44
michael@0 45 // Load stubcode pointer from BaselineStubEntry.
michael@0 46 // R2 won't be active when we call ICs, so we can use it as scratch.
michael@0 47 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
michael@0 48
michael@0 49 // Call the stubcode via a direct jump-and-link
michael@0 50 masm.call(R2.scratchReg());
michael@0 51 }
michael@0 52
michael@0 53 inline void
michael@0 54 EmitEnterTypeMonitorIC(MacroAssembler &masm,
michael@0 55 size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
michael@0 56 {
michael@0 57 // This is expected to be called from within an IC, when BaselineStubReg
michael@0 58 // is properly initialized to point to the stub.
michael@0 59 masm.loadPtr(Address(BaselineStubReg, (uint32_t) monitorStubOffset), BaselineStubReg);
michael@0 60
michael@0 61 // Load stubcode pointer from BaselineStubEntry.
michael@0 62 // R2 won't be active when we call ICs, so we can use it.
michael@0 63 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
michael@0 64
michael@0 65 // Jump to the stubcode.
michael@0 66 masm.branch(R2.scratchReg());
michael@0 67 }
michael@0 68
michael@0 69 inline void
michael@0 70 EmitReturnFromIC(MacroAssembler &masm)
michael@0 71 {
michael@0 72 masm.branch(ra);
michael@0 73 }
michael@0 74
michael@0 75 inline void
michael@0 76 EmitChangeICReturnAddress(MacroAssembler &masm, Register reg)
michael@0 77 {
michael@0 78 masm.movePtr(reg, ra);
michael@0 79 }
michael@0 80
michael@0 81 inline void
michael@0 82 EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize)
michael@0 83 {
michael@0 84 // We assume during this that R0 and R1 have been pushed, and that R2 is
michael@0 85 // unused.
michael@0 86 MOZ_ASSERT(R2 == ValueOperand(t7, t6));
michael@0 87
michael@0 88 // Compute frame size.
michael@0 89 masm.movePtr(BaselineFrameReg, t6);
michael@0 90 masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), t6);
michael@0 91 masm.subPtr(BaselineStackReg, t6);
michael@0 92
michael@0 93 // Store frame size without VMFunction arguments for GC marking.
michael@0 94 masm.ma_subu(t7, t6, Imm32(argSize));
michael@0 95 masm.storePtr(t7, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
michael@0 96
michael@0 97 // Push frame descriptor and perform the tail call.
michael@0 98 // BaselineTailCallReg (ra) already contains the return address (as we
michael@0 99 // keep it there through the stub calls), but the VMWrapper code being
michael@0 100 // called expects the return address to also be pushed on the stack.
michael@0 101 MOZ_ASSERT(BaselineTailCallReg == ra);
michael@0 102 masm.makeFrameDescriptor(t6, JitFrame_BaselineJS);
michael@0 103 masm.subPtr(Imm32(sizeof(IonCommonFrameLayout)), StackPointer);
michael@0 104 masm.storePtr(t6, Address(StackPointer, IonCommonFrameLayout::offsetOfDescriptor()));
michael@0 105 masm.storePtr(ra, Address(StackPointer, IonCommonFrameLayout::offsetOfReturnAddress()));
michael@0 106
michael@0 107 masm.branch(target);
michael@0 108 }
michael@0 109
michael@0 110 inline void
michael@0 111 EmitCreateStubFrameDescriptor(MacroAssembler &masm, Register reg)
michael@0 112 {
michael@0 113 // Compute stub frame size. We have to add two pointers: the stub reg and
michael@0 114 // previous frame pointer pushed by EmitEnterStubFrame.
michael@0 115 masm.movePtr(BaselineFrameReg, reg);
michael@0 116 masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg);
michael@0 117 masm.subPtr(BaselineStackReg, reg);
michael@0 118
michael@0 119 masm.makeFrameDescriptor(reg, JitFrame_BaselineStub);
michael@0 120 }
michael@0 121
michael@0 122 inline void
michael@0 123 EmitCallVM(JitCode *target, MacroAssembler &masm)
michael@0 124 {
michael@0 125 EmitCreateStubFrameDescriptor(masm, t6);
michael@0 126 masm.push(t6);
michael@0 127 masm.call(target);
michael@0 128 }
michael@0 129
michael@0 130 struct BaselineStubFrame {
michael@0 131 uintptr_t savedFrame;
michael@0 132 uintptr_t savedStub;
michael@0 133 uintptr_t returnAddress;
michael@0 134 uintptr_t descriptor;
michael@0 135 };
michael@0 136
michael@0 137 static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame);
michael@0 138 static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub);
michael@0 139
michael@0 140 inline void
michael@0 141 EmitEnterStubFrame(MacroAssembler &masm, Register scratch)
michael@0 142 {
michael@0 143 MOZ_ASSERT(scratch != BaselineTailCallReg);
michael@0 144
michael@0 145 // Compute frame size.
michael@0 146 masm.movePtr(BaselineFrameReg, scratch);
michael@0 147 masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch);
michael@0 148 masm.subPtr(BaselineStackReg, scratch);
michael@0 149
michael@0 150 masm.storePtr(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
michael@0 151
michael@0 152 // Note: when making changes here, don't forget to update
michael@0 153 // BaselineStubFrame if needed.
michael@0 154
michael@0 155 // Push frame descriptor and return address.
michael@0 156 masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS);
michael@0 157 masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
michael@0 158 masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor)));
michael@0 159 masm.storePtr(BaselineTailCallReg, Address(StackPointer,
michael@0 160 offsetof(BaselineStubFrame, returnAddress)));
michael@0 161
michael@0 162 // Save old frame pointer, stack pointer and stub reg.
michael@0 163 masm.storePtr(BaselineStubReg, Address(StackPointer,
michael@0 164 offsetof(BaselineStubFrame, savedStub)));
michael@0 165 masm.storePtr(BaselineFrameReg, Address(StackPointer,
michael@0 166 offsetof(BaselineStubFrame, savedFrame)));
michael@0 167 masm.movePtr(BaselineStackReg, BaselineFrameReg);
michael@0 168
michael@0 169 // We pushed 4 words, so the stack is still aligned to 8 bytes.
michael@0 170 masm.checkStackAlignment();
michael@0 171 }
michael@0 172
michael@0 173 inline void
michael@0 174 EmitLeaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false)
michael@0 175 {
michael@0 176 // Ion frames do not save and restore the frame pointer. If we called
michael@0 177 // into Ion, we have to restore the stack pointer from the frame descriptor.
michael@0 178 // If we performed a VM call, the descriptor has been popped already so
michael@0 179 // in that case we use the frame pointer.
michael@0 180 if (calledIntoIon) {
michael@0 181 masm.pop(ScratchRegister);
michael@0 182 masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), ScratchRegister);
michael@0 183 masm.addPtr(ScratchRegister, BaselineStackReg);
michael@0 184 } else {
michael@0 185 masm.movePtr(BaselineFrameReg, BaselineStackReg);
michael@0 186 }
michael@0 187
michael@0 188 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)),
michael@0 189 BaselineFrameReg);
michael@0 190 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedStub)),
michael@0 191 BaselineStubReg);
michael@0 192
michael@0 193 // Load the return address.
michael@0 194 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, returnAddress)),
michael@0 195 BaselineTailCallReg);
michael@0 196
michael@0 197 // Discard the frame descriptor.
michael@0 198 masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, descriptor)), ScratchRegister);
michael@0 199 masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
michael@0 200 }
michael@0 201
michael@0 202 inline void
michael@0 203 EmitStowICValues(MacroAssembler &masm, int values)
michael@0 204 {
michael@0 205 MOZ_ASSERT(values >= 0 && values <= 2);
michael@0 206 switch(values) {
michael@0 207 case 1:
michael@0 208 // Stow R0
michael@0 209 masm.pushValue(R0);
michael@0 210 break;
michael@0 211 case 2:
michael@0 212 // Stow R0 and R1
michael@0 213 masm.pushValue(R0);
michael@0 214 masm.pushValue(R1);
michael@0 215 break;
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 inline void
michael@0 220 EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
michael@0 221 {
michael@0 222 MOZ_ASSERT(values >= 0 && values <= 2);
michael@0 223 switch(values) {
michael@0 224 case 1:
michael@0 225 // Unstow R0.
michael@0 226 if (discard)
michael@0 227 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
michael@0 228 else
michael@0 229 masm.popValue(R0);
michael@0 230 break;
michael@0 231 case 2:
michael@0 232 // Unstow R0 and R1.
michael@0 233 if (discard) {
michael@0 234 masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
michael@0 235 } else {
michael@0 236 masm.popValue(R1);
michael@0 237 masm.popValue(R0);
michael@0 238 }
michael@0 239 break;
michael@0 240 }
michael@0 241 }
michael@0 242
michael@0 243 inline void
michael@0 244 EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset)
michael@0 245 {
michael@0 246 // R0 contains the value that needs to be typechecked.
michael@0 247 // The object we're updating is a boxed Value on the stack, at offset
michael@0 248 // objectOffset from $sp, excluding the return address.
michael@0 249
michael@0 250 // Save the current BaselineStubReg to stack, as well as the TailCallReg,
michael@0 251 // since on mips, the $ra is live.
michael@0 252 masm.subPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
michael@0 253 masm.storePtr(BaselineStubReg, Address(StackPointer, sizeof(intptr_t)));
michael@0 254 masm.storePtr(BaselineTailCallReg, Address(StackPointer, 0));
michael@0 255
michael@0 256 // This is expected to be called from within an IC, when BaselineStubReg
michael@0 257 // is properly initialized to point to the stub.
michael@0 258 masm.loadPtr(Address(BaselineStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()),
michael@0 259 BaselineStubReg);
michael@0 260
michael@0 261 // Load stubcode pointer from BaselineStubReg into BaselineTailCallReg.
michael@0 262 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
michael@0 263
michael@0 264 // Call the stubcode.
michael@0 265 masm.call(R2.scratchReg());
michael@0 266
michael@0 267 // Restore the old stub reg and tailcall reg.
michael@0 268 masm.loadPtr(Address(StackPointer, 0), BaselineTailCallReg);
michael@0 269 masm.loadPtr(Address(StackPointer, sizeof(intptr_t)), BaselineStubReg);
michael@0 270 masm.addPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
michael@0 271
michael@0 272 // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
michael@0 273 // value in R0 type-checked properly or not.
michael@0 274 Label success;
michael@0 275 masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump);
michael@0 276
michael@0 277 // If the IC failed, then call the update fallback function.
michael@0 278 EmitEnterStubFrame(masm, R1.scratchReg());
michael@0 279
michael@0 280 masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
michael@0 281
michael@0 282 masm.pushValue(R0);
michael@0 283 masm.pushValue(R1);
michael@0 284 masm.push(BaselineStubReg);
michael@0 285
michael@0 286 // Load previous frame pointer, push BaselineFrame *.
michael@0 287 masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
michael@0 288 masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
michael@0 289
michael@0 290 EmitCallVM(code, masm);
michael@0 291 EmitLeaveStubFrame(masm);
michael@0 292
michael@0 293 // Success at end.
michael@0 294 masm.bind(&success);
michael@0 295 }
michael@0 296
michael@0 297 template <typename AddrType>
michael@0 298 inline void
michael@0 299 EmitPreBarrier(MacroAssembler &masm, const AddrType &addr, MIRType type)
michael@0 300 {
michael@0 301 // On MIPS, $ra is clobbered by patchableCallPreBarrier. Save it first.
michael@0 302 masm.push(ra);
michael@0 303 masm.patchableCallPreBarrier(addr, type);
michael@0 304 masm.pop(ra);
michael@0 305 }
michael@0 306
michael@0 307 inline void
michael@0 308 EmitStubGuardFailure(MacroAssembler &masm)
michael@0 309 {
michael@0 310 // NOTE: This routine assumes that the stub guard code left the stack in
michael@0 311 // the same state it was in when it was entered.
michael@0 312
michael@0 313 // BaselineStubEntry points to the current stub.
michael@0 314
michael@0 315 // Load next stub into BaselineStubReg
michael@0 316 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfNext()), BaselineStubReg);
michael@0 317
michael@0 318 // Load stubcode pointer from BaselineStubEntry into scratch register.
michael@0 319 masm.loadPtr(Address(BaselineStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
michael@0 320
michael@0 321 // Return address is already loaded, just jump to the next stubcode.
michael@0 322 MOZ_ASSERT(BaselineTailCallReg == ra);
michael@0 323 masm.branch(R2.scratchReg());
michael@0 324 }
michael@0 325
michael@0 326
michael@0 327 } // namespace jit
michael@0 328 } // namespace js
michael@0 329
michael@0 330 #endif // JS_ION
michael@0 331
michael@0 332 #endif /* jit_mips_BaselineHelpers_mips_h */
michael@0 333

mercurial