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

mercurial