LCOV - code coverage report
Current view: directory - js/src/methodjit - FastArithmetic.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 883 846 95.8 %
Date: 2012-06-02 Functions: 20 20 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Brendan Eich <brendan@mozilla.org>
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   David Anderson <danderson@mozilla.com>
      25                 :  *   David Mandelin <dmandelin@mozilla.com>
      26                 :  *   Sean Stangl    <sstangl@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : #include "jsbool.h"
      42                 : #include "jslibmath.h"
      43                 : #include "jsnum.h"
      44                 : #include "methodjit/MethodJIT.h"
      45                 : #include "methodjit/Compiler.h"
      46                 : #include "methodjit/StubCalls.h"
      47                 : #include "methodjit/FrameState-inl.h"
      48                 : 
      49                 : using namespace js;
      50                 : using namespace js::mjit;
      51                 : using namespace js::analyze;
      52                 : using namespace JSC;
      53                 : 
      54                 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
      55                 : 
      56                 : bool
      57          675197 : mjit::Compiler::tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
      58                 :                                       FrameEntry *lhs, FrameEntry *rhs, Value *vp)
      59                 : {
      60          675197 :     if (!lhs->isConstant() || !rhs->isConstant())
      61          674276 :         return false;
      62                 : 
      63             921 :     const Value &L = lhs->getValue();
      64             921 :     const Value &R = rhs->getValue();
      65                 : 
      66            1659 :     if (!L.isPrimitive() || !R.isPrimitive() ||
      67             738 :         (op == JSOP_ADD && (L.isString() || R.isString()))) {
      68             192 :         return false;
      69                 :     }
      70                 : 
      71                 :     bool needInt;
      72             729 :     switch (op) {
      73                 :       case JSOP_ADD:
      74                 :       case JSOP_SUB:
      75                 :       case JSOP_MUL:
      76                 :       case JSOP_DIV:
      77             721 :         needInt = false;
      78             721 :         break;
      79                 : 
      80                 :       case JSOP_MOD:
      81              14 :         needInt = (L.isInt32() && R.isInt32() &&
      82              14 :                    L.toInt32() >= 0 && R.toInt32() > 0);
      83               8 :         break;
      84                 : 
      85                 :       default:
      86               0 :         JS_NOT_REACHED("NYI");
      87                 :         needInt = false; /* Silence compiler warning. */
      88                 :         break;
      89                 :     }
      90                 : 
      91             729 :     double dL = 0, dR = 0;
      92             729 :     int32_t nL = 0, nR = 0;
      93                 :     /*
      94                 :      * We don't need to check for conversion failure, since primitive conversion
      95                 :      * is infallible.
      96                 :      */
      97             729 :     if (needInt) {
      98               2 :         JS_ALWAYS_TRUE(ToInt32(cx, L, &nL));
      99               2 :         JS_ALWAYS_TRUE(ToInt32(cx, R, &nR));
     100                 :     } else {
     101             727 :         JS_ALWAYS_TRUE(ToNumber(cx, L, &dL));
     102             727 :         JS_ALWAYS_TRUE(ToNumber(cx, R, &dR));
     103                 :     }
     104                 : 
     105             729 :     switch (op) {
     106                 :       case JSOP_ADD:
     107             278 :         dL += dR;
     108             278 :         break;
     109                 :       case JSOP_SUB:
     110             124 :         dL -= dR;
     111             124 :         break;
     112                 :       case JSOP_MUL:
     113              60 :         dL *= dR;
     114              60 :         break;
     115                 :       case JSOP_DIV:
     116             259 :         dL = js::NumberDiv(dL, dR);
     117             259 :         break;
     118                 :       case JSOP_MOD:
     119               8 :         if (needInt)
     120               2 :             nL %= nR;
     121               6 :         else if (dR == 0)
     122               2 :             dL = js_NaN;
     123                 :         else
     124               4 :             dL = js_fmod(dL, dR);
     125               8 :         break;
     126                 : 
     127                 :       default:
     128               0 :         JS_NOT_REACHED("NYI");
     129                 :         break;
     130                 :     }
     131                 : 
     132             729 :     if (needInt)
     133               2 :         vp->setInt32(nL);
     134                 :     else
     135             727 :         vp->setNumber(dL);
     136                 : 
     137             729 :     return true;
     138                 : }
     139                 : 
     140                 : void
     141          276171 : mjit::Compiler::slowLoadConstantDouble(Assembler &masm,
     142                 :                                        FrameEntry *fe, FPRegisterID fpreg)
     143                 : {
     144          276171 :     if (fe->getValue().isInt32())
     145          275216 :         masm.slowLoadConstantDouble((double) fe->getValue().toInt32(), fpreg);
     146                 :     else
     147             955 :         masm.slowLoadConstantDouble(fe->getValue().toDouble(), fpreg);
     148          276171 : }
     149                 : 
     150                 : void
     151            2385 : mjit::Compiler::maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
     152                 :                                     MaybeRegisterID &mreg)
     153                 : {
     154            2385 :     if (!fe->isTypeKnown()) {
     155            2382 :         if (mreg.isSet())
     156            2354 :             mj.setJump(masm.testInt32(Assembler::NotEqual, mreg.reg()));
     157                 :         else
     158              28 :             mj.setJump(masm.testInt32(Assembler::NotEqual, frame.addressOf(fe)));
     159               3 :     } else if (fe->getKnownType() != JSVAL_TYPE_INT32) {
     160               0 :         mj.setJump(masm.jump());
     161                 :     }
     162            2385 : }
     163                 : 
     164                 : void
     165            2385 : mjit::Compiler::maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
     166                 :                                     MaybeRegisterID &mreg)
     167                 : {
     168            2385 :     if (!fe->isTypeKnown()) {
     169            2382 :         if (mreg.isSet())
     170            2354 :             mj.setJump(masm.testDouble(Assembler::NotEqual, mreg.reg()));
     171                 :         else
     172              28 :             mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe)));
     173               3 :     } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
     174               3 :         mj.setJump(masm.jump());
     175                 :     }
     176            2385 : }
     177                 : 
     178                 : bool
     179           68703 : mjit::Compiler::jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type,
     180                 :                                  FrameEntry *lhs, FrameEntry *rhs)
     181                 : {
     182                 :     bool isStringResult = (op == JSOP_ADD) &&
     183           68703 :                           (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING));
     184           68703 :     JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
     185                 : 
     186           68703 :     prepareStubCall(Uses(2));
     187           68703 :     INLINE_STUBCALL(stub, REJOIN_BINARY);
     188           68703 :     frame.popn(2);
     189           68703 :     frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
     190           68703 :     return true;
     191                 : }
     192                 : 
     193                 : bool
     194          671302 : mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
     195                 : {
     196          671302 :     FrameEntry *rhs = frame.peek(-1);
     197          671302 :     FrameEntry *lhs = frame.peek(-2);
     198                 : 
     199                 :     Value v;
     200          671302 :     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
     201             721 :         if (!v.isInt32() && typeSet && !typeSet->hasType(types::Type::DoubleType())) {
     202                 :             /*
     203                 :              * OK to ignore failure here, we aren't performing the operation
     204                 :              * itself. Note that monitorOverflow will propagate the type as
     205                 :              * necessary if a *INC operation overflowed.
     206                 :              */
     207               8 :             types::TypeScript::MonitorOverflow(cx, script, PC);
     208               8 :             return false;
     209                 :         }
     210             713 :         frame.popn(2);
     211             713 :         frame.push(v);
     212             713 :         return true;
     213                 :     }
     214                 : 
     215                 :     /*
     216                 :      * Bail out if there are unhandled types or ops.
     217                 :      * This is temporary while ops are still being implemented.
     218                 :      */
     219         2346418 :     if ((lhs->isConstant() && rhs->isConstant()) ||
     220          749052 :         (lhs->isTypeKnown() && (lhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) ||
     221          926785 :         (rhs->isTypeKnown() && (rhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)))
     222                 :     {
     223           68703 :         return jsop_binary_slow(op, stub, type, lhs, rhs);
     224                 :     }
     225                 : 
     226                 :     /*
     227                 :      * If this is an operation on which integer overflows can be ignored, treat
     228                 :      * the result as an integer even if it has been marked as overflowing by
     229                 :      * the interpreter. Doing this changes the values we maintain on the stack
     230                 :      * from those the interpreter would maintain; this is OK as values derived
     231                 :      * from ignored overflows are not live across points where the interpreter
     232                 :      * can join into JIT code (loop heads and safe points).
     233                 :      */
     234          601878 :     CrossSSAValue pushv(a->inlineIndex, SSAValue::PushedValue(PC - script->code, 0));
     235          601878 :     bool cannotOverflow = loop && loop->cannotIntegerOverflow(pushv);
     236          601878 :     bool ignoreOverflow = loop && loop->ignoreIntegerOverflow(pushv);
     237                 : 
     238          601878 :     if (rhs->isType(JSVAL_TYPE_INT32) && lhs->isType(JSVAL_TYPE_INT32) &&
     239                 :         op == JSOP_ADD && ignoreOverflow) {
     240              14 :         type = JSVAL_TYPE_INT32;
     241                 :     }
     242                 : 
     243                 :     /* Can do int math iff there is no double constant and the op is not division. */
     244                 :     bool canDoIntMath = op != JSOP_DIV && type != JSVAL_TYPE_DOUBLE &&
     245          601878 :                         !(rhs->isType(JSVAL_TYPE_DOUBLE) || lhs->isType(JSVAL_TYPE_DOUBLE));
     246                 : 
     247          601878 :     if (!masm.supportsFloatingPoint() && (!canDoIntMath || frame.haveSameBacking(lhs, rhs)))
     248               0 :         return jsop_binary_slow(op, stub, type, lhs, rhs);
     249                 : 
     250          601878 :     if (canDoIntMath)
     251          588997 :         jsop_binary_full(lhs, rhs, op, stub, type, cannotOverflow, ignoreOverflow);
     252                 :     else
     253           12881 :         jsop_binary_double(lhs, rhs, op, stub, type);
     254                 : 
     255          601878 :     return true;
     256                 : }
     257                 : 
     258                 : static void
     259          576208 : EmitDoubleOp(JSOp op, FPRegisterID fpRight, FPRegisterID fpLeft, Assembler &masm)
     260                 : {
     261          576208 :     switch (op) {
     262                 :       case JSOP_ADD:
     263          528861 :         masm.addDouble(fpRight, fpLeft);
     264          528861 :         break;
     265                 : 
     266                 :       case JSOP_SUB:
     267           34440 :         masm.subDouble(fpRight, fpLeft);
     268           34440 :         break;
     269                 : 
     270                 :       case JSOP_MUL:
     271            4933 :         masm.mulDouble(fpRight, fpLeft);
     272            4933 :         break;
     273                 : 
     274                 :       case JSOP_DIV:
     275            7974 :         masm.divDouble(fpRight, fpLeft);
     276            7974 :         break;
     277                 : 
     278                 :       default:
     279               0 :         JS_NOT_REACHED("unrecognized binary op");
     280                 :     }
     281          576208 : }
     282                 : 
     283                 : mjit::MaybeJump
     284           29947 : mjit::Compiler::loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated)
     285                 : {
     286           29947 :     MaybeJump notNumber;
     287                 : 
     288           29947 :     if (!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE)) {
     289            9698 :         *fpReg = frame.tempFPRegForData(fe);
     290            9698 :         *allocated = false;
     291            9698 :         return notNumber;
     292                 :     }
     293                 : 
     294           20249 :     *fpReg = frame.allocFPReg();
     295           20249 :     *allocated = true;
     296                 : 
     297           20249 :     if (fe->isConstant()) {
     298            8904 :         slowLoadConstantDouble(masm, fe, *fpReg);
     299           11345 :     } else if (!fe->isTypeKnown()) {
     300            8942 :         frame.tempRegForType(fe);
     301            8942 :         Jump j = frame.testDouble(Assembler::Equal, fe);
     302            8942 :         notNumber = frame.testInt32(Assembler::NotEqual, fe);
     303            8942 :         frame.convertInt32ToDouble(masm, fe, *fpReg);
     304            8942 :         Jump converted = masm.jump();
     305            8942 :         j.linkTo(masm.label(), &masm);
     306                 :         // CANDIDATE
     307            8942 :         frame.loadDouble(fe, *fpReg, masm);
     308            8942 :         converted.linkTo(masm.label(), &masm);
     309                 :     } else {
     310            2403 :         JS_ASSERT(fe->isType(JSVAL_TYPE_INT32));
     311            2403 :         frame.tempRegForData(fe);
     312            2403 :         frame.convertInt32ToDouble(masm, fe, *fpReg);
     313                 :     }
     314                 : 
     315           20249 :     return notNumber;
     316                 : }
     317                 : 
     318                 : /*
     319                 :  * This function emits a single fast-path for handling numerical arithmetic.
     320                 :  * Unlike jsop_binary_full(), all integers are converted to doubles.
     321                 :  */
     322                 : void
     323           12881 : mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op,
     324                 :                                    VoidStub stub, JSValueType type)
     325                 : {
     326                 :     FPRegisterID fpLeft, fpRight;
     327                 :     bool allocateLeft, allocateRight;
     328                 : 
     329           12881 :     MaybeJump lhsNotNumber = loadDouble(lhs, &fpLeft, &allocateLeft);
     330           12881 :     if (lhsNotNumber.isSet())
     331            7072 :         stubcc.linkExit(lhsNotNumber.get(), Uses(2));
     332                 : 
     333                 :     /* The left register holds the result, and needs to be mutable. */
     334           12881 :     if (!allocateLeft) {
     335            3614 :         FPRegisterID res = frame.allocFPReg();
     336            3614 :         masm.moveDouble(fpLeft, res);
     337            3614 :         fpLeft = res;
     338            3614 :         allocateLeft = true;
     339                 :     }
     340                 : 
     341           12881 :     MaybeJump rhsNotNumber;
     342           12881 :     if (frame.haveSameBacking(lhs, rhs)) {
     343              41 :         fpRight = fpLeft;
     344              41 :         allocateRight = false;
     345                 :     } else {
     346           12840 :         rhsNotNumber = loadDouble(rhs, &fpRight, &allocateRight);
     347           12840 :         if (rhsNotNumber.isSet())
     348            1639 :             stubcc.linkExit(rhsNotNumber.get(), Uses(2));
     349                 :     }
     350                 : 
     351           12881 :     EmitDoubleOp(op, fpRight, fpLeft, masm);
     352                 :     
     353           12881 :     MaybeJump done;
     354                 : 
     355                 :     /*
     356                 :      * Try to convert result to integer, if the result has unknown or integer type.
     357                 :      * Skip this for 1/x or -1/x, as the result is unlikely to fit in an int.
     358                 :      */
     359           26084 :     if (op == JSOP_DIV &&
     360                 :         (type == JSVAL_TYPE_INT32 ||
     361                 :          (type == JSVAL_TYPE_UNKNOWN &&
     362            6610 :           !(lhs->isConstant() && lhs->isType(JSVAL_TYPE_INT32) &&
     363             252 :             abs(lhs->getValue().toInt32()) == 1)))) {
     364            6845 :         RegisterID reg = frame.allocReg();
     365            6845 :         FPRegisterID fpReg = frame.allocFPReg();
     366           13690 :         JumpList isDouble;
     367            6845 :         masm.branchConvertDoubleToInt32(fpLeft, reg, isDouble, fpReg);
     368                 :         
     369                 :         masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), reg,
     370            6845 :                                       frame.addressOf(lhs));
     371                 :         
     372            6845 :         frame.freeReg(reg);
     373            6845 :         frame.freeReg(fpReg);
     374            6845 :         done.setJump(masm.jump());
     375                 : 
     376            6845 :         isDouble.linkTo(masm.label(), &masm);
     377                 :     }
     378                 : 
     379                 :     /*
     380                 :      * Inference needs to know about any operation on integers that produces a
     381                 :      * double result. Unless the pushed type set already contains the double
     382                 :      * type, we need to call a stub rather than push. Note that looking at
     383                 :      * the pushed type tag is not sufficient, as it will be UNKNOWN if
     384                 :      * we do not yet know the possible types of the division's operands.
     385                 :      */
     386           12881 :     types::TypeSet *resultTypes = pushedTypeSet(0);
     387           12881 :     if (resultTypes && !resultTypes->hasType(types::Type::DoubleType())) {
     388                 :         /*
     389                 :          * Call a stub and try harder to convert to int32, failing that trigger
     390                 :          * recompilation of this script.
     391                 :          */
     392             950 :         stubcc.linkExit(masm.jump(), Uses(2));
     393                 :     } else {
     394           11931 :         JS_ASSERT(type != JSVAL_TYPE_INT32);
     395           11931 :         if (type != JSVAL_TYPE_DOUBLE)
     396            6334 :             masm.storeDouble(fpLeft, frame.addressOf(lhs));
     397                 :     }
     398                 : 
     399           12881 :     if (done.isSet())
     400            6845 :         done.getJump().linkTo(masm.label(), &masm);
     401                 : 
     402           12881 :     stubcc.leave();
     403           12881 :     OOL_STUBCALL(stub, REJOIN_BINARY);
     404                 : 
     405           12881 :     if (allocateRight)
     406            9556 :         frame.freeReg(fpRight);
     407                 : 
     408           12881 :     frame.popn(2);
     409                 : 
     410           12881 :     if (type == JSVAL_TYPE_DOUBLE) {
     411            5597 :         frame.pushDouble(fpLeft);
     412                 :     } else {
     413            7284 :         frame.freeReg(fpLeft);
     414            7284 :         frame.pushSynced(type);
     415                 :     }
     416                 : 
     417           12881 :     stubcc.rejoin(Changes(1));
     418           12881 : }
     419                 : 
     420                 : /*
     421                 :  * Simpler version of jsop_binary_full() for when lhs == rhs.
     422                 :  */
     423                 : void
     424              89 : mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub, JSValueType type)
     425                 : {
     426              89 :     FrameEntry *lhs = frame.peek(-2);
     427                 : 
     428                 :     /* Easiest case: known double. Don't bother conversion back yet? */
     429              89 :     if (fe->isType(JSVAL_TYPE_DOUBLE)) {
     430               0 :         FPRegisterID fpreg = frame.allocFPReg();
     431               0 :         FPRegisterID lhs = frame.tempFPRegForData(fe);
     432               0 :         masm.moveDouble(lhs, fpreg);
     433               0 :         EmitDoubleOp(op, fpreg, fpreg, masm);
     434               0 :         frame.popn(2);
     435                 : 
     436               0 :         JS_ASSERT(type == JSVAL_TYPE_DOUBLE);  /* :XXX: can fail */
     437               0 :         frame.pushDouble(fpreg);
     438               0 :         return;
     439                 :     }
     440                 : 
     441                 :     /* Allocate all registers up-front. */
     442              89 :     FrameState::BinaryAlloc regs;
     443              89 :     frame.allocForSameBinary(fe, op, regs);
     444                 : 
     445              89 :     MaybeJump notNumber;
     446              89 :     MaybeJump doublePathDone;
     447              89 :     if (!fe->isTypeKnown()) {
     448              61 :         Jump notInt = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg());
     449              61 :         stubcc.linkExitDirect(notInt, stubcc.masm.label());
     450                 : 
     451              61 :         notNumber = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
     452              61 :         frame.loadDouble(fe, regs.lhsFP, stubcc.masm);
     453              61 :         EmitDoubleOp(op, regs.lhsFP, regs.lhsFP, stubcc.masm);
     454                 : 
     455                 :         /* Force the double back to memory. */
     456              61 :         Address result = frame.addressOf(lhs);
     457              61 :         stubcc.masm.storeDouble(regs.lhsFP, result);
     458                 : 
     459                 :         /* Load the payload into the result reg so the rejoin is safe. */
     460              61 :         stubcc.masm.loadPayload(result, regs.result);
     461                 : 
     462              61 :         doublePathDone = stubcc.masm.jump();
     463                 :     }
     464                 : 
     465                 :     /* Okay - good to emit the integer fast-path. */
     466              89 :     MaybeJump overflow;
     467              89 :     switch (op) {
     468                 :       case JSOP_ADD:
     469              35 :         overflow = masm.branchAdd32(Assembler::Overflow, regs.result, regs.result);
     470              35 :         break;
     471                 : 
     472                 :       case JSOP_SUB:
     473               0 :         overflow = masm.branchSub32(Assembler::Overflow, regs.result, regs.result);
     474               0 :         break;
     475                 : 
     476                 :       case JSOP_MUL:
     477              54 :         overflow = masm.branchMul32(Assembler::Overflow, regs.result, regs.result);
     478              54 :         break;
     479                 : 
     480                 :       default:
     481               0 :         JS_NOT_REACHED("unrecognized op");
     482                 :     }
     483                 :     
     484              89 :     JS_ASSERT(overflow.isSet());
     485                 : 
     486                 :     /*
     487                 :      * Integer overflow path. Restore the original values and make a stub call,
     488                 :      * which could trigger recompilation.
     489                 :      */
     490              89 :     stubcc.linkExitDirect(overflow.get(), stubcc.masm.label());
     491              89 :     frame.rematBinary(fe, NULL, regs, stubcc.masm);
     492              89 :     stubcc.syncExitAndJump(Uses(2));
     493                 : 
     494                 :     /* Slow paths funnel here. */
     495              89 :     if (notNumber.isSet())
     496              61 :         notNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     497                 : 
     498                 :     /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */
     499              89 :     frame.sync(stubcc.masm, Uses(2));
     500              89 :     stubcc.leave();
     501              89 :     OOL_STUBCALL(stub, REJOIN_BINARY);
     502                 : 
     503                 :     /* Finish up stack operations. */
     504              89 :     frame.popn(2);
     505                 : 
     506              89 :     if (type == JSVAL_TYPE_INT32)
     507              28 :         frame.pushTypedPayload(type, regs.result);
     508                 :     else
     509              61 :         frame.pushNumber(regs.result, true);
     510                 : 
     511              89 :     frame.freeReg(regs.lhsFP);
     512                 : 
     513                 :     /* Merge back OOL double path. */
     514              89 :     if (doublePathDone.isSet())
     515              61 :         stubcc.linkRejoin(doublePathDone.get());
     516                 : 
     517              89 :     stubcc.rejoin(Changes(1));
     518                 : }
     519                 : 
     520                 : /*
     521                 :  * This function emits multiple fast-paths for handling numerical arithmetic.
     522                 :  * Currently, it handles only ADD, SUB, and MUL, where both LHS and RHS are
     523                 :  * known not to be doubles.
     524                 :  *
     525                 :  * The control flow of the emitted code depends on which types are known.
     526                 :  * Given both types are unknown, the full spread looks like:
     527                 :  *
     528                 :  * Inline                              OOL
     529                 :  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     530                 :  * Is LHS Int32?  ------ No -------->  Is LHS Double?  ----- No -------,
     531                 :  *                                     Sync LHS                        |
     532                 :  *                                     Load LHS into XMM1              |
     533                 :  *                                     Is RHS Double? ---- Yes --,     |
     534                 :  *                                       Is RHS Int32? ---- No --|-----|
     535                 :  *                                       Convert RHS into XMM0   |     |
     536                 :  *                                     Else  <-------------------'     |
     537                 :  *                                       Sync RHS                      |
     538                 :  *                                       Load RHS into XMM0            |
     539                 :  *                                     [Add,Sub,Mul] XMM0,XMM1         |
     540                 :  *                                     Jump ---------------------,     |
     541                 :  *                                                               |     |
     542                 :  * Is RHS Int32?  ------ No ------->   Is RHS Double? ----- No --|-----|
     543                 :  *                                     Sync RHS                  |     |
     544                 :  *                                     Load RHS into XMM0        |     |
     545                 :  *                                     Convert LHS into XMM1     |     |
     546                 :  *                                     [Add,Sub,Mul] XMM0,XMM1   |     |
     547                 :  *                                     Jump ---------------------|   Slow Call
     548                 :  *                                                               |
     549                 :  * [Add,Sub,Mul] RHS, LHS                                        |
     550                 :  * Overflow      ------ Yes ------->   Convert RHS into XMM0     |
     551                 :  *                                     Convert LHS into XMM1     |
     552                 :  *                                     [Add,Sub,Mul] XMM0,XMM1   |
     553                 :  *                                     Sync XMM1 to stack    <---'
     554                 :  *  <--------------------------------- Rejoin
     555                 :  */
     556                 : void
     557          588997 : mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op,
     558                 :                                  VoidStub stub, JSValueType type,
     559                 :                                  bool cannotOverflow, bool ignoreOverflow)
     560                 : {
     561          588997 :     if (frame.haveSameBacking(lhs, rhs)) {
     562              89 :         jsop_binary_full_simple(lhs, op, stub, type);
     563              89 :         return;
     564                 :     }
     565                 : 
     566                 :     /* Allocate all registers up-front. */
     567          588908 :     FrameState::BinaryAlloc regs;
     568          588908 :     frame.allocForBinary(lhs, rhs, op, regs);
     569                 : 
     570                 :     /* Quick-test some invariants. */
     571          588908 :     JS_ASSERT_IF(lhs->isTypeKnown(), lhs->getKnownType() == JSVAL_TYPE_INT32);
     572          588908 :     JS_ASSERT_IF(rhs->isTypeKnown(), rhs->getKnownType() == JSVAL_TYPE_INT32);
     573                 : 
     574          588908 :     MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone;
     575          588908 :     if (!lhs->isTypeKnown())
     576          561916 :         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
     577                 : 
     578          588908 :     MaybeJump rhsNotNumber2;
     579          588908 :     if (!rhs->isTypeKnown())
     580          321793 :         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
     581                 : 
     582                 :     /* Perform the double addition. */
     583          588908 :     MaybeJump doublePathDone;
     584          588908 :     if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown())) {
     585                 :         /* If the LHS type was not known, link its path here. */
     586          563266 :         if (lhsUnknownDone.isSet())
     587          561916 :             lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     588                 :         
     589                 :         /* Perform the double operation. */
     590          563266 :         EmitDoubleOp(op, regs.rhsFP, regs.lhsFP, stubcc.masm);
     591                 : 
     592                 :         /* Force the double back to memory. */
     593          563266 :         Address result = frame.addressOf(lhs);
     594          563266 :         stubcc.masm.storeDouble(regs.lhsFP, result);
     595                 : 
     596                 :         /* Load the payload into the result reg so the rejoin is safe. */
     597          563266 :         stubcc.masm.loadPayload(result, regs.result);
     598                 : 
     599                 :         /* We'll link this back up later, at the bottom of the op. */
     600          563266 :         doublePathDone = stubcc.masm.jump();
     601                 :     }
     602                 : 
     603                 :     /* Time to do the integer path. Figure out the immutable side. */
     604          588908 :     int32_t value = 0;
     605          588908 :     JSOp origOp = op;
     606          588908 :     MaybeRegisterID reg;
     607          588908 :     MaybeJump preOverflow;
     608          588908 :     if (!regs.resultHasRhs) {
     609          586730 :         if (!regs.rhsData.isSet())
     610          262482 :             value = rhs->getValue().toInt32();
     611                 :         else
     612          324248 :             reg = regs.rhsData.reg();
     613                 :     } else {
     614            2178 :         if (!regs.lhsData.isSet())
     615            1426 :             value = lhs->getValue().toInt32();
     616                 :         else
     617             752 :             reg = regs.lhsData.reg();
     618            2178 :         if (op == JSOP_SUB) {
     619                 :             // If the RHS is 0x80000000, the smallest negative value, neg does
     620                 :             // not work. Guard against this and treat it as an overflow.
     621             598 :             preOverflow = masm.branch32(Assembler::Equal, regs.result, Imm32(0x80000000));
     622             598 :             masm.neg32(regs.result);
     623             598 :             op = JSOP_ADD;
     624                 :         }
     625                 :     }
     626                 : 
     627                 :     /* Okay - good to emit the integer fast-path. */
     628          588908 :     MaybeJump overflow;
     629          588908 :     switch (op) {
     630                 :       case JSOP_ADD:
     631          537928 :         if (cannotOverflow || ignoreOverflow) {
     632             460 :             if (reg.isSet())
     633             118 :                 masm.add32(reg.reg(), regs.result);
     634                 :             else
     635             112 :                 masm.add32(Imm32(value), regs.result);
     636                 :         } else {
     637          537698 :             if (reg.isSet())
     638          319018 :                 overflow = masm.branchAdd32(Assembler::Overflow, reg.reg(), regs.result);
     639                 :             else
     640          218680 :                 overflow = masm.branchAdd32(Assembler::Overflow, Imm32(value), regs.result);
     641                 :         }
     642          537928 :         break;
     643                 : 
     644                 :       case JSOP_SUB:
     645           47214 :         if (cannotOverflow) {
     646            1118 :             if (reg.isSet())
     647               0 :                 masm.sub32(reg.reg(), regs.result);
     648                 :             else
     649            1118 :                 masm.sub32(Imm32(value), regs.result);
     650                 :         } else {
     651           46096 :             if (reg.isSet())
     652            3979 :                 overflow = masm.branchSub32(Assembler::Overflow, reg.reg(), regs.result);
     653                 :             else
     654           42117 :                 overflow = masm.branchSub32(Assembler::Overflow, Imm32(value), regs.result);
     655                 :         }
     656           47214 :         break;
     657                 : 
     658                 :       case JSOP_MUL:
     659                 :       {
     660            3766 :         MaybeJump storeNegZero;
     661            3766 :         bool maybeNegZero = !ignoreOverflow;
     662            3766 :         bool hasConstant = (lhs->isConstant() || rhs->isConstant());
     663                 : 
     664            3766 :         if (hasConstant && maybeNegZero) {
     665            1878 :             value = (lhs->isConstant() ? lhs : rhs)->getValue().toInt32();
     666            1878 :             RegisterID nonConstReg = lhs->isConstant() ? regs.rhsData.reg() : regs.lhsData.reg();
     667                 : 
     668            1878 :             if (value > 0)
     669            1813 :                 maybeNegZero = false;
     670              65 :             else if (value < 0)
     671              57 :                 storeNegZero = masm.branchTest32(Assembler::Zero, nonConstReg);
     672                 :             else
     673               8 :                 storeNegZero = masm.branch32(Assembler::LessThan, nonConstReg, Imm32(0));
     674                 :         }
     675                 : 
     676            3766 :         if (cannotOverflow) {
     677              12 :             if (reg.isSet())
     678              12 :                 masm.mul32(reg.reg(), regs.result);
     679                 :             else
     680               0 :                 masm.mul32(Imm32(value), regs.result, regs.result);
     681                 :         } else {
     682            3754 :             if (reg.isSet()) {
     683            1873 :                 overflow = masm.branchMul32(Assembler::Overflow, reg.reg(), regs.result);
     684                 :             } else {
     685                 :                 overflow = masm.branchMul32(Assembler::Overflow, Imm32(value), regs.result,
     686            1881 :                                             regs.result);
     687                 :             }
     688                 :         }
     689                 : 
     690            3766 :         if (maybeNegZero) {
     691            1942 :             if (hasConstant) {
     692              65 :                 stubcc.linkExit(storeNegZero.get(), Uses(2));
     693                 :             } else {
     694            1877 :                 Jump isZero = masm.branchTest32(Assembler::Zero, regs.result);
     695            1877 :                 stubcc.linkExitDirect(isZero, stubcc.masm.label());
     696                 : 
     697                 :                 /* Restore original value. */
     698            1877 :                 if (regs.resultHasRhs) {
     699             233 :                     if (regs.rhsNeedsRemat)
     700             233 :                         stubcc.masm.loadPayload(frame.addressForDataRemat(rhs), regs.result);
     701                 :                     else
     702               0 :                         stubcc.masm.move(regs.rhsData.reg(), regs.result);
     703                 :                 } else {
     704            1644 :                     if (regs.lhsNeedsRemat)
     705             481 :                         stubcc.masm.loadPayload(frame.addressForDataRemat(lhs), regs.result);
     706                 :                     else
     707            1163 :                         stubcc.masm.move(regs.lhsData.reg(), regs.result);
     708                 :                 }
     709            1877 :                 storeNegZero = stubcc.masm.branchOr32(Assembler::Signed, reg.reg(), regs.result);
     710            1877 :                 stubcc.masm.xor32(regs.result, regs.result);
     711            1877 :                 stubcc.crossJump(stubcc.masm.jump(), masm.label());
     712            1877 :                 storeNegZero.getJump().linkTo(stubcc.masm.label(), &stubcc.masm);
     713            1877 :                 frame.rematBinary(lhs, rhs, regs, stubcc.masm);
     714                 :             }
     715            1942 :             stubcc.syncExitAndJump(Uses(2));
     716                 :         }
     717            3766 :         break;
     718                 :       }
     719                 : 
     720                 :       default:
     721               0 :         JS_NOT_REACHED("unrecognized op");
     722                 :     }
     723          588908 :     op = origOp;
     724                 :     
     725                 :     /*
     726                 :      * Integer overflow path. Restore the original values and make a stub call,
     727                 :      * which could trigger recompilation.
     728                 :      */
     729          588908 :     MaybeJump overflowDone;
     730          588908 :     if (preOverflow.isSet())
     731             598 :         stubcc.linkExitDirect(preOverflow.get(), stubcc.masm.label());
     732          588908 :     if (overflow.isSet())
     733          587548 :         stubcc.linkExitDirect(overflow.get(), stubcc.masm.label());
     734                 : 
     735                 :     /* Restore the original operand registers for ADD. */
     736          588908 :     if (regs.undoResult) {
     737           40964 :         if (reg.isSet()) {
     738            8639 :             JS_ASSERT(op == JSOP_ADD);
     739            8639 :             stubcc.masm.neg32(reg.reg());
     740            8639 :             stubcc.masm.add32(reg.reg(), regs.result);
     741            8639 :             stubcc.masm.neg32(reg.reg());
     742                 :         } else {
     743           32325 :             JS_ASSERT(op == JSOP_ADD || op == JSOP_SUB);
     744           32325 :             int32_t fixValue = (op == JSOP_ADD) ? -value : value;
     745           32325 :             stubcc.masm.add32(Imm32(fixValue), regs.result);
     746                 :         }
     747                 :     }
     748                 : 
     749          588908 :     frame.rematBinary(lhs, rhs, regs, stubcc.masm);
     750          588908 :     stubcc.syncExitAndJump(Uses(2));
     751                 : 
     752                 :     /* The register allocator creates at most one temporary. */
     753          588908 :     if (regs.extraFree.isSet())
     754               0 :         frame.freeReg(regs.extraFree.reg());
     755                 : 
     756                 :     /* Slow paths funnel here. */
     757          588908 :     if (lhsNotDouble.isSet()) {
     758          561916 :         lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     759          561916 :         if (rhsNotNumber.isSet())
     760          320443 :             rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     761                 :     }
     762          588908 :     if (rhsNotNumber2.isSet())
     763          321793 :         rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     764                 : 
     765                 :     /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */
     766          588908 :     frame.sync(stubcc.masm, Uses(2));
     767          588908 :     stubcc.leave();
     768          588908 :     OOL_STUBCALL(stub, REJOIN_BINARY);
     769                 : 
     770                 :     /* Finish up stack operations. */
     771          588908 :     frame.popn(2);
     772                 : 
     773                 :     /*
     774                 :      * Steal the result register if we remat the LHS/RHS by undoing the operation.
     775                 :      * In this case the result register was still assigned to the corresponding
     776                 :      * frame entry (so it is synced properly in OOL paths), so steal it back.
     777                 :      */
     778          588908 :     if (regs.undoResult)
     779           40964 :         frame.takeReg(regs.result);
     780                 : 
     781          588908 :     if (type == JSVAL_TYPE_INT32)
     782           29740 :         frame.pushTypedPayload(type, regs.result);
     783                 :     else
     784          559168 :         frame.pushNumber(regs.result, true);
     785                 : 
     786          588908 :     frame.freeReg(regs.lhsFP);
     787          588908 :     frame.freeReg(regs.rhsFP);
     788                 : 
     789                 :     /* Merge back OOL double path. */
     790          588908 :     if (doublePathDone.isSet())
     791          563266 :         stubcc.linkRejoin(doublePathDone.get());
     792                 : 
     793          588908 :     stubcc.rejoin(Changes(1));
     794                 : }
     795                 : 
     796                 : void
     797            3786 : mjit::Compiler::jsop_neg()
     798                 : {
     799            3786 :     FrameEntry *fe = frame.peek(-1);
     800            3786 :     JSValueType type = knownPushedType(0);
     801                 : 
     802            7468 :     if ((fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) ||
     803            3682 :         !masm.supportsFloatingPoint())
     804                 :     {
     805             104 :         prepareStubCall(Uses(1));
     806             104 :         INLINE_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
     807             104 :         frame.pop();
     808             104 :         frame.pushSynced(type);
     809             104 :         return;
     810                 :     }
     811                 : 
     812            3682 :     JS_ASSERT(!fe->isConstant());
     813                 : 
     814                 :     /* Handle negation of a known double, or of a known integer which has previously overflowed. */
     815            6560 :     if (fe->isType(JSVAL_TYPE_DOUBLE) ||
     816            2878 :         (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_DOUBLE))
     817                 :     {
     818                 :         FPRegisterID fpreg;
     819             865 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
     820             804 :             fpreg = frame.tempFPRegForData(fe);
     821                 :         } else {
     822              61 :             fpreg = frame.allocFPReg();
     823              61 :             frame.convertInt32ToDouble(masm, fe, fpreg);
     824                 :         }
     825                 : 
     826             865 :         FPRegisterID res = frame.allocFPReg();
     827             865 :         masm.moveDouble(fpreg, res);
     828             865 :         masm.negateDouble(res);
     829                 : 
     830             865 :         if (!fe->isType(JSVAL_TYPE_DOUBLE))
     831              61 :             frame.freeReg(fpreg);
     832                 : 
     833             865 :         frame.pop();
     834             865 :         frame.pushDouble(res);
     835                 : 
     836             865 :         return;
     837                 :     }
     838                 : 
     839                 :     /* Inline integer path for known integers. */
     840            2817 :     if (fe->isType(JSVAL_TYPE_INT32) && type == JSVAL_TYPE_INT32) {
     841             432 :         RegisterID reg = frame.copyDataIntoReg(fe);
     842                 : 
     843                 :         /* Test for 0 and -2147483648 (both result in a double). */
     844             432 :         Jump zeroOrMinInt = masm.branchTest32(Assembler::Zero, reg, Imm32(0x7fffffff));
     845             432 :         stubcc.linkExit(zeroOrMinInt, Uses(1));
     846                 : 
     847             432 :         masm.neg32(reg);
     848                 : 
     849             432 :         stubcc.leave();
     850             432 :         OOL_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
     851                 : 
     852             432 :         frame.pop();
     853             432 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
     854                 : 
     855             432 :         stubcc.rejoin(Changes(1));
     856             432 :         return;
     857                 :     }
     858                 : 
     859                 :     /* Load type information into register. */
     860            2385 :     MaybeRegisterID feTypeReg;
     861            2385 :     if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe)) {
     862                 :         /* Safe because only one type is loaded. */
     863            2354 :         feTypeReg.setReg(frame.tempRegForType(fe));
     864                 : 
     865                 :         /* Don't get clobbered by copyDataIntoReg(). */
     866            2354 :         frame.pinReg(feTypeReg.reg());
     867                 :     }
     868                 : 
     869            2385 :     RegisterID reg = frame.copyDataIntoReg(masm, fe);
     870            2385 :     Label feSyncTarget = stubcc.syncExitAndJump(Uses(1));
     871                 : 
     872                 :     /* Try a double path (inline). */
     873            2385 :     MaybeJump jmpNotDbl;
     874                 :     {
     875            2385 :         maybeJumpIfNotDouble(masm, jmpNotDbl, fe, feTypeReg);
     876                 : 
     877            2385 :         FPRegisterID fpreg = frame.allocFPReg();
     878            2385 :         frame.loadDouble(fe, fpreg, masm);
     879            2385 :         masm.negateDouble(fpreg);
     880                 : 
     881                 :         /* Overwrite pushed frame's memory (before push). */
     882            2385 :         masm.storeDouble(fpreg, frame.addressOf(fe));
     883            2385 :         frame.freeReg(fpreg);
     884                 :     }
     885                 : 
     886                 :     /* Try an integer path (out-of-line). */
     887            2385 :     MaybeJump jmpNotInt;
     888            2385 :     MaybeJump jmpMinIntOrIntZero;
     889            2385 :     MaybeJump jmpIntRejoin;
     890            2385 :     Label lblIntPath = stubcc.masm.label();
     891                 :     {
     892            2385 :         maybeJumpIfNotInt32(stubcc.masm, jmpNotInt, fe, feTypeReg);
     893                 : 
     894                 :         /* Test for 0 and -2147483648 (both result in a double). */
     895            2385 :         jmpMinIntOrIntZero = stubcc.masm.branchTest32(Assembler::Zero, reg, Imm32(0x7fffffff));
     896                 : 
     897            2385 :         stubcc.masm.neg32(reg);
     898                 : 
     899                 :         /* Sync back with double path. */
     900            2385 :         if (type == JSVAL_TYPE_DOUBLE) {
     901              41 :             stubcc.masm.convertInt32ToDouble(reg, Registers::FPConversionTemp);
     902              41 :             stubcc.masm.storeDouble(Registers::FPConversionTemp, frame.addressOf(fe));
     903                 :         } else {
     904                 :             stubcc.masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), reg,
     905            2344 :                                                  frame.addressOf(fe));
     906                 :         }
     907                 : 
     908            2385 :         jmpIntRejoin.setJump(stubcc.masm.jump());
     909                 :     }
     910                 : 
     911            2385 :     frame.freeReg(reg);
     912            2385 :     if (feTypeReg.isSet())
     913            2354 :         frame.unpinReg(feTypeReg.reg());
     914                 : 
     915            2385 :     stubcc.leave();
     916            2385 :     OOL_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
     917                 : 
     918            2385 :     frame.pop();
     919            2385 :     frame.pushSynced(type);
     920                 : 
     921                 :     /* Link jumps. */
     922            2385 :     if (jmpNotDbl.isSet())
     923            2385 :         stubcc.linkExitDirect(jmpNotDbl.getJump(), lblIntPath);
     924                 : 
     925            2385 :     if (jmpNotInt.isSet())
     926            2382 :         jmpNotInt.getJump().linkTo(feSyncTarget, &stubcc.masm);
     927            2385 :     if (jmpMinIntOrIntZero.isSet())
     928            2385 :         jmpMinIntOrIntZero.getJump().linkTo(feSyncTarget, &stubcc.masm);
     929            2385 :     if (jmpIntRejoin.isSet())
     930            2385 :         stubcc.crossJump(jmpIntRejoin.getJump(), masm.label());
     931                 : 
     932            2385 :     stubcc.rejoin(Changes(1));
     933                 : }
     934                 : 
     935                 : bool
     936            3895 : mjit::Compiler::jsop_mod()
     937                 : {
     938                 : #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
     939            3895 :     JSValueType type = knownPushedType(0);
     940            3895 :     FrameEntry *lhs = frame.peek(-2);
     941            3895 :     FrameEntry *rhs = frame.peek(-1);
     942                 : 
     943                 :     Value v;
     944            3895 :     if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
     945               8 :         types::TypeSet *pushed = pushedTypeSet(0);
     946               8 :         if (!v.isInt32() && pushed && !pushed->hasType(types::Type::DoubleType())) {
     947               2 :             types::TypeScript::MonitorOverflow(cx, script, PC);
     948               2 :             return false;
     949                 :         }
     950               6 :         frame.popn(2);
     951               6 :         frame.push(v);
     952               6 :         return true;
     953                 :     }
     954                 : 
     955           15895 :     if ((lhs->isConstant() && rhs->isConstant()) ||
     956            4487 :         (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_INT32) ||
     957            7521 :         (rhs->isTypeKnown() && rhs->getKnownType() != JSVAL_TYPE_INT32) ||
     958                 :         (type != JSVAL_TYPE_INT32 && type != JSVAL_TYPE_UNKNOWN))
     959                 : #endif
     960                 :     {
     961              74 :         prepareStubCall(Uses(2));
     962              74 :         INLINE_STUBCALL(stubs::Mod, REJOIN_FALLTHROUGH);
     963              74 :         frame.popn(2);
     964              74 :         frame.pushSynced(knownPushedType(0));
     965              74 :         return true;
     966                 :     }
     967                 : 
     968                 : #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
     969            3813 :     if (!lhs->isTypeKnown()) {
     970            3271 :         Jump j = frame.testInt32(Assembler::NotEqual, lhs);
     971            3271 :         stubcc.linkExit(j, Uses(2));
     972                 :     }
     973            3813 :     if (!rhs->isTypeKnown()) {
     974             158 :         Jump j = frame.testInt32(Assembler::NotEqual, rhs);
     975             158 :         stubcc.linkExit(j, Uses(2));
     976                 :     }
     977                 : 
     978                 :     /* LHS must be in EAX:EDX */
     979            3813 :     if (!lhs->isConstant()) {
     980            3805 :         frame.copyDataIntoReg(lhs, X86Registers::eax);
     981                 :     } else {
     982               8 :         frame.takeReg(X86Registers::eax);
     983               8 :         masm.move(Imm32(lhs->getValue().toInt32()), X86Registers::eax);
     984                 :     }
     985                 : 
     986                 :     /* Get RHS into anything but EDX - could avoid more spilling? */
     987            3813 :     MaybeRegisterID temp;
     988                 :     RegisterID rhsReg;
     989            3813 :     uint32_t mask = Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx);
     990            3813 :     if (!rhs->isConstant()) {
     991             303 :         rhsReg = frame.tempRegInMaskForData(rhs, mask).reg();
     992             303 :         JS_ASSERT(rhsReg != X86Registers::edx);
     993                 :     } else {
     994            3510 :         rhsReg = frame.allocReg(mask).reg();
     995            3510 :         JS_ASSERT(rhsReg != X86Registers::edx);
     996            3510 :         masm.move(Imm32(rhs->getValue().toInt32()), rhsReg);
     997            3510 :         temp = rhsReg;
     998                 :     }
     999            3813 :     frame.takeReg(X86Registers::edx);
    1000            3813 :     frame.freeReg(X86Registers::eax);
    1001                 : 
    1002            3813 :     if (temp.isSet())
    1003            3510 :         frame.freeReg(temp.reg());
    1004                 : 
    1005            3813 :     bool slowPath = !(lhs->isTypeKnown() && rhs->isTypeKnown());
    1006            3813 :     if (rhs->isConstant() && rhs->getValue().toInt32() != 0) {
    1007            3504 :         if (rhs->getValue().toInt32() == -1) {
    1008                 :             /* Guard against -1 / INT_MIN which throws a hardware exception. */
    1009                 :             Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax,
    1010               4 :                                              Imm32(0x80000000));
    1011               4 :             stubcc.linkExit(checkDivExc, Uses(2));
    1012               4 :             slowPath = true;
    1013                 :         }
    1014                 :     } else {
    1015             309 :         Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax, Imm32(0x80000000));
    1016             309 :         stubcc.linkExit(checkDivExc, Uses(2));
    1017             309 :         Jump checkZero = masm.branchTest32(Assembler::Zero, rhsReg, rhsReg);
    1018             309 :         stubcc.linkExit(checkZero, Uses(2));
    1019             309 :         slowPath = true;
    1020                 :     }
    1021                 : 
    1022                 :     /* Perform division. */
    1023            3813 :     masm.idiv(rhsReg);
    1024                 : 
    1025                 :     /* ECMA-262 11.5.3 requires the result to have the same sign as the lhs.
    1026                 :      * Thus, if the remainder of the div instruction is zero and the lhs is
    1027                 :      * negative, we must return negative 0. */
    1028                 : 
    1029            3813 :     bool lhsMaybeNeg = true;
    1030            3813 :     bool lhsIsNeg = false;
    1031            3813 :     if (lhs->isConstant()) {
    1032                 :         /* This condition is established at the top of this function. */
    1033               8 :         JS_ASSERT(lhs->getValue().isInt32());
    1034               8 :         lhsMaybeNeg = lhsIsNeg = (lhs->getValue().toInt32() < 0);
    1035                 :     }
    1036                 : 
    1037            3813 :     MaybeJump gotNegZero;
    1038            3813 :     MaybeJump done;
    1039            3813 :     if (lhsMaybeNeg) {
    1040            3805 :         MaybeRegisterID lhsData;
    1041            3805 :         if (!lhsIsNeg)
    1042            3805 :             lhsData = frame.tempRegForData(lhs);
    1043            3805 :         Jump negZero1 = masm.branchTest32(Assembler::NonZero, X86Registers::edx);
    1044            3805 :         MaybeJump negZero2;
    1045            3805 :         if (!lhsIsNeg)
    1046            3805 :             negZero2 = masm.branchTest32(Assembler::Zero, lhsData.reg(), Imm32(0x80000000));
    1047                 :         /*
    1048                 :          * Darn, negative 0. This goes to a stub call (after our in progress call)
    1049                 :          * which triggers recompilation if necessary.
    1050                 :          */
    1051            3805 :         gotNegZero = masm.jump();
    1052                 : 
    1053                 :         /* :TODO: This is wrong, must load into EDX as well. */
    1054                 : 
    1055            3805 :         done = masm.jump();
    1056            3805 :         negZero1.linkTo(masm.label(), &masm);
    1057            3805 :         if (negZero2.isSet())
    1058            3805 :             negZero2.getJump().linkTo(masm.label(), &masm);
    1059                 :     }
    1060                 : 
    1061                 :     /* Better - integer. */
    1062            3813 :     masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), frame.addressOf(lhs));
    1063                 : 
    1064            3813 :     if (done.isSet())
    1065            3805 :         done.getJump().linkTo(masm.label(), &masm);
    1066                 : 
    1067            3813 :     if (slowPath) {
    1068            3472 :         stubcc.leave();
    1069            3472 :         OOL_STUBCALL(stubs::Mod, REJOIN_FALLTHROUGH);
    1070                 :     }
    1071                 : 
    1072            3813 :     frame.popn(2);
    1073                 : 
    1074            3813 :     if (type == JSVAL_TYPE_INT32)
    1075             749 :         frame.pushTypedPayload(type, X86Registers::edx);
    1076                 :     else
    1077            3064 :         frame.pushNumber(X86Registers::edx);
    1078                 : 
    1079            3813 :     if (slowPath)
    1080            3472 :         stubcc.rejoin(Changes(1));
    1081                 : 
    1082            3813 :     if (gotNegZero.isSet()) {
    1083            3805 :         stubcc.linkExit(gotNegZero.getJump(), Uses(2));
    1084            3805 :         stubcc.leave();
    1085            3805 :         OOL_STUBCALL(stubs::NegZeroHelper, REJOIN_FALLTHROUGH);
    1086            3805 :         stubcc.rejoin(Changes(1));
    1087                 :     }
    1088                 : #endif
    1089                 : 
    1090            3813 :     return true;
    1091                 : }
    1092                 : 
    1093                 : bool
    1094           19019 : mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub,
    1095                 :                                          jsbytecode *target, JSOp fused)
    1096                 : {
    1097           19019 :     FrameEntry *rhs = frame.peek(-1);
    1098           19019 :     FrameEntry *lhs = frame.peek(-2);
    1099                 : 
    1100                 :     /* Swap the LHS and RHS if it makes register allocation better... or possible. */
    1101           40489 :     if (lhs->isConstant() ||
    1102           21470 :         (frame.shouldAvoidDataRemat(lhs) && !rhs->isConstant())) {
    1103            2433 :         FrameEntry *temp = rhs;
    1104            2433 :         rhs = lhs;
    1105            2433 :         lhs = temp;
    1106                 :     }
    1107                 : 
    1108           19019 :     bool lhsInt = lhs->isType(JSVAL_TYPE_INT32);
    1109           19019 :     bool rhsInt = rhs->isType(JSVAL_TYPE_INT32);
    1110                 : 
    1111                 :     /* Invert the condition if fusing with an IFEQ branch. */
    1112           19019 :     bool flipCondition = (target && fused == JSOP_IFEQ);
    1113                 : 
    1114                 :     /* Get the condition being tested. */
    1115                 :     Assembler::Condition cond;
    1116           19019 :     switch (op) {
    1117                 :       case JSOP_EQ:
    1118           14442 :         cond = flipCondition ? Assembler::NotEqual : Assembler::Equal;
    1119           14442 :         break;
    1120                 :       case JSOP_NE:
    1121            4577 :         cond = flipCondition ? Assembler::Equal : Assembler::NotEqual;
    1122            4577 :         break;
    1123                 :       default:
    1124               0 :         JS_NOT_REACHED("wat");
    1125                 :         return false;
    1126                 :     }
    1127                 : 
    1128           19019 :     if (target) {
    1129           13071 :         Value rval = UndefinedValue();  /* quiet gcc warning */
    1130           13071 :         bool rhsConst = false;
    1131           13071 :         if (rhs->isConstant()) {
    1132            6869 :             rhsConst = true;
    1133            6869 :             rval = rhs->getValue();
    1134                 :         }
    1135                 : 
    1136                 :         ValueRemat lvr, rvr;
    1137           13071 :         frame.pinEntry(lhs, lvr);
    1138           13071 :         frame.pinEntry(rhs, rvr);
    1139                 : 
    1140                 :         /*
    1141                 :          * Sync everything except the top two entries.
    1142                 :          * We will handle the lhs/rhs in the stub call path.
    1143                 :          */
    1144           13071 :         frame.syncAndKill(Registers(Registers::AvailRegs), Uses(frame.frameSlots()), Uses(2));
    1145                 : 
    1146           13071 :         RegisterID tempReg = frame.allocReg();
    1147                 : 
    1148           13071 :         JaegerSpew(JSpew_Insns, " ---- BEGIN STUB CALL CODE ---- \n");
    1149                 : 
    1150                 :         RESERVE_OOL_SPACE(stubcc.masm);
    1151                 : 
    1152                 :         /* Start of the slow path for equality stub call. */
    1153           13071 :         Label stubEntry = stubcc.masm.label();
    1154                 : 
    1155                 :         /* The lhs/rhs need to be synced in the stub call path. */
    1156           13071 :         frame.ensureValueSynced(stubcc.masm, lhs, lvr);
    1157           13071 :         frame.ensureValueSynced(stubcc.masm, rhs, rvr);
    1158                 : 
    1159           13071 :         bool needIntPath = (!lhs->isTypeKnown() || lhsInt) && (!rhs->isTypeKnown() || rhsInt);
    1160                 : 
    1161           13071 :         frame.pop();
    1162           13071 :         frame.pop();
    1163           13071 :         frame.discardFrame();
    1164                 : 
    1165           13071 :         bool needStub = true;
    1166                 :         
    1167                 : #ifdef JS_MONOIC
    1168           13071 :         EqualityGenInfo ic;
    1169                 : 
    1170           13071 :         ic.cond = cond;
    1171           13071 :         ic.tempReg = tempReg;
    1172           13071 :         ic.lvr = lvr;
    1173           13071 :         ic.rvr = rvr;
    1174           13071 :         ic.stubEntry = stubEntry;
    1175           13071 :         ic.stub = stub;
    1176                 : 
    1177           13071 :         bool useIC = !a->parent && bytecodeInChunk(target);
    1178                 : 
    1179                 :         /* Call the IC stub, which may generate a fast path. */
    1180           13071 :         if (useIC) {
    1181                 :             /* Adjust for the two values just pushed. */
    1182           12842 :             ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
    1183           12842 :             ic.stubCall = OOL_STUBCALL_LOCAL_SLOTS(ic::Equality, REJOIN_BRANCH,
    1184           12842 :                                                    frame.totalDepth() + 2);
    1185           12842 :             needStub = false;
    1186                 :         }
    1187                 : #endif
    1188                 : 
    1189           13071 :         if (needStub)
    1190             229 :             OOL_STUBCALL_LOCAL_SLOTS(stub, REJOIN_BRANCH, frame.totalDepth() + 2);
    1191                 : 
    1192                 :         /*
    1193                 :          * The stub call has no need to rejoin, since state is synced.
    1194                 :          * Instead, we can just test the return value.
    1195                 :          */
    1196                 :         Jump stubBranch = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
    1197           13071 :                                                    Registers::ReturnReg, Registers::ReturnReg);
    1198           13071 :         Jump stubFallthrough = stubcc.masm.jump();
    1199                 : 
    1200           13071 :         JaegerSpew(JSpew_Insns, " ---- END STUB CALL CODE ---- \n");
    1201                 :         CHECK_OOL_SPACE();
    1202                 : 
    1203           13071 :         Jump fast;
    1204           13071 :         MaybeJump firstStubJump;
    1205                 : 
    1206           13071 :         if (needIntPath) {
    1207            9012 :             if (!lhsInt) {
    1208            7026 :                 Jump lhsFail = masm.testInt32(Assembler::NotEqual, lvr.typeReg());
    1209            7026 :                 stubcc.linkExitDirect(lhsFail, stubEntry);
    1210            7026 :                 firstStubJump = lhsFail;
    1211                 :             }
    1212            9012 :             if (!rhsInt) {
    1213            5142 :                 Jump rhsFail = masm.testInt32(Assembler::NotEqual, rvr.typeReg());
    1214            5142 :                 stubcc.linkExitDirect(rhsFail, stubEntry);
    1215            5142 :                 if (!firstStubJump.isSet())
    1216              23 :                     firstStubJump = rhsFail;
    1217                 :             }
    1218                 : 
    1219            9012 :             if (rhsConst)
    1220            2856 :                 fast = masm.branch32(cond, lvr.dataReg(), Imm32(rval.toInt32()));
    1221                 :             else
    1222            6156 :                 fast = masm.branch32(cond, lvr.dataReg(), rvr.dataReg());
    1223                 :         } else {
    1224            4059 :             Jump j = masm.jump();
    1225            4059 :             stubcc.linkExitDirect(j, stubEntry);
    1226            4059 :             firstStubJump = j;
    1227                 : 
    1228                 :             /* This is just a dummy jump. */
    1229            4059 :             fast = masm.jump();
    1230                 :         }
    1231                 : 
    1232                 :         /* Jump from the stub call fallthrough to here. */
    1233           13071 :         stubcc.crossJump(stubFallthrough, masm.label());
    1234                 : 
    1235           13071 :         bool *ptrampoline = NULL;
    1236                 : #ifdef JS_MONOIC
    1237                 :         /* Remember the stub label in case there is a trampoline for the IC. */
    1238           13071 :         ic.trampoline = false;
    1239           13071 :         ic.trampolineStart = stubcc.masm.label();
    1240           13071 :         if (useIC)
    1241           12842 :             ptrampoline = &ic.trampoline;
    1242                 : #endif
    1243                 : 
    1244                 :         /*
    1245                 :          * NB: jumpAndRun emits to the OOL path, so make sure not to use it
    1246                 :          * in the middle of an in-progress slow path.
    1247                 :          */
    1248           13071 :         if (!jumpAndRun(fast, target, &stubBranch, ptrampoline))
    1249               0 :             return false;
    1250                 : 
    1251                 : #ifdef JS_MONOIC
    1252           13071 :         if (useIC) {
    1253           12842 :             ic.jumpToStub = firstStubJump;
    1254           12842 :             ic.fallThrough = masm.label();
    1255           12842 :             ic.jumpTarget = target;
    1256           12842 :             equalityICs.append(ic);
    1257                 :         }
    1258                 : #endif
    1259                 : 
    1260                 :     } else {
    1261                 :         /* No fusing. Compare, set, and push a boolean. */
    1262                 : 
    1263                 :         /* Should have filtered these out in the caller. */
    1264            5948 :         JS_ASSERT(!lhs->isType(JSVAL_TYPE_STRING) && !rhs->isType(JSVAL_TYPE_STRING));
    1265                 : 
    1266                 :         /* Test the types. */
    1267            5948 :         if ((lhs->isTypeKnown() && !lhsInt) || (rhs->isTypeKnown() && !rhsInt)) {
    1268               0 :             stubcc.linkExit(masm.jump(), Uses(2));
    1269                 :         } else {
    1270            5948 :             if (!lhsInt) {
    1271            5242 :                 Jump lhsFail = frame.testInt32(Assembler::NotEqual, lhs);
    1272            5242 :                 stubcc.linkExit(lhsFail, Uses(2));
    1273                 :             }
    1274            5948 :             if (!rhsInt) {
    1275            1800 :                 Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs);
    1276            1800 :                 stubcc.linkExit(rhsFail, Uses(2));
    1277                 :             }
    1278                 :         }
    1279                 : 
    1280            5948 :         stubcc.leave();
    1281            5948 :         OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
    1282                 : 
    1283            5948 :         RegisterID reg = frame.ownRegForData(lhs);
    1284                 : 
    1285                 :         /* x86/64's SET instruction can only take single-byte regs.*/
    1286            5948 :         RegisterID resultReg = reg;
    1287            5948 :         if (!(Registers::maskReg(reg) & Registers::SingleByteRegs))
    1288            3112 :             resultReg = frame.allocReg(Registers::SingleByteRegs).reg();
    1289                 : 
    1290                 :         /* Emit the compare & set. */
    1291            5948 :         if (rhs->isConstant()) {
    1292            3880 :             masm.set32(cond, reg, Imm32(rhs->getValue().toInt32()), resultReg);
    1293            2068 :         } else if (frame.shouldAvoidDataRemat(rhs)) {
    1294                 :             masm.set32(cond, reg,
    1295             297 :                        masm.payloadOf(frame.addressOf(rhs)),
    1296             297 :                        resultReg);
    1297                 :         } else {
    1298            1771 :             masm.set32(cond, reg, frame.tempRegForData(rhs), resultReg);
    1299                 :         }
    1300                 : 
    1301                 :         /* Clean up and push a boolean. */
    1302            5948 :         frame.pop();
    1303            5948 :         frame.pop();
    1304            5948 :         if (reg != resultReg)
    1305            3112 :             frame.freeReg(reg);
    1306            5948 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
    1307            5948 :         stubcc.rejoin(Changes(1));
    1308                 :     }
    1309           19019 :     return true;
    1310                 : }
    1311                 : 
    1312                 : /*
    1313                 :  * Emit an OOL path for a possibly double LHS, and possibly int32_t or number RHS.
    1314                 :  */
    1315                 : void
    1316          613721 : mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
    1317                 :                                    MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
    1318                 :                                    MaybeJump &lhsUnknownDone)
    1319                 : {
    1320                 :     /* If the LHS is not a 32-bit integer, take OOL path. */
    1321          613721 :     Jump lhsNotInt32 = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg());
    1322          613721 :     stubcc.linkExitDirect(lhsNotInt32, stubcc.masm.label());
    1323                 : 
    1324          613721 :     if (!masm.supportsFloatingPoint()) {
    1325               0 :         lhsNotDouble = stubcc.masm.jump();
    1326               0 :         return;
    1327                 :     }
    1328                 : 
    1329                 :     /* OOL path for LHS as a double - first test LHS is double. */
    1330          613721 :     lhsNotDouble = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg());
    1331                 : 
    1332                 :     /* Ensure the RHS is a number. */
    1333          613721 :     MaybeJump rhsIsDouble;
    1334          613721 :     if (!rhs->isTypeKnown()) {
    1335          341556 :         rhsIsDouble = stubcc.masm.testDouble(Assembler::Equal, regs.rhsType.reg());
    1336          341556 :         rhsNotNumber = stubcc.masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
    1337                 :     }
    1338                 : 
    1339                 :     /* If RHS is constant, convert now. */
    1340          613721 :     if (rhs->isConstant())
    1341          266357 :         slowLoadConstantDouble(stubcc.masm, rhs, regs.rhsFP);
    1342                 :     else
    1343          347364 :         stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), regs.rhsFP);
    1344                 : 
    1345          613721 :     if (!rhs->isTypeKnown()) {
    1346                 :         /* Jump past double load, bind double type check. */
    1347          341556 :         Jump converted = stubcc.masm.jump();
    1348          341556 :         rhsIsDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1349                 : 
    1350                 :         /* Load the double. */
    1351                 :         frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(),
    1352          341556 :                          rhs, regs.rhsFP, stubcc.masm);
    1353                 : 
    1354          341556 :         converted.linkTo(stubcc.masm.label(), &stubcc.masm);
    1355                 :     }
    1356                 : 
    1357                 :     /* Load the LHS. */
    1358                 :     frame.loadDouble(regs.lhsType.reg(), regs.lhsData.reg(),
    1359          613721 :                      lhs, regs.lhsFP, stubcc.masm);
    1360          613721 :     lhsUnknownDone = stubcc.masm.jump();
    1361                 : }
    1362                 : 
    1363                 : /*
    1364                 :  * Emit an OOL path for an integer LHS, possibly double RHS.
    1365                 :  */
    1366                 : void
    1367          343999 : mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
    1368                 :                                     MaybeJump &rhsNotNumber2)
    1369                 : {
    1370                 :     /* If the RHS is not a double, take OOL path. */
    1371          343999 :     Jump notInt32 = masm.testInt32(Assembler::NotEqual, regs.rhsType.reg());
    1372          343999 :     stubcc.linkExitDirect(notInt32, stubcc.masm.label());
    1373                 : 
    1374          343999 :     if (!masm.supportsFloatingPoint()) {
    1375               0 :         rhsNotNumber2 = stubcc.masm.jump();
    1376               0 :         return;
    1377                 :     }
    1378                 : 
    1379                 :     /* Now test if RHS is a double. */
    1380          343999 :     rhsNotNumber2 = stubcc.masm.testDouble(Assembler::NotEqual, regs.rhsType.reg());
    1381                 : 
    1382                 :     /* We know LHS is an integer. */
    1383          343999 :     if (lhs->isConstant())
    1384             910 :         slowLoadConstantDouble(stubcc.masm, lhs, regs.lhsFP);
    1385                 :     else
    1386          343089 :         stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), regs.lhsFP);
    1387                 : 
    1388                 :     /* Load the RHS. */
    1389                 :     frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(),
    1390          343999 :                      rhs, regs.rhsFP, stubcc.masm);
    1391                 : }
    1392                 : 
    1393                 : static inline Assembler::DoubleCondition
    1394           54494 : DoubleCondForOp(JSOp op, JSOp fused)
    1395                 : {
    1396           54494 :     bool ifeq = fused == JSOP_IFEQ;
    1397           54494 :     switch (op) {
    1398                 :       case JSOP_GT:
    1399                 :         return ifeq 
    1400                 :                ? Assembler::DoubleLessThanOrEqualOrUnordered
    1401            4467 :                : Assembler::DoubleGreaterThan;
    1402                 :       case JSOP_GE:
    1403                 :         return ifeq
    1404                 :                ? Assembler::DoubleLessThanOrUnordered
    1405            6796 :                : Assembler::DoubleGreaterThanOrEqual;
    1406                 :       case JSOP_LT:
    1407                 :         return ifeq
    1408                 :                ? Assembler::DoubleGreaterThanOrEqualOrUnordered
    1409           39003 :                : Assembler::DoubleLessThan;
    1410                 :       case JSOP_LE:
    1411                 :         return ifeq
    1412                 :                ? Assembler::DoubleGreaterThanOrUnordered
    1413            4228 :                : Assembler::DoubleLessThanOrEqual;
    1414                 :       default:
    1415               0 :         JS_NOT_REACHED("unrecognized op");
    1416                 :         return Assembler::DoubleLessThan;
    1417                 :     }
    1418                 : }
    1419                 : 
    1420                 : bool
    1421            1585 : mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
    1422                 : {
    1423            1585 :     FrameEntry *rhs = frame.peek(-1);
    1424            1585 :     FrameEntry *lhs = frame.peek(-2);
    1425                 : 
    1426            1585 :     JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
    1427                 : 
    1428                 :     FPRegisterID fpLeft, fpRight;
    1429                 :     bool allocateLeft, allocateRight;
    1430                 : 
    1431            1585 :     MaybeJump lhsNotNumber = loadDouble(lhs, &fpLeft, &allocateLeft);
    1432            1585 :     if (lhsNotNumber.isSet()) {
    1433             166 :         if (target)
    1434             111 :             stubcc.linkExitForBranch(lhsNotNumber.get());
    1435                 :         else
    1436              55 :             stubcc.linkExit(lhsNotNumber.get(), Uses(2));
    1437                 :     }
    1438            1585 :     if (!allocateLeft)
    1439            1195 :         frame.pinReg(fpLeft);
    1440                 : 
    1441            1585 :     MaybeJump rhsNotNumber = loadDouble(rhs, &fpRight, &allocateRight);
    1442            1585 :     if (rhsNotNumber.isSet()) {
    1443              49 :         if (target)
    1444              18 :             stubcc.linkExitForBranch(rhsNotNumber.get());
    1445                 :         else
    1446              31 :             stubcc.linkExit(rhsNotNumber.get(), Uses(2));
    1447                 :     }
    1448            1585 :     if (!allocateLeft)
    1449            1195 :         frame.unpinReg(fpLeft);
    1450                 : 
    1451            1585 :     Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
    1452                 : 
    1453            1585 :     if (target) {
    1454            1131 :         stubcc.leave();
    1455            1131 :         OOL_STUBCALL(stub, REJOIN_BRANCH);
    1456                 : 
    1457            1131 :         if (!allocateLeft)
    1458             860 :             frame.pinReg(fpLeft);
    1459            1131 :         if (!allocateRight)
    1460             742 :             frame.pinReg(fpRight);
    1461                 : 
    1462            1131 :         frame.syncAndKillEverything();
    1463                 : 
    1464            1131 :         Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
    1465                 : 
    1466            1131 :         if (allocateLeft)
    1467             271 :             frame.freeReg(fpLeft);
    1468                 :         else
    1469             860 :             frame.unpinKilledReg(fpLeft);
    1470                 : 
    1471            1131 :         if (allocateRight)
    1472             389 :             frame.freeReg(fpRight);
    1473                 :         else
    1474             742 :             frame.unpinKilledReg(fpRight);
    1475                 : 
    1476            1131 :         frame.popn(2);
    1477                 : 
    1478                 :         Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
    1479            1131 :                                            Registers::ReturnReg, Registers::ReturnReg);
    1480                 : 
    1481                 :         /* Rejoin from the slow path. */
    1482            1131 :         stubcc.rejoin(Changes(0));
    1483                 : 
    1484                 :         /*
    1485                 :          * NB: jumpAndRun emits to the OOL path, so make sure not to use it
    1486                 :          * in the middle of an in-progress slow path.
    1487                 :          */
    1488            1131 :         if (!jumpAndRun(j, target, &sj))
    1489               0 :             return false;
    1490                 :     } else {
    1491             454 :         stubcc.leave();
    1492             454 :         OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
    1493                 : 
    1494             454 :         frame.popn(2);
    1495                 : 
    1496             454 :         RegisterID reg = frame.allocReg();
    1497             454 :         Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
    1498             454 :         masm.move(Imm32(0), reg);
    1499             454 :         Jump skip = masm.jump();
    1500             454 :         j.linkTo(masm.label(), &masm);
    1501             454 :         masm.move(Imm32(1), reg);
    1502             454 :         skip.linkTo(masm.label(), &masm);
    1503                 : 
    1504             454 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
    1505                 : 
    1506             454 :         stubcc.rejoin(Changes(1));
    1507                 : 
    1508             454 :         if (allocateLeft)
    1509             119 :             frame.freeReg(fpLeft);
    1510             454 :         if (allocateRight)
    1511             324 :             frame.freeReg(fpRight);
    1512                 :     }
    1513                 : 
    1514            1585 :     return true;
    1515                 : }
    1516                 : 
    1517                 : bool
    1518           16115 : mjit::Compiler::jsop_relational_int(JSOp op, jsbytecode *target, JSOp fused)
    1519                 : {
    1520           16115 :     FrameEntry *rhs = frame.peek(-1);
    1521           16115 :     FrameEntry *lhs = frame.peek(-2);
    1522                 : 
    1523                 :     /* Reverse N cmp A comparisons.  The left side must be in a register. */
    1524           16115 :     if (lhs->isConstant()) {
    1525               0 :         JS_ASSERT(!rhs->isConstant());
    1526               0 :         FrameEntry *tmp = lhs;
    1527               0 :         lhs = rhs;
    1528               0 :         rhs = tmp;
    1529               0 :         op = ReverseCompareOp(op);
    1530                 :     }
    1531                 : 
    1532           16115 :     JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
    1533           16115 :     Assembler::Condition cond = GetCompareCondition(op, fused);
    1534                 : 
    1535           16115 :     if (target) {
    1536           15530 :         if (!frame.syncForBranch(target, Uses(2)))
    1537               0 :             return false;
    1538                 : 
    1539           15530 :         RegisterID lreg = frame.tempRegForData(lhs);
    1540           15530 :         Jump fast;
    1541           15530 :         if (rhs->isConstant()) {
    1542           11237 :             fast = masm.branch32(cond, lreg, Imm32(rhs->getValue().toInt32()));
    1543                 :         } else {
    1544            4293 :             frame.pinReg(lreg);
    1545            4293 :             RegisterID rreg = frame.tempRegForData(rhs);
    1546            4293 :             frame.unpinReg(lreg);
    1547            4293 :             fast = masm.branch32(cond, lreg, rreg);
    1548                 :         }
    1549           15530 :         frame.popn(2);
    1550                 : 
    1551                 :         Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
    1552           15530 :                                            Registers::ReturnReg, Registers::ReturnReg);
    1553                 : 
    1554           15530 :         return jumpAndRun(fast, target, &sj);
    1555                 :     } else {
    1556             585 :         RegisterID result = frame.allocReg();
    1557             585 :         RegisterID lreg = frame.tempRegForData(lhs);
    1558                 : 
    1559             585 :         if (rhs->isConstant()) {
    1560             415 :             masm.branchValue(cond, lreg, rhs->getValue().toInt32(), result);
    1561                 :         } else {
    1562             170 :             frame.pinReg(lreg);
    1563             170 :             RegisterID rreg = frame.tempRegForData(rhs);
    1564             170 :             frame.unpinReg(lreg);
    1565             170 :             masm.branchValue(cond, lreg, rreg, result);
    1566                 :         }
    1567                 : 
    1568             585 :         frame.popn(2);
    1569             585 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    1570                 :     }
    1571                 : 
    1572             585 :     return true;
    1573                 : }
    1574                 : 
    1575                 : /* See jsop_binary_full() for more information on how this works. */
    1576                 : bool
    1577           52909 : mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
    1578                 : {
    1579           52909 :     FrameEntry *rhs = frame.peek(-1);
    1580           52909 :     FrameEntry *lhs = frame.peek(-2);
    1581                 : 
    1582                 :     /* Allocate all registers up-front. */
    1583           52909 :     FrameState::BinaryAlloc regs;
    1584           52909 :     frame.allocForBinary(lhs, rhs, op, regs, !target);
    1585                 : 
    1586           52909 :     MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone;
    1587           52909 :     if (!lhs->isTypeKnown())
    1588           51805 :         emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone);
    1589                 : 
    1590           52909 :     MaybeJump rhsNotNumber2;
    1591           52909 :     if (!rhs->isTypeKnown())
    1592           22206 :         emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2);
    1593                 : 
    1594                 :     /* Both double paths will join here. */
    1595           52909 :     bool hasDoublePath = false;
    1596           52909 :     if (masm.supportsFloatingPoint() && (!rhs->isTypeKnown() || !lhs->isTypeKnown()))
    1597           52898 :         hasDoublePath = true;
    1598                 : 
    1599                 :     /* Integer path - figure out the immutable side. */
    1600           52909 :     JSOp cmpOp = op;
    1601           52909 :     int32_t value = 0;
    1602                 :     RegisterID cmpReg;
    1603           52909 :     MaybeRegisterID reg;
    1604           52909 :     if (regs.lhsData.isSet()) {
    1605           52768 :         cmpReg = regs.lhsData.reg();
    1606           52768 :         if (!regs.rhsData.isSet())
    1607           25666 :             value = rhs->getValue().toInt32();
    1608                 :         else
    1609           27102 :             reg = regs.rhsData.reg();
    1610                 :     } else {
    1611             141 :         cmpReg = regs.rhsData.reg();
    1612             141 :         value = lhs->getValue().toInt32();
    1613             141 :         cmpOp = ReverseCompareOp(op);
    1614                 :     }
    1615                 : 
    1616                 :     /*
    1617                 :      * Emit the actual comparisons. When a fusion is in play, it's faster to
    1618                 :      * combine the comparison with the jump, so these two cases are implemented
    1619                 :      * separately.
    1620                 :      */
    1621                 : 
    1622           52909 :     if (target) {
    1623                 :         /*
    1624                 :          * Emit the double path now, necessary to complete the OOL fast-path
    1625                 :          * before emitting the slow path.
    1626                 :          *
    1627                 :          * Note: doubles have not been swapped yet. Use original op.
    1628                 :          */
    1629           44664 :         MaybeJump doubleTest, doubleFall;
    1630           44664 :         Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
    1631           44664 :         if (hasDoublePath) {
    1632           44658 :             if (lhsUnknownDone.isSet())
    1633           43726 :                 lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1634           44658 :             frame.sync(stubcc.masm, Uses(frame.frameSlots()));
    1635           44658 :             doubleTest = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
    1636           44658 :             doubleFall = stubcc.masm.jump();
    1637                 :         }
    1638                 : 
    1639                 :         /* Link all incoming slow paths to here. */
    1640           44664 :         if (lhsNotDouble.isSet()) {
    1641           43726 :             lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1642           43726 :             if (rhsNotNumber.isSet())
    1643           20183 :                 rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1644                 :         }
    1645           44664 :         if (rhsNotNumber2.isSet())
    1646           21115 :             rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1647                 : 
    1648                 :         /*
    1649                 :          * For fusions, spill the tracker state. xmm* remain intact. Note
    1650                 :          * that frame.sync() must be used directly, to avoid syncExit()'s
    1651                 :          * jumping logic.
    1652                 :          */
    1653           44664 :         frame.sync(stubcc.masm, Uses(frame.frameSlots()));
    1654           44664 :         stubcc.leave();
    1655           44664 :         OOL_STUBCALL(stub, REJOIN_BRANCH);
    1656                 : 
    1657                 :         /* Forget the world, preserving data. */
    1658           44664 :         frame.pinReg(cmpReg);
    1659           44664 :         if (reg.isSet())
    1660           26131 :             frame.pinReg(reg.reg());
    1661                 :         
    1662           44664 :         frame.popn(2);
    1663                 : 
    1664           44664 :         frame.syncAndKillEverything();
    1665           44664 :         frame.unpinKilledReg(cmpReg);
    1666           44664 :         if (reg.isSet())
    1667           26131 :             frame.unpinKilledReg(reg.reg());
    1668           44664 :         frame.freeReg(regs.lhsFP);
    1669           44664 :         frame.freeReg(regs.rhsFP);
    1670                 : 
    1671                 :         /* Operands could have been reordered, so use cmpOp. */
    1672           44664 :         Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
    1673                 : 
    1674                 :         /* Emit the i32 path. */
    1675           44664 :         Jump fast;
    1676           44664 :         if (reg.isSet())
    1677           26131 :             fast = masm.branch32(i32Cond, cmpReg, reg.reg());
    1678                 :         else
    1679           18533 :             fast = masm.branch32(i32Cond, cmpReg, Imm32(value));
    1680                 : 
    1681                 :         /*
    1682                 :          * The stub call has no need to rejoin since state is synced. Instead,
    1683                 :          * we can just test the return value.
    1684                 :          */
    1685                 :         Jump j = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
    1686           44664 :                                           Registers::ReturnReg, Registers::ReturnReg);
    1687                 : 
    1688                 :         /* Rejoin from the slow path. */
    1689           44664 :         Jump j2 = stubcc.masm.jump();
    1690           44664 :         stubcc.crossJump(j2, masm.label());
    1691                 : 
    1692           44664 :         if (hasDoublePath) {
    1693           44658 :             j.linkTo(stubcc.masm.label(), &stubcc.masm);
    1694           44658 :             doubleTest.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1695           44658 :             j = stubcc.masm.jump();
    1696                 :         }
    1697                 : 
    1698                 :         /*
    1699                 :          * NB: jumpAndRun emits to the OOL path, so make sure not to use it
    1700                 :          * in the middle of an in-progress slow path.
    1701                 :          */
    1702           44664 :         if (!jumpAndRun(fast, target, &j))
    1703               0 :             return false;
    1704                 : 
    1705                 :         /* Rejoin from the double path. */
    1706           44664 :         if (hasDoublePath)
    1707           44658 :             stubcc.crossJump(doubleFall.get(), masm.label());
    1708                 :     } else {
    1709                 :         /*
    1710                 :          * Emit the double path now, necessary to complete the OOL fast-path
    1711                 :          * before emitting the slow path.
    1712                 :          */
    1713            8245 :         MaybeJump doubleDone;
    1714            8245 :         Assembler::DoubleCondition dblCond = DoubleCondForOp(op, JSOP_NOP);
    1715            8245 :         if (hasDoublePath) {
    1716            8240 :             if (lhsUnknownDone.isSet())
    1717            8079 :                 lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1718                 :             /* :FIXME: Use SET if we can? */
    1719            8240 :             Jump test = stubcc.masm.branchDouble(dblCond, regs.lhsFP, regs.rhsFP);
    1720            8240 :             stubcc.masm.move(Imm32(0), regs.result);
    1721            8240 :             Jump skip = stubcc.masm.jump();
    1722            8240 :             test.linkTo(stubcc.masm.label(), &stubcc.masm);
    1723            8240 :             stubcc.masm.move(Imm32(1), regs.result);
    1724            8240 :             skip.linkTo(stubcc.masm.label(), &stubcc.masm);
    1725            8240 :             doubleDone = stubcc.masm.jump();
    1726                 :         }
    1727                 : 
    1728                 :         /* Link all incoming slow paths to here. */
    1729            8245 :         if (lhsNotDouble.isSet()) {
    1730            8079 :             lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1731            8079 :             if (rhsNotNumber.isSet())
    1732             930 :                 rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1733                 :         }
    1734            8245 :         if (rhsNotNumber2.isSet())
    1735            1091 :             rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    1736                 : 
    1737                 :         /* Emit the slow path - note full frame syncage. */
    1738            8245 :         frame.sync(stubcc.masm, Uses(2));
    1739            8245 :         stubcc.leave();
    1740            8245 :         OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
    1741                 : 
    1742                 :         /* Get an integer comparison condition. */
    1743            8245 :         Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
    1744                 : 
    1745                 :         /* Emit the compare & set. */
    1746            8245 :         if (reg.isSet())
    1747             971 :             masm.branchValue(i32Cond, cmpReg, reg.reg(), regs.result);
    1748                 :         else
    1749            7274 :             masm.branchValue(i32Cond, cmpReg, value, regs.result);
    1750                 : 
    1751            8245 :         frame.popn(2);
    1752            8245 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, regs.result);
    1753                 : 
    1754            8245 :         if (hasDoublePath)
    1755            8240 :             stubcc.crossJump(doubleDone.get(), masm.label());
    1756            8245 :         stubcc.rejoin(Changes(1));
    1757                 : 
    1758            8245 :         frame.freeReg(regs.lhsFP);
    1759            8245 :         frame.freeReg(regs.rhsFP);
    1760                 :     }
    1761                 : 
    1762           52909 :     return true;
    1763                 : }
    1764                 : 

Generated by: LCOV version 1.7