js/src/jit/shared/CodeGenerator-x86-shared.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/shared/CodeGenerator-x86-shared.h"
     9 #include "mozilla/DebugOnly.h"
    10 #include "mozilla/MathAlgorithms.h"
    12 #include "jsmath.h"
    14 #include "jit/IonFrames.h"
    15 #include "jit/IonLinker.h"
    16 #include "jit/JitCompartment.h"
    17 #include "jit/RangeAnalysis.h"
    18 #include "vm/TraceLogging.h"
    20 #include "jit/shared/CodeGenerator-shared-inl.h"
    22 using namespace js;
    23 using namespace js::jit;
    25 using mozilla::Abs;
    26 using mozilla::FloatingPoint;
    27 using mozilla::FloorLog2;
    28 using mozilla::NegativeInfinity;
    29 using mozilla::SpecificNaN;
    31 namespace js {
    32 namespace jit {
    34 CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
    35   : CodeGeneratorShared(gen, graph, masm)
    36 {
    37 }
    39 bool
    40 CodeGeneratorX86Shared::generatePrologue()
    41 {
    42     JS_ASSERT(!gen->compilingAsmJS());
    44     // Note that this automatically sets MacroAssembler::framePushed().
    45     masm.reserveStack(frameSize());
    47     return true;
    48 }
    50 bool
    51 CodeGeneratorX86Shared::generateAsmJSPrologue(Label *stackOverflowLabel)
    52 {
    53     JS_ASSERT(gen->compilingAsmJS());
    55     // The asm.js over-recursed handler wants to be able to assume that SP
    56     // points to the return address, so perform the check before pushing
    57     // frameDepth.
    58     if (!omitOverRecursedCheck()) {
    59         masm.branchPtr(Assembler::AboveOrEqual,
    60                        AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
    61                        StackPointer,
    62                        stackOverflowLabel);
    63     }
    65     // Note that this automatically sets MacroAssembler::framePushed().
    66     masm.reserveStack(frameSize());
    67     return true;
    68 }
    70 bool
    71 CodeGeneratorX86Shared::generateEpilogue()
    72 {
    73     masm.bind(&returnLabel_);
    75 #ifdef JS_TRACE_LOGGING
    76     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
    77         if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
    78             return false;
    79         if (!emitTracelogScriptStop())
    80             return false;
    81     }
    82 #endif
    84     // Pop the stack we allocated at the start of the function.
    85     masm.freeStack(frameSize());
    86     JS_ASSERT(masm.framePushed() == 0);
    88     masm.ret();
    89     return true;
    90 }
    92 bool
    93 OutOfLineBailout::accept(CodeGeneratorX86Shared *codegen)
    94 {
    95     return codegen->visitOutOfLineBailout(this);
    96 }
    98 void
    99 CodeGeneratorX86Shared::emitBranch(Assembler::Condition cond, MBasicBlock *mirTrue,
   100                                    MBasicBlock *mirFalse, Assembler::NaNCond ifNaN)
   101 {
   102     if (ifNaN == Assembler::NaN_IsFalse)
   103         jumpToBlock(mirFalse, Assembler::Parity);
   104     else if (ifNaN == Assembler::NaN_IsTrue)
   105         jumpToBlock(mirTrue, Assembler::Parity);
   107     if (isNextBlock(mirFalse->lir())) {
   108         jumpToBlock(mirTrue, cond);
   109     } else {
   110         jumpToBlock(mirFalse, Assembler::InvertCondition(cond));
   111         jumpToBlock(mirTrue);
   112     }
   113 }
   115 bool
   116 CodeGeneratorX86Shared::visitDouble(LDouble *ins)
   117 {
   118     const LDefinition *out = ins->getDef(0);
   119     masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out));
   120     return true;
   121 }
   123 bool
   124 CodeGeneratorX86Shared::visitFloat32(LFloat32 *ins)
   125 {
   126     const LDefinition *out = ins->getDef(0);
   127     masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out));
   128     return true;
   129 }
   131 bool
   132 CodeGeneratorX86Shared::visitTestIAndBranch(LTestIAndBranch *test)
   133 {
   134     const LAllocation *opd = test->input();
   136     // Test the operand
   137     masm.testl(ToRegister(opd), ToRegister(opd));
   138     emitBranch(Assembler::NonZero, test->ifTrue(), test->ifFalse());
   139     return true;
   140 }
   142 bool
   143 CodeGeneratorX86Shared::visitTestDAndBranch(LTestDAndBranch *test)
   144 {
   145     const LAllocation *opd = test->input();
   147     // ucomisd flags:
   148     //             Z  P  C
   149     //            ---------
   150     //      NaN    1  1  1
   151     //        >    0  0  0
   152     //        <    0  0  1
   153     //        =    1  0  0
   154     //
   155     // NaN is falsey, so comparing against 0 and then using the Z flag is
   156     // enough to determine which branch to take.
   157     masm.xorpd(ScratchFloatReg, ScratchFloatReg);
   158     masm.ucomisd(ToFloatRegister(opd), ScratchFloatReg);
   159     emitBranch(Assembler::NotEqual, test->ifTrue(), test->ifFalse());
   160     return true;
   161 }
   163 bool
   164 CodeGeneratorX86Shared::visitTestFAndBranch(LTestFAndBranch *test)
   165 {
   166     const LAllocation *opd = test->input();
   167     // ucomiss flags are the same as doubles; see comment above
   168     masm.xorps(ScratchFloatReg, ScratchFloatReg);
   169     masm.ucomiss(ToFloatRegister(opd), ScratchFloatReg);
   170     emitBranch(Assembler::NotEqual, test->ifTrue(), test->ifFalse());
   171     return true;
   172 }
   174 bool
   175 CodeGeneratorX86Shared::visitBitAndAndBranch(LBitAndAndBranch *baab)
   176 {
   177     if (baab->right()->isConstant())
   178         masm.testl(ToRegister(baab->left()), Imm32(ToInt32(baab->right())));
   179     else
   180         masm.testl(ToRegister(baab->left()), ToRegister(baab->right()));
   181     emitBranch(Assembler::NonZero, baab->ifTrue(), baab->ifFalse());
   182     return true;
   183 }
   185 void
   186 CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right)
   187 {
   188 #ifdef JS_CODEGEN_X64
   189     if (type == MCompare::Compare_Object) {
   190         masm.cmpq(ToRegister(left), ToOperand(right));
   191         return;
   192     }
   193 #endif
   195     if (right->isConstant())
   196         masm.cmpl(ToRegister(left), Imm32(ToInt32(right)));
   197     else
   198         masm.cmpl(ToRegister(left), ToOperand(right));
   199 }
   201 bool
   202 CodeGeneratorX86Shared::visitCompare(LCompare *comp)
   203 {
   204     MCompare *mir = comp->mir();
   205     emitCompare(mir->compareType(), comp->left(), comp->right());
   206     masm.emitSet(JSOpToCondition(mir->compareType(), comp->jsop()), ToRegister(comp->output()));
   207     return true;
   208 }
   210 bool
   211 CodeGeneratorX86Shared::visitCompareAndBranch(LCompareAndBranch *comp)
   212 {
   213     MCompare *mir = comp->cmpMir();
   214     emitCompare(mir->compareType(), comp->left(), comp->right());
   215     Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop());
   216     emitBranch(cond, comp->ifTrue(), comp->ifFalse());
   217     return true;
   218 }
   220 bool
   221 CodeGeneratorX86Shared::visitCompareD(LCompareD *comp)
   222 {
   223     FloatRegister lhs = ToFloatRegister(comp->left());
   224     FloatRegister rhs = ToFloatRegister(comp->right());
   226     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
   228     Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
   229     if (comp->mir()->operandsAreNeverNaN())
   230         nanCond = Assembler::NaN_HandledByCond;
   232     masm.compareDouble(cond, lhs, rhs);
   233     masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()), nanCond);
   234     return true;
   235 }
   237 bool
   238 CodeGeneratorX86Shared::visitCompareF(LCompareF *comp)
   239 {
   240     FloatRegister lhs = ToFloatRegister(comp->left());
   241     FloatRegister rhs = ToFloatRegister(comp->right());
   243     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
   245     Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
   246     if (comp->mir()->operandsAreNeverNaN())
   247         nanCond = Assembler::NaN_HandledByCond;
   249     masm.compareFloat(cond, lhs, rhs);
   250     masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()), nanCond);
   251     return true;
   252 }
   254 bool
   255 CodeGeneratorX86Shared::visitNotI(LNotI *ins)
   256 {
   257     masm.cmpl(ToRegister(ins->input()), Imm32(0));
   258     masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
   259     return true;
   260 }
   262 bool
   263 CodeGeneratorX86Shared::visitNotD(LNotD *ins)
   264 {
   265     FloatRegister opd = ToFloatRegister(ins->input());
   267     // Not returns true if the input is a NaN. We don't have to worry about
   268     // it if we know the input is never NaN though.
   269     Assembler::NaNCond nanCond = Assembler::NaN_IsTrue;
   270     if (ins->mir()->operandIsNeverNaN())
   271         nanCond = Assembler::NaN_HandledByCond;
   273     masm.xorpd(ScratchFloatReg, ScratchFloatReg);
   274     masm.compareDouble(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg);
   275     masm.emitSet(Assembler::Equal, ToRegister(ins->output()), nanCond);
   276     return true;
   277 }
   279 bool
   280 CodeGeneratorX86Shared::visitNotF(LNotF *ins)
   281 {
   282     FloatRegister opd = ToFloatRegister(ins->input());
   284     // Not returns true if the input is a NaN. We don't have to worry about
   285     // it if we know the input is never NaN though.
   286     Assembler::NaNCond nanCond = Assembler::NaN_IsTrue;
   287     if (ins->mir()->operandIsNeverNaN())
   288         nanCond = Assembler::NaN_HandledByCond;
   290     masm.xorps(ScratchFloatReg, ScratchFloatReg);
   291     masm.compareFloat(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg);
   292     masm.emitSet(Assembler::Equal, ToRegister(ins->output()), nanCond);
   293     return true;
   294 }
   296 bool
   297 CodeGeneratorX86Shared::visitCompareDAndBranch(LCompareDAndBranch *comp)
   298 {
   299     FloatRegister lhs = ToFloatRegister(comp->left());
   300     FloatRegister rhs = ToFloatRegister(comp->right());
   302     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
   304     Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
   305     if (comp->cmpMir()->operandsAreNeverNaN())
   306         nanCond = Assembler::NaN_HandledByCond;
   308     masm.compareDouble(cond, lhs, rhs);
   309     emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(), nanCond);
   310     return true;
   311 }
   313 bool
   314 CodeGeneratorX86Shared::visitCompareFAndBranch(LCompareFAndBranch *comp)
   315 {
   316     FloatRegister lhs = ToFloatRegister(comp->left());
   317     FloatRegister rhs = ToFloatRegister(comp->right());
   319     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
   321     Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
   322     if (comp->cmpMir()->operandsAreNeverNaN())
   323         nanCond = Assembler::NaN_HandledByCond;
   325     masm.compareFloat(cond, lhs, rhs);
   326     emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(), nanCond);
   327     return true;
   328 }
   330 bool
   331 CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
   332 {
   333     const MAsmJSPassStackArg *mir = ins->mir();
   334     Address dst(StackPointer, mir->spOffset());
   335     if (ins->arg()->isConstant()) {
   336         masm.storePtr(ImmWord(ToInt32(ins->arg())), dst);
   337     } else {
   338         if (ins->arg()->isGeneralReg())
   339             masm.storePtr(ToRegister(ins->arg()), dst);
   340         else
   341             masm.storeDouble(ToFloatRegister(ins->arg()), dst);
   342     }
   343     return true;
   344 }
   346 bool
   347 CodeGeneratorX86Shared::generateOutOfLineCode()
   348 {
   349     if (!CodeGeneratorShared::generateOutOfLineCode())
   350         return false;
   352     if (deoptLabel_.used()) {
   353         // All non-table-based bailouts will go here.
   354         masm.bind(&deoptLabel_);
   356         // Push the frame size, so the handler can recover the IonScript.
   357         masm.push(Imm32(frameSize()));
   359         JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler();
   360         masm.jmp(ImmPtr(handler->raw()), Relocation::JITCODE);
   361     }
   363     return true;
   364 }
   366 class BailoutJump {
   367     Assembler::Condition cond_;
   369   public:
   370     BailoutJump(Assembler::Condition cond) : cond_(cond)
   371     { }
   372 #ifdef JS_CODEGEN_X86
   373     void operator()(MacroAssembler &masm, uint8_t *code) const {
   374         masm.j(cond_, ImmPtr(code), Relocation::HARDCODED);
   375     }
   376 #endif
   377     void operator()(MacroAssembler &masm, Label *label) const {
   378         masm.j(cond_, label);
   379     }
   380 };
   382 class BailoutLabel {
   383     Label *label_;
   385   public:
   386     BailoutLabel(Label *label) : label_(label)
   387     { }
   388 #ifdef JS_CODEGEN_X86
   389     void operator()(MacroAssembler &masm, uint8_t *code) const {
   390         masm.retarget(label_, ImmPtr(code), Relocation::HARDCODED);
   391     }
   392 #endif
   393     void operator()(MacroAssembler &masm, Label *label) const {
   394         masm.retarget(label_, label);
   395     }
   396 };
   398 template <typename T> bool
   399 CodeGeneratorX86Shared::bailout(const T &binder, LSnapshot *snapshot)
   400 {
   401     CompileInfo &info = snapshot->mir()->block()->info();
   402     switch (info.executionMode()) {
   403       case ParallelExecution: {
   404         // in parallel mode, make no attempt to recover, just signal an error.
   405         OutOfLineAbortPar *ool = oolAbortPar(ParallelBailoutUnsupported,
   406                                              snapshot->mir()->block(),
   407                                              snapshot->mir()->pc());
   408         binder(masm, ool->entry());
   409         return true;
   410       }
   411       case SequentialExecution:
   412         break;
   413       default:
   414         MOZ_ASSUME_UNREACHABLE("No such execution mode");
   415     }
   417     if (!encode(snapshot))
   418         return false;
   420     // Though the assembler doesn't track all frame pushes, at least make sure
   421     // the known value makes sense. We can't use bailout tables if the stack
   422     // isn't properly aligned to the static frame size.
   423     JS_ASSERT_IF(frameClass_ != FrameSizeClass::None() && deoptTable_,
   424                  frameClass_.frameSize() == masm.framePushed());
   426 #ifdef JS_CODEGEN_X86
   427     // On x64, bailout tables are pointless, because 16 extra bytes are
   428     // reserved per external jump, whereas it takes only 10 bytes to encode a
   429     // a non-table based bailout.
   430     if (assignBailoutId(snapshot)) {
   431         binder(masm, deoptTable_->raw() + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE);
   432         return true;
   433     }
   434 #endif
   436     // We could not use a jump table, either because all bailout IDs were
   437     // reserved, or a jump table is not optimal for this frame size or
   438     // platform. Whatever, we will generate a lazy bailout.
   439     OutOfLineBailout *ool = new(alloc()) OutOfLineBailout(snapshot);
   440     if (!addOutOfLineCode(ool))
   441         return false;
   443     binder(masm, ool->entry());
   444     return true;
   445 }
   447 bool
   448 CodeGeneratorX86Shared::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
   449 {
   450     return bailout(BailoutJump(condition), snapshot);
   451 }
   453 bool
   454 CodeGeneratorX86Shared::bailoutIf(Assembler::DoubleCondition condition, LSnapshot *snapshot)
   455 {
   456     JS_ASSERT(Assembler::NaNCondFromDoubleCondition(condition) == Assembler::NaN_HandledByCond);
   457     return bailoutIf(Assembler::ConditionFromDoubleCondition(condition), snapshot);
   458 }
   460 bool
   461 CodeGeneratorX86Shared::bailoutFrom(Label *label, LSnapshot *snapshot)
   462 {
   463     JS_ASSERT(label->used() && !label->bound());
   464     return bailout(BailoutLabel(label), snapshot);
   465 }
   467 bool
   468 CodeGeneratorX86Shared::bailout(LSnapshot *snapshot)
   469 {
   470     Label label;
   471     masm.jump(&label);
   472     return bailoutFrom(&label, snapshot);
   473 }
   475 bool
   476 CodeGeneratorX86Shared::visitOutOfLineBailout(OutOfLineBailout *ool)
   477 {
   478     masm.push(Imm32(ool->snapshot()->snapshotOffset()));
   479     masm.jmp(&deoptLabel_);
   480     return true;
   481 }
   483 bool
   484 CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
   485 {
   486     FloatRegister first = ToFloatRegister(ins->first());
   487     FloatRegister second = ToFloatRegister(ins->second());
   488 #ifdef DEBUG
   489     FloatRegister output = ToFloatRegister(ins->output());
   490     JS_ASSERT(first == output);
   491 #endif
   493     Label done, nan, minMaxInst;
   495     // Do a ucomisd to catch equality and NaNs, which both require special
   496     // handling. If the operands are ordered and inequal, we branch straight to
   497     // the min/max instruction. If we wanted, we could also branch for less-than
   498     // or greater-than here instead of using min/max, however these conditions
   499     // will sometimes be hard on the branch predictor.
   500     masm.ucomisd(first, second);
   501     masm.j(Assembler::NotEqual, &minMaxInst);
   502     if (!ins->mir()->range() || ins->mir()->range()->canBeNaN())
   503         masm.j(Assembler::Parity, &nan);
   505     // Ordered and equal. The operands are bit-identical unless they are zero
   506     // and negative zero. These instructions merge the sign bits in that
   507     // case, and are no-ops otherwise.
   508     if (ins->mir()->isMax())
   509         masm.andpd(second, first);
   510     else
   511         masm.orpd(second, first);
   512     masm.jump(&done);
   514     // x86's min/max are not symmetric; if either operand is a NaN, they return
   515     // the read-only operand. We need to return a NaN if either operand is a
   516     // NaN, so we explicitly check for a NaN in the read-write operand.
   517     if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) {
   518         masm.bind(&nan);
   519         masm.ucomisd(first, first);
   520         masm.j(Assembler::Parity, &done);
   521     }
   523     // When the values are inequal, or second is NaN, x86's min and max will
   524     // return the value we need.
   525     masm.bind(&minMaxInst);
   526     if (ins->mir()->isMax())
   527         masm.maxsd(second, first);
   528     else
   529         masm.minsd(second, first);
   531     masm.bind(&done);
   532     return true;
   533 }
   535 bool
   536 CodeGeneratorX86Shared::visitAbsD(LAbsD *ins)
   537 {
   538     FloatRegister input = ToFloatRegister(ins->input());
   539     JS_ASSERT(input == ToFloatRegister(ins->output()));
   540     // Load a value which is all ones except for the sign bit.
   541     masm.loadConstantDouble(SpecificNaN<double>(0, FloatingPoint<double>::SignificandBits),
   542                             ScratchFloatReg);
   543     masm.andpd(ScratchFloatReg, input);
   544     return true;
   545 }
   547 bool
   548 CodeGeneratorX86Shared::visitAbsF(LAbsF *ins)
   549 {
   550     FloatRegister input = ToFloatRegister(ins->input());
   551     JS_ASSERT(input == ToFloatRegister(ins->output()));
   552     // Same trick as visitAbsD above.
   553     masm.loadConstantFloat32(SpecificNaN<float>(0, FloatingPoint<float>::SignificandBits),
   554                              ScratchFloatReg);
   555     masm.andps(ScratchFloatReg, input);
   556     return true;
   557 }
   559 bool
   560 CodeGeneratorX86Shared::visitSqrtD(LSqrtD *ins)
   561 {
   562     FloatRegister input = ToFloatRegister(ins->input());
   563     FloatRegister output = ToFloatRegister(ins->output());
   564     masm.sqrtsd(input, output);
   565     return true;
   566 }
   568 bool
   569 CodeGeneratorX86Shared::visitSqrtF(LSqrtF *ins)
   570 {
   571     FloatRegister input = ToFloatRegister(ins->input());
   572     FloatRegister output = ToFloatRegister(ins->output());
   573     masm.sqrtss(input, output);
   574     return true;
   575 }
   577 bool
   578 CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
   579 {
   580     FloatRegister input = ToFloatRegister(ins->input());
   581     JS_ASSERT(input == ToFloatRegister(ins->output()));
   583     Label done, sqrt;
   585     if (!ins->mir()->operandIsNeverNegativeInfinity()) {
   586         // Branch if not -Infinity.
   587         masm.loadConstantDouble(NegativeInfinity<double>(), ScratchFloatReg);
   589         Assembler::DoubleCondition cond = Assembler::DoubleNotEqualOrUnordered;
   590         if (ins->mir()->operandIsNeverNaN())
   591             cond = Assembler::DoubleNotEqual;
   592         masm.branchDouble(cond, input, ScratchFloatReg, &sqrt);
   594         // Math.pow(-Infinity, 0.5) == Infinity.
   595         masm.xorpd(input, input);
   596         masm.subsd(ScratchFloatReg, input);
   597         masm.jump(&done);
   599         masm.bind(&sqrt);
   600     }
   602     if (!ins->mir()->operandIsNeverNegativeZero()) {
   603         // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). Adding 0 converts any -0 to 0.
   604         masm.xorpd(ScratchFloatReg, ScratchFloatReg);
   605         masm.addsd(ScratchFloatReg, input);
   606     }
   608     masm.sqrtsd(input, input);
   610     masm.bind(&done);
   611     return true;
   612 }
   614 class OutOfLineUndoALUOperation : public OutOfLineCodeBase<CodeGeneratorX86Shared>
   615 {
   616     LInstruction *ins_;
   618   public:
   619     OutOfLineUndoALUOperation(LInstruction *ins)
   620         : ins_(ins)
   621     { }
   623     virtual bool accept(CodeGeneratorX86Shared *codegen) {
   624         return codegen->visitOutOfLineUndoALUOperation(this);
   625     }
   626     LInstruction *ins() const {
   627         return ins_;
   628     }
   629 };
   631 bool
   632 CodeGeneratorX86Shared::visitAddI(LAddI *ins)
   633 {
   634     if (ins->rhs()->isConstant())
   635         masm.addl(Imm32(ToInt32(ins->rhs())), ToOperand(ins->lhs()));
   636     else
   637         masm.addl(ToOperand(ins->rhs()), ToRegister(ins->lhs()));
   639     if (ins->snapshot()) {
   640         if (ins->recoversInput()) {
   641             OutOfLineUndoALUOperation *ool = new(alloc()) OutOfLineUndoALUOperation(ins);
   642             if (!addOutOfLineCode(ool))
   643                 return false;
   644             masm.j(Assembler::Overflow, ool->entry());
   645         } else {
   646             if (!bailoutIf(Assembler::Overflow, ins->snapshot()))
   647                 return false;
   648         }
   649     }
   650     return true;
   651 }
   653 bool
   654 CodeGeneratorX86Shared::visitSubI(LSubI *ins)
   655 {
   656     if (ins->rhs()->isConstant())
   657         masm.subl(Imm32(ToInt32(ins->rhs())), ToOperand(ins->lhs()));
   658     else
   659         masm.subl(ToOperand(ins->rhs()), ToRegister(ins->lhs()));
   661     if (ins->snapshot()) {
   662         if (ins->recoversInput()) {
   663             OutOfLineUndoALUOperation *ool = new(alloc()) OutOfLineUndoALUOperation(ins);
   664             if (!addOutOfLineCode(ool))
   665                 return false;
   666             masm.j(Assembler::Overflow, ool->entry());
   667         } else {
   668             if (!bailoutIf(Assembler::Overflow, ins->snapshot()))
   669                 return false;
   670         }
   671     }
   672     return true;
   673 }
   675 bool
   676 CodeGeneratorX86Shared::visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation *ool)
   677 {
   678     LInstruction *ins = ool->ins();
   679     Register reg = ToRegister(ins->getDef(0));
   681     mozilla::DebugOnly<LAllocation *> lhs = ins->getOperand(0);
   682     LAllocation *rhs = ins->getOperand(1);
   684     JS_ASSERT(reg == ToRegister(lhs));
   685     JS_ASSERT_IF(rhs->isGeneralReg(), reg != ToRegister(rhs));
   687     // Undo the effect of the ALU operation, which was performed on the output
   688     // register and overflowed. Writing to the output register clobbered an
   689     // input reg, and the original value of the input needs to be recovered
   690     // to satisfy the constraint imposed by any RECOVERED_INPUT operands to
   691     // the bailout snapshot.
   693     if (rhs->isConstant()) {
   694         Imm32 constant(ToInt32(rhs));
   695         if (ins->isAddI())
   696             masm.subl(constant, reg);
   697         else
   698             masm.addl(constant, reg);
   699     } else {
   700         if (ins->isAddI())
   701             masm.subl(ToOperand(rhs), reg);
   702         else
   703             masm.addl(ToOperand(rhs), reg);
   704     }
   706     return bailout(ool->ins()->snapshot());
   707 }
   709 class MulNegativeZeroCheck : public OutOfLineCodeBase<CodeGeneratorX86Shared>
   710 {
   711     LMulI *ins_;
   713   public:
   714     MulNegativeZeroCheck(LMulI *ins)
   715       : ins_(ins)
   716     { }
   718     virtual bool accept(CodeGeneratorX86Shared *codegen) {
   719         return codegen->visitMulNegativeZeroCheck(this);
   720     }
   721     LMulI *ins() const {
   722         return ins_;
   723     }
   724 };
   726 bool
   727 CodeGeneratorX86Shared::visitMulI(LMulI *ins)
   728 {
   729     const LAllocation *lhs = ins->lhs();
   730     const LAllocation *rhs = ins->rhs();
   731     MMul *mul = ins->mir();
   732     JS_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow());
   734     if (rhs->isConstant()) {
   735         // Bailout on -0.0
   736         int32_t constant = ToInt32(rhs);
   737         if (mul->canBeNegativeZero() && constant <= 0) {
   738             Assembler::Condition bailoutCond = (constant == 0) ? Assembler::Signed : Assembler::Equal;
   739             masm.testl(ToRegister(lhs), ToRegister(lhs));
   740             if (!bailoutIf(bailoutCond, ins->snapshot()))
   741                     return false;
   742         }
   744         switch (constant) {
   745           case -1:
   746             masm.negl(ToOperand(lhs));
   747             break;
   748           case 0:
   749             masm.xorl(ToOperand(lhs), ToRegister(lhs));
   750             return true; // escape overflow check;
   751           case 1:
   752             // nop
   753             return true; // escape overflow check;
   754           case 2:
   755             masm.addl(ToOperand(lhs), ToRegister(lhs));
   756             break;
   757           default:
   758             if (!mul->canOverflow() && constant > 0) {
   759                 // Use shift if cannot overflow and constant is power of 2
   760                 int32_t shift = FloorLog2(constant);
   761                 if ((1 << shift) == constant) {
   762                     masm.shll(Imm32(shift), ToRegister(lhs));
   763                     return true;
   764                 }
   765             }
   766             masm.imull(Imm32(ToInt32(rhs)), ToRegister(lhs));
   767         }
   769         // Bailout on overflow
   770         if (mul->canOverflow() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
   771             return false;
   772     } else {
   773         masm.imull(ToOperand(rhs), ToRegister(lhs));
   775         // Bailout on overflow
   776         if (mul->canOverflow() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
   777             return false;
   779         if (mul->canBeNegativeZero()) {
   780             // Jump to an OOL path if the result is 0.
   781             MulNegativeZeroCheck *ool = new(alloc()) MulNegativeZeroCheck(ins);
   782             if (!addOutOfLineCode(ool))
   783                 return false;
   785             masm.testl(ToRegister(lhs), ToRegister(lhs));
   786             masm.j(Assembler::Zero, ool->entry());
   787             masm.bind(ool->rejoin());
   788         }
   789     }
   791     return true;
   792 }
   794 class ReturnZero : public OutOfLineCodeBase<CodeGeneratorX86Shared>
   795 {
   796     Register reg_;
   798   public:
   799     explicit ReturnZero(Register reg)
   800       : reg_(reg)
   801     { }
   803     virtual bool accept(CodeGeneratorX86Shared *codegen) {
   804         return codegen->visitReturnZero(this);
   805     }
   806     Register reg() const {
   807         return reg_;
   808     }
   809 };
   811 bool
   812 CodeGeneratorX86Shared::visitReturnZero(ReturnZero *ool)
   813 {
   814     masm.mov(ImmWord(0), ool->reg());
   815     masm.jmp(ool->rejoin());
   816     return true;
   817 }
   819 bool
   820 CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
   821 {
   822     Register lhs = ToRegister(ins->lhs());
   823     Register rhs = ToRegister(ins->rhs());
   824     Register output = ToRegister(ins->output());
   826     JS_ASSERT_IF(lhs != rhs, rhs != eax);
   827     JS_ASSERT(rhs != edx);
   828     JS_ASSERT_IF(output == eax, ToRegister(ins->remainder()) == edx);
   830     ReturnZero *ool = nullptr;
   832     // Put the lhs in eax.
   833     if (lhs != eax)
   834         masm.mov(lhs, eax);
   836     // Prevent divide by zero.
   837     if (ins->canBeDivideByZero()) {
   838         masm.testl(rhs, rhs);
   839         if (ins->mir()->isTruncated()) {
   840             if (!ool)
   841                 ool = new(alloc()) ReturnZero(output);
   842             masm.j(Assembler::Zero, ool->entry());
   843         } else {
   844             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
   845                 return false;
   846         }
   847     }
   849     // Zero extend the lhs into edx to make (edx:eax), since udiv is 64-bit.
   850     masm.mov(ImmWord(0), edx);
   851     masm.udiv(rhs);
   853     // Unsigned div or mod can return a value that's not a signed int32.
   854     // If our users aren't expecting that, bail.
   855     if (!ins->mir()->isTruncated()) {
   856         masm.testl(output, output);
   857         if (!bailoutIf(Assembler::Signed, ins->snapshot()))
   858             return false;
   859     }
   861     if (ool) {
   862         if (!addOutOfLineCode(ool))
   863             return false;
   864         masm.bind(ool->rejoin());
   865     }
   867     return true;
   868 }
   870 bool
   871 CodeGeneratorX86Shared::visitMulNegativeZeroCheck(MulNegativeZeroCheck *ool)
   872 {
   873     LMulI *ins = ool->ins();
   874     Register result = ToRegister(ins->output());
   875     Operand lhsCopy = ToOperand(ins->lhsCopy());
   876     Operand rhs = ToOperand(ins->rhs());
   877     JS_ASSERT_IF(lhsCopy.kind() == Operand::REG, lhsCopy.reg() != result.code());
   879     // Result is -0 if lhs or rhs is negative.
   880     masm.movl(lhsCopy, result);
   881     masm.orl(rhs, result);
   882     if (!bailoutIf(Assembler::Signed, ins->snapshot()))
   883         return false;
   885     masm.mov(ImmWord(0), result);
   886     masm.jmp(ool->rejoin());
   887     return true;
   888 }
   890 bool
   891 CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
   892 {
   893     Register lhs = ToRegister(ins->numerator());
   894     mozilla::DebugOnly<Register> output = ToRegister(ins->output());
   896     int32_t shift = ins->shift();
   897     bool negativeDivisor = ins->negativeDivisor();
   898     MDiv *mir = ins->mir();
   900     // We use defineReuseInput so these should always be the same, which is
   901     // convenient since all of our instructions here are two-address.
   902     JS_ASSERT(lhs == output);
   904     if (!mir->isTruncated() && negativeDivisor) {
   905         // 0 divided by a negative number must return a double.
   906         masm.testl(lhs, lhs);
   907         if (!bailoutIf(Assembler::Zero, ins->snapshot()))
   908             return false;
   909     }
   911     if (shift != 0) {
   912         if (!mir->isTruncated()) {
   913             // If the remainder is != 0, bailout since this must be a double.
   914             masm.testl(lhs, Imm32(UINT32_MAX >> (32 - shift)));
   915             if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
   916                 return false;
   917         }
   919         // Adjust the value so that shifting produces a correctly rounded result
   920         // when the numerator is negative. See 10-1 "Signed Division by a Known
   921         // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
   922         if (mir->canBeNegativeDividend()) {
   923             Register lhsCopy = ToRegister(ins->numeratorCopy());
   924             JS_ASSERT(lhsCopy != lhs);
   925             if (shift > 1)
   926                 masm.sarl(Imm32(31), lhs);
   927             masm.shrl(Imm32(32 - shift), lhs);
   928             masm.addl(lhsCopy, lhs);
   929         }
   931         masm.sarl(Imm32(shift), lhs);
   932         if (negativeDivisor)
   933             masm.negl(lhs);
   934     } else if (shift == 0 && negativeDivisor) {
   935         // INT32_MIN / -1 overflows.
   936         masm.negl(lhs);
   937         if (!mir->isTruncated() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
   938             return false;
   939     }
   941     return true;
   942 }
   944 bool
   945 CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
   946     Register lhs = ToRegister(ins->numerator());
   947     Register output = ToRegister(ins->output());
   948     int32_t d = ins->denominator();
   950     // This emits the division answer into edx or the modulus answer into eax.
   951     JS_ASSERT(output == eax || output == edx);
   952     JS_ASSERT(lhs != eax && lhs != edx);
   953     bool isDiv = (output == edx);
   955     // The absolute value of the denominator isn't a power of 2 (see LDivPowTwoI
   956     // and LModPowTwoI).
   957     JS_ASSERT((Abs(d) & (Abs(d) - 1)) != 0);
   959     // We will first divide by Abs(d), and negate the answer if d is negative.
   960     // If desired, this can be avoided by generalizing computeDivisionConstants.
   961     ReciprocalMulConstants rmc = computeDivisionConstants(Abs(d));
   963     // As explained in the comments of computeDivisionConstants, we first compute
   964     // X >> (32 + shift), where X is either (rmc.multiplier * n) if the multiplier
   965     // is non-negative or (rmc.multiplier * n) + (2^32 * n) otherwise. This is the
   966     // desired division result if n is non-negative, and is one less than the result
   967     // otherwise.
   968     masm.movl(Imm32(rmc.multiplier), eax);
   969     masm.imull(lhs);
   970     if (rmc.multiplier < 0)
   971         masm.addl(lhs, edx);
   972     masm.sarl(Imm32(rmc.shiftAmount), edx);
   974     // We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
   975     // computed with just a sign-extending shift of 31 bits.
   976     if (ins->canBeNegativeDividend()) {
   977         masm.movl(lhs, eax);
   978         masm.sarl(Imm32(31), eax);
   979         masm.subl(eax, edx);
   980     }
   982     // After this, edx contains the correct truncated division result.
   983     if (d < 0)
   984         masm.negl(edx);
   986     if (!isDiv) {
   987         masm.imull(Imm32(-d), edx, eax);
   988         masm.addl(lhs, eax);
   989     }
   991     if (!ins->mir()->isTruncated()) {
   992         if (isDiv) {
   993             // This is a division op. Multiply the obtained value by d to check if
   994             // the correct answer is an integer. This cannot overflow, since |d| > 1.
   995             masm.imull(Imm32(d), edx, eax);
   996             masm.cmpl(lhs, eax);
   997             if (!bailoutIf(Assembler::NotEqual, ins->snapshot()))
   998                 return false;
  1000             // If lhs is zero and the divisor is negative, the answer should have
  1001             // been -0.
  1002             if (d < 0) {
  1003                 masm.testl(lhs, lhs);
  1004                 if (!bailoutIf(Assembler::Zero, ins->snapshot()))
  1005                     return false;
  1007         } else if (ins->canBeNegativeDividend()) {
  1008             // This is a mod op. If the computed value is zero and lhs
  1009             // is negative, the answer should have been -0.
  1010             Label done;
  1012             masm.cmpl(lhs, Imm32(0));
  1013             masm.j(Assembler::GreaterThanOrEqual, &done);
  1015             masm.testl(eax, eax);
  1016             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
  1017                 return false;
  1019             masm.bind(&done);
  1023     return true;
  1026 bool
  1027 CodeGeneratorX86Shared::visitDivI(LDivI *ins)
  1029     Register remainder = ToRegister(ins->remainder());
  1030     Register lhs = ToRegister(ins->lhs());
  1031     Register rhs = ToRegister(ins->rhs());
  1032     Register output = ToRegister(ins->output());
  1034     MDiv *mir = ins->mir();
  1036     JS_ASSERT_IF(lhs != rhs, rhs != eax);
  1037     JS_ASSERT(rhs != edx);
  1038     JS_ASSERT(remainder == edx);
  1039     JS_ASSERT(output == eax);
  1041     Label done;
  1042     ReturnZero *ool = nullptr;
  1044     // Put the lhs in eax, for either the negative overflow case or the regular
  1045     // divide case.
  1046     if (lhs != eax)
  1047         masm.mov(lhs, eax);
  1049     // Handle divide by zero.
  1050     if (mir->canBeDivideByZero()) {
  1051         masm.testl(rhs, rhs);
  1052         if (mir->canTruncateInfinities()) {
  1053             // Truncated division by zero is zero (Infinity|0 == 0)
  1054             if (!ool)
  1055                 ool = new(alloc()) ReturnZero(output);
  1056             masm.j(Assembler::Zero, ool->entry());
  1057         } else {
  1058             JS_ASSERT(mir->fallible());
  1059             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
  1060                 return false;
  1064     // Handle an integer overflow exception from -2147483648 / -1.
  1065     if (mir->canBeNegativeOverflow()) {
  1066         Label notmin;
  1067         masm.cmpl(lhs, Imm32(INT32_MIN));
  1068         masm.j(Assembler::NotEqual, &notmin);
  1069         masm.cmpl(rhs, Imm32(-1));
  1070         if (mir->canTruncateOverflow()) {
  1071             // (-INT32_MIN)|0 == INT32_MIN and INT32_MIN is already in the
  1072             // output register (lhs == eax).
  1073             masm.j(Assembler::Equal, &done);
  1074         } else {
  1075             JS_ASSERT(mir->fallible());
  1076             if (!bailoutIf(Assembler::Equal, ins->snapshot()))
  1077                 return false;
  1079         masm.bind(&notmin);
  1082     // Handle negative 0.
  1083     if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
  1084         Label nonzero;
  1085         masm.testl(lhs, lhs);
  1086         masm.j(Assembler::NonZero, &nonzero);
  1087         masm.cmpl(rhs, Imm32(0));
  1088         if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
  1089             return false;
  1090         masm.bind(&nonzero);
  1093     // Sign extend the lhs into edx to make (edx:eax), since idiv is 64-bit.
  1094     if (lhs != eax)
  1095         masm.mov(lhs, eax);
  1096     masm.cdq();
  1097     masm.idiv(rhs);
  1099     if (!mir->canTruncateRemainder()) {
  1100         // If the remainder is > 0, bailout since this must be a double.
  1101         masm.testl(remainder, remainder);
  1102         if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
  1103             return false;
  1106     masm.bind(&done);
  1108     if (ool) {
  1109         if (!addOutOfLineCode(ool))
  1110             return false;
  1111         masm.bind(ool->rejoin());
  1114     return true;
  1117 bool
  1118 CodeGeneratorX86Shared::visitModPowTwoI(LModPowTwoI *ins)
  1120     Register lhs = ToRegister(ins->getOperand(0));
  1121     int32_t shift = ins->shift();
  1123     Label negative;
  1125     if (ins->mir()->canBeNegativeDividend()) {
  1126         // Switch based on sign of the lhs.
  1127         // Positive numbers are just a bitmask
  1128         masm.branchTest32(Assembler::Signed, lhs, lhs, &negative);
  1131     masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
  1133     if (ins->mir()->canBeNegativeDividend()) {
  1134         Label done;
  1135         masm.jump(&done);
  1137         // Negative numbers need a negate, bitmask, negate
  1138         masm.bind(&negative);
  1140         // Unlike in the visitModI case, we are not computing the mod by means of a
  1141         // division. Therefore, the divisor = -1 case isn't problematic (the andl
  1142         // always returns 0, which is what we expect).
  1143         //
  1144         // The negl instruction overflows if lhs == INT32_MIN, but this is also not
  1145         // a problem: shift is at most 31, and so the andl also always returns 0.
  1146         masm.negl(lhs);
  1147         masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
  1148         masm.negl(lhs);
  1150         // Since a%b has the same sign as b, and a is negative in this branch,
  1151         // an answer of 0 means the correct result is actually -0. Bail out.
  1152         if (!ins->mir()->isTruncated() && !bailoutIf(Assembler::Zero, ins->snapshot()))
  1153             return false;
  1154         masm.bind(&done);
  1156     return true;
  1160 class ModOverflowCheck : public OutOfLineCodeBase<CodeGeneratorX86Shared>
  1162     Label done_;
  1163     LModI *ins_;
  1164     Register rhs_;
  1166   public:
  1167     explicit ModOverflowCheck(LModI *ins, Register rhs)
  1168       : ins_(ins), rhs_(rhs)
  1169     { }
  1171     virtual bool accept(CodeGeneratorX86Shared *codegen) {
  1172         return codegen->visitModOverflowCheck(this);
  1174     Label *done() {
  1175         return &done_;
  1177     LModI *ins() const {
  1178         return ins_;
  1180     Register rhs() const {
  1181         return rhs_;
  1183 };
  1185 bool
  1186 CodeGeneratorX86Shared::visitModOverflowCheck(ModOverflowCheck *ool)
  1188     masm.cmpl(ool->rhs(), Imm32(-1));
  1189     if (ool->ins()->mir()->isTruncated()) {
  1190         masm.j(Assembler::NotEqual, ool->rejoin());
  1191         masm.mov(ImmWord(0), edx);
  1192         masm.jmp(ool->done());
  1193     } else {
  1194         if (!bailoutIf(Assembler::Equal, ool->ins()->snapshot()))
  1195             return false;
  1196        masm.jmp(ool->rejoin());
  1198     return true;
  1201 bool
  1202 CodeGeneratorX86Shared::visitModI(LModI *ins)
  1204     Register remainder = ToRegister(ins->remainder());
  1205     Register lhs = ToRegister(ins->lhs());
  1206     Register rhs = ToRegister(ins->rhs());
  1208     // Required to use idiv.
  1209     JS_ASSERT_IF(lhs != rhs, rhs != eax);
  1210     JS_ASSERT(rhs != edx);
  1211     JS_ASSERT(remainder == edx);
  1212     JS_ASSERT(ToRegister(ins->getTemp(0)) == eax);
  1214     Label done;
  1215     ReturnZero *ool = nullptr;
  1216     ModOverflowCheck *overflow = nullptr;
  1218     // Set up eax in preparation for doing a div.
  1219     if (lhs != eax)
  1220         masm.mov(lhs, eax);
  1222     // Prevent divide by zero.
  1223     if (ins->mir()->canBeDivideByZero()) {
  1224         masm.testl(rhs, rhs);
  1225         if (ins->mir()->isTruncated()) {
  1226             if (!ool)
  1227                 ool = new(alloc()) ReturnZero(edx);
  1228             masm.j(Assembler::Zero, ool->entry());
  1229         } else {
  1230             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
  1231                 return false;
  1235     Label negative;
  1237     // Switch based on sign of the lhs.
  1238     if (ins->mir()->canBeNegativeDividend())
  1239         masm.branchTest32(Assembler::Signed, lhs, lhs, &negative);
  1241     // If lhs >= 0 then remainder = lhs % rhs. The remainder must be positive.
  1243         // Check if rhs is a power-of-two.
  1244         if (ins->mir()->canBePowerOfTwoDivisor()) {
  1245             JS_ASSERT(rhs != remainder);
  1247             // Rhs y is a power-of-two if (y & (y-1)) == 0. Note that if
  1248             // y is any negative number other than INT32_MIN, both y and
  1249             // y-1 will have the sign bit set so these are never optimized
  1250             // as powers-of-two. If y is INT32_MIN, y-1 will be INT32_MAX
  1251             // and because lhs >= 0 at this point, lhs & INT32_MAX returns
  1252             // the correct value.
  1253             Label notPowerOfTwo;
  1254             masm.mov(rhs, remainder);
  1255             masm.subl(Imm32(1), remainder);
  1256             masm.branchTest32(Assembler::NonZero, remainder, rhs, &notPowerOfTwo);
  1258                 masm.andl(lhs, remainder);
  1259                 masm.jmp(&done);
  1261             masm.bind(&notPowerOfTwo);
  1264         // Since lhs >= 0, the sign-extension will be 0
  1265         masm.mov(ImmWord(0), edx);
  1266         masm.idiv(rhs);
  1269     // Otherwise, we have to beware of two special cases:
  1270     if (ins->mir()->canBeNegativeDividend()) {
  1271         masm.jump(&done);
  1273         masm.bind(&negative);
  1275         // Prevent an integer overflow exception from -2147483648 % -1
  1276         Label notmin;
  1277         masm.cmpl(lhs, Imm32(INT32_MIN));
  1278         overflow = new(alloc()) ModOverflowCheck(ins, rhs);
  1279         masm.j(Assembler::Equal, overflow->entry());
  1280         masm.bind(overflow->rejoin());
  1281         masm.cdq();
  1282         masm.idiv(rhs);
  1284         if (!ins->mir()->isTruncated()) {
  1285             // A remainder of 0 means that the rval must be -0, which is a double.
  1286             masm.testl(remainder, remainder);
  1287             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
  1288                 return false;
  1292     masm.bind(&done);
  1294     if (overflow) {
  1295         if (!addOutOfLineCode(overflow))
  1296             return false;
  1297         masm.bind(overflow->done());
  1300     if (ool) {
  1301         if (!addOutOfLineCode(ool))
  1302             return false;
  1303         masm.bind(ool->rejoin());
  1306     return true;
  1309 bool
  1310 CodeGeneratorX86Shared::visitBitNotI(LBitNotI *ins)
  1312     const LAllocation *input = ins->getOperand(0);
  1313     JS_ASSERT(!input->isConstant());
  1315     masm.notl(ToOperand(input));
  1316     return true;
  1319 bool
  1320 CodeGeneratorX86Shared::visitBitOpI(LBitOpI *ins)
  1322     const LAllocation *lhs = ins->getOperand(0);
  1323     const LAllocation *rhs = ins->getOperand(1);
  1325     switch (ins->bitop()) {
  1326         case JSOP_BITOR:
  1327             if (rhs->isConstant())
  1328                 masm.orl(Imm32(ToInt32(rhs)), ToOperand(lhs));
  1329             else
  1330                 masm.orl(ToOperand(rhs), ToRegister(lhs));
  1331             break;
  1332         case JSOP_BITXOR:
  1333             if (rhs->isConstant())
  1334                 masm.xorl(Imm32(ToInt32(rhs)), ToOperand(lhs));
  1335             else
  1336                 masm.xorl(ToOperand(rhs), ToRegister(lhs));
  1337             break;
  1338         case JSOP_BITAND:
  1339             if (rhs->isConstant())
  1340                 masm.andl(Imm32(ToInt32(rhs)), ToOperand(lhs));
  1341             else
  1342                 masm.andl(ToOperand(rhs), ToRegister(lhs));
  1343             break;
  1344         default:
  1345             MOZ_ASSUME_UNREACHABLE("unexpected binary opcode");
  1348     return true;
  1351 bool
  1352 CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
  1354     Register lhs = ToRegister(ins->lhs());
  1355     const LAllocation *rhs = ins->rhs();
  1357     if (rhs->isConstant()) {
  1358         int32_t shift = ToInt32(rhs) & 0x1F;
  1359         switch (ins->bitop()) {
  1360           case JSOP_LSH:
  1361             if (shift)
  1362                 masm.shll(Imm32(shift), lhs);
  1363             break;
  1364           case JSOP_RSH:
  1365             if (shift)
  1366                 masm.sarl(Imm32(shift), lhs);
  1367             break;
  1368           case JSOP_URSH:
  1369             if (shift) {
  1370                 masm.shrl(Imm32(shift), lhs);
  1371             } else if (ins->mir()->toUrsh()->fallible()) {
  1372                 // x >>> 0 can overflow.
  1373                 masm.testl(lhs, lhs);
  1374                 if (!bailoutIf(Assembler::Signed, ins->snapshot()))
  1375                     return false;
  1377             break;
  1378           default:
  1379             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
  1381     } else {
  1382         JS_ASSERT(ToRegister(rhs) == ecx);
  1383         switch (ins->bitop()) {
  1384           case JSOP_LSH:
  1385             masm.shll_cl(lhs);
  1386             break;
  1387           case JSOP_RSH:
  1388             masm.sarl_cl(lhs);
  1389             break;
  1390           case JSOP_URSH:
  1391             masm.shrl_cl(lhs);
  1392             if (ins->mir()->toUrsh()->fallible()) {
  1393                 // x >>> 0 can overflow.
  1394                 masm.testl(lhs, lhs);
  1395                 if (!bailoutIf(Assembler::Signed, ins->snapshot()))
  1396                     return false;
  1398             break;
  1399           default:
  1400             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
  1404     return true;
  1407 bool
  1408 CodeGeneratorX86Shared::visitUrshD(LUrshD *ins)
  1410     Register lhs = ToRegister(ins->lhs());
  1411     JS_ASSERT(ToRegister(ins->temp()) == lhs);
  1413     const LAllocation *rhs = ins->rhs();
  1414     FloatRegister out = ToFloatRegister(ins->output());
  1416     if (rhs->isConstant()) {
  1417         int32_t shift = ToInt32(rhs) & 0x1F;
  1418         if (shift)
  1419             masm.shrl(Imm32(shift), lhs);
  1420     } else {
  1421         JS_ASSERT(ToRegister(rhs) == ecx);
  1422         masm.shrl_cl(lhs);
  1425     masm.convertUInt32ToDouble(lhs, out);
  1426     return true;
  1429 MoveOperand
  1430 CodeGeneratorX86Shared::toMoveOperand(const LAllocation *a) const
  1432     if (a->isGeneralReg())
  1433         return MoveOperand(ToRegister(a));
  1434     if (a->isFloatReg())
  1435         return MoveOperand(ToFloatRegister(a));
  1436     return MoveOperand(StackPointer, ToStackOffset(a));
  1439 class OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorX86Shared>
  1441     MTableSwitch *mir_;
  1442     CodeLabel jumpLabel_;
  1444     bool accept(CodeGeneratorX86Shared *codegen) {
  1445         return codegen->visitOutOfLineTableSwitch(this);
  1448   public:
  1449     OutOfLineTableSwitch(MTableSwitch *mir)
  1450       : mir_(mir)
  1451     {}
  1453     MTableSwitch *mir() const {
  1454         return mir_;
  1457     CodeLabel *jumpLabel() {
  1458         return &jumpLabel_;
  1460 };
  1462 bool
  1463 CodeGeneratorX86Shared::visitOutOfLineTableSwitch(OutOfLineTableSwitch *ool)
  1465     MTableSwitch *mir = ool->mir();
  1467     masm.align(sizeof(void*));
  1468     masm.bind(ool->jumpLabel()->src());
  1469     if (!masm.addCodeLabel(*ool->jumpLabel()))
  1470         return false;
  1472     for (size_t i = 0; i < mir->numCases(); i++) {
  1473         LBlock *caseblock = mir->getCase(i)->lir();
  1474         Label *caseheader = caseblock->label();
  1475         uint32_t caseoffset = caseheader->offset();
  1477         // The entries of the jump table need to be absolute addresses and thus
  1478         // must be patched after codegen is finished.
  1479         CodeLabel cl;
  1480         masm.writeCodePointer(cl.dest());
  1481         cl.src()->bind(caseoffset);
  1482         if (!masm.addCodeLabel(cl))
  1483             return false;
  1486     return true;
  1489 bool
  1490 CodeGeneratorX86Shared::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
  1491                                                 const Register &base)
  1493     Label *defaultcase = mir->getDefault()->lir()->label();
  1495     // Lower value with low value
  1496     if (mir->low() != 0)
  1497         masm.subl(Imm32(mir->low()), index);
  1499     // Jump to default case if input is out of range
  1500     int32_t cases = mir->numCases();
  1501     masm.cmpl(index, Imm32(cases));
  1502     masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
  1504     // To fill in the CodeLabels for the case entries, we need to first
  1505     // generate the case entries (we don't yet know their offsets in the
  1506     // instruction stream).
  1507     OutOfLineTableSwitch *ool = new(alloc()) OutOfLineTableSwitch(mir);
  1508     if (!addOutOfLineCode(ool))
  1509         return false;
  1511     // Compute the position where a pointer to the right case stands.
  1512     masm.mov(ool->jumpLabel()->dest(), base);
  1513     Operand pointer = Operand(base, index, ScalePointer);
  1515     // Jump to the right case
  1516     masm.jmp(pointer);
  1518     return true;
  1521 bool
  1522 CodeGeneratorX86Shared::visitMathD(LMathD *math)
  1524     FloatRegister lhs = ToFloatRegister(math->lhs());
  1525     Operand rhs = ToOperand(math->rhs());
  1527     JS_ASSERT(ToFloatRegister(math->output()) == lhs);
  1529     switch (math->jsop()) {
  1530       case JSOP_ADD:
  1531         masm.addsd(rhs, lhs);
  1532         break;
  1533       case JSOP_SUB:
  1534         masm.subsd(rhs, lhs);
  1535         break;
  1536       case JSOP_MUL:
  1537         masm.mulsd(rhs, lhs);
  1538         break;
  1539       case JSOP_DIV:
  1540         masm.divsd(rhs, lhs);
  1541         break;
  1542       default:
  1543         MOZ_ASSUME_UNREACHABLE("unexpected opcode");
  1545     return true;
  1548 bool
  1549 CodeGeneratorX86Shared::visitMathF(LMathF *math)
  1551     FloatRegister lhs = ToFloatRegister(math->lhs());
  1552     Operand rhs = ToOperand(math->rhs());
  1554     JS_ASSERT(ToFloatRegister(math->output()) == lhs);
  1556     switch (math->jsop()) {
  1557       case JSOP_ADD:
  1558         masm.addss(rhs, lhs);
  1559         break;
  1560       case JSOP_SUB:
  1561         masm.subss(rhs, lhs);
  1562         break;
  1563       case JSOP_MUL:
  1564         masm.mulss(rhs, lhs);
  1565         break;
  1566       case JSOP_DIV:
  1567         masm.divss(rhs, lhs);
  1568         break;
  1569       default:
  1570         MOZ_ASSUME_UNREACHABLE("unexpected opcode");
  1571         return false;
  1573     return true;
  1576 bool
  1577 CodeGeneratorX86Shared::visitFloor(LFloor *lir)
  1579     FloatRegister input = ToFloatRegister(lir->input());
  1580     FloatRegister scratch = ScratchFloatReg;
  1581     Register output = ToRegister(lir->output());
  1583     Label bailout;
  1585     if (AssemblerX86Shared::HasSSE41()) {
  1586         // Bail on negative-zero.
  1587         masm.branchNegativeZero(input, output, &bailout);
  1588         if (!bailoutFrom(&bailout, lir->snapshot()))
  1589             return false;
  1591         // Round toward -Infinity.
  1592         masm.roundsd(input, scratch, JSC::X86Assembler::RoundDown);
  1594         masm.cvttsd2si(scratch, output);
  1595         masm.cmp32(output, Imm32(INT_MIN));
  1596         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1597             return false;
  1598     } else {
  1599         Label negative, end;
  1601         // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
  1602         masm.xorpd(scratch, scratch);
  1603         masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &negative);
  1605         // Bail on negative-zero.
  1606         masm.branchNegativeZero(input, output, &bailout);
  1607         if (!bailoutFrom(&bailout, lir->snapshot()))
  1608             return false;
  1610         // Input is non-negative, so truncation correctly rounds.
  1611         masm.cvttsd2si(input, output);
  1612         masm.cmp32(output, Imm32(INT_MIN));
  1613         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1614             return false;
  1616         masm.jump(&end);
  1618         // Input is negative, but isn't -0.
  1619         // Negative values go on a comparatively expensive path, since no
  1620         // native rounding mode matches JS semantics. Still better than callVM.
  1621         masm.bind(&negative);
  1623             // Truncate and round toward zero.
  1624             // This is off-by-one for everything but integer-valued inputs.
  1625             masm.cvttsd2si(input, output);
  1626             masm.cmp32(output, Imm32(INT_MIN));
  1627             if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1628                 return false;
  1630             // Test whether the input double was integer-valued.
  1631             masm.convertInt32ToDouble(output, scratch);
  1632             masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
  1634             // Input is not integer-valued, so we rounded off-by-one in the
  1635             // wrong direction. Correct by subtraction.
  1636             masm.subl(Imm32(1), output);
  1637             // Cannot overflow: output was already checked against INT_MIN.
  1640         masm.bind(&end);
  1642     return true;
  1645 bool
  1646 CodeGeneratorX86Shared::visitFloorF(LFloorF *lir)
  1648     FloatRegister input = ToFloatRegister(lir->input());
  1649     FloatRegister scratch = ScratchFloatReg;
  1650     Register output = ToRegister(lir->output());
  1652     Label bailout;
  1654     if (AssemblerX86Shared::HasSSE41()) {
  1655         // Bail on negative-zero.
  1656         masm.branchNegativeZeroFloat32(input, output, &bailout);
  1657         if (!bailoutFrom(&bailout, lir->snapshot()))
  1658             return false;
  1660         // Round toward -Infinity.
  1661         masm.roundss(input, scratch, JSC::X86Assembler::RoundDown);
  1663         masm.cvttss2si(scratch, output);
  1664         masm.cmp32(output, Imm32(INT_MIN));
  1665         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1666             return false;
  1667     } else {
  1668         Label negative, end;
  1670         // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
  1671         masm.xorps(scratch, scratch);
  1672         masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative);
  1674         // Bail on negative-zero.
  1675         masm.branchNegativeZeroFloat32(input, output, &bailout);
  1676         if (!bailoutFrom(&bailout, lir->snapshot()))
  1677             return false;
  1679         // Input is non-negative, so truncation correctly rounds.
  1680         masm.cvttss2si(input, output);
  1681         masm.cmp32(output, Imm32(INT_MIN));
  1682         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1683             return false;
  1685         masm.jump(&end);
  1687         // Input is negative, but isn't -0.
  1688         // Negative values go on a comparatively expensive path, since no
  1689         // native rounding mode matches JS semantics. Still better than callVM.
  1690         masm.bind(&negative);
  1692             // Truncate and round toward zero.
  1693             // This is off-by-one for everything but integer-valued inputs.
  1694             masm.cvttss2si(input, output);
  1695             masm.cmp32(output, Imm32(INT_MIN));
  1696             if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1697                 return false;
  1699             // Test whether the input double was integer-valued.
  1700             masm.convertInt32ToFloat32(output, scratch);
  1701             masm.branchFloat(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
  1703             // Input is not integer-valued, so we rounded off-by-one in the
  1704             // wrong direction. Correct by subtraction.
  1705             masm.subl(Imm32(1), output);
  1706             // Cannot overflow: output was already checked against INT_MIN.
  1709         masm.bind(&end);
  1711     return true;
  1714 bool
  1715 CodeGeneratorX86Shared::visitRound(LRound *lir)
  1717     FloatRegister input = ToFloatRegister(lir->input());
  1718     FloatRegister temp = ToFloatRegister(lir->temp());
  1719     FloatRegister scratch = ScratchFloatReg;
  1720     Register output = ToRegister(lir->output());
  1722     Label negative, end, bailout;
  1724     // Load 0.5 in the temp register.
  1725     masm.loadConstantDouble(0.5, temp);
  1727     // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
  1728     masm.xorpd(scratch, scratch);
  1729     masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &negative);
  1731     // Bail on negative-zero.
  1732     masm.branchNegativeZero(input, output, &bailout);
  1733     if (!bailoutFrom(&bailout, lir->snapshot()))
  1734         return false;
  1736     // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we
  1737     // have to add the input to the temp register (which contains 0.5) because
  1738     // we're not allowed to modify the input register.
  1739     masm.addsd(input, temp);
  1741     masm.cvttsd2si(temp, output);
  1742     masm.cmp32(output, Imm32(INT_MIN));
  1743     if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1744         return false;
  1746     masm.jump(&end);
  1749     // Input is negative, but isn't -0.
  1750     masm.bind(&negative);
  1752     if (AssemblerX86Shared::HasSSE41()) {
  1753         // Add 0.5 and round toward -Infinity. The result is stored in the temp
  1754         // register (currently contains 0.5).
  1755         masm.addsd(input, temp);
  1756         masm.roundsd(temp, scratch, JSC::X86Assembler::RoundDown);
  1758         // Truncate.
  1759         masm.cvttsd2si(scratch, output);
  1760         masm.cmp32(output, Imm32(INT_MIN));
  1761         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1762             return false;
  1764         // If the result is positive zero, then the actual result is -0. Bail.
  1765         // Otherwise, the truncation will have produced the correct negative integer.
  1766         masm.testl(output, output);
  1767         if (!bailoutIf(Assembler::Zero, lir->snapshot()))
  1768             return false;
  1770     } else {
  1771         masm.addsd(input, temp);
  1773         // Round toward -Infinity without the benefit of ROUNDSD.
  1775             // If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0.
  1776             masm.compareDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch);
  1777             if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot()))
  1778                 return false;
  1780             // Truncate and round toward zero.
  1781             // This is off-by-one for everything but integer-valued inputs.
  1782             masm.cvttsd2si(temp, output);
  1783             masm.cmp32(output, Imm32(INT_MIN));
  1784             if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1785                 return false;
  1787             // Test whether the truncated double was integer-valued.
  1788             masm.convertInt32ToDouble(output, scratch);
  1789             masm.branchDouble(Assembler::DoubleEqualOrUnordered, temp, scratch, &end);
  1791             // Input is not integer-valued, so we rounded off-by-one in the
  1792             // wrong direction. Correct by subtraction.
  1793             masm.subl(Imm32(1), output);
  1794             // Cannot overflow: output was already checked against INT_MIN.
  1798     masm.bind(&end);
  1799     return true;
  1802 bool
  1803 CodeGeneratorX86Shared::visitRoundF(LRoundF *lir)
  1805     FloatRegister input = ToFloatRegister(lir->input());
  1806     FloatRegister temp = ToFloatRegister(lir->temp());
  1807     FloatRegister scratch = ScratchFloatReg;
  1808     Register output = ToRegister(lir->output());
  1810     Label negative, end, bailout;
  1812     // Load 0.5 in the temp register.
  1813     masm.loadConstantFloat32(0.5f, temp);
  1815     // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
  1816     masm.xorps(scratch, scratch);
  1817     masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative);
  1819     // Bail on negative-zero.
  1820     masm.branchNegativeZeroFloat32(input, output, &bailout);
  1821     if (!bailoutFrom(&bailout, lir->snapshot()))
  1822         return false;
  1824     // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we
  1825     // have to add the input to the temp register (which contains 0.5) because
  1826     // we're not allowed to modify the input register.
  1827     masm.addss(input, temp);
  1829     masm.cvttss2si(temp, output);
  1830     masm.cmp32(output, Imm32(INT_MIN));
  1831     if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1832         return false;
  1834     masm.jump(&end);
  1837     // Input is negative, but isn't -0.
  1838     masm.bind(&negative);
  1840     if (AssemblerX86Shared::HasSSE41()) {
  1841         // Add 0.5 and round toward -Infinity. The result is stored in the temp
  1842         // register (currently contains 0.5).
  1843         masm.addss(input, temp);
  1844         masm.roundss(temp, scratch, JSC::X86Assembler::RoundDown);
  1846         // Truncate.
  1847         masm.cvttss2si(scratch, output);
  1848         masm.cmp32(output, Imm32(INT_MIN));
  1849         if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1850             return false;
  1852         // If the result is positive zero, then the actual result is -0. Bail.
  1853         // Otherwise, the truncation will have produced the correct negative integer.
  1854         masm.testl(output, output);
  1855         if (!bailoutIf(Assembler::Zero, lir->snapshot()))
  1856             return false;
  1858     } else {
  1859         masm.addss(input, temp);
  1860         // Round toward -Infinity without the benefit of ROUNDSS.
  1862             // If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0.
  1863             masm.compareFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch);
  1864             if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot()))
  1865                 return false;
  1867             // Truncate and round toward zero.
  1868             // This is off-by-one for everything but integer-valued inputs.
  1869             masm.cvttss2si(temp, output);
  1870             masm.cmp32(output, Imm32(INT_MIN));
  1871             if (!bailoutIf(Assembler::Equal, lir->snapshot()))
  1872                 return false;
  1874             // Test whether the truncated double was integer-valued.
  1875             masm.convertInt32ToFloat32(output, scratch);
  1876             masm.branchFloat(Assembler::DoubleEqualOrUnordered, temp, scratch, &end);
  1878             // Input is not integer-valued, so we rounded off-by-one in the
  1879             // wrong direction. Correct by subtraction.
  1880             masm.subl(Imm32(1), output);
  1881             // Cannot overflow: output was already checked against INT_MIN.
  1885     masm.bind(&end);
  1886     return true;
  1889 bool
  1890 CodeGeneratorX86Shared::visitGuardShape(LGuardShape *guard)
  1892     Register obj = ToRegister(guard->input());
  1893     masm.cmpPtr(Operand(obj, JSObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
  1895     return bailoutIf(Assembler::NotEqual, guard->snapshot());
  1898 bool
  1899 CodeGeneratorX86Shared::visitGuardObjectType(LGuardObjectType *guard)
  1901     Register obj = ToRegister(guard->input());
  1902     masm.cmpPtr(Operand(obj, JSObject::offsetOfType()), ImmGCPtr(guard->mir()->typeObject()));
  1904     Assembler::Condition cond =
  1905         guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
  1906     return bailoutIf(cond, guard->snapshot());
  1909 bool
  1910 CodeGeneratorX86Shared::visitGuardClass(LGuardClass *guard)
  1912     Register obj = ToRegister(guard->input());
  1913     Register tmp = ToRegister(guard->tempInt());
  1915     masm.loadPtr(Address(obj, JSObject::offsetOfType()), tmp);
  1916     masm.cmpPtr(Operand(tmp, types::TypeObject::offsetOfClasp()), ImmPtr(guard->mir()->getClass()));
  1917     if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
  1918         return false;
  1919     return true;
  1922 bool
  1923 CodeGeneratorX86Shared::visitEffectiveAddress(LEffectiveAddress *ins)
  1925     const MEffectiveAddress *mir = ins->mir();
  1926     Register base = ToRegister(ins->base());
  1927     Register index = ToRegister(ins->index());
  1928     Register output = ToRegister(ins->output());
  1929     masm.leal(Operand(base, index, mir->scale(), mir->displacement()), output);
  1930     return true;
  1933 Operand
  1934 CodeGeneratorX86Shared::createArrayElementOperand(Register elements, const LAllocation *index)
  1936     if (index->isConstant())
  1937         return Operand(elements, ToInt32(index) * sizeof(js::Value));
  1939     return Operand(elements, ToRegister(index), TimesEight);
  1941 bool
  1942 CodeGeneratorX86Shared::generateInvalidateEpilogue()
  1944     // Ensure that there is enough space in the buffer for the OsiPoint
  1945     // patching to occur. Otherwise, we could overwrite the invalidation
  1946     // epilogue.
  1947     for (size_t i = 0; i < sizeof(void *); i+= Assembler::nopSize())
  1948         masm.nop();
  1950     masm.bind(&invalidate_);
  1952     // Push the Ion script onto the stack (when we determine what that pointer is).
  1953     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
  1954     JitCode *thunk = gen->jitRuntime()->getInvalidationThunk();
  1956     masm.call(thunk);
  1958     // We should never reach this point in JIT code -- the invalidation thunk should
  1959     // pop the invalidated JS frame and return directly to its caller.
  1960     masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
  1961     return true;
  1964 bool
  1965 CodeGeneratorX86Shared::visitNegI(LNegI *ins)
  1967     Register input = ToRegister(ins->input());
  1968     JS_ASSERT(input == ToRegister(ins->output()));
  1970     masm.neg32(input);
  1971     return true;
  1974 bool
  1975 CodeGeneratorX86Shared::visitNegD(LNegD *ins)
  1977     FloatRegister input = ToFloatRegister(ins->input());
  1978     JS_ASSERT(input == ToFloatRegister(ins->output()));
  1980     masm.negateDouble(input);
  1981     return true;
  1984 bool
  1985 CodeGeneratorX86Shared::visitNegF(LNegF *ins)
  1987     FloatRegister input = ToFloatRegister(ins->input());
  1988     JS_ASSERT(input == ToFloatRegister(ins->output()));
  1990     masm.negateFloat(input);
  1991     return true;
  1994 bool
  1995 CodeGeneratorX86Shared::visitForkJoinGetSlice(LForkJoinGetSlice *ins)
  1997     MOZ_ASSERT(gen->info().executionMode() == ParallelExecution);
  1998     MOZ_ASSERT(ToRegister(ins->forkJoinContext()) == ForkJoinGetSliceReg_cx);
  1999     MOZ_ASSERT(ToRegister(ins->temp1()) == eax);
  2000     MOZ_ASSERT(ToRegister(ins->temp2()) == edx);
  2001     MOZ_ASSERT(ToRegister(ins->temp3()) == ForkJoinGetSliceReg_temp0);
  2002     MOZ_ASSERT(ToRegister(ins->temp4()) == ForkJoinGetSliceReg_temp1);
  2003     MOZ_ASSERT(ToRegister(ins->output()) == ForkJoinGetSliceReg_output);
  2005     masm.call(gen->jitRuntime()->forkJoinGetSliceStub());
  2006     return true;
  2009 JitCode *
  2010 JitRuntime::generateForkJoinGetSliceStub(JSContext *cx)
  2012 #ifdef JS_THREADSAFE
  2013     MacroAssembler masm(cx);
  2015     // We need two fixed temps. We need to fix eax for cmpxchg, and edx for
  2016     // div.
  2017     Register cxReg = ForkJoinGetSliceReg_cx, worker = cxReg;
  2018     Register pool = ForkJoinGetSliceReg_temp0;
  2019     Register bounds = ForkJoinGetSliceReg_temp1;
  2020     Register output = ForkJoinGetSliceReg_output;
  2022     MOZ_ASSERT(worker != eax && worker != edx);
  2023     MOZ_ASSERT(pool != eax && pool != edx);
  2024     MOZ_ASSERT(bounds != eax && bounds != edx);
  2025     MOZ_ASSERT(output != eax && output != edx);
  2027     Label stealWork, noMoreWork, gotSlice;
  2028     Operand workerSliceBounds(Address(worker, ThreadPoolWorker::offsetOfSliceBounds()));
  2030     // Clobber cx to load the worker.
  2031     masm.push(cxReg);
  2032     masm.loadPtr(Address(cxReg, ForkJoinContext::offsetOfWorker()), worker);
  2034     // Load the thread pool, which is used in all cases below.
  2035     masm.loadThreadPool(pool);
  2038         // Try to get a slice from the current thread.
  2039         Label getOwnSliceLoopHead;
  2040         masm.bind(&getOwnSliceLoopHead);
  2042         // Load the slice bounds for the current thread.
  2043         masm.loadSliceBounds(worker, bounds);
  2045         // The slice bounds is a uint32 composed from two uint16s:
  2046         // [ from          , to           ]
  2047         //   ^~~~            ^~
  2048         //   upper 16 bits | lower 16 bits
  2049         masm.move32(bounds, output);
  2050         masm.shrl(Imm32(16), output);
  2052         // If we don't have any slices left ourselves, move on to stealing.
  2053         masm.branch16(Assembler::Equal, output, bounds, &stealWork);
  2055         // If we still have work, try to CAS [ from+1, to ].
  2056         masm.move32(bounds, edx);
  2057         masm.add32(Imm32(0x10000), edx);
  2058         masm.move32(bounds, eax);
  2059         masm.atomic_cmpxchg32(edx, workerSliceBounds, eax);
  2060         masm.j(Assembler::NonZero, &getOwnSliceLoopHead);
  2062         // If the CAS succeeded, return |from| in output.
  2063         masm.jump(&gotSlice);
  2066     // Try to steal work.
  2067     masm.bind(&stealWork);
  2069     // It's not technically correct to test whether work-stealing is turned on
  2070     // only during stub-generation time, but it's a DEBUG only thing.
  2071     if (cx->runtime()->threadPool.workStealing()) {
  2072         Label stealWorkLoopHead;
  2073         masm.bind(&stealWorkLoopHead);
  2075         // Check if we have work.
  2076         masm.branch32(Assembler::Equal,
  2077                       Address(pool, ThreadPool::offsetOfPendingSlices()),
  2078                       Imm32(0), &noMoreWork);
  2080         // Get an id at random. The following is an inline of
  2081         // the 32-bit xorshift in ThreadPoolWorker::randomWorker().
  2083             // Reload the current worker.
  2084             masm.loadPtr(Address(StackPointer, 0), cxReg);
  2085             masm.loadPtr(Address(cxReg, ForkJoinContext::offsetOfWorker()), worker);
  2087             // Perform the xorshift to get a random number in eax, using edx
  2088             // as a temp.
  2089             Address rngState(worker, ThreadPoolWorker::offsetOfSchedulerRNGState());
  2090             masm.load32(rngState, eax);
  2091             masm.move32(eax, edx);
  2092             masm.shll(Imm32(ThreadPoolWorker::XORSHIFT_A), eax);
  2093             masm.xor32(edx, eax);
  2094             masm.move32(eax, edx);
  2095             masm.shrl(Imm32(ThreadPoolWorker::XORSHIFT_B), eax);
  2096             masm.xor32(edx, eax);
  2097             masm.move32(eax, edx);
  2098             masm.shll(Imm32(ThreadPoolWorker::XORSHIFT_C), eax);
  2099             masm.xor32(edx, eax);
  2100             masm.store32(eax, rngState);
  2102             // Compute the random worker id by computing % numWorkers. Reuse
  2103             // output as a temp.
  2104             masm.move32(Imm32(0), edx);
  2105             masm.move32(Imm32(cx->runtime()->threadPool.numWorkers()), output);
  2106             masm.udiv(output);
  2109         // Load the worker from the workers array.
  2110         masm.loadPtr(Address(pool, ThreadPool::offsetOfWorkers()), worker);
  2111         masm.loadPtr(BaseIndex(worker, edx, ScalePointer), worker);
  2113         // Try to get a slice from the designated victim worker.
  2114         Label stealSliceFromWorkerLoopHead;
  2115         masm.bind(&stealSliceFromWorkerLoopHead);
  2117         // Load the slice bounds and decompose for the victim worker.
  2118         masm.loadSliceBounds(worker, bounds);
  2119         masm.move32(bounds, eax);
  2120         masm.shrl(Imm32(16), eax);
  2122         // If the victim worker has no more slices left, find another worker.
  2123         masm.branch16(Assembler::Equal, eax, bounds, &stealWorkLoopHead);
  2125         // If the victim worker still has work, try to CAS [ from, to-1 ].
  2126         masm.move32(bounds, output);
  2127         masm.sub32(Imm32(1), output);
  2128         masm.move32(bounds, eax);
  2129         masm.atomic_cmpxchg32(output, workerSliceBounds, eax);
  2130         masm.j(Assembler::NonZero, &stealSliceFromWorkerLoopHead);
  2132         // If the CAS succeeded, return |to-1| in output.
  2133 #ifdef DEBUG
  2134         masm.atomic_inc32(Operand(Address(pool, ThreadPool::offsetOfStolenSlices())));
  2135 #endif
  2136         // Copies lower 16 bits only.
  2137         masm.movzwl(output, output);
  2140     // If we successfully got a slice, decrement pool->pendingSlices_ and
  2141     // return the slice.
  2142     masm.bind(&gotSlice);
  2143     masm.atomic_dec32(Operand(Address(pool, ThreadPool::offsetOfPendingSlices())));
  2144     masm.pop(cxReg);
  2145     masm.ret();
  2147     // There's no more slices to give out, return a sentinel value.
  2148     masm.bind(&noMoreWork);
  2149     masm.move32(Imm32(ThreadPool::MAX_SLICE_ID), output);
  2150     masm.pop(cxReg);
  2151     masm.ret();
  2153     Linker linker(masm);
  2154     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
  2156 #ifdef JS_ION_PERF
  2157     writePerfSpewerJitCodeProfile(code, "ForkJoinGetSliceStub");
  2158 #endif
  2160     return code;
  2161 #else
  2162     return nullptr;
  2163 #endif // JS_THREADSAFE
  2166 } // namespace jit
  2167 } // namespace js

mercurial