js/src/jit/x64/Trampoline-x64.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.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/Bailouts.h"
     8 #include "jit/IonFrames.h"
     9 #include "jit/IonLinker.h"
    10 #include "jit/JitCompartment.h"
    11 #ifdef JS_ION_PERF
    12 # include "jit/PerfSpewer.h"
    13 #endif
    14 #include "jit/VMFunctions.h"
    15 #include "jit/x64/BaselineHelpers-x64.h"
    17 using namespace js;
    18 using namespace js::jit;
    20 // All registers to save and restore. This includes the stack pointer, since we
    21 // use the ability to reference register values on the stack by index.
    22 static const RegisterSet AllRegs =
    23   RegisterSet(GeneralRegisterSet(Registers::AllMask),
    24               FloatRegisterSet(FloatRegisters::AllMask));
    26 /* This method generates a trampoline on x64 for a c++ function with
    27  * the following signature:
    28  *   bool blah(void *code, int argc, Value *argv, JSObject *scopeChain,
    29  *               Value *vp)
    30  *   ...using standard x64 fastcall calling convention
    31  */
    32 JitCode *
    33 JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
    34 {
    35     MacroAssembler masm(cx);
    37     const Register reg_code  = IntArgReg0;
    38     const Register reg_argc  = IntArgReg1;
    39     const Register reg_argv  = IntArgReg2;
    40     JS_ASSERT(OsrFrameReg == IntArgReg3);
    42 #if defined(_WIN64)
    43     const Operand token  = Operand(rbp, 16 + ShadowStackSpace);
    44     const Operand scopeChain = Operand(rbp, 24 + ShadowStackSpace);
    45     const Operand numStackValuesAddr = Operand(rbp, 32 + ShadowStackSpace);
    46     const Operand result = Operand(rbp, 40 + ShadowStackSpace);
    47 #else
    48     const Register token = IntArgReg4;
    49     const Register scopeChain = IntArgReg5;
    50     const Operand numStackValuesAddr = Operand(rbp, 16 + ShadowStackSpace);
    51     const Operand result = Operand(rbp, 24 + ShadowStackSpace);
    52 #endif
    54     // Save old stack frame pointer, set new stack frame pointer.
    55     masm.push(rbp);
    56     masm.mov(rsp, rbp);
    58     // Save non-volatile registers. These must be saved by the trampoline, rather
    59     // than by the JIT'd code, because they are scanned by the conservative scanner.
    60     masm.push(rbx);
    61     masm.push(r12);
    62     masm.push(r13);
    63     masm.push(r14);
    64     masm.push(r15);
    65 #if defined(_WIN64)
    66     masm.push(rdi);
    67     masm.push(rsi);
    69     // 16-byte aligment for movdqa
    70     masm.subq(Imm32(16 * 10 + 8), rsp);
    72     masm.movdqa(xmm6, Operand(rsp, 16 * 0));
    73     masm.movdqa(xmm7, Operand(rsp, 16 * 1));
    74     masm.movdqa(xmm8, Operand(rsp, 16 * 2));
    75     masm.movdqa(xmm9, Operand(rsp, 16 * 3));
    76     masm.movdqa(xmm10, Operand(rsp, 16 * 4));
    77     masm.movdqa(xmm11, Operand(rsp, 16 * 5));
    78     masm.movdqa(xmm12, Operand(rsp, 16 * 6));
    79     masm.movdqa(xmm13, Operand(rsp, 16 * 7));
    80     masm.movdqa(xmm14, Operand(rsp, 16 * 8));
    81     masm.movdqa(xmm15, Operand(rsp, 16 * 9));
    82 #endif
    84     // Push the EnterJIT sps mark.
    85     masm.spsMarkJit(&cx->runtime()->spsProfiler, rbp, rbx);
    87     // Save arguments passed in registers needed after function call.
    88     masm.push(result);
    90     // Remember stack depth without padding and arguments.
    91     masm.mov(rsp, r14);
    93     // Remember number of bytes occupied by argument vector
    94     masm.mov(reg_argc, r13);
    95     masm.shll(Imm32(3), r13);
    97     // Guarantee 16-byte alignment.
    98     // We push argc, callee token, frame size, and return address.
    99     // The latter two are 16 bytes together, so we only consider argc and the
   100     // token.
   101     masm.mov(rsp, r12);
   102     masm.subq(r13, r12);
   103     masm.subq(Imm32(8), r12);
   104     masm.andl(Imm32(0xf), r12);
   105     masm.subq(r12, rsp);
   107     /***************************************************************
   108     Loop over argv vector, push arguments onto stack in reverse order
   109     ***************************************************************/
   111     // r13 still stores the number of bytes in the argument vector.
   112     masm.addq(reg_argv, r13); // r13 points above last argument.
   114     // while r13 > rdx, push arguments.
   115     {
   116         Label header, footer;
   117         masm.bind(&header);
   119         masm.cmpq(r13, reg_argv);
   120         masm.j(AssemblerX86Shared::BelowOrEqual, &footer);
   122         masm.subq(Imm32(8), r13);
   123         masm.push(Operand(r13, 0));
   124         masm.jmp(&header);
   126         masm.bind(&footer);
   127     }
   129     // Push the number of actual arguments.  |result| is used to store the
   130     // actual number of arguments without adding an extra argument to the enter
   131     // JIT.
   132     masm.movq(result, reg_argc);
   133     masm.unboxInt32(Operand(reg_argc, 0), reg_argc);
   134     masm.push(reg_argc);
   136     // Push the callee token.
   137     masm.push(token);
   139     /*****************************************************************
   140     Push the number of bytes we've pushed so far on the stack and call
   141     *****************************************************************/
   142     masm.subq(rsp, r14);
   144     // Create a frame descriptor.
   145     masm.makeFrameDescriptor(r14, JitFrame_Entry);
   146     masm.push(r14);
   148     CodeLabel returnLabel;
   149     if (type == EnterJitBaseline) {
   150         // Handle OSR.
   151         GeneralRegisterSet regs(GeneralRegisterSet::All());
   152         regs.takeUnchecked(OsrFrameReg);
   153         regs.take(rbp);
   154         regs.take(reg_code);
   156         // Ensure that |scratch| does not end up being JSReturnOperand.
   157         // Do takeUnchecked because on Win64/x64, reg_code (IntArgReg0) and JSReturnOperand are
   158         // the same (rcx).  See bug 849398.
   159         regs.takeUnchecked(JSReturnOperand);
   160         Register scratch = regs.takeAny();
   162         Label notOsr;
   163         masm.branchTestPtr(Assembler::Zero, OsrFrameReg, OsrFrameReg, &notOsr);
   165         Register numStackValues = regs.takeAny();
   166         masm.movq(numStackValuesAddr, numStackValues);
   168         // Push return address, previous frame pointer.
   169         masm.mov(returnLabel.dest(), scratch);
   170         masm.push(scratch);
   171         masm.push(rbp);
   173         // Reserve frame.
   174         Register framePtr = rbp;
   175         masm.subPtr(Imm32(BaselineFrame::Size()), rsp);
   176         masm.mov(rsp, framePtr);
   178 #ifdef XP_WIN
   179         // Can't push large frames blindly on windows.  Touch frame memory incrementally.
   180         masm.mov(numStackValues, scratch);
   181         masm.lshiftPtr(Imm32(3), scratch);
   182         masm.subPtr(scratch, framePtr);
   183         {
   184             masm.movePtr(rsp, scratch);
   185             masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
   187             Label touchFrameLoop;
   188             Label touchFrameLoopEnd;
   189             masm.bind(&touchFrameLoop);
   190             masm.branchPtr(Assembler::Below, scratch, framePtr, &touchFrameLoopEnd);
   191             masm.store32(Imm32(0), Address(scratch, 0));
   192             masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
   193             masm.jump(&touchFrameLoop);
   194             masm.bind(&touchFrameLoopEnd);
   195         }
   196         masm.mov(rsp, framePtr);
   197 #endif
   199         // Reserve space for locals and stack values.
   200         Register valuesSize = regs.takeAny();
   201         masm.mov(numStackValues, valuesSize);
   202         masm.shll(Imm32(3), valuesSize);
   203         masm.subPtr(valuesSize, rsp);
   205         // Enter exit frame.
   206         masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), valuesSize);
   207         masm.makeFrameDescriptor(valuesSize, JitFrame_BaselineJS);
   208         masm.push(valuesSize);
   209         masm.push(Imm32(0)); // Fake return address.
   210         masm.enterFakeExitFrame();
   212         regs.add(valuesSize);
   214         masm.push(framePtr);
   215         masm.push(reg_code);
   217         masm.setupUnalignedABICall(3, scratch);
   218         masm.passABIArg(framePtr); // BaselineFrame
   219         masm.passABIArg(OsrFrameReg); // InterpreterFrame
   220         masm.passABIArg(numStackValues);
   221         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, jit::InitBaselineFrameForOsr));
   223         masm.pop(reg_code);
   224         masm.pop(framePtr);
   226         JS_ASSERT(reg_code != ReturnReg);
   228         Label error;
   229         masm.addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), rsp);
   230         masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
   231         masm.branchIfFalseBool(ReturnReg, &error);
   233         masm.jump(reg_code);
   235         // OOM: load error value, discard return address and previous frame
   236         // pointer and return.
   237         masm.bind(&error);
   238         masm.mov(framePtr, rsp);
   239         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), rsp);
   240         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
   241         masm.mov(returnLabel.dest(), scratch);
   242         masm.jump(scratch);
   244         masm.bind(&notOsr);
   245         masm.movq(scopeChain, R1.scratchReg());
   246     }
   248     // Call function.
   249     masm.call(reg_code);
   251     if (type == EnterJitBaseline) {
   252         // Baseline OSR will return here.
   253         masm.bind(returnLabel.src());
   254         if (!masm.addCodeLabel(returnLabel))
   255             return nullptr;
   256     }
   258     // Pop arguments and padding from stack.
   259     masm.pop(r14);              // Pop and decode descriptor.
   260     masm.shrq(Imm32(FRAMESIZE_SHIFT), r14);
   261     masm.addq(r14, rsp);        // Remove arguments.
   263     /*****************************************************************
   264     Place return value where it belongs, pop all saved registers
   265     *****************************************************************/
   266     masm.pop(r12); // vp
   267     masm.storeValue(JSReturnOperand, Operand(r12, 0));
   269     // Unwind the sps mark.
   270     masm.spsUnmarkJit(&cx->runtime()->spsProfiler, rbx);
   272     // Restore non-volatile registers.
   273 #if defined(_WIN64)
   274     masm.movdqa(Operand(rsp, 16 * 0), xmm6);
   275     masm.movdqa(Operand(rsp, 16 * 1), xmm7);
   276     masm.movdqa(Operand(rsp, 16 * 2), xmm8);
   277     masm.movdqa(Operand(rsp, 16 * 3), xmm9);
   278     masm.movdqa(Operand(rsp, 16 * 4), xmm10);
   279     masm.movdqa(Operand(rsp, 16 * 5), xmm11);
   280     masm.movdqa(Operand(rsp, 16 * 6), xmm12);
   281     masm.movdqa(Operand(rsp, 16 * 7), xmm13);
   282     masm.movdqa(Operand(rsp, 16 * 8), xmm14);
   283     masm.movdqa(Operand(rsp, 16 * 9), xmm15);
   285     masm.addq(Imm32(16 * 10 + 8), rsp);
   287     masm.pop(rsi);
   288     masm.pop(rdi);
   289 #endif
   290     masm.pop(r15);
   291     masm.pop(r14);
   292     masm.pop(r13);
   293     masm.pop(r12);
   294     masm.pop(rbx);
   296     // Restore frame pointer and return.
   297     masm.pop(rbp);
   298     masm.ret();
   300     Linker linker(masm);
   301     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   303 #ifdef JS_ION_PERF
   304     writePerfSpewerJitCodeProfile(code, "EnterJIT");
   305 #endif
   307     return code;
   308 }
   310 JitCode *
   311 JitRuntime::generateInvalidator(JSContext *cx)
   312 {
   313     AutoIonContextAlloc aica(cx);
   314     MacroAssembler masm(cx);
   316     // See explanatory comment in x86's JitRuntime::generateInvalidator.
   318     masm.addq(Imm32(sizeof(uintptr_t)), rsp);
   320     // Push registers such that we can access them from [base + code].
   321     masm.PushRegsInMask(AllRegs);
   323     masm.movq(rsp, rax); // Argument to jit::InvalidationBailout.
   325     // Make space for InvalidationBailout's frameSize outparam.
   326     masm.reserveStack(sizeof(size_t));
   327     masm.movq(rsp, rbx);
   329     // Make space for InvalidationBailout's bailoutInfo outparam.
   330     masm.reserveStack(sizeof(void *));
   331     masm.movq(rsp, r9);
   333     masm.setupUnalignedABICall(3, rdx);
   334     masm.passABIArg(rax);
   335     masm.passABIArg(rbx);
   336     masm.passABIArg(r9);
   337     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, InvalidationBailout));
   339     masm.pop(r9); // Get the bailoutInfo outparam.
   340     masm.pop(rbx); // Get the frameSize outparam.
   342     // Pop the machine state and the dead frame.
   343     masm.lea(Operand(rsp, rbx, TimesOne, sizeof(InvalidationBailoutStack)), rsp);
   345     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
   346     JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
   347     masm.jmp(bailoutTail);
   349     Linker linker(masm);
   350     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   352 #ifdef JS_ION_PERF
   353     writePerfSpewerJitCodeProfile(code, "Invalidator");
   354 #endif
   356     return code;
   357 }
   359 JitCode *
   360 JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
   361 {
   362     // Do not erase the frame pointer in this function.
   364     MacroAssembler masm(cx);
   366     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
   367     // Including |this|, there are (|nargs| + 1) arguments to copy.
   368     JS_ASSERT(ArgumentsRectifierReg == r8);
   370     // Load the number of |undefined|s to push into %rcx.
   371     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfCalleeToken()), rax);
   372     masm.movzwl(Operand(rax, JSFunction::offsetOfNargs()), rcx);
   373     masm.subq(r8, rcx);
   375     // Copy the number of actual arguments
   376     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfNumActualArgs()), rdx);
   378     masm.moveValue(UndefinedValue(), r10);
   380     masm.movq(rsp, r9); // Save %rsp.
   382     // Push undefined.
   383     {
   384         Label undefLoopTop;
   385         masm.bind(&undefLoopTop);
   387         masm.push(r10);
   388         masm.subl(Imm32(1), rcx);
   389         masm.j(Assembler::NonZero, &undefLoopTop);
   390     }
   392     // Get the topmost argument.
   393     BaseIndex b = BaseIndex(r9, r8, TimesEight, sizeof(IonRectifierFrameLayout));
   394     masm.lea(Operand(b), rcx);
   396     // Push arguments, |nargs| + 1 times (to include |this|).
   397     masm.addl(Imm32(1), r8);
   398     {
   399         Label copyLoopTop;
   401         masm.bind(&copyLoopTop);
   402         masm.push(Operand(rcx, 0x0));
   403         masm.subq(Imm32(sizeof(Value)), rcx);
   404         masm.subl(Imm32(1), r8);
   405         masm.j(Assembler::NonZero, &copyLoopTop);
   406     }
   408     // Construct descriptor.
   409     masm.subq(rsp, r9);
   410     masm.makeFrameDescriptor(r9, JitFrame_Rectifier);
   412     // Construct IonJSFrameLayout.
   413     masm.push(rdx); // numActualArgs
   414     masm.push(rax); // callee token
   415     masm.push(r9); // descriptor
   417     // Call the target function.
   418     // Note that this code assumes the function is JITted.
   419     masm.loadPtr(Address(rax, JSFunction::offsetOfNativeOrScript()), rax);
   420     masm.loadBaselineOrIonRaw(rax, rax, mode, nullptr);
   421     masm.call(rax);
   422     uint32_t returnOffset = masm.currentOffset();
   424     // Remove the rectifier frame.
   425     masm.pop(r9);             // r9 <- descriptor with FrameType.
   426     masm.shrq(Imm32(FRAMESIZE_SHIFT), r9);
   427     masm.pop(r11);            // Discard calleeToken.
   428     masm.pop(r11);            // Discard numActualArgs.
   429     masm.addq(r9, rsp);       // Discard pushed arguments.
   431     masm.ret();
   433     Linker linker(masm);
   434     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   436 #ifdef JS_ION_PERF
   437     writePerfSpewerJitCodeProfile(code, "ArgumentsRectifier");
   438 #endif
   440     CodeOffsetLabel returnLabel(returnOffset);
   441     returnLabel.fixup(&masm);
   442     if (returnAddrOut)
   443         *returnAddrOut = (void *) (code->raw() + returnLabel.offset());
   444     return code;
   445 }
   447 static void
   448 GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32_t frameClass)
   449 {
   450     // Push registers such that we can access them from [base + code].
   451     masm.PushRegsInMask(AllRegs);
   453     // Get the stack pointer into a register, pre-alignment.
   454     masm.movq(rsp, r8);
   456     // Make space for Bailout's bailoutInfo outparam.
   457     masm.reserveStack(sizeof(void *));
   458     masm.movq(rsp, r9);
   460     // Call the bailout function.
   461     masm.setupUnalignedABICall(2, rax);
   462     masm.passABIArg(r8);
   463     masm.passABIArg(r9);
   464     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Bailout));
   466     masm.pop(r9); // Get the bailoutInfo outparam.
   468     // Stack is:
   469     //     [frame]
   470     //     snapshotOffset
   471     //     frameSize
   472     //     [bailoutFrame]
   473     //
   474     // Remove both the bailout frame and the topmost Ion frame's stack.
   475     static const uint32_t BailoutDataSize = sizeof(void *) * Registers::Total +
   476                                           sizeof(double) * FloatRegisters::Total;
   477     masm.addq(Imm32(BailoutDataSize), rsp);
   478     masm.pop(rcx);
   479     masm.lea(Operand(rsp, rcx, TimesOne, sizeof(void *)), rsp);
   481     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
   482     JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
   483     masm.jmp(bailoutTail);
   484 }
   486 JitCode *
   487 JitRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
   488 {
   489     MOZ_ASSUME_UNREACHABLE("x64 does not use bailout tables");
   490 }
   492 JitCode *
   493 JitRuntime::generateBailoutHandler(JSContext *cx)
   494 {
   495     MacroAssembler masm;
   497     GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
   499     Linker linker(masm);
   500     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   502 #ifdef JS_ION_PERF
   503     writePerfSpewerJitCodeProfile(code, "BailoutHandler");
   504 #endif
   506     return code;
   507 }
   509 JitCode *
   510 JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
   511 {
   512     JS_ASSERT(!StackKeptAligned);
   513     JS_ASSERT(functionWrappers_);
   514     JS_ASSERT(functionWrappers_->initialized());
   515     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
   516     if (p)
   517         return p->value();
   519     // Generate a separated code for the wrapper.
   520     MacroAssembler masm;
   522     // Avoid conflicts with argument registers while discarding the result after
   523     // the function call.
   524     GeneralRegisterSet regs = GeneralRegisterSet(Register::Codes::WrapperMask);
   526     // Wrapper register set is a superset of Volatile register set.
   527     JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
   529     // The context is the first argument.
   530     Register cxreg = IntArgReg0;
   531     regs.take(cxreg);
   533     // Stack is:
   534     //    ... frame ...
   535     //  +12 [args]
   536     //  +8  descriptor
   537     //  +0  returnAddress
   538     //
   539     // We're aligned to an exit frame, so link it up.
   540     masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
   542     // Save the current stack pointer as the base for copying arguments.
   543     Register argsBase = InvalidReg;
   544     if (f.explicitArgs) {
   545         argsBase = r10;
   546         regs.take(argsBase);
   547         masm.lea(Operand(rsp,IonExitFrameLayout::SizeWithFooter()), argsBase);
   548     }
   550     // Reserve space for the outparameter.
   551     Register outReg = InvalidReg;
   552     switch (f.outParam) {
   553       case Type_Value:
   554         outReg = regs.takeAny();
   555         masm.reserveStack(sizeof(Value));
   556         masm.movq(esp, outReg);
   557         break;
   559       case Type_Handle:
   560         outReg = regs.takeAny();
   561         masm.PushEmptyRooted(f.outParamRootType);
   562         masm.movq(esp, outReg);
   563         break;
   565       case Type_Int32:
   566       case Type_Bool:
   567         outReg = regs.takeAny();
   568         masm.reserveStack(sizeof(int32_t));
   569         masm.movq(esp, outReg);
   570         break;
   572       case Type_Double:
   573         outReg = regs.takeAny();
   574         masm.reserveStack(sizeof(double));
   575         masm.movq(esp, outReg);
   576         break;
   578       case Type_Pointer:
   579         outReg = regs.takeAny();
   580         masm.reserveStack(sizeof(uintptr_t));
   581         masm.movq(esp, outReg);
   582         break;
   584       default:
   585         JS_ASSERT(f.outParam == Type_Void);
   586         break;
   587     }
   589     masm.setupUnalignedABICall(f.argc(), regs.getAny());
   590     masm.passABIArg(cxreg);
   592     size_t argDisp = 0;
   594     // Copy arguments.
   595     for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
   596         MoveOperand from;
   597         switch (f.argProperties(explicitArg)) {
   598           case VMFunction::WordByValue:
   599             if (f.argPassedInFloatReg(explicitArg))
   600                 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
   601             else
   602                 masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
   603             argDisp += sizeof(void *);
   604             break;
   605           case VMFunction::WordByRef:
   606             masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
   607                             MoveOp::GENERAL);
   608             argDisp += sizeof(void *);
   609             break;
   610           case VMFunction::DoubleByValue:
   611           case VMFunction::DoubleByRef:
   612             MOZ_ASSUME_UNREACHABLE("NYI: x64 callVM should not be used with 128bits values.");
   613         }
   614     }
   616     // Copy the implicit outparam, if any.
   617     if (outReg != InvalidReg)
   618         masm.passABIArg(outReg);
   620     masm.callWithABI(f.wrapped);
   622     // Test for failure.
   623     switch (f.failType()) {
   624       case Type_Object:
   625         masm.branchTestPtr(Assembler::Zero, rax, rax, masm.failureLabel(f.executionMode));
   626         break;
   627       case Type_Bool:
   628         masm.testb(rax, rax);
   629         masm.j(Assembler::Zero, masm.failureLabel(f.executionMode));
   630         break;
   631       default:
   632         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
   633     }
   635     // Load the outparam and free any allocated stack.
   636     switch (f.outParam) {
   637       case Type_Handle:
   638         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
   639         break;
   641       case Type_Value:
   642         masm.loadValue(Address(esp, 0), JSReturnOperand);
   643         masm.freeStack(sizeof(Value));
   644         break;
   646       case Type_Int32:
   647         masm.load32(Address(esp, 0), ReturnReg);
   648         masm.freeStack(sizeof(int32_t));
   649         break;
   651       case Type_Bool:
   652         masm.load8ZeroExtend(Address(esp, 0), ReturnReg);
   653         masm.freeStack(sizeof(int32_t));
   654         break;
   656       case Type_Double:
   657         JS_ASSERT(cx->runtime()->jitSupportsFloatingPoint);
   658         masm.loadDouble(Address(esp, 0), ReturnFloatReg);
   659         masm.freeStack(sizeof(double));
   660         break;
   662       case Type_Pointer:
   663         masm.loadPtr(Address(esp, 0), ReturnReg);
   664         masm.freeStack(sizeof(uintptr_t));
   665         break;
   667       default:
   668         JS_ASSERT(f.outParam == Type_Void);
   669         break;
   670     }
   671     masm.leaveExitFrame();
   672     masm.retn(Imm32(sizeof(IonExitFrameLayout) +
   673                     f.explicitStackSlots() * sizeof(void *) +
   674                     f.extraValuesToPop * sizeof(Value)));
   676     Linker linker(masm);
   677     JitCode *wrapper = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   678     if (!wrapper)
   679         return nullptr;
   681 #ifdef JS_ION_PERF
   682     writePerfSpewerJitCodeProfile(wrapper, "VMWrapper");
   683 #endif
   685     // linker.newCode may trigger a GC and sweep functionWrappers_ so we have to
   686     // use relookupOrAdd instead of add.
   687     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
   688         return nullptr;
   690     return wrapper;
   691 }
   693 JitCode *
   694 JitRuntime::generatePreBarrier(JSContext *cx, MIRType type)
   695 {
   696     MacroAssembler masm;
   698     RegisterSet regs = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
   699                                    FloatRegisterSet(FloatRegisters::VolatileMask));
   700     masm.PushRegsInMask(regs);
   702     JS_ASSERT(PreBarrierReg == rdx);
   703     masm.mov(ImmPtr(cx->runtime()), rcx);
   705     masm.setupUnalignedABICall(2, rax);
   706     masm.passABIArg(rcx);
   707     masm.passABIArg(rdx);
   708     if (type == MIRType_Value) {
   709         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon));
   710     } else {
   711         JS_ASSERT(type == MIRType_Shape);
   712         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon));
   713     }
   715     masm.PopRegsInMask(regs);
   716     masm.ret();
   718     Linker linker(masm);
   719     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   721 #ifdef JS_ION_PERF
   722     writePerfSpewerJitCodeProfile(code, "PreBarrier");
   723 #endif
   725     return code;
   726 }
   728 typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *);
   729 static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap);
   731 JitCode *
   732 JitRuntime::generateDebugTrapHandler(JSContext *cx)
   733 {
   734     MacroAssembler masm;
   736     Register scratch1 = rax;
   737     Register scratch2 = rcx;
   738     Register scratch3 = rdx;
   740     // Load the return address in scratch1.
   741     masm.loadPtr(Address(rsp, 0), scratch1);
   743     // Load BaselineFrame pointer in scratch2.
   744     masm.mov(rbp, scratch2);
   745     masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
   747     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
   748     // the stub frame has a nullptr ICStub pointer, since this pointer is marked
   749     // during GC.
   750     masm.movePtr(ImmPtr(nullptr), BaselineStubReg);
   751     EmitEnterStubFrame(masm, scratch3);
   753     JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
   754     if (!code)
   755         return nullptr;
   757     masm.push(scratch1);
   758     masm.push(scratch2);
   759     EmitCallVM(code, masm);
   761     EmitLeaveStubFrame(masm);
   763     // If the stub returns |true|, we have to perform a forced return
   764     // (return from the JS frame). If the stub returns |false|, just return
   765     // from the trap stub so that execution continues at the current pc.
   766     Label forcedReturn;
   767     masm.branchTest32(Assembler::NonZero, ReturnReg, ReturnReg, &forcedReturn);
   768     masm.ret();
   770     masm.bind(&forcedReturn);
   771     masm.loadValue(Address(ebp, BaselineFrame::reverseOffsetOfReturnValue()),
   772                    JSReturnOperand);
   773     masm.mov(rbp, rsp);
   774     masm.pop(rbp);
   775     masm.ret();
   777     Linker linker(masm);
   778     JitCode *codeDbg = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   780 #ifdef JS_ION_PERF
   781     writePerfSpewerJitCodeProfile(codeDbg, "DebugTrapHandler");
   782 #endif
   784     return codeDbg;
   785 }
   787 JitCode *
   788 JitRuntime::generateExceptionTailStub(JSContext *cx)
   789 {
   790     MacroAssembler masm;
   792     masm.handleFailureWithHandlerTail();
   794     Linker linker(masm);
   795     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   797 #ifdef JS_ION_PERF
   798     writePerfSpewerJitCodeProfile(code, "ExceptionTailStub");
   799 #endif
   801     return code;
   802 }
   804 JitCode *
   805 JitRuntime::generateBailoutTailStub(JSContext *cx)
   806 {
   807     MacroAssembler masm;
   809     masm.generateBailoutTail(rdx, r9);
   811     Linker linker(masm);
   812     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
   814 #ifdef JS_ION_PERF
   815     writePerfSpewerJitCodeProfile(code, "BailoutTailStub");
   816 #endif
   818     return code;
   819 }

mercurial