js/src/jit/arm/Trampoline-arm.cpp

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 #include "jscompartment.h"
michael@0 8
michael@0 9 #include "assembler/assembler/MacroAssembler.h"
michael@0 10 #include "jit/arm/BaselineHelpers-arm.h"
michael@0 11 #include "jit/Bailouts.h"
michael@0 12 #include "jit/IonFrames.h"
michael@0 13 #include "jit/IonLinker.h"
michael@0 14 #include "jit/IonSpewer.h"
michael@0 15 #include "jit/JitCompartment.h"
michael@0 16 #ifdef JS_ION_PERF
michael@0 17 # include "jit/PerfSpewer.h"
michael@0 18 #endif
michael@0 19 #include "jit/VMFunctions.h"
michael@0 20
michael@0 21 #include "jit/ExecutionMode-inl.h"
michael@0 22
michael@0 23 using namespace js;
michael@0 24 using namespace js::jit;
michael@0 25
michael@0 26 static const FloatRegisterSet NonVolatileFloatRegs =
michael@0 27 FloatRegisterSet((1 << FloatRegisters::d8) |
michael@0 28 (1 << FloatRegisters::d9) |
michael@0 29 (1 << FloatRegisters::d10) |
michael@0 30 (1 << FloatRegisters::d11) |
michael@0 31 (1 << FloatRegisters::d12) |
michael@0 32 (1 << FloatRegisters::d13) |
michael@0 33 (1 << FloatRegisters::d14) |
michael@0 34 (1 << FloatRegisters::d15));
michael@0 35
michael@0 36 static void
michael@0 37 GenerateReturn(MacroAssembler &masm, int returnCode, SPSProfiler *prof)
michael@0 38 {
michael@0 39 // Restore non-volatile floating point registers
michael@0 40 masm.transferMultipleByRuns(NonVolatileFloatRegs, IsLoad, StackPointer, IA);
michael@0 41
michael@0 42 // Unwind the sps mark.
michael@0 43 masm.spsUnmarkJit(prof, r8);
michael@0 44
michael@0 45 // Set up return value
michael@0 46 masm.ma_mov(Imm32(returnCode), r0);
michael@0 47
michael@0 48 // Pop and return
michael@0 49 masm.startDataTransferM(IsLoad, sp, IA, WriteBack);
michael@0 50 masm.transferReg(r4);
michael@0 51 masm.transferReg(r5);
michael@0 52 masm.transferReg(r6);
michael@0 53 masm.transferReg(r7);
michael@0 54 masm.transferReg(r8);
michael@0 55 masm.transferReg(r9);
michael@0 56 masm.transferReg(r10);
michael@0 57 masm.transferReg(r11);
michael@0 58 // r12 isn't saved, so it shouldn't be restored.
michael@0 59 masm.transferReg(pc);
michael@0 60 masm.finishDataTransfer();
michael@0 61 masm.dumpPool();
michael@0 62 }
michael@0 63
michael@0 64 struct EnterJITStack
michael@0 65 {
michael@0 66 double d8;
michael@0 67 double d9;
michael@0 68 double d10;
michael@0 69 double d11;
michael@0 70 double d12;
michael@0 71 double d13;
michael@0 72 double d14;
michael@0 73 double d15;
michael@0 74
michael@0 75 size_t hasSPSMark;
michael@0 76
michael@0 77 // non-volatile registers.
michael@0 78 void *r4;
michael@0 79 void *r5;
michael@0 80 void *r6;
michael@0 81 void *r7;
michael@0 82 void *r8;
michael@0 83 void *r9;
michael@0 84 void *r10;
michael@0 85 void *r11;
michael@0 86 // The abi does not expect r12 (ip) to be preserved
michael@0 87 void *lr;
michael@0 88
michael@0 89 // Arguments.
michael@0 90 // code == r0
michael@0 91 // argc == r1
michael@0 92 // argv == r2
michael@0 93 // frame == r3
michael@0 94 CalleeToken token;
michael@0 95 JSObject *scopeChain;
michael@0 96 size_t numStackValues;
michael@0 97 Value *vp;
michael@0 98 };
michael@0 99
michael@0 100 /*
michael@0 101 * This method generates a trampoline for a c++ function with the following
michael@0 102 * signature:
michael@0 103 * void enter(void *code, int argc, Value *argv, InterpreterFrame *fp, CalleeToken
michael@0 104 * calleeToken, JSObject *scopeChain, Value *vp)
michael@0 105 * ...using standard EABI calling convention
michael@0 106 */
michael@0 107 JitCode *
michael@0 108 JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
michael@0 109 {
michael@0 110 const Address slot_token(sp, offsetof(EnterJITStack, token));
michael@0 111 const Address slot_vp(sp, offsetof(EnterJITStack, vp));
michael@0 112
michael@0 113 JS_ASSERT(OsrFrameReg == r3);
michael@0 114
michael@0 115 MacroAssembler masm(cx);
michael@0 116 Assembler *aasm = &masm;
michael@0 117
michael@0 118 // Save non-volatile registers. These must be saved by the trampoline,
michael@0 119 // rather than the JIT'd code, because they are scanned by the conservative
michael@0 120 // scanner.
michael@0 121 masm.startDataTransferM(IsStore, sp, DB, WriteBack);
michael@0 122 masm.transferReg(r4); // [sp,0]
michael@0 123 masm.transferReg(r5); // [sp,4]
michael@0 124 masm.transferReg(r6); // [sp,8]
michael@0 125 masm.transferReg(r7); // [sp,12]
michael@0 126 masm.transferReg(r8); // [sp,16]
michael@0 127 masm.transferReg(r9); // [sp,20]
michael@0 128 masm.transferReg(r10); // [sp,24]
michael@0 129 masm.transferReg(r11); // [sp,28]
michael@0 130 // The abi does not expect r12 (ip) to be preserved
michael@0 131 masm.transferReg(lr); // [sp,32]
michael@0 132 // The 5th argument is located at [sp, 36]
michael@0 133 masm.finishDataTransfer();
michael@0 134
michael@0 135 // Push the EnterJIT sps mark. "Frame pointer" = start of saved core regs.
michael@0 136 masm.movePtr(sp, r8);
michael@0 137 masm.spsMarkJit(&cx->runtime()->spsProfiler, r8, r9);
michael@0 138
michael@0 139 // Push the float registers.
michael@0 140 masm.transferMultipleByRuns(NonVolatileFloatRegs, IsStore, sp, DB);
michael@0 141
michael@0 142 // Save stack pointer into r8
michael@0 143 masm.movePtr(sp, r8);
michael@0 144
michael@0 145 // Load calleeToken into r9.
michael@0 146 masm.loadPtr(slot_token, r9);
michael@0 147
michael@0 148 // Save stack pointer.
michael@0 149 if (type == EnterJitBaseline)
michael@0 150 masm.movePtr(sp, r11);
michael@0 151
michael@0 152 // Load the number of actual arguments into r10.
michael@0 153 masm.loadPtr(slot_vp, r10);
michael@0 154 masm.unboxInt32(Address(r10, 0), r10);
michael@0 155
michael@0 156 // Subtract off the size of the arguments from the stack pointer, store elsewhere
michael@0 157 aasm->as_sub(r4, sp, O2RegImmShift(r1, LSL, 3)); //r4 = sp - argc*8
michael@0 158 // Get the final position of the stack pointer into the stack pointer
michael@0 159 aasm->as_sub(sp, r4, Imm8(16)); // sp' = sp - argc*8 - 16
michael@0 160 // Get a copy of the number of args to use as a decrement counter, also
michael@0 161 // Set the zero condition code
michael@0 162 aasm->as_mov(r5, O2Reg(r1), SetCond);
michael@0 163
michael@0 164 // Loop over arguments, copying them from an unknown buffer onto the Ion
michael@0 165 // stack so they can be accessed from JIT'ed code.
michael@0 166 {
michael@0 167 Label header, footer;
michael@0 168 // If there aren't any arguments, don't do anything
michael@0 169 aasm->as_b(&footer, Assembler::Zero);
michael@0 170 // Get the top of the loop
michael@0 171 masm.bind(&header);
michael@0 172 aasm->as_sub(r5, r5, Imm8(1), SetCond);
michael@0 173 // We could be more awesome, and unroll this, using a loadm
michael@0 174 // (particularly since the offset is effectively 0)
michael@0 175 // but that seems more error prone, and complex.
michael@0 176 // BIG FAT WARNING: this loads both r6 and r7.
michael@0 177 aasm->as_extdtr(IsLoad, 64, true, PostIndex, r6, EDtrAddr(r2, EDtrOffImm(8)));
michael@0 178 aasm->as_extdtr(IsStore, 64, true, PostIndex, r6, EDtrAddr(r4, EDtrOffImm(8)));
michael@0 179 aasm->as_b(&header, Assembler::NonZero);
michael@0 180 masm.bind(&footer);
michael@0 181 }
michael@0 182
michael@0 183 masm.ma_sub(r8, sp, r8);
michael@0 184 masm.makeFrameDescriptor(r8, JitFrame_Entry);
michael@0 185
michael@0 186 masm.startDataTransferM(IsStore, sp, IB, NoWriteBack);
michael@0 187 // [sp] = return address (written later)
michael@0 188 masm.transferReg(r8); // [sp',4] = descriptor, argc*8+20
michael@0 189 masm.transferReg(r9); // [sp',8] = callee token
michael@0 190 masm.transferReg(r10); // [sp',12] = actual arguments
michael@0 191 masm.finishDataTransfer();
michael@0 192
michael@0 193 Label returnLabel;
michael@0 194 if (type == EnterJitBaseline) {
michael@0 195 // Handle OSR.
michael@0 196 GeneralRegisterSet regs(GeneralRegisterSet::All());
michael@0 197 regs.take(JSReturnOperand);
michael@0 198 regs.takeUnchecked(OsrFrameReg);
michael@0 199 regs.take(r11);
michael@0 200 regs.take(ReturnReg);
michael@0 201
michael@0 202 const Address slot_numStackValues(r11, offsetof(EnterJITStack, numStackValues));
michael@0 203
michael@0 204 Label notOsr;
michael@0 205 masm.branchTestPtr(Assembler::Zero, OsrFrameReg, OsrFrameReg, &notOsr);
michael@0 206
michael@0 207 Register scratch = regs.takeAny();
michael@0 208
michael@0 209 Register numStackValues = regs.takeAny();
michael@0 210 masm.load32(slot_numStackValues, numStackValues);
michael@0 211
michael@0 212 // Write return address. On ARM, CodeLabel is only used for tableswitch,
michael@0 213 // so we can't use it here to get the return address. Instead, we use
michael@0 214 // pc + a fixed offset to a jump to returnLabel. The pc register holds
michael@0 215 // pc + 8, so we add the size of 2 instructions to skip the instructions
michael@0 216 // emitted by storePtr and jump(&skipJump).
michael@0 217 {
michael@0 218 AutoForbidPools afp(&masm);
michael@0 219 Label skipJump;
michael@0 220 masm.mov(pc, scratch);
michael@0 221 masm.addPtr(Imm32(2 * sizeof(uint32_t)), scratch);
michael@0 222 masm.storePtr(scratch, Address(sp, 0));
michael@0 223 masm.jump(&skipJump);
michael@0 224 masm.jump(&returnLabel);
michael@0 225 masm.bind(&skipJump);
michael@0 226 }
michael@0 227
michael@0 228 // Push previous frame pointer.
michael@0 229 masm.push(r11);
michael@0 230
michael@0 231 // Reserve frame.
michael@0 232 Register framePtr = r11;
michael@0 233 masm.subPtr(Imm32(BaselineFrame::Size()), sp);
michael@0 234 masm.mov(sp, framePtr);
michael@0 235
michael@0 236 #ifdef XP_WIN
michael@0 237 // Can't push large frames blindly on windows. Touch frame memory incrementally.
michael@0 238 masm.ma_lsl(Imm32(3), numStackValues, scratch);
michael@0 239 masm.subPtr(scratch, framePtr);
michael@0 240 {
michael@0 241 masm.ma_sub(sp, Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
michael@0 242
michael@0 243 Label touchFrameLoop;
michael@0 244 Label touchFrameLoopEnd;
michael@0 245 masm.bind(&touchFrameLoop);
michael@0 246 masm.branchPtr(Assembler::Below, scratch, framePtr, &touchFrameLoopEnd);
michael@0 247 masm.store32(Imm32(0), Address(scratch, 0));
michael@0 248 masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
michael@0 249 masm.jump(&touchFrameLoop);
michael@0 250 masm.bind(&touchFrameLoopEnd);
michael@0 251 }
michael@0 252 masm.mov(sp, framePtr);
michael@0 253 #endif
michael@0 254
michael@0 255 // Reserve space for locals and stack values.
michael@0 256 masm.ma_lsl(Imm32(3), numStackValues, scratch);
michael@0 257 masm.ma_sub(sp, scratch, sp);
michael@0 258
michael@0 259 // Enter exit frame.
michael@0 260 masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), scratch);
michael@0 261 masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS);
michael@0 262 masm.push(scratch);
michael@0 263 masm.push(Imm32(0)); // Fake return address.
michael@0 264 masm.enterFakeExitFrame();
michael@0 265
michael@0 266 masm.push(framePtr); // BaselineFrame
michael@0 267 masm.push(r0); // jitcode
michael@0 268
michael@0 269 masm.setupUnalignedABICall(3, scratch);
michael@0 270 masm.passABIArg(r11); // BaselineFrame
michael@0 271 masm.passABIArg(OsrFrameReg); // InterpreterFrame
michael@0 272 masm.passABIArg(numStackValues);
michael@0 273 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, jit::InitBaselineFrameForOsr));
michael@0 274
michael@0 275 Register jitcode = regs.takeAny();
michael@0 276 masm.pop(jitcode);
michael@0 277 masm.pop(framePtr);
michael@0 278
michael@0 279 JS_ASSERT(jitcode != ReturnReg);
michael@0 280
michael@0 281 Label error;
michael@0 282 masm.addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), sp);
michael@0 283 masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
michael@0 284 masm.branchIfFalseBool(ReturnReg, &error);
michael@0 285
michael@0 286 masm.jump(jitcode);
michael@0 287
michael@0 288 // OOM: load error value, discard return address and previous frame
michael@0 289 // pointer and return.
michael@0 290 masm.bind(&error);
michael@0 291 masm.mov(framePtr, sp);
michael@0 292 masm.addPtr(Imm32(2 * sizeof(uintptr_t)), sp);
michael@0 293 masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
michael@0 294 masm.jump(&returnLabel);
michael@0 295
michael@0 296 masm.bind(&notOsr);
michael@0 297 // Load the scope chain in R1.
michael@0 298 JS_ASSERT(R1.scratchReg() != r0);
michael@0 299 masm.loadPtr(Address(r11, offsetof(EnterJITStack, scopeChain)), R1.scratchReg());
michael@0 300 }
michael@0 301
michael@0 302 // Call the function.
michael@0 303 masm.ma_callIonNoPush(r0);
michael@0 304
michael@0 305 if (type == EnterJitBaseline) {
michael@0 306 // Baseline OSR will return here.
michael@0 307 masm.bind(&returnLabel);
michael@0 308 }
michael@0 309
michael@0 310 // The top of the stack now points to the address of the field following
michael@0 311 // the return address because the return address is popped for the
michael@0 312 // return, so we need to remove the size of the return address field.
michael@0 313 aasm->as_sub(sp, sp, Imm8(4));
michael@0 314
michael@0 315 // Load off of the stack the size of our local stack
michael@0 316 masm.loadPtr(Address(sp, IonJSFrameLayout::offsetOfDescriptor()), r5);
michael@0 317 aasm->as_add(sp, sp, lsr(r5, FRAMESIZE_SHIFT));
michael@0 318
michael@0 319 // Store the returned value into the slot_vp
michael@0 320 masm.loadPtr(slot_vp, r5);
michael@0 321 masm.storeValue(JSReturnOperand, Address(r5, 0));
michael@0 322
michael@0 323 // :TODO: Optimize storeValue with:
michael@0 324 // We're using a load-double here. In order for that to work,
michael@0 325 // the data needs to be stored in two consecutive registers,
michael@0 326 // make sure this is the case
michael@0 327 // ASSERT(JSReturnReg_Type.code() == JSReturnReg_Data.code()+1);
michael@0 328 // aasm->as_extdtr(IsStore, 64, true, Offset,
michael@0 329 // JSReturnReg_Data, EDtrAddr(r5, EDtrOffImm(0)));
michael@0 330
michael@0 331 // Restore non-volatile registers and return.
michael@0 332 GenerateReturn(masm, true, &cx->runtime()->spsProfiler);
michael@0 333
michael@0 334 Linker linker(masm);
michael@0 335 AutoFlushICache afc("EnterJIT");
michael@0 336 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 337
michael@0 338 #ifdef JS_ION_PERF
michael@0 339 writePerfSpewerJitCodeProfile(code, "EnterJIT");
michael@0 340 #endif
michael@0 341
michael@0 342 return code;
michael@0 343 }
michael@0 344
michael@0 345 JitCode *
michael@0 346 JitRuntime::generateInvalidator(JSContext *cx)
michael@0 347 {
michael@0 348 // See large comment in x86's JitRuntime::generateInvalidator.
michael@0 349 MacroAssembler masm(cx);
michael@0 350 //masm.as_bkpt();
michael@0 351 // At this point, one of two things has happened.
michael@0 352 // 1) Execution has just returned from C code, which left the stack aligned
michael@0 353 // 2) Execution has just returned from Ion code, which left the stack unaligned.
michael@0 354 // The old return address should not matter, but we still want the
michael@0 355 // stack to be aligned, and there is no good reason to automatically align it with
michael@0 356 // a call to setupUnalignedABICall.
michael@0 357 masm.ma_and(Imm32(~7), sp, sp);
michael@0 358 masm.startDataTransferM(IsStore, sp, DB, WriteBack);
michael@0 359 // We don't have to push everything, but this is likely easier.
michael@0 360 // setting regs_
michael@0 361 for (uint32_t i = 0; i < Registers::Total; i++)
michael@0 362 masm.transferReg(Register::FromCode(i));
michael@0 363 masm.finishDataTransfer();
michael@0 364
michael@0 365 masm.startFloatTransferM(IsStore, sp, DB, WriteBack);
michael@0 366 for (uint32_t i = 0; i < FloatRegisters::Total; i++)
michael@0 367 masm.transferFloatReg(FloatRegister::FromCode(i));
michael@0 368 masm.finishFloatTransfer();
michael@0 369
michael@0 370 masm.ma_mov(sp, r0);
michael@0 371 const int sizeOfRetval = sizeof(size_t)*2;
michael@0 372 masm.reserveStack(sizeOfRetval);
michael@0 373 masm.mov(sp, r1);
michael@0 374 const int sizeOfBailoutInfo = sizeof(void *)*2;
michael@0 375 masm.reserveStack(sizeOfBailoutInfo);
michael@0 376 masm.mov(sp, r2);
michael@0 377 masm.setupAlignedABICall(3);
michael@0 378 masm.passABIArg(r0);
michael@0 379 masm.passABIArg(r1);
michael@0 380 masm.passABIArg(r2);
michael@0 381 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, InvalidationBailout));
michael@0 382
michael@0 383 masm.ma_ldr(Address(sp, 0), r2);
michael@0 384 masm.ma_ldr(Address(sp, sizeOfBailoutInfo), r1);
michael@0 385 // Remove the return address, the IonScript, the register state
michael@0 386 // (InvaliationBailoutStack) and the space that was allocated for the return value
michael@0 387 masm.ma_add(sp, Imm32(sizeof(InvalidationBailoutStack) + sizeOfRetval + sizeOfBailoutInfo), sp);
michael@0 388 // remove the space that this frame was using before the bailout
michael@0 389 // (computed by InvalidationBailout)
michael@0 390 masm.ma_add(sp, r1, sp);
michael@0 391
michael@0 392 // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
michael@0 393 JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
michael@0 394 masm.branch(bailoutTail);
michael@0 395
michael@0 396 Linker linker(masm);
michael@0 397 AutoFlushICache afc("Invalidator");
michael@0 398 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 399 IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw());
michael@0 400
michael@0 401 #ifdef JS_ION_PERF
michael@0 402 writePerfSpewerJitCodeProfile(code, "Invalidator");
michael@0 403 #endif
michael@0 404
michael@0 405 return code;
michael@0 406 }
michael@0 407
michael@0 408 JitCode *
michael@0 409 JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
michael@0 410 {
michael@0 411 MacroAssembler masm(cx);
michael@0 412 // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
michael@0 413 // Including |this|, there are (|nargs| + 1) arguments to copy.
michael@0 414 JS_ASSERT(ArgumentsRectifierReg == r8);
michael@0 415
michael@0 416 // Copy number of actual arguments into r0
michael@0 417 masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfNumActualArgs())), r0);
michael@0 418
michael@0 419 // Load the number of |undefined|s to push into r6.
michael@0 420 masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfCalleeToken())), r1);
michael@0 421 masm.ma_ldrh(EDtrAddr(r1, EDtrOffImm(JSFunction::offsetOfNargs())), r6);
michael@0 422
michael@0 423 masm.ma_sub(r6, r8, r2);
michael@0 424
michael@0 425 masm.moveValue(UndefinedValue(), r5, r4);
michael@0 426
michael@0 427 masm.ma_mov(sp, r3); // Save %sp.
michael@0 428 masm.ma_mov(sp, r7); // Save %sp again.
michael@0 429
michael@0 430 // Push undefined.
michael@0 431 {
michael@0 432 Label undefLoopTop;
michael@0 433 masm.bind(&undefLoopTop);
michael@0 434 masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
michael@0 435 masm.ma_sub(r2, Imm32(1), r2, SetCond);
michael@0 436
michael@0 437 masm.ma_b(&undefLoopTop, Assembler::NonZero);
michael@0 438 }
michael@0 439
michael@0 440 // Get the topmost argument.
michael@0 441
michael@0 442 masm.ma_alu(r3, lsl(r8, 3), r3, op_add); // r3 <- r3 + nargs * 8
michael@0 443 masm.ma_add(r3, Imm32(sizeof(IonRectifierFrameLayout)), r3);
michael@0 444
michael@0 445 // Push arguments, |nargs| + 1 times (to include |this|).
michael@0 446 {
michael@0 447 Label copyLoopTop;
michael@0 448 masm.bind(&copyLoopTop);
michael@0 449 masm.ma_dataTransferN(IsLoad, 64, true, r3, Imm32(-8), r4, PostIndex);
michael@0 450 masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
michael@0 451
michael@0 452 masm.ma_sub(r8, Imm32(1), r8, SetCond);
michael@0 453 masm.ma_b(&copyLoopTop, Assembler::NotSigned);
michael@0 454 }
michael@0 455
michael@0 456 // translate the framesize from values into bytes
michael@0 457 masm.ma_add(r6, Imm32(1), r6);
michael@0 458 masm.ma_lsl(Imm32(3), r6, r6);
michael@0 459
michael@0 460 // Construct sizeDescriptor.
michael@0 461 masm.makeFrameDescriptor(r6, JitFrame_Rectifier);
michael@0 462
michael@0 463 // Construct IonJSFrameLayout.
michael@0 464 masm.ma_push(r0); // actual arguments.
michael@0 465 masm.ma_push(r1); // callee token
michael@0 466 masm.ma_push(r6); // frame descriptor.
michael@0 467
michael@0 468 // Call the target function.
michael@0 469 // Note that this code assumes the function is JITted.
michael@0 470 masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
michael@0 471 masm.loadBaselineOrIonRaw(r3, r3, mode, nullptr);
michael@0 472 masm.ma_callIonHalfPush(r3);
michael@0 473
michael@0 474 uint32_t returnOffset = masm.currentOffset();
michael@0 475
michael@0 476 // arg1
michael@0 477 // ...
michael@0 478 // argN
michael@0 479 // num actual args
michael@0 480 // callee token
michael@0 481 // sizeDescriptor <- sp now
michael@0 482 // return address
michael@0 483
michael@0 484 // Remove the rectifier frame.
michael@0 485 masm.ma_dtr(IsLoad, sp, Imm32(12), r4, PostIndex);
michael@0 486
michael@0 487 // arg1
michael@0 488 // ...
michael@0 489 // argN <- sp now; r4 <- frame descriptor
michael@0 490 // num actual args
michael@0 491 // callee token
michael@0 492 // sizeDescriptor
michael@0 493 // return address
michael@0 494
michael@0 495 // Discard pushed arguments.
michael@0 496 masm.ma_alu(sp, lsr(r4, FRAMESIZE_SHIFT), sp, op_add);
michael@0 497
michael@0 498 masm.ret();
michael@0 499 Linker linker(masm);
michael@0 500 AutoFlushICache afc("ArgumentsRectifier");
michael@0 501 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 502
michael@0 503 CodeOffsetLabel returnLabel(returnOffset);
michael@0 504 returnLabel.fixup(&masm);
michael@0 505 if (returnAddrOut)
michael@0 506 *returnAddrOut = (void *) (code->raw() + returnLabel.offset());
michael@0 507
michael@0 508 #ifdef JS_ION_PERF
michael@0 509 writePerfSpewerJitCodeProfile(code, "ArgumentsRectifier");
michael@0 510 #endif
michael@0 511
michael@0 512 return code;
michael@0 513 }
michael@0 514
michael@0 515 static void
michael@0 516 GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32_t frameClass)
michael@0 517 {
michael@0 518 // the stack should look like:
michael@0 519 // [IonFrame]
michael@0 520 // bailoutFrame.registersnapshot
michael@0 521 // bailoutFrame.fpsnapshot
michael@0 522 // bailoutFrame.snapshotOffset
michael@0 523 // bailoutFrame.frameSize
michael@0 524
michael@0 525 // STEP 1a: save our register sets to the stack so Bailout() can
michael@0 526 // read everything.
michael@0 527 // sp % 8 == 0
michael@0 528 masm.startDataTransferM(IsStore, sp, DB, WriteBack);
michael@0 529 // We don't have to push everything, but this is likely easier.
michael@0 530 // setting regs_
michael@0 531 for (uint32_t i = 0; i < Registers::Total; i++)
michael@0 532 masm.transferReg(Register::FromCode(i));
michael@0 533 masm.finishDataTransfer();
michael@0 534
michael@0 535 masm.startFloatTransferM(IsStore, sp, DB, WriteBack);
michael@0 536 for (uint32_t i = 0; i < FloatRegisters::Total; i++)
michael@0 537 masm.transferFloatReg(FloatRegister::FromCode(i));
michael@0 538 masm.finishFloatTransfer();
michael@0 539
michael@0 540 // STEP 1b: Push both the "return address" of the function call (the
michael@0 541 // address of the instruction after the call that we used to get
michael@0 542 // here) as well as the callee token onto the stack. The return
michael@0 543 // address is currently in r14. We will proceed by loading the
michael@0 544 // callee token into a sacrificial register <= r14, then pushing
michael@0 545 // both onto the stack
michael@0 546
michael@0 547 // now place the frameClass onto the stack, via a register
michael@0 548 masm.ma_mov(Imm32(frameClass), r4);
michael@0 549 // And onto the stack. Since the stack is full, we need to put this
michael@0 550 // one past the end of the current stack. Sadly, the ABI says that we need
michael@0 551 // to always point to the lowest place that has been written. the OS is
michael@0 552 // free to do whatever it wants below sp.
michael@0 553 masm.startDataTransferM(IsStore, sp, DB, WriteBack);
michael@0 554 // set frameClassId_
michael@0 555 masm.transferReg(r4);
michael@0 556 // Set tableOffset_; higher registers are stored at higher locations on
michael@0 557 // the stack.
michael@0 558 masm.transferReg(lr);
michael@0 559 masm.finishDataTransfer();
michael@0 560
michael@0 561 // SP % 8 == 4
michael@0 562 // STEP 1c: Call the bailout function, giving a pointer to the
michael@0 563 // structure we just blitted onto the stack
michael@0 564 masm.ma_mov(sp, r0);
michael@0 565 const int sizeOfBailoutInfo = sizeof(void *)*2;
michael@0 566 masm.reserveStack(sizeOfBailoutInfo);
michael@0 567 masm.mov(sp, r1);
michael@0 568 masm.setupAlignedABICall(2);
michael@0 569
michael@0 570 // Decrement sp by another 4, so we keep alignment
michael@0 571 // Not Anymore! pushing both the snapshotoffset as well as the
michael@0 572 // masm.as_sub(sp, sp, Imm8(4));
michael@0 573
michael@0 574 // Set the old (4-byte aligned) value of the sp as the first argument
michael@0 575 masm.passABIArg(r0);
michael@0 576 masm.passABIArg(r1);
michael@0 577
michael@0 578 // Sp % 8 == 0
michael@0 579 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Bailout));
michael@0 580 masm.ma_ldr(Address(sp, 0), r2);
michael@0 581 masm.ma_add(sp, Imm32(sizeOfBailoutInfo), sp);
michael@0 582 // Common size of a bailout frame.
michael@0 583 uint32_t bailoutFrameSize = sizeof(void *) + // frameClass
michael@0 584 sizeof(double) * FloatRegisters::Total +
michael@0 585 sizeof(void *) * Registers::Total;
michael@0 586
michael@0 587 if (frameClass == NO_FRAME_SIZE_CLASS_ID) {
michael@0 588 // Make sure the bailout frame size fits into the offset for a load
michael@0 589 masm.as_dtr(IsLoad, 32, Offset,
michael@0 590 r4, DTRAddr(sp, DtrOffImm(4)));
michael@0 591 // used to be: offsetof(BailoutStack, frameSize_)
michael@0 592 // this structure is no longer available to us :(
michael@0 593 // We add 12 to the bailoutFrameSize because:
michael@0 594 // sizeof(uint32_t) for the tableOffset that was pushed onto the stack
michael@0 595 // sizeof(uintptr_t) for the snapshotOffset;
michael@0 596 // alignment to round the uintptr_t up to a multiple of 8 bytes.
michael@0 597 masm.ma_add(sp, Imm32(bailoutFrameSize+12), sp);
michael@0 598 masm.as_add(sp, sp, O2Reg(r4));
michael@0 599 } else {
michael@0 600 uint32_t frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
michael@0 601 masm.ma_add(Imm32(frameSize // the frame that was added when we entered the most recent function
michael@0 602 + sizeof(void*) // the size of the "return address" that was dumped on the stack
michael@0 603 + bailoutFrameSize) // everything else that was pushed on the stack
michael@0 604 , sp);
michael@0 605 }
michael@0 606
michael@0 607 // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
michael@0 608 JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
michael@0 609 masm.branch(bailoutTail);
michael@0 610 }
michael@0 611
michael@0 612 JitCode *
michael@0 613 JitRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
michael@0 614 {
michael@0 615 MacroAssembler masm(cx);
michael@0 616
michael@0 617 Label bailout;
michael@0 618 for (size_t i = 0; i < BAILOUT_TABLE_SIZE; i++)
michael@0 619 masm.ma_bl(&bailout);
michael@0 620 masm.bind(&bailout);
michael@0 621
michael@0 622 GenerateBailoutThunk(cx, masm, frameClass);
michael@0 623
michael@0 624 Linker linker(masm);
michael@0 625 AutoFlushICache afc("BailoutTable");
michael@0 626 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 627
michael@0 628 #ifdef JS_ION_PERF
michael@0 629 writePerfSpewerJitCodeProfile(code, "BailoutTable");
michael@0 630 #endif
michael@0 631
michael@0 632 return code;
michael@0 633 }
michael@0 634
michael@0 635 JitCode *
michael@0 636 JitRuntime::generateBailoutHandler(JSContext *cx)
michael@0 637 {
michael@0 638 MacroAssembler masm(cx);
michael@0 639 GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
michael@0 640
michael@0 641 Linker linker(masm);
michael@0 642 AutoFlushICache afc("BailoutHandler");
michael@0 643 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 644
michael@0 645 #ifdef JS_ION_PERF
michael@0 646 writePerfSpewerJitCodeProfile(code, "BailoutHandler");
michael@0 647 #endif
michael@0 648
michael@0 649 return code;
michael@0 650 }
michael@0 651
michael@0 652 JitCode *
michael@0 653 JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
michael@0 654 {
michael@0 655 JS_ASSERT(functionWrappers_);
michael@0 656 JS_ASSERT(functionWrappers_->initialized());
michael@0 657 VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
michael@0 658 if (p)
michael@0 659 return p->value();
michael@0 660
michael@0 661 // Generate a separated code for the wrapper.
michael@0 662 MacroAssembler masm(cx);
michael@0 663 GeneralRegisterSet regs = GeneralRegisterSet(Register::Codes::WrapperMask);
michael@0 664
michael@0 665 // Wrapper register set is a superset of Volatile register set.
michael@0 666 JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
michael@0 667
michael@0 668 // The context is the first argument; r0 is the first argument register.
michael@0 669 Register cxreg = r0;
michael@0 670 regs.take(cxreg);
michael@0 671
michael@0 672 // Stack is:
michael@0 673 // ... frame ...
michael@0 674 // +8 [args] + argPadding
michael@0 675 // +0 ExitFrame
michael@0 676 //
michael@0 677 // We're aligned to an exit frame, so link it up.
michael@0 678 masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
michael@0 679
michael@0 680 // Save the base of the argument set stored on the stack.
michael@0 681 Register argsBase = InvalidReg;
michael@0 682 if (f.explicitArgs) {
michael@0 683 argsBase = r5;
michael@0 684 regs.take(argsBase);
michael@0 685 masm.ma_add(sp, Imm32(IonExitFrameLayout::SizeWithFooter()), argsBase);
michael@0 686 }
michael@0 687
michael@0 688 // Reserve space for the outparameter.
michael@0 689 Register outReg = InvalidReg;
michael@0 690 switch (f.outParam) {
michael@0 691 case Type_Value:
michael@0 692 outReg = r4;
michael@0 693 regs.take(outReg);
michael@0 694 masm.reserveStack(sizeof(Value));
michael@0 695 masm.ma_mov(sp, outReg);
michael@0 696 break;
michael@0 697
michael@0 698 case Type_Handle:
michael@0 699 outReg = r4;
michael@0 700 regs.take(outReg);
michael@0 701 masm.PushEmptyRooted(f.outParamRootType);
michael@0 702 masm.ma_mov(sp, outReg);
michael@0 703 break;
michael@0 704
michael@0 705 case Type_Int32:
michael@0 706 case Type_Pointer:
michael@0 707 case Type_Bool:
michael@0 708 outReg = r4;
michael@0 709 regs.take(outReg);
michael@0 710 masm.reserveStack(sizeof(int32_t));
michael@0 711 masm.ma_mov(sp, outReg);
michael@0 712 break;
michael@0 713
michael@0 714 case Type_Double:
michael@0 715 outReg = r4;
michael@0 716 regs.take(outReg);
michael@0 717 masm.reserveStack(sizeof(double));
michael@0 718 masm.ma_mov(sp, outReg);
michael@0 719 break;
michael@0 720
michael@0 721 default:
michael@0 722 JS_ASSERT(f.outParam == Type_Void);
michael@0 723 break;
michael@0 724 }
michael@0 725
michael@0 726 masm.setupUnalignedABICall(f.argc(), regs.getAny());
michael@0 727 masm.passABIArg(cxreg);
michael@0 728
michael@0 729 size_t argDisp = 0;
michael@0 730
michael@0 731 // Copy any arguments.
michael@0 732 for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
michael@0 733 MoveOperand from;
michael@0 734 switch (f.argProperties(explicitArg)) {
michael@0 735 case VMFunction::WordByValue:
michael@0 736 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
michael@0 737 argDisp += sizeof(void *);
michael@0 738 break;
michael@0 739 case VMFunction::DoubleByValue:
michael@0 740 // Values should be passed by reference, not by value, so we
michael@0 741 // assert that the argument is a double-precision float.
michael@0 742 JS_ASSERT(f.argPassedInFloatReg(explicitArg));
michael@0 743 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
michael@0 744 argDisp += sizeof(double);
michael@0 745 break;
michael@0 746 case VMFunction::WordByRef:
michael@0 747 masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), MoveOp::GENERAL);
michael@0 748 argDisp += sizeof(void *);
michael@0 749 break;
michael@0 750 case VMFunction::DoubleByRef:
michael@0 751 masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), MoveOp::GENERAL);
michael@0 752 argDisp += 2 * sizeof(void *);
michael@0 753 break;
michael@0 754 }
michael@0 755 }
michael@0 756
michael@0 757 // Copy the implicit outparam, if any.
michael@0 758 if (outReg != InvalidReg)
michael@0 759 masm.passABIArg(outReg);
michael@0 760
michael@0 761 masm.callWithABI(f.wrapped);
michael@0 762
michael@0 763 // Test for failure.
michael@0 764 switch (f.failType()) {
michael@0 765 case Type_Object:
michael@0 766 masm.branchTestPtr(Assembler::Zero, r0, r0, masm.failureLabel(f.executionMode));
michael@0 767 break;
michael@0 768 case Type_Bool:
michael@0 769 masm.branchIfFalseBool(r0, masm.failureLabel(f.executionMode));
michael@0 770 break;
michael@0 771 default:
michael@0 772 MOZ_ASSUME_UNREACHABLE("unknown failure kind");
michael@0 773 }
michael@0 774
michael@0 775 // Load the outparam and free any allocated stack.
michael@0 776 switch (f.outParam) {
michael@0 777 case Type_Handle:
michael@0 778 masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
michael@0 779 break;
michael@0 780
michael@0 781 case Type_Value:
michael@0 782 masm.loadValue(Address(sp, 0), JSReturnOperand);
michael@0 783 masm.freeStack(sizeof(Value));
michael@0 784 break;
michael@0 785
michael@0 786 case Type_Int32:
michael@0 787 case Type_Pointer:
michael@0 788 masm.load32(Address(sp, 0), ReturnReg);
michael@0 789 masm.freeStack(sizeof(int32_t));
michael@0 790 break;
michael@0 791
michael@0 792 case Type_Bool:
michael@0 793 masm.load8ZeroExtend(Address(sp, 0), ReturnReg);
michael@0 794 masm.freeStack(sizeof(int32_t));
michael@0 795 break;
michael@0 796
michael@0 797 case Type_Double:
michael@0 798 if (cx->runtime()->jitSupportsFloatingPoint)
michael@0 799 masm.loadDouble(Address(sp, 0), ReturnFloatReg);
michael@0 800 else
michael@0 801 masm.assumeUnreachable("Unable to load into float reg, with no FP support.");
michael@0 802 masm.freeStack(sizeof(double));
michael@0 803 break;
michael@0 804
michael@0 805 default:
michael@0 806 JS_ASSERT(f.outParam == Type_Void);
michael@0 807 break;
michael@0 808 }
michael@0 809 masm.leaveExitFrame();
michael@0 810 masm.retn(Imm32(sizeof(IonExitFrameLayout) +
michael@0 811 f.explicitStackSlots() * sizeof(void *) +
michael@0 812 f.extraValuesToPop * sizeof(Value)));
michael@0 813
michael@0 814 Linker linker(masm);
michael@0 815 AutoFlushICache afc("VMWrapper");
michael@0 816 JitCode *wrapper = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 817 if (!wrapper)
michael@0 818 return nullptr;
michael@0 819
michael@0 820 // linker.newCode may trigger a GC and sweep functionWrappers_ so we have to
michael@0 821 // use relookupOrAdd instead of add.
michael@0 822 if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
michael@0 823 return nullptr;
michael@0 824
michael@0 825 #ifdef JS_ION_PERF
michael@0 826 writePerfSpewerJitCodeProfile(wrapper, "VMWrapper");
michael@0 827 #endif
michael@0 828
michael@0 829 return wrapper;
michael@0 830 }
michael@0 831
michael@0 832 JitCode *
michael@0 833 JitRuntime::generatePreBarrier(JSContext *cx, MIRType type)
michael@0 834 {
michael@0 835 MacroAssembler masm(cx);
michael@0 836
michael@0 837 RegisterSet save;
michael@0 838 if (cx->runtime()->jitSupportsFloatingPoint) {
michael@0 839 save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
michael@0 840 FloatRegisterSet(FloatRegisters::VolatileMask));
michael@0 841 } else {
michael@0 842 save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
michael@0 843 FloatRegisterSet());
michael@0 844 }
michael@0 845 masm.PushRegsInMask(save);
michael@0 846
michael@0 847 JS_ASSERT(PreBarrierReg == r1);
michael@0 848 masm.movePtr(ImmPtr(cx->runtime()), r0);
michael@0 849
michael@0 850 masm.setupUnalignedABICall(2, r2);
michael@0 851 masm.passABIArg(r0);
michael@0 852 masm.passABIArg(r1);
michael@0 853 if (type == MIRType_Value) {
michael@0 854 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon));
michael@0 855 } else {
michael@0 856 JS_ASSERT(type == MIRType_Shape);
michael@0 857 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon));
michael@0 858 }
michael@0 859
michael@0 860 masm.PopRegsInMask(save);
michael@0 861 masm.ret();
michael@0 862
michael@0 863 Linker linker(masm);
michael@0 864 AutoFlushICache afc("PreBarrier");
michael@0 865 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 866
michael@0 867 #ifdef JS_ION_PERF
michael@0 868 writePerfSpewerJitCodeProfile(code, "PreBarrier");
michael@0 869 #endif
michael@0 870
michael@0 871 return code;
michael@0 872 }
michael@0 873
michael@0 874 typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *);
michael@0 875 static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap);
michael@0 876
michael@0 877 JitCode *
michael@0 878 JitRuntime::generateDebugTrapHandler(JSContext *cx)
michael@0 879 {
michael@0 880 MacroAssembler masm;
michael@0 881
michael@0 882 Register scratch1 = r0;
michael@0 883 Register scratch2 = r1;
michael@0 884
michael@0 885 // Load BaselineFrame pointer in scratch1.
michael@0 886 masm.mov(r11, scratch1);
michael@0 887 masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
michael@0 888
michael@0 889 // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
michael@0 890 // the stub frame has a nullptr ICStub pointer, since this pointer is
michael@0 891 // marked during GC.
michael@0 892 masm.movePtr(ImmPtr(nullptr), BaselineStubReg);
michael@0 893 EmitEnterStubFrame(masm, scratch2);
michael@0 894
michael@0 895 JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
michael@0 896 if (!code)
michael@0 897 return nullptr;
michael@0 898
michael@0 899 masm.push(lr);
michael@0 900 masm.push(scratch1);
michael@0 901 EmitCallVM(code, masm);
michael@0 902
michael@0 903 EmitLeaveStubFrame(masm);
michael@0 904
michael@0 905 // If the stub returns |true|, we have to perform a forced return
michael@0 906 // (return from the JS frame). If the stub returns |false|, just return
michael@0 907 // from the trap stub so that execution continues at the current pc.
michael@0 908 Label forcedReturn;
michael@0 909 masm.branchTest32(Assembler::NonZero, ReturnReg, ReturnReg, &forcedReturn);
michael@0 910 masm.mov(lr, pc);
michael@0 911
michael@0 912 masm.bind(&forcedReturn);
michael@0 913 masm.loadValue(Address(r11, BaselineFrame::reverseOffsetOfReturnValue()),
michael@0 914 JSReturnOperand);
michael@0 915 masm.mov(r11, sp);
michael@0 916 masm.pop(r11);
michael@0 917 masm.ret();
michael@0 918
michael@0 919 Linker linker(masm);
michael@0 920 AutoFlushICache afc("DebugTrapHandler");
michael@0 921 JitCode *codeDbg = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 922
michael@0 923 #ifdef JS_ION_PERF
michael@0 924 writePerfSpewerJitCodeProfile(codeDbg, "DebugTrapHandler");
michael@0 925 #endif
michael@0 926
michael@0 927 return codeDbg;
michael@0 928 }
michael@0 929
michael@0 930 JitCode *
michael@0 931 JitRuntime::generateExceptionTailStub(JSContext *cx)
michael@0 932 {
michael@0 933 MacroAssembler masm;
michael@0 934
michael@0 935 masm.handleFailureWithHandlerTail();
michael@0 936
michael@0 937 Linker linker(masm);
michael@0 938 AutoFlushICache afc("ExceptionTailStub");
michael@0 939 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 940
michael@0 941 #ifdef JS_ION_PERF
michael@0 942 writePerfSpewerJitCodeProfile(code, "ExceptionTailStub");
michael@0 943 #endif
michael@0 944
michael@0 945 return code;
michael@0 946 }
michael@0 947
michael@0 948 JitCode *
michael@0 949 JitRuntime::generateBailoutTailStub(JSContext *cx)
michael@0 950 {
michael@0 951 MacroAssembler masm;
michael@0 952
michael@0 953 masm.generateBailoutTail(r1, r2);
michael@0 954
michael@0 955 Linker linker(masm);
michael@0 956 AutoFlushICache afc("BailoutTailStub");
michael@0 957 JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
michael@0 958
michael@0 959 #ifdef JS_ION_PERF
michael@0 960 writePerfSpewerJitCodeProfile(code, "BailoutTailStub");
michael@0 961 #endif
michael@0 962
michael@0 963 return code;
michael@0 964 }

mercurial