LCOV - code coverage report
Current view: directory - js/src/methodjit - FastOps.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1436 1368 95.3 %
Date: 2012-06-02 Functions: 33 32 97.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                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "jsbool.h"
      42                 : #include "jscntxt.h"
      43                 : #include "jslibmath.h"
      44                 : #include "jsnum.h"
      45                 : #include "jsscope.h"
      46                 : #include "jsobjinlines.h"
      47                 : #include "jsscriptinlines.h"
      48                 : #include "jstypedarrayinlines.h"
      49                 : 
      50                 : #include "frontend/BytecodeEmitter.h"
      51                 : #include "methodjit/MethodJIT.h"
      52                 : #include "methodjit/Compiler.h"
      53                 : #include "methodjit/StubCalls.h"
      54                 : #include "methodjit/FrameState-inl.h"
      55                 : 
      56                 : #include "jsautooplen.h"
      57                 : 
      58                 : using namespace js;
      59                 : using namespace js::mjit;
      60                 : 
      61                 : typedef JSC::MacroAssembler::RegisterID RegisterID;
      62                 : 
      63                 : void
      64           24487 : mjit::Compiler::ensureInteger(FrameEntry *fe, Uses uses)
      65                 : {
      66           24487 :     if (fe->isConstant()) {
      67            8175 :         if (!fe->isType(JSVAL_TYPE_INT32)) {
      68             456 :             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
      69             456 :             fe->convertConstantDoubleToInt32(cx);
      70                 :         }
      71           16312 :     } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
      72             290 :         FPRegisterID fpreg = frame.tempFPRegForData(fe);
      73             290 :         FPRegisterID fptemp = frame.allocFPReg();
      74             290 :         RegisterID data = frame.allocReg();
      75             290 :         Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, data);
      76                 : 
      77             290 :         Label syncPath = stubcc.syncExitAndJump(uses);
      78             290 :         stubcc.linkExitDirect(truncateGuard, stubcc.masm.label());
      79                 : 
      80                 :         /*
      81                 :          * Try an OOL path to convert doubles representing integers within 2^32
      82                 :          * of a signed integer, by adding/subtracting 2^32 and then trying to
      83                 :          * convert to int32. This has to be an exact conversion, as otherwise
      84                 :          * the truncation works incorrectly on the modified value.
      85                 :          */
      86                 : 
      87             290 :         stubcc.masm.zeroDouble(fptemp);
      88             290 :         Jump positive = stubcc.masm.branchDouble(Assembler::DoubleGreaterThan, fpreg, fptemp);
      89             290 :         stubcc.masm.slowLoadConstantDouble(double(4294967296.0), fptemp);
      90             290 :         Jump skip = stubcc.masm.jump();
      91             290 :         positive.linkTo(stubcc.masm.label(), &stubcc.masm);
      92             290 :         stubcc.masm.slowLoadConstantDouble(double(-4294967296.0), fptemp);
      93             290 :         skip.linkTo(stubcc.masm.label(), &stubcc.masm);
      94                 : 
      95             580 :         JumpList isDouble;
      96             290 :         stubcc.masm.addDouble(fpreg, fptemp);
      97             290 :         stubcc.masm.branchConvertDoubleToInt32(fptemp, data, isDouble, Registers::FPConversionTemp);
      98             290 :         stubcc.crossJump(stubcc.masm.jump(), masm.label());
      99             290 :         isDouble.linkTo(syncPath, &stubcc.masm);
     100                 : 
     101             290 :         frame.freeReg(fptemp);
     102             290 :         frame.learnType(fe, JSVAL_TYPE_INT32, data);
     103           16022 :     } else if (!fe->isType(JSVAL_TYPE_INT32)) {
     104            5580 :         if (masm.supportsFloatingPoint()) {
     105            5580 :             FPRegisterID fptemp = frame.allocFPReg();
     106            5580 :             RegisterID typeReg = frame.tempRegForType(fe);
     107            5580 :             frame.pinReg(typeReg);
     108            5580 :             RegisterID dataReg = frame.copyDataIntoReg(fe);
     109            5580 :             frame.unpinReg(typeReg);
     110                 : 
     111            5580 :             Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
     112                 : 
     113            5580 :             Label syncPath = stubcc.syncExitAndJump(uses);
     114            5580 :             stubcc.linkExitDirect(intGuard, stubcc.masm.label());
     115                 : 
     116                 :             /* Try an OOL path to truncate doubles representing int32s. */
     117            5580 :             Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
     118            5580 :             doubleGuard.linkTo(syncPath, &stubcc.masm);
     119                 : 
     120            5580 :             frame.loadDouble(fe, fptemp, stubcc.masm);
     121            5580 :             Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
     122            5580 :             truncateGuard.linkTo(syncPath, &stubcc.masm);
     123            5580 :             stubcc.crossJump(stubcc.masm.jump(), masm.label());
     124                 : 
     125            5580 :             frame.freeReg(fptemp);
     126            5580 :             frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
     127                 :         } else {
     128               0 :             RegisterID typeReg = frame.tempRegForType(fe);
     129               0 :             frame.pinReg(typeReg);
     130               0 :             RegisterID dataReg = frame.copyDataIntoReg(fe);
     131               0 :             frame.unpinReg(typeReg);
     132                 : 
     133               0 :             Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
     134                 : 
     135               0 :             Label syncPath = stubcc.syncExitAndJump(uses);
     136               0 :             stubcc.linkExitDirect(intGuard, syncPath);
     137                 : 
     138               0 :             frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
     139                 :         }
     140                 :     }
     141           24487 : }
     142                 : 
     143                 : void
     144             167 : mjit::Compiler::jsop_bitnot()
     145                 : {
     146             167 :     FrameEntry *top = frame.peek(-1);
     147                 : 
     148                 :     /* We only want to handle integers here. */
     149             167 :     if (top->isNotType(JSVAL_TYPE_INT32) && top->isNotType(JSVAL_TYPE_DOUBLE)) {
     150               0 :         prepareStubCall(Uses(1));
     151               0 :         INLINE_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
     152               0 :         frame.pop();
     153               0 :         frame.pushSynced(JSVAL_TYPE_INT32);
     154               0 :         return;
     155                 :     }
     156                 : 
     157             167 :     ensureInteger(top, Uses(1));
     158                 : 
     159             167 :     stubcc.leave();
     160             167 :     OOL_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
     161                 : 
     162             167 :     RegisterID reg = frame.ownRegForData(top);
     163             167 :     masm.not32(reg);
     164             167 :     frame.pop();
     165             167 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
     166                 : 
     167             167 :     stubcc.rejoin(Changes(1));
     168                 : }
     169                 : 
     170                 : void
     171           13099 : mjit::Compiler::jsop_bitop(JSOp op)
     172                 : {
     173           13099 :     FrameEntry *rhs = frame.peek(-1);
     174           13099 :     FrameEntry *lhs = frame.peek(-2);
     175                 : 
     176                 :     /* The operands we ensure are integers cannot be copied by each other. */
     177           13099 :     frame.separateBinaryEntries(lhs, rhs);
     178                 : 
     179                 :     VoidStub stub;
     180           13099 :     switch (op) {
     181                 :       case JSOP_BITOR:
     182            1695 :         stub = stubs::BitOr;
     183            1695 :         break;
     184                 :       case JSOP_BITAND:
     185            4009 :         stub = stubs::BitAnd;
     186            4009 :         break;
     187                 :       case JSOP_BITXOR:
     188            1578 :         stub = stubs::BitXor;
     189            1578 :         break;
     190                 :       case JSOP_LSH:
     191            2132 :         stub = stubs::Lsh;
     192            2132 :         break;
     193                 :       case JSOP_RSH:
     194            2847 :         stub = stubs::Rsh;
     195            2847 :         break;
     196                 :       case JSOP_URSH:
     197             838 :         stub = stubs::Ursh;
     198             838 :         break;
     199                 :       default:
     200               0 :         JS_NOT_REACHED("wat");
     201                 :         return;
     202                 :     }
     203                 : 
     204                 :     /* Convert a double RHS to integer if it's constant for the test below. */
     205           13099 :     if (rhs->isConstant() && rhs->getValue().isDouble())
     206             630 :         rhs->convertConstantDoubleToInt32(cx);
     207                 : 
     208                 :     /* We only want to handle integers here. */
     209           27144 :     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
     210           12980 :         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
     211            1065 :         (op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) {
     212             939 :         prepareStubCall(Uses(2));
     213             939 :         INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
     214             939 :         frame.popn(2);
     215             939 :         frame.pushSynced(op != JSOP_URSH ? JSVAL_TYPE_INT32 : knownPushedType(0));
     216             939 :         return;
     217                 :     }
     218                 : 
     219           12160 :     ensureInteger(lhs, Uses(2));
     220           12160 :     ensureInteger(rhs, Uses(2));
     221                 : 
     222           12160 :     if (lhs->isConstant() && rhs->isConstant()) {
     223             210 :         int32_t L = lhs->getValue().toInt32();
     224             210 :         int32_t R = rhs->getValue().toInt32();
     225                 : 
     226             210 :         frame.popn(2);
     227             210 :         switch (op) {
     228                 :           case JSOP_BITOR:
     229              23 :             frame.push(Int32Value(L | R));
     230              23 :             return;
     231                 :           case JSOP_BITXOR:
     232              20 :             frame.push(Int32Value(L ^ R));
     233              20 :             return;
     234                 :           case JSOP_BITAND:
     235              88 :             frame.push(Int32Value(L & R));
     236              88 :             return;
     237                 :           case JSOP_LSH:
     238               0 :             frame.push(Int32Value(L << (R & 31)));
     239               0 :             return;
     240                 :           case JSOP_RSH:
     241              79 :             frame.push(Int32Value(L >> (R & 31)));
     242              79 :             return;
     243                 :           case JSOP_URSH:
     244                 :           {
     245                 :             uint32_t unsignedL;
     246               0 :             ToUint32(cx, Int32Value(L), (uint32_t*)&unsignedL);  /* Can't fail. */
     247               0 :             Value v = NumberValue(uint32_t(unsignedL >> (R & 31)));
     248               0 :             JS_ASSERT(v.isInt32());
     249               0 :             frame.push(v);
     250               0 :             return;
     251                 :           }
     252                 :           default:
     253               0 :             JS_NOT_REACHED("say wat");
     254                 :         }
     255                 :     }
     256                 : 
     257                 :     RegisterID reg;
     258                 : 
     259           11950 :     switch (op) {
     260                 :       case JSOP_BITOR:
     261                 :       case JSOP_BITXOR:
     262                 :       case JSOP_BITAND:
     263                 :       {
     264                 :         /* Commutative, and we're guaranteed both are ints. */
     265            6547 :         if (lhs->isConstant()) {
     266             425 :             JS_ASSERT(!rhs->isConstant());
     267             425 :             FrameEntry *temp = rhs;
     268             425 :             rhs = lhs;
     269             425 :             lhs = temp;
     270                 :         }
     271                 : 
     272            6547 :         reg = frame.ownRegForData(lhs);
     273            6547 :         if (rhs->isConstant()) {
     274            3588 :             int32_t rhsInt = rhs->getValue().toInt32();
     275            3588 :             if (op == JSOP_BITAND)
     276            2839 :                 masm.and32(Imm32(rhsInt), reg);
     277             749 :             else if (op == JSOP_BITXOR)
     278             361 :                 masm.xor32(Imm32(rhsInt), reg);
     279             388 :             else if (rhsInt != 0)
     280             233 :                 masm.or32(Imm32(rhsInt), reg);
     281            2959 :         } else if (frame.shouldAvoidDataRemat(rhs)) {
     282              20 :             Address rhsAddr = masm.payloadOf(frame.addressOf(rhs));
     283              20 :             if (op == JSOP_BITAND)
     284              20 :                 masm.and32(rhsAddr, reg);
     285               0 :             else if (op == JSOP_BITXOR)
     286               0 :                 masm.xor32(rhsAddr, reg);
     287                 :             else
     288               0 :                 masm.or32(rhsAddr, reg);
     289                 :         } else {
     290            2939 :             RegisterID rhsReg = frame.tempRegForData(rhs);
     291            2939 :             if (op == JSOP_BITAND)
     292             914 :                 masm.and32(rhsReg, reg);
     293            2025 :             else if (op == JSOP_BITXOR)
     294             928 :                 masm.xor32(rhsReg, reg);
     295                 :             else
     296            1097 :                 masm.or32(rhsReg, reg);
     297                 :         }
     298                 : 
     299            6547 :         break;
     300                 :       }
     301                 : 
     302                 :       case JSOP_LSH:
     303                 :       case JSOP_RSH:
     304                 :       case JSOP_URSH:
     305                 :       {
     306                 :         /* Not commutative. */
     307            5403 :         if (rhs->isConstant()) {
     308            2937 :             RegisterID reg = frame.ownRegForData(lhs);
     309            2937 :             int shift = rhs->getValue().toInt32() & 0x1F;
     310                 : 
     311            2937 :             stubcc.leave();
     312            2937 :             OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
     313                 : 
     314            2937 :             if (shift) {
     315            2825 :                 if (op == JSOP_LSH)
     316             838 :                     masm.lshift32(Imm32(shift), reg);
     317            1987 :                 else if (op == JSOP_RSH)
     318            1736 :                     masm.rshift32(Imm32(shift), reg);
     319                 :                 else
     320             251 :                     masm.urshift32(Imm32(shift), reg);
     321                 :             }
     322            2937 :             frame.popn(2);
     323                 :             
     324                 :             /* x >>> 0 may result in a double, handled above. */
     325            2937 :             JS_ASSERT_IF(op == JSOP_URSH, shift >= 1);
     326            2937 :             frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
     327                 : 
     328            2937 :             stubcc.rejoin(Changes(1));
     329            2937 :             return;
     330                 :         }
     331                 : #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
     332                 :         /* Grosssssss! RHS _must_ be in ECX, on x86 */
     333                 :         RegisterID rr = frame.tempRegInMaskForData(rhs,
     334            2466 :                                                    Registers::maskReg(JSC::X86Registers::ecx)).reg();
     335                 : #else
     336                 :         RegisterID rr = frame.tempRegForData(rhs);
     337                 : #endif
     338                 : 
     339            2466 :         if (frame.haveSameBacking(lhs, rhs)) {
     340                 :             // It's okay to allocReg(). If |rr| is evicted, it won't result in
     341                 :             // a load, and |rr == reg| is fine since this is (x << x).
     342               4 :             reg = frame.allocReg();
     343               4 :             if (rr != reg)
     344               4 :                 masm.move(rr, reg);
     345                 :         } else {
     346            2462 :             frame.pinReg(rr);
     347            2462 :             if (lhs->isConstant()) {
     348            1230 :                 reg = frame.allocReg();
     349            1230 :                 masm.move(Imm32(lhs->getValue().toInt32()), reg);
     350                 :             } else {
     351            1232 :                 reg = frame.copyDataIntoReg(lhs);
     352                 :             }
     353            2462 :             frame.unpinReg(rr);
     354                 :         }
     355                 :         
     356            2466 :         if (op == JSOP_LSH) {
     357            1153 :             masm.lshift32(rr, reg);
     358            1313 :         } else if (op == JSOP_RSH) {
     359             884 :             masm.rshift32(rr, reg);
     360                 :         } else {
     361             429 :             masm.urshift32(rr, reg);
     362                 :             
     363             429 :             Jump isNegative = masm.branch32(Assembler::LessThan, reg, Imm32(0));
     364             429 :             stubcc.linkExit(isNegative, Uses(2));
     365                 :         }
     366            2466 :         break;
     367                 :       }
     368                 : 
     369                 :       default:
     370               0 :         JS_NOT_REACHED("NYI");
     371                 :         return;
     372                 :     }
     373                 : 
     374            9013 :     stubcc.leave();
     375            9013 :     OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
     376                 : 
     377            9013 :     frame.pop();
     378            9013 :     frame.pop();
     379                 : 
     380            9013 :     JSValueType type = knownPushedType(0);
     381                 : 
     382            9013 :     if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE)
     383            6661 :         frame.pushTypedPayload(type, reg);
     384            2352 :     else if (op == JSOP_URSH)
     385             158 :         frame.pushNumber(reg, true);
     386                 :     else
     387            2194 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
     388                 : 
     389            9013 :     stubcc.rejoin(Changes(1));
     390                 : }
     391                 : 
     392                 : static inline bool
     393            3558 : CheckNullOrUndefined(FrameEntry *fe)
     394                 : {
     395            3558 :     if (!fe->isTypeKnown())
     396            1352 :         return false;
     397            2206 :     JSValueType type = fe->getKnownType();
     398            2206 :     return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED;
     399                 : }
     400                 : 
     401                 : CompileStatus
     402             209 : mjit::Compiler::jsop_equality_obj_obj(JSOp op, jsbytecode *target, JSOp fused)
     403                 : {
     404             209 :     FrameEntry *rhs = frame.peek(-1);
     405             209 :     FrameEntry *lhs = frame.peek(-2);
     406                 : 
     407             627 :     JS_ASSERT(cx->typeInferenceEnabled() &&
     408             627 :               lhs->isType(JSVAL_TYPE_OBJECT) && rhs->isType(JSVAL_TYPE_OBJECT));
     409                 : 
     410                 :     /*
     411                 :      * Handle equality between two objects. We have to ensure there is no
     412                 :      * special equality operator on either object, if that passes then
     413                 :      * this is a pointer comparison.
     414                 :      */
     415             209 :     types::TypeSet *lhsTypes = analysis->poppedTypes(PC, 1);
     416             209 :     types::TypeSet *rhsTypes = analysis->poppedTypes(PC, 0);
     417             407 :     if (!lhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) &&
     418             198 :         !rhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY)) {
     419                 :         /* :TODO: Merge with jsop_relational_int? */
     420             198 :         JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
     421             198 :         frame.forgetMismatchedObject(lhs);
     422             198 :         frame.forgetMismatchedObject(rhs);
     423             198 :         Assembler::Condition cond = GetCompareCondition(op, fused);
     424             198 :         if (target) {
     425                 :             Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
     426              35 :                                                Registers::ReturnReg, Registers::ReturnReg);
     427              35 :             if (!frame.syncForBranch(target, Uses(2)))
     428               0 :                 return Compile_Error;
     429              35 :             RegisterID lreg = frame.tempRegForData(lhs);
     430              35 :             frame.pinReg(lreg);
     431              35 :             RegisterID rreg = frame.tempRegForData(rhs);
     432              35 :             frame.unpinReg(lreg);
     433              35 :             Jump fast = masm.branchPtr(cond, lreg, rreg);
     434              35 :             frame.popn(2);
     435              35 :             return jumpAndRun(fast, target, &sj) ? Compile_Okay : Compile_Error;
     436                 :         } else {
     437             163 :             RegisterID result = frame.allocReg();
     438             163 :             RegisterID lreg = frame.tempRegForData(lhs);
     439             163 :             frame.pinReg(lreg);
     440             163 :             RegisterID rreg = frame.tempRegForData(rhs);
     441             163 :             frame.unpinReg(lreg);
     442             163 :             masm.branchValue(cond, lreg, rreg, result);
     443                 : 
     444             163 :             frame.popn(2);
     445             163 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
     446             163 :             return Compile_Okay;
     447                 :         }
     448                 :     }
     449                 : 
     450              11 :     return Compile_Skipped;
     451                 : }
     452                 : 
     453                 : bool
     454            1873 : mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
     455                 : {
     456            1873 :     FrameEntry *rhs = frame.peek(-1);
     457            1873 :     FrameEntry *lhs = frame.peek(-2);
     458                 : 
     459                 :     /* The compiler should have handled constant folding. */
     460            1873 :     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
     461                 : 
     462                 :     bool lhsTest;
     463            1873 :     if ((lhsTest = CheckNullOrUndefined(lhs)) || CheckNullOrUndefined(rhs)) {
     464                 :         /* What's the other mask? */
     465            1657 :         FrameEntry *test = lhsTest ? rhs : lhs;
     466                 : 
     467            1657 :         if (test->isType(JSVAL_TYPE_NULL) || test->isType(JSVAL_TYPE_UNDEFINED)) {
     468             138 :             return emitStubCmpOp(stub, target, fused);
     469            1519 :         } else if (test->isTypeKnown()) {
     470                 :             /* The test will not succeed, constant fold the compare. */
     471             213 :             bool result = GetCompareCondition(op, fused) == Assembler::NotEqual;
     472             213 :             frame.pop();
     473             213 :             frame.pop();
     474             213 :             if (target)
     475             147 :                 return constantFoldBranch(target, result);
     476              66 :             frame.push(BooleanValue(result));
     477              66 :             return true;
     478                 :         }
     479                 : 
     480                 :         /* The other side must be null or undefined. */
     481            1306 :         RegisterID reg = frame.ownRegForType(test);
     482            1306 :         frame.pop();
     483            1306 :         frame.pop();
     484                 : 
     485                 :         /*
     486                 :          * :FIXME: Easier test for undefined || null?
     487                 :          * Maybe put them next to each other, subtract, do a single compare?
     488                 :          */
     489                 : 
     490            1306 :         if (target) {
     491            1016 :             frame.syncAndKillEverything();
     492            1016 :             frame.freeReg(reg);
     493                 : 
     494                 :             Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
     495            1016 :                                                Registers::ReturnReg, Registers::ReturnReg);
     496                 : 
     497            1016 :             if ((op == JSOP_EQ && fused == JSOP_IFNE) ||
     498                 :                 (op == JSOP_NE && fused == JSOP_IFEQ)) {
     499             650 :                 Jump b1 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
     500             650 :                 Jump b2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL));
     501             650 :                 Jump j1 = masm.jump();
     502             650 :                 b1.linkTo(masm.label(), &masm);
     503             650 :                 b2.linkTo(masm.label(), &masm);
     504             650 :                 Jump j2 = masm.jump();
     505             650 :                 if (!jumpAndRun(j2, target, &sj))
     506               0 :                     return false;
     507             650 :                 j1.linkTo(masm.label(), &masm);
     508                 :             } else {
     509             366 :                 Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
     510             366 :                 Jump j2 = masm.branchPtr(Assembler::NotEqual, reg, ImmType(JSVAL_TYPE_NULL));
     511             366 :                 if (!jumpAndRun(j2, target, &sj))
     512               0 :                     return false;
     513             366 :                 j.linkTo(masm.label(), &masm);
     514                 :             }
     515                 :         } else {
     516             290 :             Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
     517             290 :             Jump j2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL));
     518             290 :             masm.move(Imm32(op == JSOP_NE), reg);
     519             290 :             Jump j3 = masm.jump();
     520             290 :             j2.linkTo(masm.label(), &masm);
     521             290 :             j.linkTo(masm.label(), &masm);
     522             290 :             masm.move(Imm32(op == JSOP_EQ), reg);
     523             290 :             j3.linkTo(masm.label(), &masm);
     524             290 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
     525                 :         }
     526            1306 :         return true;
     527                 :     }
     528                 : 
     529             518 :     if (cx->typeInferenceEnabled() &&
     530             302 :         lhs->isType(JSVAL_TYPE_OBJECT) && rhs->isType(JSVAL_TYPE_OBJECT))
     531                 :     {
     532              92 :         CompileStatus status = jsop_equality_obj_obj(op, target, fused);
     533              92 :         if (status == Compile_Okay) return true;
     534               1 :         else if (status == Compile_Error) return false;
     535                 :     }
     536                 : 
     537             125 :     return emitStubCmpOp(stub, target, fused);
     538                 : }
     539                 : 
     540                 : bool
     541           94282 : mjit::Compiler::jsop_relational(JSOp op, BoolStub stub,
     542                 :                                 jsbytecode *target, JSOp fused)
     543                 : {
     544           94282 :     FrameEntry *rhs = frame.peek(-1);
     545           94282 :     FrameEntry *lhs = frame.peek(-2);
     546                 : 
     547                 :     /* The compiler should have handled constant folding. */
     548           94282 :     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
     549           94282 :     JS_ASSERT(fused == JSOP_NOP || fused == JSOP_IFEQ || fused == JSOP_IFNE);
     550                 : 
     551                 :     /* Always slow path... */
     552          205589 :     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE) &&
     553            1234 :          lhs->isNotType(JSVAL_TYPE_STRING)) ||
     554          102596 :         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE) &&
     555            7477 :          rhs->isNotType(JSVAL_TYPE_STRING))) {
     556            2174 :         if (op == JSOP_EQ || op == JSOP_NE)
     557            1873 :             return jsop_equality(op, stub, target, fused);
     558             301 :         return emitStubCmpOp(stub, target, fused);
     559                 :     }
     560                 : 
     561           92108 :     if (op == JSOP_EQ || op == JSOP_NE) {
     562           48450 :         if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_STRING)) ||
     563           27011 :             (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_STRING))) {
     564             534 :             return emitStubCmpOp(stub, target, fused);
     565           20905 :         } else if (!target && (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING))) {
     566            1865 :             return emitStubCmpOp(stub, target, fused);
     567           19040 :         } else if (frame.haveSameBacking(lhs, rhs)) {
     568              21 :             return emitStubCmpOp(stub, target, fused);
     569                 :         } else {
     570           19019 :             return jsop_equality_int_string(op, stub, target, fused);
     571                 :         }
     572                 :     }
     573                 : 
     574           70669 :     if (frame.haveSameBacking(lhs, rhs)) {
     575               0 :         return emitStubCmpOp(stub, target, fused);
     576           70669 :     } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
     577              60 :         return emitStubCmpOp(stub, target, fused);
     578           70609 :     } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
     579            1585 :         if (!masm.supportsFloatingPoint())
     580               0 :             return emitStubCmpOp(stub, target, fused);
     581            1585 :         return jsop_relational_double(op, stub, target, fused);
     582          119423 :     } else if (cx->typeInferenceEnabled() &&
     583           50399 :                lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
     584           16115 :         return jsop_relational_int(op, target, fused);
     585                 :     } else {
     586           52909 :         return jsop_relational_full(op, stub, target, fused);
     587                 :     }
     588                 : }
     589                 : 
     590                 : void
     591           32963 : mjit::Compiler::jsop_not()
     592                 : {
     593           32963 :     FrameEntry *top = frame.peek(-1);
     594                 : 
     595           32963 :     if (top->isConstant()) {
     596               7 :         const Value &v = top->getValue();
     597               7 :         frame.pop();
     598               7 :         frame.push(BooleanValue(!js_ValueToBoolean(v)));
     599               7 :         return;
     600                 :     }
     601                 : 
     602           32956 :     if (top->isTypeKnown()) {
     603           17944 :         JSValueType type = top->getKnownType();
     604           17944 :         switch (type) {
     605                 :           case JSVAL_TYPE_INT32:
     606                 :           {
     607             102 :             RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
     608             102 :             if (frame.shouldAvoidDataRemat(top))
     609              91 :                 masm.loadPayload(frame.addressOf(top), data);
     610                 :             else
     611              11 :                 masm.move(frame.tempRegForData(top), data);
     612                 : 
     613             102 :             masm.set32(Assembler::Equal, data, Imm32(0), data);
     614                 : 
     615             102 :             frame.pop();
     616             102 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data);
     617             102 :             break;
     618                 :           }
     619                 : 
     620                 :           case JSVAL_TYPE_BOOLEAN:
     621                 :           {
     622           17525 :             RegisterID reg = frame.ownRegForData(top);
     623                 : 
     624           17525 :             masm.xor32(Imm32(1), reg);
     625                 : 
     626           17525 :             frame.pop();
     627           17525 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
     628           17525 :             break;
     629                 :           }
     630                 : 
     631                 :           case JSVAL_TYPE_OBJECT:
     632                 :           {
     633              37 :             RegisterID reg = frame.allocReg();
     634              37 :             masm.move(Imm32(0), reg);
     635                 : 
     636              37 :             frame.pop();
     637              37 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
     638              37 :             break;
     639                 :           }
     640                 : 
     641                 :           default:
     642                 :           {
     643             280 :             prepareStubCall(Uses(1));
     644             280 :             INLINE_STUBCALL_USES(stubs::ValueToBoolean, REJOIN_NONE, Uses(1));
     645                 : 
     646             280 :             RegisterID reg = Registers::ReturnReg;
     647             280 :             frame.takeReg(reg);
     648             280 :             masm.xor32(Imm32(1), reg);
     649                 : 
     650             280 :             frame.pop();
     651             280 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
     652             280 :             break;
     653                 :           }
     654                 :         }
     655                 : 
     656           17944 :         return;
     657                 :     }
     658                 : 
     659           15012 :     RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
     660           15012 :     if (frame.shouldAvoidDataRemat(top))
     661            3246 :         masm.loadPayload(frame.addressOf(top), data);
     662                 :     else
     663           11766 :         masm.move(frame.tempRegForData(top), data);
     664           15012 :     RegisterID type = frame.tempRegForType(top);
     665           15012 :     Label syncTarget = stubcc.syncExitAndJump(Uses(1));
     666                 : 
     667                 : 
     668                 :     /* Inline path is for booleans. */
     669           15012 :     Jump jmpNotBool = masm.testBoolean(Assembler::NotEqual, type);
     670           15012 :     masm.xor32(Imm32(1), data);
     671                 : 
     672                 : 
     673                 :     /* OOL path is for int + object. */
     674           15012 :     Label lblMaybeInt32 = stubcc.masm.label();
     675                 : 
     676           15012 :     Jump jmpNotInt32 = stubcc.masm.testInt32(Assembler::NotEqual, type);
     677           15012 :     stubcc.masm.set32(Assembler::Equal, data, Imm32(0), data);
     678           15012 :     Jump jmpInt32Exit = stubcc.masm.jump();
     679                 : 
     680           15012 :     Label lblMaybeObject = stubcc.masm.label();
     681           15012 :     Jump jmpNotObject = stubcc.masm.testPrimitive(Assembler::Equal, type);
     682           15012 :     stubcc.masm.move(Imm32(0), data);
     683           15012 :     Jump jmpObjectExit = stubcc.masm.jump();
     684                 : 
     685                 : 
     686                 :     /* Rejoin location. */
     687           15012 :     Label lblRejoin = masm.label();
     688                 : 
     689                 :     /* Patch up jumps. */
     690           15012 :     stubcc.linkExitDirect(jmpNotBool, lblMaybeInt32);
     691                 : 
     692           15012 :     jmpNotInt32.linkTo(lblMaybeObject, &stubcc.masm);
     693           15012 :     stubcc.crossJump(jmpInt32Exit, lblRejoin);
     694                 : 
     695           15012 :     jmpNotObject.linkTo(syncTarget, &stubcc.masm);
     696           15012 :     stubcc.crossJump(jmpObjectExit, lblRejoin);
     697                 :     
     698                 : 
     699                 :     /* Leave. */
     700           15012 :     stubcc.leave();
     701           15012 :     OOL_STUBCALL(stubs::Not, REJOIN_FALLTHROUGH);
     702                 : 
     703           15012 :     frame.pop();
     704           15012 :     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data);
     705                 : 
     706           15012 :     stubcc.rejoin(Changes(1));
     707                 : }
     708                 : 
     709                 : void
     710            2549 : mjit::Compiler::jsop_typeof()
     711                 : {
     712            2549 :     FrameEntry *fe = frame.peek(-1);
     713                 : 
     714            2549 :     if (fe->isTypeKnown()) {
     715             572 :         JSRuntime *rt = cx->runtime;
     716                 : 
     717             572 :         JSAtom *atom = NULL;
     718             572 :         switch (fe->getKnownType()) {
     719                 :           case JSVAL_TYPE_STRING:
     720              17 :             atom = rt->atomState.typeAtoms[JSTYPE_STRING];
     721              17 :             break;
     722                 :           case JSVAL_TYPE_UNDEFINED:
     723             393 :             atom = rt->atomState.typeAtoms[JSTYPE_VOID];
     724             393 :             break;
     725                 :           case JSVAL_TYPE_NULL:
     726               8 :             atom = rt->atomState.typeAtoms[JSTYPE_OBJECT];
     727               8 :             break;
     728                 :           case JSVAL_TYPE_OBJECT:
     729             105 :             atom = NULL;
     730             105 :             break;
     731                 :           case JSVAL_TYPE_BOOLEAN:
     732               4 :             atom = rt->atomState.typeAtoms[JSTYPE_BOOLEAN];
     733               4 :             break;
     734                 :           default:
     735              45 :             atom = rt->atomState.typeAtoms[JSTYPE_NUMBER];
     736              45 :             break;
     737                 :         }
     738                 : 
     739             572 :         if (atom) {
     740             467 :             frame.pop();
     741             467 :             frame.push(StringValue(atom));
     742             467 :             return;
     743                 :         }
     744                 :     }
     745                 : 
     746            2082 :     JSOp fused = JSOp(PC[JSOP_TYPEOF_LENGTH]);
     747            2082 :     if (fused == JSOP_STRING && !fe->isTypeKnown()) {
     748            1691 :         JSOp op = JSOp(PC[JSOP_TYPEOF_LENGTH + JSOP_STRING_LENGTH]);
     749                 : 
     750            1691 :         if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) {
     751            1502 :             JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH));
     752            1502 :             JSRuntime *rt = cx->runtime;
     753            1502 :             JSValueType type = JSVAL_TYPE_UNKNOWN;
     754                 :             Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ)
     755                 :                                         ? Assembler::Equal
     756            1502 :                                         : Assembler::NotEqual;
     757                 :             
     758            1502 :             if (atom == rt->atomState.typeAtoms[JSTYPE_VOID]) {
     759             949 :                 type = JSVAL_TYPE_UNDEFINED;
     760             553 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_STRING]) {
     761             247 :                 type = JSVAL_TYPE_STRING;
     762             306 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_BOOLEAN]) {
     763               2 :                 type = JSVAL_TYPE_BOOLEAN;
     764             304 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_NUMBER]) {
     765              27 :                 type = JSVAL_TYPE_INT32;
     766                 : 
     767                 :                 /* JSVAL_TYPE_DOUBLE is 0x0 and JSVAL_TYPE_INT32 is 0x1, use <= or > to match both */
     768              27 :                 cond = (cond == Assembler::Equal) ? Assembler::BelowOrEqual : Assembler::Above;
     769                 :             }
     770                 : 
     771            1502 :             jsbytecode *afterPC = PC + JSOP_STRING_LENGTH + JSOP_EQ_LENGTH;
     772                 : 
     773            1502 :             if (type != JSVAL_TYPE_UNKNOWN && bytecodeInChunk(afterPC)) {
     774            1225 :                 PC = afterPC;
     775                 : 
     776            1225 :                 RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
     777                 : 
     778                 : #if defined JS_NUNBOX32
     779            1225 :                 if (frame.shouldAvoidTypeRemat(fe))
     780               6 :                     masm.set32(cond, masm.tagOf(frame.addressOf(fe)), ImmType(type), result);
     781                 :                 else
     782            1219 :                     masm.set32(cond, frame.tempRegForType(fe), ImmType(type), result);
     783                 : #elif defined JS_PUNBOX64
     784                 :                 masm.setPtr(cond, frame.tempRegForType(fe), ImmType(type), result);
     785                 : #endif
     786                 : 
     787            1225 :                 frame.pop();
     788            1225 :                 frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
     789            1225 :                 return;
     790                 :             }
     791                 :         }
     792                 :     }
     793                 : 
     794             857 :     prepareStubCall(Uses(1));
     795             857 :     INLINE_STUBCALL(stubs::TypeOf, REJOIN_NONE);
     796             857 :     frame.pop();
     797             857 :     frame.takeReg(Registers::ReturnReg);
     798             857 :     frame.pushTypedPayload(JSVAL_TYPE_STRING, Registers::ReturnReg);
     799                 : }
     800                 : 
     801                 : bool
     802           87401 : mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
     803                 : {
     804                 :     // JSOP_AND and JSOP_OR may leave the value on the stack (despite
     805                 :     // the frame.pop() below), so we need to sync it.
     806           87401 :     if (op == JSOP_AND || op == JSOP_OR) {
     807           17609 :         frame.syncForBranch(target, Uses(0));
     808                 :     } else {
     809           69792 :         JS_ASSERT(op == JSOP_IFEQ || op == JSOP_IFNE);
     810           69792 :         frame.syncForBranch(target, Uses(1));
     811                 :     }
     812                 : 
     813           87401 :     FrameEntry *fe = frame.peek(-1);
     814                 :     Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR)
     815                 :                                 ? Assembler::NonZero
     816           87401 :                                 : Assembler::Zero;
     817                 : 
     818                 :     // Load data register and pin it so that frame.testBoolean
     819                 :     // below cannot evict it.
     820           87401 :     MaybeRegisterID data;
     821           87401 :     if (!fe->isType(JSVAL_TYPE_DOUBLE)) {
     822           87384 :         data = frame.tempRegForData(fe);
     823           87384 :         frame.pinReg(data.reg());
     824                 :     }
     825                 : 
     826                 :     // Test for boolean if needed.
     827           87401 :     bool needStub = false;
     828           87401 :     if (!fe->isType(JSVAL_TYPE_BOOLEAN) && !fe->isType(JSVAL_TYPE_INT32)) {
     829           70332 :         Jump notBool;
     830           70332 :         if (fe->mightBeType(JSVAL_TYPE_BOOLEAN))
     831           69748 :             notBool = frame.testBoolean(Assembler::NotEqual, fe);
     832                 :         else
     833             584 :             notBool = masm.jump();
     834                 : 
     835           70332 :         stubcc.linkExitForBranch(notBool);
     836           70332 :         needStub = true;
     837                 :     }
     838           87401 :     if (data.isSet())
     839           87384 :         frame.unpinReg(data.reg());
     840                 : 
     841                 :     // Test + branch.
     842           87401 :     Jump branch;
     843           87401 :     if (!fe->isType(JSVAL_TYPE_DOUBLE))
     844           87384 :         branch = masm.branchTest32(cond, data.reg());
     845                 :     else
     846              17 :         branch = masm.jump(); // dummy jump
     847                 : 
     848                 :     // OOL path: call ValueToBoolean and branch.
     849           87401 :     if (needStub) {
     850           70332 :         stubcc.leave();
     851                 : 
     852                 :         // Note: this cannot overwrite slots holding loop invariants.
     853                 :         stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::ValueToBoolean),
     854           70332 :                                      frame.totalDepth());
     855                 :     }
     856                 : 
     857           87401 :     Jump stubBranch = stubcc.masm.branchTest32(cond, Registers::ReturnReg);
     858                 : 
     859                 :     // Rejoin from the stub call fallthrough.
     860           87401 :     if (needStub)
     861           70332 :         stubcc.rejoin(Changes(0));
     862                 : 
     863           87401 :     frame.pop();
     864                 : 
     865           87401 :     return jumpAndRun(branch, target, &stubBranch);
     866                 : }
     867                 : 
     868                 : bool
     869           70707 : mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target)
     870                 : {
     871           70707 :     FrameEntry *fe = frame.peek(-1);
     872                 : 
     873           70707 :     if (fe->isConstant()) {
     874             915 :         JSBool b = js_ValueToBoolean(fe->getValue());
     875                 : 
     876             915 :         frame.pop();
     877                 : 
     878             915 :         if (op == JSOP_IFEQ)
     879             308 :             b = !b;
     880             915 :         if (b) {
     881             609 :             if (!frame.syncForBranch(target, Uses(0)))
     882               0 :                 return false;
     883             609 :             if (!jumpAndRun(masm.jump(), target))
     884               0 :                 return false;
     885                 :         } else {
     886             306 :             if (target < PC && !finishLoop(target))
     887               0 :                 return false;
     888                 :         }
     889             915 :         return true;
     890                 :     }
     891                 : 
     892           69792 :     return booleanJumpScript(op, target);
     893                 : }
     894                 : 
     895                 : bool
     896           18723 : mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target)
     897                 : {
     898           18723 :     FrameEntry *fe = frame.peek(-1);
     899                 : 
     900           18723 :     if (fe->isConstant()) {
     901            1114 :         JSBool b = js_ValueToBoolean(fe->getValue());
     902                 :         
     903                 :         /* Short-circuit. */
     904            1114 :         if ((op == JSOP_OR && b == JS_TRUE) ||
     905                 :             (op == JSOP_AND && b == JS_FALSE)) {
     906             602 :             if (!frame.syncForBranch(target, Uses(0)))
     907               0 :                 return false;
     908             602 :             if (!jumpAndRun(masm.jump(), target))
     909               0 :                 return false;
     910                 :         }
     911                 : 
     912            1114 :         frame.pop();
     913            1114 :         return true;
     914                 :     }
     915                 : 
     916           17609 :     return booleanJumpScript(op, target);
     917                 : }
     918                 : 
     919                 : bool
     920           38629 : mjit::Compiler::jsop_localinc(JSOp op, uint32_t slot)
     921                 : {
     922           38629 :     restoreVarType();
     923                 : 
     924           38629 :     types::TypeSet *types = pushedTypeSet(0);
     925           38629 :     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
     926                 : 
     927           38629 :     int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1;
     928                 : 
     929           38629 :     if (!analysis->incrementInitialValueObserved(PC)) {
     930                 :         // Before: 
     931                 :         // After:  V
     932           37707 :         frame.pushLocal(slot);
     933                 : 
     934                 :         // Before: V
     935                 :         // After:  V 1
     936           37707 :         frame.push(Int32Value(-amt));
     937                 : 
     938                 :         // Note, SUB will perform integer conversion for us.
     939                 :         // Before: V 1
     940                 :         // After:  N+1
     941           37707 :         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
     942               1 :             return false;
     943                 : 
     944                 :         // Before: N+1
     945                 :         // After:  N+1
     946           37706 :         frame.storeLocal(slot, analysis->popGuaranteed(PC));
     947                 :     } else {
     948                 :         // Before:
     949                 :         // After: V
     950             922 :         frame.pushLocal(slot);
     951                 : 
     952                 :         // Before: V
     953                 :         // After:  N
     954             922 :         jsop_pos();
     955                 : 
     956                 :         // Before: N
     957                 :         // After:  N N
     958             922 :         frame.dup();
     959                 : 
     960                 :         // Before: N N
     961                 :         // After:  N N 1
     962             922 :         frame.push(Int32Value(amt));
     963                 : 
     964                 :         // Before: N N 1
     965                 :         // After:  N N+1
     966             922 :         if (!jsop_binary(JSOP_ADD, stubs::Add, type, types))
     967               0 :             return false;
     968                 : 
     969                 :         // Before: N N+1
     970                 :         // After:  N N+1
     971             922 :         frame.storeLocal(slot, true);
     972                 : 
     973                 :         // Before: N N+1
     974                 :         // After:  N
     975             922 :         frame.pop();
     976                 :     }
     977                 : 
     978           38628 :     updateVarType();
     979           38628 :     return true;
     980                 : }
     981                 : 
     982                 : bool
     983             444 : mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
     984                 : {
     985             444 :     restoreVarType();
     986                 : 
     987             444 :     types::TypeSet *types = pushedTypeSet(0);
     988             444 :     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
     989                 : 
     990             444 :     int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
     991                 : 
     992             444 :     if (!analysis->incrementInitialValueObserved(PC)) {
     993                 :         // Before: 
     994                 :         // After:  V
     995             257 :         frame.pushArg(slot);
     996                 : 
     997                 :         // Before: V
     998                 :         // After:  V 1
     999             257 :         frame.push(Int32Value(-amt));
    1000                 : 
    1001                 :         // Note, SUB will perform integer conversion for us.
    1002                 :         // Before: V 1
    1003                 :         // After:  N+1
    1004             257 :         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
    1005               0 :             return false;
    1006                 : 
    1007                 :         // Before: N+1
    1008                 :         // After:  N+1
    1009             257 :         frame.storeArg(slot, analysis->popGuaranteed(PC));
    1010                 :     } else {
    1011                 :         // Before:
    1012                 :         // After: V
    1013             187 :         frame.pushArg(slot);
    1014                 : 
    1015                 :         // Before: V
    1016                 :         // After:  N
    1017             187 :         jsop_pos();
    1018                 : 
    1019                 :         // Before: N
    1020                 :         // After:  N N
    1021             187 :         frame.dup();
    1022                 : 
    1023                 :         // Before: N N
    1024                 :         // After:  N N 1
    1025             187 :         frame.push(Int32Value(amt));
    1026                 : 
    1027                 :         // Before: N N 1
    1028                 :         // After:  N N+1
    1029             187 :         if (!jsop_binary(JSOP_ADD, stubs::Add, type, types))
    1030               0 :             return false;
    1031                 : 
    1032                 :         // Before: N N+1
    1033                 :         // After:  N N+1
    1034             187 :         frame.storeArg(slot, true);
    1035                 : 
    1036                 :         // Before: N N+1
    1037                 :         // After:  N
    1038             187 :         frame.pop();
    1039                 :     }
    1040                 : 
    1041             444 :     updateVarType();
    1042             444 :     return true;
    1043                 : }
    1044                 : 
    1045                 : static inline bool
    1046          211207 : IsCacheableSetElem(FrameEntry *obj, FrameEntry *id, FrameEntry *value)
    1047                 : {
    1048          211207 :     if (obj->isNotType(JSVAL_TYPE_OBJECT))
    1049             498 :         return false;
    1050          210709 :     if (id->isNotType(JSVAL_TYPE_INT32) && id->isNotType(JSVAL_TYPE_DOUBLE))
    1051            1232 :         return false;
    1052          209477 :     if (id->isConstant()) {
    1053          196315 :         if (id->isNotType(JSVAL_TYPE_INT32))
    1054              16 :             return false;
    1055          196299 :         if (id->getValue().toInt32() < 0)
    1056               6 :             return false;
    1057          196293 :         if (id->getValue().toInt32() + 1 < 0)  // watch for overflow in hole paths
    1058               4 :             return false;
    1059                 :     }
    1060                 : 
    1061                 :     // obj[obj] * is not allowed, since it will never optimize.
    1062                 :     // obj[id] = id is allowed.
    1063                 :     // obj[id] = obj is allowed.
    1064          209451 :     if (obj->hasSameBacking(id))
    1065               1 :         return false;
    1066                 : 
    1067          209450 :     return true;
    1068                 : }
    1069                 : 
    1070                 : void
    1071            7815 : mjit::Compiler::jsop_setelem_dense()
    1072                 : {
    1073            7815 :     FrameEntry *obj = frame.peek(-3);
    1074            7815 :     FrameEntry *id = frame.peek(-2);
    1075            7815 :     FrameEntry *value = frame.peek(-1);
    1076                 : 
    1077                 :     // We might not know whether this is an object, but if it is an object we
    1078                 :     // know it is a dense array.
    1079            7815 :     if (!obj->isTypeKnown()) {
    1080            1741 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
    1081            1741 :         stubcc.linkExit(guard, Uses(3));
    1082                 :     }
    1083                 : 
    1084            7815 :     if (id->isType(JSVAL_TYPE_DOUBLE))
    1085               0 :         tryConvertInteger(id, Uses(2));
    1086                 : 
    1087                 :     // Test for integer index.
    1088            7815 :     if (!id->isTypeKnown()) {
    1089            2692 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
    1090            2692 :         stubcc.linkExit(guard, Uses(3));
    1091                 :     }
    1092                 : 
    1093                 :     // Allocate registers.
    1094                 : 
    1095                 :     ValueRemat vr;
    1096            7815 :     frame.pinEntry(value, vr, /* breakDouble = */ false);
    1097                 : 
    1098            7815 :     Int32Key key = id->isConstant()
    1099            1220 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
    1100            9035 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
    1101            7815 :     bool pinKey = !key.isConstant() && !frame.haveSameBacking(id, value);
    1102            7815 :     if (pinKey)
    1103            6560 :         frame.pinReg(key.reg());
    1104                 : 
    1105                 :     // Register to hold the computed slots pointer for the object. If we can
    1106                 :     // hoist the initialized length check, we make the slots pointer loop
    1107                 :     // invariant and never access the object itself.
    1108                 :     RegisterID slotsReg;
    1109            7815 :     analyze::CrossSSAValue objv(a->inlineIndex, analysis->poppedValue(PC, 2));
    1110            7815 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 1));
    1111            6480 :     bool hoisted = loop && id->isType(JSVAL_TYPE_INT32) &&
    1112           14295 :         loop->hoistArrayLengthCheck(DENSE_ARRAY, objv, indexv);
    1113                 : 
    1114            7815 :     MaybeJump initlenExit;
    1115                 : 
    1116            7815 :     if (hoisted) {
    1117             290 :         FrameEntry *slotsFe = loop->invariantArraySlots(objv);
    1118             290 :         slotsReg = frame.tempRegForData(slotsFe);
    1119                 : 
    1120             290 :         frame.unpinEntry(vr);
    1121             290 :         if (pinKey)
    1122             173 :             frame.unpinReg(key.reg());
    1123                 :     } else {
    1124                 :         // Get a register for the object which we can clobber, and load its elements.
    1125            7525 :         if (frame.haveSameBacking(obj, value)) {
    1126               4 :             slotsReg = frame.allocReg();
    1127               4 :             masm.move(vr.dataReg(), slotsReg);
    1128            7521 :         } else if (frame.haveSameBacking(obj, id)) {
    1129               0 :             slotsReg = frame.allocReg();
    1130               0 :             masm.move(key.reg(), slotsReg);
    1131                 :         } else {
    1132            7521 :             slotsReg = frame.copyDataIntoReg(obj);
    1133                 :         }
    1134            7525 :         masm.loadPtr(Address(slotsReg, JSObject::offsetOfElements()), slotsReg);
    1135                 : 
    1136            7525 :         frame.unpinEntry(vr);
    1137            7525 :         if (pinKey)
    1138            6387 :             frame.unpinReg(key.reg());
    1139                 : 
    1140                 :         // Make an OOL path for setting exactly the initialized length.
    1141            7525 :         Label syncTarget = stubcc.syncExitAndJump(Uses(3));
    1142                 : 
    1143                 :         Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
    1144            7525 :                                                   slotsReg, key, Assembler::BelowOrEqual);
    1145            7525 :         stubcc.linkExitDirect(initlenGuard, stubcc.masm.label());
    1146                 : 
    1147                 :         // Recheck for an exact initialized length. :TODO: would be nice to
    1148                 :         // reuse the condition bits from the previous test.
    1149                 :         Jump exactlenGuard = stubcc.masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
    1150            7525 :                                                           slotsReg, key, Assembler::NotEqual);
    1151            7525 :         exactlenGuard.linkTo(syncTarget, &stubcc.masm);
    1152                 : 
    1153                 :         // Check array capacity.
    1154                 :         Jump capacityGuard = stubcc.masm.guardArrayExtent(ObjectElements::offsetOfCapacity(),
    1155            7525 :                                                           slotsReg, key, Assembler::BelowOrEqual);
    1156            7525 :         capacityGuard.linkTo(syncTarget, &stubcc.masm);
    1157                 : 
    1158                 :         // Bump the index for setting the array length.  The above guard
    1159                 :         // ensures this won't overflow, due to NSLOTS_LIMIT.
    1160            7525 :         stubcc.masm.bumpKey(key, 1);
    1161                 : 
    1162                 :         // Update the initialized length.
    1163            7525 :         stubcc.masm.storeKey(key, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
    1164                 : 
    1165                 :         // Update the array length if needed.
    1166                 :         Jump lengthGuard = stubcc.masm.guardArrayExtent(ObjectElements::offsetOfLength(),
    1167            7525 :                                                         slotsReg, key, Assembler::AboveOrEqual);
    1168            7525 :         stubcc.masm.storeKey(key, Address(slotsReg, ObjectElements::offsetOfLength()));
    1169            7525 :         lengthGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
    1170                 : 
    1171                 :         // Restore the index.
    1172            7525 :         stubcc.masm.bumpKey(key, -1);
    1173                 : 
    1174            7525 :         initlenExit = stubcc.masm.jump();
    1175                 :     }
    1176                 : 
    1177                 : #ifdef JSGC_INCREMENTAL_MJ
    1178                 :     /*
    1179                 :      * Write barrier.
    1180                 :      * We skip over the barrier if we incremented initializedLength above,
    1181                 :      * because in that case the slot we're overwriting was previously
    1182                 :      * undefined.
    1183                 :      */
    1184            7815 :     types::TypeSet *types = frame.extra(obj).types;
    1185            7815 :     if (cx->compartment->needsBarrier() && (!types || types->propertyNeedsBarrier(cx, JSID_VOID))) {
    1186               2 :         Label barrierStart = stubcc.masm.label();
    1187               2 :         stubcc.linkExitDirect(masm.jump(), barrierStart);
    1188                 : 
    1189                 :         /*
    1190                 :          * The sync call below can potentially clobber key.reg() and slotsReg.
    1191                 :          * We pin key.reg() to avoid it being clobbered. If |hoisted| is true,
    1192                 :          * we can also pin slotsReg. If not, then slotsReg is owned by the
    1193                 :          * compiler and we save in manually to VMFrame::scratch.
    1194                 :          *
    1195                 :          * Additionally, the WriteBarrier stub can clobber both registers. The
    1196                 :          * rejoin call will restore key.reg() but not slotsReg. So we save
    1197                 :          * slotsReg in the frame and restore it after the stub call.
    1198                 :          */
    1199               2 :         stubcc.masm.storePtr(slotsReg, FrameAddress(offsetof(VMFrame, scratch)));
    1200               2 :         if (hoisted)
    1201               1 :             frame.pinReg(slotsReg);
    1202               2 :         if (!key.isConstant())
    1203               2 :             frame.pinReg(key.reg());
    1204               2 :         frame.sync(stubcc.masm, Uses(3));
    1205               2 :         if (!key.isConstant())
    1206               2 :             frame.unpinReg(key.reg());
    1207               2 :         if (hoisted)
    1208               1 :             frame.unpinReg(slotsReg);
    1209                 :         else
    1210               1 :             stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, scratch)), slotsReg);
    1211                 : 
    1212               2 :         if (key.isConstant())
    1213               0 :             stubcc.masm.lea(Address(slotsReg, key.index() * sizeof(Value)), Registers::ArgReg1);
    1214                 :         else
    1215               2 :             stubcc.masm.lea(BaseIndex(slotsReg, key.reg(), masm.JSVAL_SCALE), Registers::ArgReg1);
    1216               2 :         OOL_STUBCALL(stubs::WriteBarrier, REJOIN_NONE);
    1217               2 :         stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, scratch)), slotsReg);
    1218               2 :         stubcc.rejoin(Changes(0));
    1219                 :     }
    1220                 : #endif
    1221                 : 
    1222                 :     /* Jump over the write barrier in the initlen case. */
    1223            7815 :     if (initlenExit.isSet())
    1224            7525 :         stubcc.crossJump(initlenExit.get(), masm.label());
    1225                 : 
    1226                 :     // Fully store the value. :TODO: don't need to do this in the non-initlen case
    1227                 :     // if the array is packed and monomorphic.
    1228            7815 :     if (key.isConstant())
    1229            1220 :         masm.storeValue(vr, Address(slotsReg, key.index() * sizeof(Value)));
    1230                 :     else
    1231            6595 :         masm.storeValue(vr, BaseIndex(slotsReg, key.reg(), masm.JSVAL_SCALE));
    1232                 : 
    1233            7815 :     stubcc.leave();
    1234            7815 :     OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
    1235                 : 
    1236            7815 :     if (!hoisted)
    1237            7525 :         frame.freeReg(slotsReg);
    1238            7815 :     frame.shimmy(2);
    1239            7815 :     stubcc.rejoin(Changes(2));
    1240            7815 : }
    1241                 : 
    1242                 : #ifdef JS_METHODJIT_TYPED_ARRAY
    1243                 : void
    1244             752 : mjit::Compiler::convertForTypedArray(int atype, ValueRemat *vr, bool *allocated)
    1245                 : {
    1246             752 :     FrameEntry *value = frame.peek(-1);
    1247                 :     bool floatArray = (atype == TypedArray::TYPE_FLOAT32 ||
    1248             752 :                        atype == TypedArray::TYPE_FLOAT64);
    1249             752 :     *allocated = false;
    1250                 : 
    1251             752 :     if (value->isConstant()) {
    1252             452 :         Value v = value->getValue();
    1253             452 :         if (floatArray) {
    1254              53 :             double d = v.isDouble() ? v.toDouble() : v.toInt32();
    1255              53 :             *vr = ValueRemat::FromConstant(DoubleValue(d));
    1256                 :         } else {
    1257                 :             int i32;
    1258             399 :             if (v.isInt32()) {
    1259             349 :                 i32 = v.toInt32();
    1260             349 :                 if (atype == TypedArray::TYPE_UINT8_CLAMPED)
    1261              43 :                     i32 = ClampIntForUint8Array(i32);
    1262                 :             } else {
    1263                 :                 i32 = (atype == TypedArray::TYPE_UINT8_CLAMPED)
    1264               4 :                     ? js_TypedArray_uint8_clamp_double(v.toDouble())
    1265              54 :                     : js_DoubleToECMAInt32(v.toDouble());
    1266                 :             }
    1267             399 :             *vr = ValueRemat::FromConstant(Int32Value(i32));
    1268                 :         }
    1269                 :     } else {
    1270             300 :         if (floatArray) {
    1271                 :             FPRegisterID fpReg;
    1272              78 :             MaybeJump notNumber = loadDouble(value, &fpReg, allocated);
    1273              78 :             if (notNumber.isSet())
    1274              16 :                 stubcc.linkExit(notNumber.get(), Uses(3));
    1275                 : 
    1276              78 :             if (atype == TypedArray::TYPE_FLOAT32) {
    1277              64 :                 if (!*allocated) {
    1278              36 :                     frame.pinReg(fpReg);
    1279              36 :                     FPRegisterID newFpReg = frame.allocFPReg();
    1280              36 :                     masm.convertDoubleToFloat(fpReg, newFpReg);
    1281              36 :                     frame.unpinReg(fpReg);
    1282              36 :                     fpReg = newFpReg;
    1283              36 :                     *allocated = true;
    1284                 :                 } else {
    1285              28 :                     masm.convertDoubleToFloat(fpReg, fpReg);
    1286                 :                 }
    1287                 :             }
    1288              78 :             *vr = ValueRemat::FromFPRegister(fpReg);
    1289                 :         } else {
    1290                 :             /*
    1291                 :              * Allocate a register with the following properties:
    1292                 :              * 1) For byte arrays the value must be in a byte register.
    1293                 :              * 2) For Uint8ClampedArray the register must be writable.
    1294                 :              * 3) If the value is definitely int32_t (and the array is not
    1295                 :              *    Uint8ClampedArray) we don't have to allocate a new register.
    1296                 :              * 4) If id and value have the same backing (e.g. arr[i] = i) and
    1297                 :              *    we need a byte register, we have to allocate a new register
    1298                 :              *    because we've already pinned a key register and can't use
    1299                 :              *    tempRegInMaskForData.
    1300                 :              */
    1301             222 :             MaybeRegisterID reg, dataReg;
    1302                 :             bool needsByteReg = (atype == TypedArray::TYPE_INT8 ||
    1303                 :                                  atype == TypedArray::TYPE_UINT8 ||
    1304             222 :                                  atype == TypedArray::TYPE_UINT8_CLAMPED);
    1305             222 :             FrameEntry *id = frame.peek(-2);
    1306             265 :             if (!value->isType(JSVAL_TYPE_INT32) || atype == TypedArray::TYPE_UINT8_CLAMPED ||
    1307              43 :                 (needsByteReg && frame.haveSameBacking(id, value))) {
    1308                 :                 // Grab data register before branching.
    1309             116 :                 if (value->mightBeType(JSVAL_TYPE_INT32)) {
    1310              81 :                     dataReg = frame.tempRegForData(value);
    1311                 : 
    1312                 :                     // Make sure it's not clobbered by allocReg or tempRegForType.
    1313              81 :                     if (!frame.haveSameBacking(id, value))
    1314              74 :                         frame.pinReg(dataReg.reg());
    1315                 :                 }
    1316                 : 
    1317                 :                 // x86 has 4 single byte registers. Worst case we've pinned 3
    1318                 :                 // registers, one for each of object, key and value. This means
    1319                 :                 // there must be at least one single byte register available.
    1320             116 :                 if (needsByteReg)
    1321              56 :                     reg = frame.allocReg(Registers::SingleByteRegs).reg();
    1322                 :                 else
    1323              60 :                     reg = frame.allocReg();
    1324             116 :                 *allocated = true;
    1325                 :             } else {
    1326             106 :                 if (needsByteReg)
    1327              38 :                     reg = frame.tempRegInMaskForData(value, Registers::SingleByteRegs).reg();
    1328                 :                 else
    1329              68 :                     reg = frame.tempRegForData(value);
    1330                 :             }
    1331                 : 
    1332                 :             // Get type register before branching.
    1333             222 :             MaybeRegisterID typeReg;
    1334             222 :             if (!value->isTypeKnown()) {
    1335                 :                 // Note: we don't need to pin reg, it's never a temporary register if the
    1336                 :                 // type of value is not known.
    1337              55 :                 JS_ASSERT(*allocated);
    1338              55 :                 typeReg = frame.tempRegForType(value);
    1339                 :             }
    1340                 : 
    1341             222 :             MaybeJump intDone;
    1342             222 :             if (value->mightBeType(JSVAL_TYPE_INT32)) {
    1343                 :                 // Check if the value is an integer.
    1344             187 :                 MaybeJump notInt;
    1345             187 :                 if (!value->isTypeKnown()) {
    1346              55 :                     JS_ASSERT(*allocated);
    1347              55 :                     notInt = masm.testInt32(Assembler::NotEqual, typeReg.reg());
    1348                 :                 }
    1349                 : 
    1350             187 :                 if (*allocated) {
    1351              81 :                     masm.move(dataReg.reg(), reg.reg());
    1352              81 :                     if (!frame.haveSameBacking(id, value))
    1353              74 :                         frame.unpinReg(dataReg.reg());
    1354                 :                 }
    1355                 : 
    1356             187 :                 if (atype == TypedArray::TYPE_UINT8_CLAMPED)
    1357              25 :                     masm.clampInt32ToUint8(reg.reg());
    1358                 : 
    1359             187 :                 if (notInt.isSet()) {
    1360              55 :                     intDone = masm.jump();
    1361              55 :                     notInt.get().linkTo(masm.label(), &masm);
    1362                 :                 }
    1363                 :             }
    1364             222 :             if (value->mightBeType(JSVAL_TYPE_DOUBLE)) {
    1365                 :                 // Check if the value is a double.
    1366              90 :                 if (!value->isTypeKnown()) {
    1367              55 :                     Jump notNumber = masm.testDouble(Assembler::NotEqual, typeReg.reg());
    1368              55 :                     stubcc.linkExit(notNumber, Uses(3));
    1369                 :                 }
    1370                 : 
    1371                 :                 // Load value in fpReg.
    1372                 :                 FPRegisterID fpReg;
    1373              90 :                 if (value->isTypeKnown()) {
    1374              35 :                     fpReg = frame.tempFPRegForData(value);
    1375                 :                 } else {
    1376              55 :                     fpReg = frame.allocFPReg();
    1377              55 :                     frame.loadDouble(value, fpReg, masm);
    1378                 :                 }
    1379                 : 
    1380                 :                 // Convert double to integer.
    1381              90 :                 if (atype == TypedArray::TYPE_UINT8_CLAMPED) {
    1382              11 :                     if (value->isTypeKnown())
    1383               7 :                         frame.pinReg(fpReg);
    1384              11 :                     FPRegisterID fpTemp = frame.allocFPReg();
    1385              11 :                     if (value->isTypeKnown())
    1386               7 :                         frame.unpinReg(fpReg);
    1387              11 :                     masm.clampDoubleToUint8(fpReg, fpTemp, reg.reg());
    1388              11 :                     frame.freeReg(fpTemp);
    1389                 :                 } else {
    1390              79 :                     Jump j = masm.branchTruncateDoubleToInt32(fpReg, reg.reg());
    1391              79 :                     stubcc.linkExit(j, Uses(3));
    1392                 :                 }
    1393              90 :                 if (!value->isTypeKnown())
    1394              55 :                     frame.freeReg(fpReg);
    1395                 :             }
    1396             222 :             if (intDone.isSet())
    1397              55 :                 intDone.get().linkTo(masm.label(), &masm);
    1398             222 :             *vr = ValueRemat::FromKnownType(JSVAL_TYPE_INT32, reg.reg());
    1399                 :         }
    1400                 :     }
    1401             752 : }
    1402                 : 
    1403                 : void
    1404             752 : mjit::Compiler::jsop_setelem_typed(int atype)
    1405                 : {
    1406             752 :     FrameEntry *obj = frame.peek(-3);
    1407             752 :     FrameEntry *id = frame.peek(-2);
    1408             752 :     FrameEntry *value = frame.peek(-1);
    1409                 : 
    1410                 :     // We might not know whether this is an object, but if it is an object we
    1411                 :     // know it's a typed array.
    1412             752 :     if (!obj->isTypeKnown()) {
    1413             294 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
    1414             294 :         stubcc.linkExit(guard, Uses(3));
    1415                 :     }
    1416                 : 
    1417             752 :     if (id->isType(JSVAL_TYPE_DOUBLE))
    1418               0 :         tryConvertInteger(id, Uses(2));
    1419                 : 
    1420                 :     // Test for integer index.
    1421             752 :     if (!id->isTypeKnown()) {
    1422              66 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
    1423              66 :         stubcc.linkExit(guard, Uses(3));
    1424                 :     }
    1425                 : 
    1426                 :     // Pin value.
    1427                 :     ValueRemat vr;
    1428             752 :     frame.pinEntry(value, vr, /* breakDouble = */ false);
    1429                 : 
    1430                 :     // Allocate and pin object and key regs.
    1431             752 :     Int32Key key = id->isConstant()
    1432             264 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
    1433            1016 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
    1434                 : 
    1435             752 :     bool pinKey = !key.isConstant() && !frame.haveSameBacking(id, value);
    1436             752 :     if (pinKey)
    1437             474 :         frame.pinReg(key.reg());
    1438                 : 
    1439             752 :     analyze::CrossSSAValue objv(a->inlineIndex, analysis->poppedValue(PC, 1));
    1440             752 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
    1441             343 :     bool hoisted = loop && id->isType(JSVAL_TYPE_INT32) &&
    1442            1095 :         loop->hoistArrayLengthCheck(TYPED_ARRAY, objv, indexv);
    1443                 : 
    1444                 :     RegisterID objReg;
    1445             752 :     if (hoisted) {
    1446               0 :         FrameEntry *slotsFe = loop->invariantArraySlots(objv);
    1447               0 :         objReg = frame.tempRegForData(slotsFe);
    1448               0 :         frame.pinReg(objReg);
    1449                 :     } else {
    1450             752 :         objReg = frame.copyDataIntoReg(obj);
    1451                 : 
    1452                 :         // Bounds check.
    1453             752 :         int lengthOffset = TypedArray::lengthOffset() + offsetof(jsval_layout, s.payload);
    1454                 :         Jump lengthGuard = masm.guardArrayExtent(lengthOffset,
    1455             752 :                                                  objReg, key, Assembler::BelowOrEqual);
    1456             752 :         stubcc.linkExit(lengthGuard, Uses(3));
    1457                 : 
    1458                 :         // Load the array's packed data vector.
    1459             752 :         masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
    1460                 :     }
    1461                 : 
    1462                 :     // Unpin value so that convertForTypedArray can assign a new data
    1463                 :     // register using tempRegInMaskForData.
    1464             752 :     frame.unpinEntry(vr);
    1465                 : 
    1466                 :     // Make sure key is pinned.
    1467             752 :     if (frame.haveSameBacking(id, value)) {
    1468              14 :         frame.pinReg(key.reg());
    1469              14 :         pinKey = true;
    1470                 :     }
    1471             752 :     JS_ASSERT(pinKey == !id->isConstant());
    1472                 : 
    1473                 :     bool allocated;
    1474             752 :     convertForTypedArray(atype, &vr, &allocated);
    1475                 : 
    1476                 :     // Store the value.
    1477             752 :     masm.storeToTypedArray(atype, objReg, key, vr);
    1478             752 :     if (allocated) {
    1479             188 :         if (vr.isFPRegister())
    1480              72 :             frame.freeReg(vr.fpReg());
    1481                 :         else
    1482             116 :             frame.freeReg(vr.dataReg());
    1483                 :     }
    1484             752 :     if (pinKey)
    1485             488 :         frame.unpinReg(key.reg());
    1486             752 :     if (hoisted)
    1487               0 :         frame.unpinReg(objReg);
    1488                 :     else
    1489             752 :         frame.freeReg(objReg);
    1490                 : 
    1491             752 :     stubcc.leave();
    1492             752 :     OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
    1493                 : 
    1494             752 :     frame.shimmy(2);
    1495             752 :     stubcc.rejoin(Changes(2));
    1496             752 : }
    1497                 : #endif /* JS_METHODJIT_TYPED_ARRAY */
    1498                 : 
    1499                 : void
    1500               2 : mjit::Compiler::tryConvertInteger(FrameEntry *fe, Uses uses)
    1501                 : {
    1502               2 :     JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
    1503                 : 
    1504               4 :     JumpList isDouble;
    1505               2 :     FPRegisterID fpreg = frame.tempFPRegForData(fe);
    1506               2 :     RegisterID reg = frame.allocReg();
    1507               2 :     masm.branchConvertDoubleToInt32(fpreg, reg, isDouble, Registers::FPConversionTemp);
    1508               2 :     Jump j = masm.jump();
    1509               2 :     isDouble.linkTo(masm.label(), &masm);
    1510               2 :     stubcc.linkExit(masm.jump(), uses);
    1511               2 :     j.linkTo(masm.label(), &masm);
    1512               2 :     frame.learnType(fe, JSVAL_TYPE_INT32, reg);
    1513               2 : }
    1514                 : 
    1515                 : /* Get the common shape used by all dense arrays with a prototype at globalObj. */
    1516                 : static inline Shape *
    1517           26089 : GetDenseArrayShape(JSContext *cx, JSObject *globalObj)
    1518                 : {
    1519           26089 :     JS_ASSERT(globalObj);
    1520                 : 
    1521           26089 :     JSObject *proto = globalObj->global().getOrCreateArrayPrototype(cx);
    1522           26089 :     if (!proto)
    1523               0 :         return NULL;
    1524                 : 
    1525                 :     return EmptyShape::getInitialShape(cx, &ArrayClass, proto,
    1526           26089 :                                        proto->getParent(), gc::FINALIZE_OBJECT0);
    1527                 : }
    1528                 : 
    1529                 : bool
    1530          211207 : mjit::Compiler::jsop_setelem(bool popGuaranteed)
    1531                 : {
    1532          211207 :     FrameEntry *obj = frame.peek(-3);
    1533          211207 :     FrameEntry *id = frame.peek(-2);
    1534          211207 :     FrameEntry *value = frame.peek(-1);
    1535                 : 
    1536          211207 :     if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
    1537            1911 :         jsop_setelem_slow();
    1538            1911 :         return true;
    1539                 :     }
    1540                 : 
    1541          209296 :     frame.forgetMismatchedObject(obj);
    1542                 : 
    1543                 :     // If the object is definitely a dense array or a typed array we can generate
    1544                 :     // code directly without using an inline cache.
    1545          209296 :     if (cx->typeInferenceEnabled()) {
    1546           10991 :         types::TypeSet *types = analysis->poppedTypes(PC, 2);
    1547                 : 
    1548           18818 :         if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
    1549            7827 :             !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
    1550                 :             // Inline dense array path.
    1551            7815 :             jsop_setelem_dense();
    1552            7815 :             return true;
    1553                 :         }
    1554                 : 
    1555                 : #ifdef JS_METHODJIT_TYPED_ARRAY
    1556            5470 :         if ((value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE)) &&
    1557            2294 :             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
    1558                 :             // Inline typed array path.
    1559             857 :             int atype = types->getTypedArrayType(cx);
    1560             857 :             if (atype != TypedArray::TYPE_MAX) {
    1561             752 :                 jsop_setelem_typed(atype);
    1562             752 :                 return true;
    1563                 :             }
    1564                 :         }
    1565                 : #endif
    1566                 :     }
    1567                 : 
    1568          200729 :     if (id->isType(JSVAL_TYPE_DOUBLE) || !globalObj) {
    1569          195035 :         jsop_setelem_slow();
    1570          195035 :         return true;
    1571                 :     }
    1572                 : 
    1573                 : #ifdef JSGC_INCREMENTAL_MJ
    1574                 :     // Write barrier.
    1575            5694 :     if (cx->compartment->needsBarrier()) {
    1576               2 :         jsop_setelem_slow();
    1577               2 :         return true;
    1578                 :     }
    1579                 : #endif
    1580                 : 
    1581            5692 :     SetElementICInfo ic = SetElementICInfo(JSOp(*PC));
    1582                 : 
    1583                 :     // One by one, check if the most important stack entries have registers,
    1584                 :     // and if so, pin them. This is to avoid spilling and reloading from the
    1585                 :     // stack as we incrementally allocate other registers.
    1586            5692 :     MaybeRegisterID pinnedValueType = frame.maybePinType(value);
    1587            5692 :     MaybeRegisterID pinnedValueData = frame.maybePinData(value);
    1588                 : 
    1589                 :     // Pin |obj| if it doesn't share a backing with |value|.
    1590            5692 :     MaybeRegisterID pinnedObjData;
    1591            5692 :     if (!obj->hasSameBacking(value))
    1592            5626 :         pinnedObjData = frame.maybePinData(obj);
    1593                 : 
    1594                 :     // Pin |id| if it doesn't share a backing with |value|.
    1595            5692 :     MaybeRegisterID pinnedIdData;
    1596            5692 :     if (!id->hasSameBacking(value))
    1597            5645 :         pinnedIdData = frame.maybePinData(id);
    1598                 : 
    1599                 :     // Note: The fact that |obj| and |value|, or |id| and |value| can be
    1600                 :     // copies, is a little complicated, but it is safe. Explanations
    1601                 :     // follow at each point. Keep in mind two points:
    1602                 :     //  1) maybePin() never allocates a register, it only pins if a register
    1603                 :     //     already existed.
    1604                 :     //  2) tempRegForData() will work fine on a pinned register.
    1605                 :  
    1606                 :     // Guard that the object is an object.
    1607            5692 :     if (!obj->isTypeKnown()) {
    1608            4934 :         Jump j = frame.testObject(Assembler::NotEqual, obj);
    1609            4934 :         stubcc.linkExit(j, Uses(3));
    1610                 :     }
    1611                 : 
    1612                 :     // Guard that the id is int32.
    1613            5692 :     if (!id->isTypeKnown()) {
    1614            2897 :         Jump j = frame.testInt32(Assembler::NotEqual, id);
    1615            2897 :         stubcc.linkExit(j, Uses(3));
    1616                 :     }
    1617                 : 
    1618                 :     // Grab a register for the object. It's safe to unpin |obj| because it
    1619                 :     // won't have been pinned if it shares a backing with |value|. However,
    1620                 :     // it would not be safe to copyDataIntoReg() if the value was pinned,
    1621                 :     // since this could evict the register. So we special case.
    1622            5692 :     frame.maybeUnpinReg(pinnedObjData);
    1623            5692 :     if (obj->hasSameBacking(value) && pinnedValueData.isSet()) {
    1624              61 :         ic.objReg = frame.allocReg();
    1625              61 :         masm.move(pinnedValueData.reg(), ic.objReg);
    1626                 :     } else {
    1627            5631 :         ic.objReg = frame.copyDataIntoReg(obj);
    1628                 :     }
    1629                 : 
    1630                 :     // pinEntry() will ensure pinned registers for |value|. To avoid a
    1631                 :     // double-pin assert, first unpin any registers that |value| had.
    1632            5692 :     frame.maybeUnpinReg(pinnedValueType);
    1633            5692 :     frame.maybeUnpinReg(pinnedValueData);
    1634            5692 :     frame.pinEntry(value, ic.vr);
    1635                 : 
    1636                 :     // Store rematerialization information about the key. This is the final
    1637                 :     // register we allocate, and thus it can use tempRegForData() without
    1638                 :     // the worry of being spilled. Once again, this is safe even if |id|
    1639                 :     // shares a backing with |value|, because tempRegForData() will work on
    1640                 :     // the pinned register, and |pinnedIdData| will not double-pin.
    1641            5692 :     frame.maybeUnpinReg(pinnedIdData);
    1642            5692 :     if (id->isConstant())
    1643            1777 :         ic.key = Int32Key::FromConstant(id->getValue().toInt32());
    1644                 :     else
    1645            3915 :         ic.key = Int32Key::FromRegister(frame.tempRegForData(id));
    1646                 : 
    1647                 :     // Unpin the value since register allocation is complete.
    1648            5692 :     frame.unpinEntry(ic.vr);
    1649                 : 
    1650                 :     // Now it's also safe to grab remat info for obj (all exits that can
    1651                 :     // generate stubs must have the same register state).
    1652            5692 :     ic.objRemat = frame.dataRematInfo(obj);
    1653                 : 
    1654                 :     // All patchable guards must occur after this point.
    1655                 :     RESERVE_IC_SPACE(masm);
    1656            5692 :     ic.fastPathStart = masm.label();
    1657                 : 
    1658                 :     // Create the common out-of-line sync block, taking care to link previous
    1659                 :     // guards here after.
    1660                 :     RESERVE_OOL_SPACE(stubcc.masm);
    1661            5692 :     ic.slowPathStart = stubcc.syncExit(Uses(3));
    1662                 : 
    1663                 :     // Guard obj is a dense array.
    1664            5692 :     Shape *shape = GetDenseArrayShape(cx, globalObj);
    1665            5692 :     if (!shape)
    1666               0 :         return false;
    1667            5692 :     ic.shapeGuard = masm.guardShape(ic.objReg, shape);
    1668            5692 :     stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
    1669                 : 
    1670                 :     // Load the dynamic elements vector.
    1671            5692 :     masm.loadPtr(Address(ic.objReg, JSObject::offsetOfElements()), ic.objReg);
    1672                 : 
    1673                 :     // Guard in range of initialized length.
    1674                 :     Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
    1675            5692 :                                               ic.objReg, ic.key, Assembler::BelowOrEqual);
    1676            5692 :     stubcc.linkExitDirect(initlenGuard, ic.slowPathStart);
    1677                 : 
    1678                 :     // Guard there's no hole, then store directly to the slot.
    1679            5692 :     if (ic.key.isConstant()) {
    1680            1777 :         Address slot(ic.objReg, ic.key.index() * sizeof(Value));
    1681            1777 :         ic.holeGuard = masm.guardNotHole(slot);
    1682            1777 :         masm.storeValue(ic.vr, slot);
    1683                 :     } else {
    1684            3915 :         BaseIndex slot(ic.objReg, ic.key.reg(), Assembler::JSVAL_SCALE);
    1685            3915 :         ic.holeGuard = masm.guardNotHole(slot);
    1686            3915 :         masm.storeValue(ic.vr, slot);
    1687                 :     }
    1688            5692 :     stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
    1689                 : 
    1690            5692 :     stubcc.leave();
    1691                 : #if defined JS_POLYIC
    1692            5692 :     passICAddress(&ic);
    1693            5692 :     ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement), REJOIN_FALLTHROUGH);
    1694                 : #else
    1695                 :     OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
    1696                 : #endif
    1697                 : 
    1698            5692 :     ic.fastPathRejoin = masm.label();
    1699                 : 
    1700                 :     // When generating typed array stubs, it may be necessary to call
    1701                 :     // js_DoubleToECMAInt32(), which would clobber registers. To deal with
    1702                 :     // this, we tell the IC exactly which registers need to be saved
    1703                 :     // across calls.
    1704            5692 :     ic.volatileMask = frame.regsInUse();
    1705                 : 
    1706                 :     // If the RHS will be popped, and doesn't overlap any live values, then
    1707                 :     // there's no need to save it across calls. Note that this is not true of
    1708                 :     // |obj| or |key|, which will be used to compute the LHS reference for
    1709                 :     // assignment.
    1710                 :     //
    1711                 :     // Note that the IC wants to clobber |vr.dataReg| to convert for typed
    1712                 :     // arrays. If this clobbering is necessary, we must preserve dataReg,
    1713                 :     // even if it's not in a volatile register.
    1714           21509 :     if (popGuaranteed &&
    1715            5476 :         !ic.vr.isConstant() &&
    1716            3655 :         !value->isCopy() &&
    1717            3343 :         !frame.haveSameBacking(value, obj) &&
    1718            3343 :         !frame.haveSameBacking(value, id))
    1719                 :     {
    1720            3343 :         ic.volatileMask &= ~Registers::maskReg(ic.vr.dataReg());
    1721            3343 :         if (!ic.vr.isTypeKnown())
    1722            2411 :             ic.volatileMask &= ~Registers::maskReg(ic.vr.typeReg());
    1723            2349 :     } else if (!ic.vr.isConstant()) {
    1724             470 :         ic.volatileMask |= Registers::maskReg(ic.vr.dataReg());
    1725                 :     }
    1726                 : 
    1727            5692 :     frame.freeReg(ic.objReg);
    1728            5692 :     frame.shimmy(2);
    1729            5692 :     stubcc.rejoin(Changes(2));
    1730                 : 
    1731                 : #if defined JS_POLYIC
    1732            5692 :     if (!setElemICs.append(ic))
    1733               0 :         return false;
    1734                 : #endif
    1735                 : 
    1736            5692 :     return true;
    1737                 : }
    1738                 : 
    1739                 : static inline bool
    1740          252899 : IsCacheableGetElem(FrameEntry *obj, FrameEntry *id)
    1741                 : {
    1742          476779 :     if (id->isTypeKnown() &&
    1743          225209 :         !(id->isType(JSVAL_TYPE_INT32) || id->isType(JSVAL_TYPE_DOUBLE)
    1744                 : #if defined JS_POLYIC
    1745            1370 :           || id->isType(JSVAL_TYPE_STRING)
    1746                 : #endif
    1747            2762 :          )) {
    1748              63 :         return false;
    1749                 :     }
    1750                 : 
    1751          252836 :     if (id->isType(JSVAL_TYPE_DOUBLE) && id->isConstant())
    1752              20 :         return false;
    1753                 : 
    1754          464866 :     if (id->isType(JSVAL_TYPE_INT32) && id->isConstant() &&
    1755          212050 :         id->getValue().toInt32() < 0) {
    1756               6 :         return false;
    1757                 :     }
    1758                 : 
    1759                 :     // obj[obj] is not allowed, since it will never optimize.
    1760          252810 :     if (obj->hasSameBacking(id))
    1761               5 :         return false;
    1762                 : 
    1763          252805 :     return true;
    1764                 : }
    1765                 : 
    1766                 : void
    1767           24592 : mjit::Compiler::jsop_getelem_dense(bool isPacked)
    1768                 : {
    1769           24592 :     FrameEntry *obj = frame.peek(-2);
    1770           24592 :     FrameEntry *id = frame.peek(-1);
    1771                 : 
    1772                 :     // We might not know whether this is an object, but if it is an object we
    1773                 :     // know it is a dense array.
    1774           24592 :     if (!obj->isTypeKnown()) {
    1775            3246 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
    1776            3246 :         stubcc.linkExit(guard, Uses(2));
    1777                 :     }
    1778                 : 
    1779           24592 :     if (id->isType(JSVAL_TYPE_DOUBLE))
    1780               2 :         tryConvertInteger(id, Uses(2));
    1781                 : 
    1782                 :     // Test for integer index.
    1783           24592 :     if (!id->isTypeKnown()) {
    1784            9663 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
    1785            9663 :         stubcc.linkExit(guard, Uses(2));
    1786                 :     }
    1787                 : 
    1788           24592 :     JSValueType type = knownPushedType(0);
    1789                 : 
    1790                 :     // Allocate registers.
    1791                 : 
    1792                 :     // If we know the result of the GETELEM may be undefined, then misses on the
    1793                 :     // initialized length or hole checks can just produce an undefined value.
    1794                 :     // We checked in the caller that prototypes do not have indexed properties.
    1795           24592 :     bool allowUndefined = mayPushUndefined(0);
    1796                 : 
    1797           24592 :     analyze::CrossSSAValue objv(a->inlineIndex, analysis->poppedValue(PC, 1));
    1798           24592 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
    1799           20053 :     bool hoisted = loop && id->isType(JSVAL_TYPE_INT32) &&
    1800           44645 :         loop->hoistArrayLengthCheck(DENSE_ARRAY, objv, indexv);
    1801                 : 
    1802                 :     // Get a register with either the object or its slots, depending on whether
    1803                 :     // we are hoisting the slots computation.
    1804                 :     RegisterID baseReg;
    1805           24592 :     if (hoisted) {
    1806             848 :         FrameEntry *slotsFe = loop->invariantArraySlots(objv);
    1807             848 :         baseReg = frame.tempRegForData(slotsFe);
    1808                 :     } else {
    1809           23744 :         baseReg = frame.tempRegForData(obj);
    1810                 :     }
    1811           24592 :     frame.pinReg(baseReg);
    1812                 : 
    1813           24592 :     Int32Key key = id->isConstant()
    1814            6688 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
    1815           31280 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
    1816           24592 :     bool pinKey = !key.isConstant() && key.reg() != baseReg;
    1817           24592 :     if (pinKey)
    1818           17904 :         frame.pinReg(key.reg());
    1819                 : 
    1820           24592 :     RegisterID dataReg = frame.allocReg();
    1821                 : 
    1822           24592 :     MaybeRegisterID typeReg;
    1823           24592 :     if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE || hasTypeBarriers(PC))
    1824           19863 :         typeReg = frame.allocReg();
    1825                 : 
    1826           24592 :     frame.unpinReg(baseReg);
    1827           24592 :     if (pinKey)
    1828           17904 :         frame.unpinReg(key.reg());
    1829                 : 
    1830                 :     RegisterID slotsReg;
    1831           24592 :     if (hoisted) {
    1832             848 :         slotsReg = baseReg;
    1833                 :     } else {
    1834           23744 :         masm.loadPtr(Address(baseReg, JSObject::offsetOfElements()), dataReg);
    1835           23744 :         slotsReg = dataReg;
    1836                 :     }
    1837                 : 
    1838                 :     // Guard on the array's initialized length.
    1839           24592 :     MaybeJump initlenGuard;
    1840           24592 :     if (!hoisted) {
    1841                 :         initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
    1842           23744 :                                              slotsReg, key, Assembler::BelowOrEqual);
    1843           23744 :         if (!allowUndefined)
    1844           22732 :             stubcc.linkExit(initlenGuard.get(), Uses(2));
    1845                 :     }
    1846                 : 
    1847                 :     // Get the slot, skipping the hole check if the array is known to be packed.
    1848           24592 :     Jump holeCheck;
    1849           24592 :     if (key.isConstant()) {
    1850            6688 :         Address slot(slotsReg, key.index() * sizeof(Value));
    1851            6688 :         holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg);
    1852                 :     } else {
    1853           17904 :         JS_ASSERT(key.reg() != dataReg);
    1854           17904 :         BaseIndex slot(slotsReg, key.reg(), masm.JSVAL_SCALE);
    1855           17904 :         holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg);
    1856                 :     }
    1857                 : 
    1858           24592 :     if (!isPacked && !allowUndefined)
    1859            1897 :         stubcc.linkExit(holeCheck, Uses(2));
    1860                 : 
    1861           24592 :     stubcc.leave();
    1862           24592 :     OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
    1863           24592 :     testPushedType(REJOIN_FALLTHROUGH, -2);
    1864                 : 
    1865           24592 :     frame.popn(2);
    1866                 : 
    1867           24592 :     BarrierState barrier;
    1868           24592 :     if (typeReg.isSet()) {
    1869           19863 :         frame.pushRegs(typeReg.reg(), dataReg, type);
    1870           19863 :         barrier = testBarrier(typeReg.reg(), dataReg, false);
    1871                 :     } else {
    1872            4729 :         frame.pushTypedPayload(type, dataReg);
    1873                 :     }
    1874                 : 
    1875           24592 :     stubcc.rejoin(Changes(2));
    1876                 : 
    1877           24592 :     if (allowUndefined) {
    1878            1022 :         if (!hoisted)
    1879            1012 :             stubcc.linkExitDirect(initlenGuard.get(), stubcc.masm.label());
    1880            1022 :         if (!isPacked)
    1881             131 :             stubcc.linkExitDirect(holeCheck, stubcc.masm.label());
    1882            1022 :         JS_ASSERT(type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_UNDEFINED);
    1883            1022 :         if (type == JSVAL_TYPE_UNDEFINED)
    1884             224 :             stubcc.masm.loadValuePayload(UndefinedValue(), dataReg);
    1885                 :         else
    1886             798 :             stubcc.masm.loadValueAsComponents(UndefinedValue(), typeReg.reg(), dataReg);
    1887            1022 :         stubcc.linkRejoin(stubcc.masm.jump());
    1888                 :     }
    1889                 : 
    1890           24592 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
    1891           24592 : }
    1892                 : 
    1893                 : void
    1894             194 : mjit::Compiler::jsop_getelem_args()
    1895                 : {
    1896             194 :     FrameEntry *id = frame.peek(-1);
    1897                 : 
    1898             194 :     if (id->isType(JSVAL_TYPE_DOUBLE))
    1899               0 :         tryConvertInteger(id, Uses(2));
    1900                 : 
    1901                 :     // Test for integer index.
    1902             194 :     if (!id->isTypeKnown()) {
    1903               1 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
    1904               1 :         stubcc.linkExit(guard, Uses(2));
    1905                 :     }
    1906                 : 
    1907                 :     // Allocate registers.
    1908                 : 
    1909             194 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
    1910              57 :     bool hoistedLength = loop && id->isType(JSVAL_TYPE_INT32) &&
    1911             251 :         loop->hoistArgsLengthCheck(indexv);
    1912             194 :     FrameEntry *actualsFe = loop ? loop->invariantArguments() : NULL;
    1913                 : 
    1914             194 :     Int32Key key = id->isConstant()
    1915             135 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
    1916             329 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
    1917             194 :     if (!key.isConstant())
    1918              59 :         frame.pinReg(key.reg());
    1919                 : 
    1920             194 :     RegisterID dataReg = frame.allocReg();
    1921             194 :     RegisterID typeReg = frame.allocReg();
    1922                 : 
    1923                 :     // Guard on nactual.
    1924             194 :     if (!hoistedLength) {
    1925             192 :         Address nactualAddr(JSFrameReg, StackFrame::offsetOfNumActual());
    1926             192 :         MaybeJump rangeGuard;
    1927             192 :         if (key.isConstant()) {
    1928             135 :             JS_ASSERT(key.index() >= 0);
    1929             135 :             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, Imm32(key.index()));
    1930                 :         } else {
    1931              57 :             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, key.reg());
    1932                 :         }
    1933             192 :         stubcc.linkExit(rangeGuard.get(), Uses(2));
    1934                 :     }
    1935                 : 
    1936                 :     RegisterID actualsReg;
    1937             194 :     if (actualsFe) {
    1938              35 :         actualsReg = frame.tempRegForData(actualsFe);
    1939                 :     } else {
    1940             159 :         actualsReg = dataReg;
    1941             159 :         masm.loadFrameActuals(outerScript->function(), actualsReg);
    1942                 :     }
    1943                 : 
    1944             194 :     if (!key.isConstant())
    1945              59 :         frame.unpinReg(key.reg());
    1946                 : 
    1947             194 :     if (key.isConstant()) {
    1948             135 :         Address arg(actualsReg, key.index() * sizeof(Value));
    1949             135 :         masm.loadValueAsComponents(arg, typeReg, dataReg);
    1950                 :     } else {
    1951              59 :         JS_ASSERT(key.reg() != dataReg);
    1952              59 :         BaseIndex arg(actualsReg, key.reg(), masm.JSVAL_SCALE);
    1953              59 :         masm.loadValueAsComponents(arg, typeReg, dataReg);
    1954                 :     }
    1955                 : 
    1956             194 :     stubcc.leave();
    1957             194 :     OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
    1958             194 :     testPushedType(REJOIN_FALLTHROUGH, -2);
    1959                 : 
    1960             194 :     frame.popn(2);
    1961             194 :     frame.pushRegs(typeReg, dataReg, knownPushedType(0));
    1962             194 :     BarrierState barrier = testBarrier(typeReg, dataReg, false);
    1963                 : 
    1964             194 :     stubcc.rejoin(Changes(2));
    1965                 : 
    1966             194 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
    1967             194 : }
    1968                 : 
    1969                 : #ifdef JS_METHODJIT_TYPED_ARRAY
    1970                 : bool
    1971            1286 : mjit::Compiler::jsop_getelem_typed(int atype)
    1972                 : {
    1973                 :     // Unlike dense arrays, the types of elements in typed arrays are not
    1974                 :     // guaranteed to be present in the object's type, and we need to use
    1975                 :     // knowledge about the possible contents of the array vs. the types
    1976                 :     // that have been read out of it to figure out how to do the load.
    1977                 : 
    1978                 :     //                          Array contents
    1979                 :     //                   Float     Uint32_t         Int32
    1980                 :     // Observed types
    1981                 :     //
    1982                 :     // {int}             XXX       reg pair+test  reg
    1983                 :     // {int,float}       FP reg    FP reg         reg pair
    1984                 :     // {X,int}           XXX       reg pair+test  reg pair
    1985                 :     // {X,int,float}     reg pair  reg pair       reg pair
    1986                 :     // {X}               XXX       XXX            XXX
    1987                 : 
    1988                 :     // Reject entries marked 'XXX' above, and compile a normal GETELEM.
    1989            1286 :     types::TypeSet *pushedTypes = pushedTypeSet(0);
    1990            1286 :     if (atype == TypedArray::TYPE_FLOAT32 || atype == TypedArray::TYPE_FLOAT64) {
    1991             710 :         if (!pushedTypes->hasType(types::Type::DoubleType()))
    1992              90 :             return false;
    1993                 :     } else {
    1994             886 :         if (!pushedTypes->hasType(types::Type::Int32Type()))
    1995             219 :             return false;
    1996                 :     }
    1997                 : 
    1998             977 :     FrameEntry *obj = frame.peek(-2);
    1999             977 :     FrameEntry *id = frame.peek(-1);
    2000                 : 
    2001                 :     // We might not know whether this is an object, but if it's an object we
    2002                 :     // know it is a typed array.
    2003             977 :     if (!obj->isTypeKnown()) {
    2004             331 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
    2005             331 :         stubcc.linkExit(guard, Uses(2));
    2006                 :     }
    2007                 : 
    2008             977 :     if (id->isType(JSVAL_TYPE_DOUBLE))
    2009               0 :         tryConvertInteger(id, Uses(2));
    2010                 : 
    2011                 :     // Test for integer index.
    2012             977 :     if (!id->isTypeKnown()) {
    2013              52 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
    2014              52 :         stubcc.linkExit(guard, Uses(2));
    2015                 :     }
    2016                 : 
    2017                 :     // Load object and key.
    2018             977 :     Int32Key key = id->isConstant()
    2019             816 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
    2020            1793 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
    2021             977 :     if (!key.isConstant())
    2022             161 :         frame.pinReg(key.reg());
    2023                 : 
    2024             977 :     analyze::CrossSSAValue objv(a->inlineIndex, analysis->poppedValue(PC, 1));
    2025             977 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
    2026             305 :     bool hoisted = loop && id->isType(JSVAL_TYPE_INT32) &&
    2027            1282 :         loop->hoistArrayLengthCheck(TYPED_ARRAY, objv, indexv);
    2028                 : 
    2029                 :     RegisterID objReg;
    2030             977 :     if (hoisted) {
    2031              12 :         FrameEntry *slotsFe = loop->invariantArraySlots(objv);
    2032              12 :         objReg = frame.tempRegForData(slotsFe);
    2033              12 :         frame.pinReg(objReg);
    2034                 :     } else {
    2035             965 :         objReg = frame.copyDataIntoReg(obj);
    2036                 : 
    2037                 :         // Bounds check.
    2038             965 :         int lengthOffset = TypedArray::lengthOffset() + offsetof(jsval_layout, s.payload);
    2039                 :         Jump lengthGuard = masm.guardArrayExtent(lengthOffset,
    2040             965 :                                                  objReg, key, Assembler::BelowOrEqual);
    2041             965 :         stubcc.linkExit(lengthGuard, Uses(2));
    2042                 : 
    2043                 :         // Load the array's packed data vector.
    2044             965 :         masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
    2045                 :     }
    2046                 : 
    2047                 :     // We can load directly into an FP-register if the following conditions
    2048                 :     // are met:
    2049                 :     // 1) The array is an Uint32Array or a float array (loadFromTypedArray
    2050                 :     //    can't load into an FP-register for other arrays).
    2051                 :     // 2) The result is definitely a double (the result type set can include
    2052                 :     //    other types after reading out-of-bound values).
    2053             977 :     AnyRegisterID dataReg;
    2054             977 :     MaybeRegisterID typeReg, tempReg;
    2055             977 :     JSValueType type = knownPushedType(0);
    2056                 :     bool maybeReadFloat = (atype == TypedArray::TYPE_FLOAT32 ||
    2057                 :                            atype == TypedArray::TYPE_FLOAT64 ||
    2058             977 :                            atype == TypedArray::TYPE_UINT32);
    2059             977 :     if (maybeReadFloat && type == JSVAL_TYPE_DOUBLE) {
    2060             325 :         dataReg = frame.allocFPReg();
    2061                 :         // Need an extra reg to convert uint32_t to double.
    2062             650 :         if (atype == TypedArray::TYPE_UINT32)
    2063              19 :             tempReg = frame.allocReg();
    2064                 :     } else {
    2065             652 :         dataReg = frame.allocReg();
    2066                 :         // loadFromTypedArray expects a type register for Uint32Array or
    2067                 :         // float arrays. Also allocate a type register if the result may not
    2068                 :         // be int32_t (due to reading out-of-bound values) or if there's a
    2069                 :         // type barrier.
    2070             652 :         if (maybeReadFloat || type != JSVAL_TYPE_INT32)
    2071             113 :             typeReg = frame.allocReg();
    2072                 :     }
    2073                 : 
    2074                 :     // Load value from the array.
    2075             977 :     masm.loadFromTypedArray(atype, objReg, key, typeReg, dataReg, tempReg);
    2076                 : 
    2077             977 :     if (hoisted)
    2078              12 :         frame.unpinReg(objReg);
    2079                 :     else
    2080             965 :         frame.freeReg(objReg);
    2081             977 :     if (!key.isConstant())
    2082             161 :         frame.unpinReg(key.reg());
    2083             977 :     if (tempReg.isSet())
    2084              19 :         frame.freeReg(tempReg.reg());
    2085                 : 
    2086            1074 :     if (atype == TypedArray::TYPE_UINT32 &&
    2087              97 :         !pushedTypes->hasType(types::Type::DoubleType())) {
    2088              78 :         Jump isDouble = masm.testDouble(Assembler::Equal, typeReg.reg());
    2089              78 :         stubcc.linkExit(isDouble, Uses(2));
    2090                 :     }
    2091                 : 
    2092             977 :     stubcc.leave();
    2093             977 :     OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
    2094             977 :     testPushedType(REJOIN_FALLTHROUGH, -2);
    2095                 : 
    2096             977 :     frame.popn(2);
    2097                 : 
    2098             977 :     BarrierState barrier;
    2099             977 :     if (dataReg.isFPReg()) {
    2100             325 :         frame.pushDouble(dataReg.fpreg());
    2101             652 :     } else if (typeReg.isSet()) {
    2102             113 :         frame.pushRegs(typeReg.reg(), dataReg.reg(), knownPushedType(0));
    2103                 :     } else {
    2104             539 :         JS_ASSERT(type == JSVAL_TYPE_INT32);
    2105             539 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, dataReg.reg());
    2106                 :     }
    2107             977 :     stubcc.rejoin(Changes(2));
    2108                 : 
    2109             977 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
    2110                 : 
    2111             977 :     return true;
    2112                 : }
    2113                 : #endif /* JS_METHODJIT_TYPED_ARRAY */
    2114                 : 
    2115                 : bool
    2116          252899 : mjit::Compiler::jsop_getelem()
    2117                 : {
    2118          252899 :     FrameEntry *obj = frame.peek(-2);
    2119          252899 :     FrameEntry *id = frame.peek(-1);
    2120                 : 
    2121          252899 :     if (!IsCacheableGetElem(obj, id)) {
    2122              94 :         jsop_getelem_slow();
    2123              94 :         return true;
    2124                 :     }
    2125                 : 
    2126                 :     // If the object is definitely an arguments object, a dense array or a typed array
    2127                 :     // we can generate code directly without using an inline cache.
    2128          252805 :     if (cx->typeInferenceEnabled() && !id->isType(JSVAL_TYPE_STRING)) {
    2129           37609 :         types::TypeSet *types = analysis->poppedTypes(PC, 1);
    2130           37609 :         if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
    2131                 :             // Inline arguments path.
    2132             194 :             jsop_getelem_args();
    2133             194 :             return true;
    2134                 :         }
    2135                 : 
    2136           98470 :         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
    2137           36425 :             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
    2138           24630 :             !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
    2139                 :             // Inline dense array path.
    2140           24592 :             bool packed = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
    2141           24592 :             jsop_getelem_dense(packed);
    2142           24592 :             return true;
    2143                 :         }
    2144                 : 
    2145                 : #ifdef JS_METHODJIT_TYPED_ARRAY
    2146           24656 :         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
    2147           11833 :             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
    2148                 :             // Inline typed array path.
    2149            1475 :             int atype = types->getTypedArrayType(cx);
    2150            1475 :             if (atype != TypedArray::TYPE_MAX) {
    2151            1286 :                 if (jsop_getelem_typed(atype))
    2152             977 :                     return true;
    2153                 :                 // Fallthrough to the normal GETELEM path.
    2154                 :             }
    2155                 :         }
    2156                 : #endif
    2157                 :     }
    2158                 : 
    2159          227042 :     frame.forgetMismatchedObject(obj);
    2160                 : 
    2161          227042 :     if (id->isType(JSVAL_TYPE_DOUBLE) || !globalObj) {
    2162          205347 :         jsop_getelem_slow();
    2163          205347 :         return true;
    2164                 :     }
    2165                 : 
    2166           21695 :     GetElementICInfo ic = GetElementICInfo(JSOp(*PC));
    2167                 : 
    2168                 :     // Pin the top of the stack to avoid spills, before allocating registers.
    2169           21695 :     MaybeRegisterID pinnedIdData = frame.maybePinData(id);
    2170           21695 :     MaybeRegisterID pinnedIdType = frame.maybePinType(id);
    2171                 : 
    2172           21695 :     MaybeJump objTypeGuard;
    2173           21695 :     if (!obj->isTypeKnown()) {
    2174                 :         // Test the type of the object without spilling the payload.
    2175           17682 :         MaybeRegisterID pinnedObjData = frame.maybePinData(obj);
    2176           17682 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
    2177           17682 :         frame.maybeUnpinReg(pinnedObjData);
    2178                 : 
    2179                 :         // Create a sync path, which we'll rejoin manually later. This is safe
    2180                 :         // as long as the IC does not build a stub; it won't, because |obj|
    2181                 :         // won't be an object. If we extend this IC to support strings, all
    2182                 :         // that needs to change is a little code movement.
    2183           17682 :         stubcc.linkExit(guard, Uses(2));
    2184           17682 :         objTypeGuard = stubcc.masm.jump();
    2185                 :     }
    2186                 : 
    2187                 :     // Get a mutable register for the object. This will be the data reg.
    2188           21695 :     ic.objReg = frame.copyDataIntoReg(obj);
    2189                 : 
    2190                 :     // Get a mutable register for pushing the result type. We kill two birds
    2191                 :     // with one stone by making sure, if the key type is not known, to be loaded
    2192                 :     // into this register. In this case it is both an input and an output.
    2193           21695 :     frame.maybeUnpinReg(pinnedIdType);
    2194           21695 :     if (id->isConstant() || id->isTypeKnown())
    2195           13454 :         ic.typeReg = frame.allocReg();
    2196                 :     else
    2197            8241 :         ic.typeReg = frame.copyTypeIntoReg(id);
    2198                 : 
    2199                 :     // Fill in the id value.
    2200           21695 :     frame.maybeUnpinReg(pinnedIdData);
    2201           21695 :     if (id->isConstant()) {
    2202           10232 :         ic.id = ValueRemat::FromConstant(id->getValue());
    2203                 :     } else {
    2204           11463 :         RegisterID dataReg = frame.tempRegForData(id);
    2205           11463 :         if (id->isTypeKnown())
    2206            3222 :             ic.id = ValueRemat::FromKnownType(id->getKnownType(), dataReg);
    2207                 :         else
    2208            8241 :             ic.id = ValueRemat::FromRegisters(ic.typeReg, dataReg);
    2209                 :     }
    2210                 : 
    2211                 :     RESERVE_IC_SPACE(masm);
    2212           21695 :     ic.fastPathStart = masm.label();
    2213                 : 
    2214                 :     // Note: slow path here is safe, since the frame will not be modified.
    2215                 :     RESERVE_OOL_SPACE(stubcc.masm);
    2216           21695 :     ic.slowPathStart = stubcc.masm.label();
    2217           21695 :     frame.sync(stubcc.masm, Uses(2));
    2218                 : 
    2219           21695 :     if (id->mightBeType(JSVAL_TYPE_INT32)) {
    2220                 :         // Always test the type first (see comment in PolyIC.h).
    2221           20397 :         if (!id->isTypeKnown()) {
    2222            8241 :             ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
    2223            8241 :             stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
    2224                 :         }
    2225                 : 
    2226                 :         // Guard obj is a dense array.
    2227           20397 :         Shape *shape = GetDenseArrayShape(cx, globalObj);
    2228           20397 :         if (!shape)
    2229               0 :             return false;
    2230           20397 :         ic.shapeGuard = masm.guardShape(ic.objReg, shape);
    2231           20397 :         stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
    2232                 : 
    2233           20397 :         Int32Key key = id->isConstant()
    2234           10205 :                        ? Int32Key::FromConstant(id->getValue().toInt32())
    2235           30602 :                        : Int32Key::FromRegister(ic.id.dataReg());
    2236                 : 
    2237                 :         Assembler::FastArrayLoadFails fails =
    2238           20397 :             masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg);
    2239                 : 
    2240           20397 :         stubcc.linkExitDirect(fails.rangeCheck, ic.slowPathStart);
    2241           20397 :         stubcc.linkExitDirect(fails.holeCheck, ic.slowPathStart);
    2242                 :     } else {
    2243                 :         // The type is known to not be dense-friendly ahead of time, so always
    2244                 :         // fall back to a slow path.
    2245            1298 :         ic.shapeGuard = masm.jump();
    2246            1298 :         stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
    2247                 :     }
    2248                 : 
    2249           21695 :     stubcc.leave();
    2250           21695 :     if (objTypeGuard.isSet())
    2251           17682 :         objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
    2252                 : #ifdef JS_POLYIC
    2253           21695 :     passICAddress(&ic);
    2254           21695 :     ic.slowPathCall = OOL_STUBCALL(ic::GetElement, REJOIN_FALLTHROUGH);
    2255                 : #else
    2256                 :     ic.slowPathCall = OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
    2257                 : #endif
    2258                 : 
    2259           21695 :     testPushedType(REJOIN_FALLTHROUGH, -2);
    2260                 : 
    2261           21695 :     ic.fastPathRejoin = masm.label();
    2262           21695 :     ic.forcedTypeBarrier = analysis->getCode(PC).getStringElement;
    2263                 : 
    2264                 :     CHECK_IC_SPACE();
    2265                 : 
    2266           21695 :     frame.popn(2);
    2267           21695 :     frame.pushRegs(ic.typeReg, ic.objReg, knownPushedType(0));
    2268                 :     BarrierState barrier = testBarrier(ic.typeReg, ic.objReg, false, false,
    2269           21695 :                                        /* force = */ ic.forcedTypeBarrier);
    2270                 : 
    2271           21695 :     stubcc.rejoin(Changes(1));
    2272                 : 
    2273                 : #ifdef JS_POLYIC
    2274           21695 :     if (!getElemICs.append(ic))
    2275               0 :         return false;
    2276                 : #endif
    2277                 : 
    2278           21695 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
    2279           21695 :     return true;
    2280                 : }
    2281                 : 
    2282                 : static inline bool
    2283           28425 : ReallySimpleStrictTest(FrameEntry *fe)
    2284                 : {
    2285           28425 :     if (!fe->isTypeKnown())
    2286           15445 :         return false;
    2287           12980 :     JSValueType type = fe->getKnownType();
    2288           12980 :     return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED;
    2289                 : }
    2290                 : 
    2291                 : static inline bool
    2292           24742 : BooleanStrictTest(FrameEntry *fe)
    2293                 : {
    2294           24742 :     return fe->isConstant() && fe->getKnownType() == JSVAL_TYPE_BOOLEAN;
    2295                 : }
    2296                 : 
    2297                 : void
    2298           15082 : mjit::Compiler::jsop_stricteq(JSOp op)
    2299                 : {
    2300           15082 :     FrameEntry *rhs = frame.peek(-1);
    2301           15082 :     FrameEntry *lhs = frame.peek(-2);
    2302                 : 
    2303           15082 :     Assembler::Condition cond = (op == JSOP_STRICTEQ) ? Assembler::Equal : Assembler::NotEqual;
    2304                 : 
    2305                 :     /*
    2306                 :      * NB: x64 can do full-Value comparisons. This is beneficial
    2307                 :      * to do if the payload/type are not yet in registers.
    2308                 :      */
    2309                 : 
    2310                 :     /* Constant-fold. */
    2311           15082 :     if (lhs->isConstant() && rhs->isConstant()) {
    2312                 :         bool b;
    2313             408 :         StrictlyEqual(cx, lhs->getValue(), rhs->getValue(), &b);
    2314             408 :         frame.popn(2);
    2315             408 :         frame.push(BooleanValue((op == JSOP_STRICTEQ) ? b : !b));
    2316             408 :         return;
    2317                 :     }
    2318                 : 
    2319           14674 :     if (frame.haveSameBacking(lhs, rhs)) {
    2320                 :         /* False iff NaN. */
    2321             269 :         frame.pop();
    2322                 : 
    2323             269 :         if (lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_DOUBLE)) {
    2324             113 :             frame.pop();
    2325             113 :             frame.push(BooleanValue(op == JSOP_STRICTEQ));
    2326             113 :             return;
    2327                 :         }
    2328                 : 
    2329             156 :         if (lhs->isType(JSVAL_TYPE_DOUBLE))
    2330               7 :             frame.forgetKnownDouble(lhs);
    2331                 : 
    2332                 :         /* Assume NaN is either in canonical form or has the sign bit set (by jsop_neg). */
    2333             156 :         RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
    2334             156 :         RegisterID treg = frame.copyTypeIntoReg(lhs);
    2335                 : 
    2336             156 :         Assembler::Condition oppositeCond = (op == JSOP_STRICTEQ) ? Assembler::NotEqual : Assembler::Equal;
    2337                 : 
    2338                 :         /* Ignore the sign bit. */
    2339             156 :         masm.lshiftPtr(Imm32(1), treg);
    2340                 : #ifdef JS_CPU_SPARC
    2341                 :         /* On Sparc the result 0/0 is 0x7FFFFFFF not 0x7FF80000 */
    2342                 :         static const int ShiftedCanonicalNaNType1 = 0x7FFFFFFF << 1;
    2343                 :         static const int ShiftedCanonicalNaNType2 = 0x7FF80000 << 1;
    2344                 :         RegisterID result1 = frame.allocReg();
    2345                 :         masm.setPtr(oppositeCond, treg, Imm32(ShiftedCanonicalNaNType1), result1);
    2346                 :         masm.setPtr(oppositeCond, treg, Imm32(ShiftedCanonicalNaNType2), result);
    2347                 :         if(op == JSOP_STRICTEQ) {
    2348                 :             masm.and32(result1, result);
    2349                 :         } else {
    2350                 :             masm.or32(result1, result);
    2351                 :         }
    2352                 :         frame.freeReg(result1);
    2353                 : #elif defined(JS_CPU_MIPS)
    2354                 :         /* On MIPS the result 0.0/0.0 is 0x7FF7FFFF.
    2355                 :            We need to manually set it to 0x7FF80000. */
    2356                 :         static const int ShiftedCanonicalNaNType = 0x7FF80000 << 1;
    2357                 :         masm.setShiftedCanonicalNaN(treg, treg);
    2358                 :         masm.setPtr(oppositeCond, treg, Imm32(ShiftedCanonicalNaNType), result);
    2359                 : #elif !defined(JS_CPU_X64)
    2360                 :         static const int ShiftedCanonicalNaNType = 0x7FF80000 << 1;
    2361             156 :         masm.setPtr(oppositeCond, treg, Imm32(ShiftedCanonicalNaNType), result);
    2362                 : #else
    2363                 :         static const void *ShiftedCanonicalNaNType = (void *)(0x7FF8000000000000 << 1);
    2364                 :         masm.move(ImmPtr(ShiftedCanonicalNaNType), Registers::ScratchReg);
    2365                 :         masm.setPtr(oppositeCond, treg, Registers::ScratchReg, result);
    2366                 : #endif
    2367             156 :         frame.freeReg(treg);
    2368                 : 
    2369             156 :         frame.pop();
    2370             156 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    2371             156 :         return;
    2372                 :     }
    2373                 : 
    2374                 :     /* Comparison against undefined or null is super easy. */
    2375                 :     bool lhsTest;
    2376           14405 :     if ((lhsTest = ReallySimpleStrictTest(lhs)) || ReallySimpleStrictTest(rhs)) {
    2377            2034 :         FrameEntry *test = lhsTest ? rhs : lhs;
    2378            2034 :         FrameEntry *known = lhsTest ? lhs : rhs;
    2379            2034 :         RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
    2380                 : 
    2381            2034 :         if (test->isTypeKnown()) {
    2382             585 :             masm.move(Imm32((test->getKnownType() == known->getKnownType()) ==
    2383             585 :                             (op == JSOP_STRICTEQ)), result);
    2384             585 :             frame.popn(2);
    2385             585 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    2386             585 :             return;
    2387                 :         }
    2388                 : 
    2389                 :         /* This is only true if the other side is |null|. */
    2390                 : #ifndef JS_CPU_X64
    2391            1449 :         JSValueTag mask = known->getKnownTag();
    2392            1449 :         if (frame.shouldAvoidTypeRemat(test))
    2393               1 :             masm.set32(cond, masm.tagOf(frame.addressOf(test)), Imm32(mask), result);
    2394                 :         else
    2395            1448 :             masm.set32(cond, frame.tempRegForType(test), Imm32(mask), result);
    2396                 : #else
    2397                 :         RegisterID maskReg = frame.allocReg();
    2398                 :         masm.move(ImmTag(known->getKnownTag()), maskReg);
    2399                 : 
    2400                 :         RegisterID r = frame.tempRegForType(test);
    2401                 :         masm.setPtr(cond, r, maskReg, result);
    2402                 : 
    2403                 :         frame.freeReg(maskReg);
    2404                 : #endif
    2405            1449 :         frame.popn(2);
    2406            1449 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    2407            1449 :         return;
    2408                 :     }
    2409                 : 
    2410                 :     /* Hardcoded booleans are easy too. */
    2411           12371 :     if ((lhsTest = BooleanStrictTest(lhs)) || BooleanStrictTest(rhs)) {
    2412             940 :         FrameEntry *test = lhsTest ? rhs : lhs;
    2413                 : 
    2414             940 :         if (test->isTypeKnown() && test->isNotType(JSVAL_TYPE_BOOLEAN)) {
    2415              26 :             RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
    2416              26 :             frame.popn(2);
    2417                 : 
    2418              26 :             masm.move(Imm32(op == JSOP_STRICTNE), result);
    2419              26 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    2420              26 :             return;
    2421                 :         }
    2422                 : 
    2423             914 :         if (test->isConstant()) {
    2424               0 :             frame.popn(2);
    2425               0 :             const Value &L = lhs->getValue();
    2426               0 :             const Value &R = rhs->getValue();
    2427               0 :             frame.push(BooleanValue((L.toBoolean() == R.toBoolean()) == (op == JSOP_STRICTEQ)));
    2428               0 :             return;
    2429                 :         }
    2430                 : 
    2431             914 :         RegisterID data = frame.copyDataIntoReg(test);
    2432                 : 
    2433             914 :         RegisterID result = data;
    2434             914 :         if (!(Registers::maskReg(data) & Registers::SingleByteRegs))
    2435             284 :             result = frame.allocReg(Registers::SingleByteRegs).reg();
    2436                 :         
    2437             914 :         Jump notBoolean;
    2438             914 :         if (!test->isTypeKnown())
    2439             812 :            notBoolean = frame.testBoolean(Assembler::NotEqual, test);
    2440                 : 
    2441                 :         /* Do a dynamic test. */
    2442             914 :         bool val = lhsTest ? lhs->getValue().toBoolean() : rhs->getValue().toBoolean();
    2443             914 :         masm.set32(cond, data, Imm32(val), result);
    2444                 : 
    2445             914 :         if (!test->isTypeKnown()) {
    2446             812 :             Jump done = masm.jump();
    2447             812 :             notBoolean.linkTo(masm.label(), &masm);
    2448             812 :             masm.move(Imm32((op == JSOP_STRICTNE)), result);
    2449             812 :             done.linkTo(masm.label(), &masm);
    2450                 :         }
    2451                 : 
    2452             914 :         if (data != result)
    2453             284 :             frame.freeReg(data);
    2454                 : 
    2455             914 :         frame.popn(2);
    2456             914 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
    2457             914 :         return;
    2458                 :     }
    2459                 : 
    2460           11431 :     if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
    2461            1431 :         FrameEntry *maybeNotStr = lhs->isType(JSVAL_TYPE_STRING) ? rhs : lhs;
    2462                 : 
    2463            1431 :         if (maybeNotStr->isNotType(JSVAL_TYPE_STRING)) {
    2464              83 :             frame.popn(2);
    2465              83 :             frame.push(BooleanValue(op == JSOP_STRICTNE));
    2466              83 :             return;
    2467                 :         }
    2468                 : 
    2469            1348 :         if (!maybeNotStr->isTypeKnown()) {
    2470            1057 :             JS_ASSERT(!maybeNotStr->isConstant());
    2471            1057 :             Jump j = frame.testString(Assembler::NotEqual, maybeNotStr);
    2472            1057 :             stubcc.linkExit(j, Uses(2));
    2473                 :         }
    2474                 : 
    2475            1348 :         FrameEntry *op1 = lhs->isConstant() ? rhs : lhs;
    2476            1348 :         FrameEntry *op2 = lhs->isConstant() ? lhs : rhs;
    2477            1348 :         JS_ASSERT(!op1->isConstant());
    2478                 : 
    2479                 :         /* ReturnReg is safely usable with set32, since %ah can be accessed. */
    2480            1348 :         RegisterID resultReg = Registers::ReturnReg;
    2481            1348 :         frame.takeReg(resultReg);
    2482            1348 :         RegisterID tmpReg = frame.allocReg();
    2483            1348 :         RegisterID reg1 = frame.tempRegForData(op1);
    2484            1348 :         frame.pinReg(reg1);
    2485                 : 
    2486                 :         RegisterID reg2;
    2487            1348 :         if (op2->isConstant()) {
    2488            1137 :             reg2 = frame.allocReg();
    2489            1137 :             JSString *str = op2->getValue().toString();
    2490            1137 :             JS_ASSERT(str->isAtom());
    2491            1137 :             masm.move(ImmPtr(str), reg2);
    2492                 :         } else {
    2493             211 :             reg2 = frame.tempRegForData(op2);
    2494             211 :             frame.pinReg(reg2);
    2495                 :         }
    2496                 : 
    2497            1348 :         JS_ASSERT(reg1 != resultReg);
    2498            1348 :         JS_ASSERT(reg1 != tmpReg);
    2499            1348 :         JS_ASSERT(reg2 != resultReg);
    2500            1348 :         JS_ASSERT(reg2 != tmpReg);
    2501                 : 
    2502                 :         /* JSString::isAtom === (lengthAndFlags & ATOM_MASK == 0) */
    2503                 :         JS_STATIC_ASSERT(JSString::ATOM_FLAGS == 0);
    2504            1348 :         Imm32 atomMask(JSString::ATOM_MASK);
    2505                 : 
    2506            1348 :         masm.load32(Address(reg1, JSString::offsetOfLengthAndFlags()), tmpReg);
    2507            1348 :         Jump op1NotAtomized = masm.branchTest32(Assembler::NonZero, tmpReg, atomMask);
    2508            1348 :         stubcc.linkExit(op1NotAtomized, Uses(2));
    2509                 : 
    2510            1348 :         if (!op2->isConstant()) {
    2511             211 :             masm.load32(Address(reg2, JSString::offsetOfLengthAndFlags()), tmpReg);
    2512             211 :             Jump op2NotAtomized = masm.branchTest32(Assembler::NonZero, tmpReg, atomMask);
    2513             211 :             stubcc.linkExit(op2NotAtomized, Uses(2));
    2514                 :         }
    2515                 : 
    2516            1348 :         masm.set32(cond, reg1, reg2, resultReg);
    2517                 : 
    2518            1348 :         frame.unpinReg(reg1);
    2519            1348 :         if (op2->isConstant())
    2520            1137 :             frame.freeReg(reg2);
    2521                 :         else
    2522             211 :             frame.unpinReg(reg2);
    2523            1348 :         frame.freeReg(tmpReg);
    2524                 : 
    2525            1348 :         stubcc.leave();
    2526            1348 :         if (op == JSOP_STRICTEQ)
    2527            1178 :             OOL_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
    2528                 :         else
    2529             170 :             OOL_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
    2530                 : 
    2531            1348 :         frame.popn(2);
    2532            1348 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
    2533                 : 
    2534            1348 :         stubcc.rejoin(Changes(1));
    2535            1348 :         return;
    2536                 :     }
    2537                 : 
    2538           13732 :     if (cx->typeInferenceEnabled() &&
    2539            3732 :         lhs->isType(JSVAL_TYPE_OBJECT) && rhs->isType(JSVAL_TYPE_OBJECT))
    2540                 :     {
    2541             117 :         CompileStatus status = jsop_equality_obj_obj(op, NULL, JSOP_NOP);
    2542             117 :         if (status == Compile_Okay) return;
    2543              10 :         JS_ASSERT(status == Compile_Skipped);
    2544                 :     }
    2545                 : 
    2546                 :     /* Is it impossible that both Values are ints? */
    2547           24646 :     if ((lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_INT32)) ||
    2548           14753 :         (rhs->isTypeKnown() && rhs->isNotType(JSVAL_TYPE_INT32))) {
    2549             687 :         prepareStubCall(Uses(2));
    2550                 : 
    2551             687 :         if (op == JSOP_STRICTEQ)
    2552             357 :             INLINE_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
    2553                 :         else
    2554             330 :             INLINE_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
    2555                 : 
    2556             687 :         frame.popn(2);
    2557             687 :         frame.pushSynced(JSVAL_TYPE_BOOLEAN);
    2558             687 :         return;
    2559                 :     }
    2560                 : 
    2561                 : #if !defined JS_CPU_ARM && !defined JS_CPU_SPARC
    2562                 :     /* Try an integer fast-path. */
    2563            9206 :     bool needStub = false;
    2564            9206 :     if (!lhs->isTypeKnown()) {
    2565            8172 :         Jump j = frame.testInt32(Assembler::NotEqual, lhs);
    2566            8172 :         stubcc.linkExit(j, Uses(2));
    2567            8172 :         needStub = true;
    2568                 :     }
    2569                 : 
    2570            9206 :     if (!rhs->isTypeKnown() && !frame.haveSameBacking(lhs, rhs)) {
    2571            3893 :         Jump j = frame.testInt32(Assembler::NotEqual, rhs);
    2572            3893 :         stubcc.linkExit(j, Uses(2));
    2573            3893 :         needStub = true;
    2574                 :     }
    2575                 : 
    2576            9206 :     FrameEntry *test  = lhs->isConstant() ? rhs : lhs;
    2577            9206 :     FrameEntry *other = lhs->isConstant() ? lhs : rhs;
    2578                 : 
    2579                 :     /* ReturnReg is safely usable with set32, since %ah can be accessed. */
    2580            9206 :     RegisterID resultReg = Registers::ReturnReg;
    2581            9206 :     frame.takeReg(resultReg);
    2582            9206 :     RegisterID testReg = frame.tempRegForData(test);
    2583            9206 :     frame.pinReg(testReg);
    2584                 : 
    2585            9206 :     JS_ASSERT(resultReg != testReg);
    2586                 : 
    2587                 :     /* Set boolean in resultReg. */
    2588            9206 :     if (other->isConstant()) {
    2589            5022 :         masm.set32(cond, testReg, Imm32(other->getValue().toInt32()), resultReg);
    2590            4184 :     } else if (frame.shouldAvoidDataRemat(other)) {
    2591             807 :         masm.set32(cond, testReg, frame.addressOf(other), resultReg);
    2592                 :     } else {
    2593            3377 :         RegisterID otherReg = frame.tempRegForData(other);
    2594                 : 
    2595            3377 :         JS_ASSERT(otherReg != resultReg);
    2596            3377 :         JS_ASSERT(otherReg != testReg);
    2597                 : 
    2598            3377 :         masm.set32(cond, testReg, otherReg, resultReg);
    2599                 :     }
    2600                 : 
    2601            9206 :     frame.unpinReg(testReg);
    2602                 : 
    2603            9206 :     if (needStub) {
    2604            8264 :         stubcc.leave();
    2605            8264 :         if (op == JSOP_STRICTEQ)
    2606            6920 :             OOL_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
    2607                 :         else
    2608            1344 :             OOL_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
    2609                 :     }
    2610                 : 
    2611            9206 :     frame.popn(2);
    2612            9206 :     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
    2613                 : 
    2614            9206 :     if (needStub)
    2615            8264 :         stubcc.rejoin(Changes(1));
    2616                 : #else
    2617                 :     /* TODO: Port set32() logic to ARM. */
    2618                 :     prepareStubCall(Uses(2));
    2619                 : 
    2620                 :     if (op == JSOP_STRICTEQ)
    2621                 :         INLINE_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
    2622                 :     else
    2623                 :         INLINE_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
    2624                 : 
    2625                 :     frame.popn(2);
    2626                 :     frame.pushSynced(JSVAL_TYPE_BOOLEAN);
    2627                 :     return;
    2628                 : #endif
    2629                 : }
    2630                 : 
    2631                 : void
    2632          206519 : mjit::Compiler::jsop_pos()
    2633                 : {
    2634          206519 :     FrameEntry *top = frame.peek(-1);
    2635                 : 
    2636          206519 :     if (top->isTypeKnown()) {
    2637            5184 :         if (top->getKnownType() <= JSVAL_TYPE_INT32)
    2638            5016 :             return;
    2639             168 :         prepareStubCall(Uses(1));
    2640             168 :         INLINE_STUBCALL(stubs::Pos, REJOIN_POS);
    2641             168 :         frame.pop();
    2642             168 :         frame.pushSynced(knownPushedType(0));
    2643             168 :         return;
    2644                 :     }
    2645                 : 
    2646          201335 :     frame.giveOwnRegs(top);
    2647                 : 
    2648          201335 :     Jump j;
    2649          201335 :     if (frame.shouldAvoidTypeRemat(top))
    2650          192623 :         j = masm.testNumber(Assembler::NotEqual, frame.addressOf(top));
    2651                 :     else
    2652            8712 :         j = masm.testNumber(Assembler::NotEqual, frame.tempRegForType(top));
    2653          201335 :     stubcc.linkExit(j, Uses(1));
    2654                 : 
    2655          201335 :     stubcc.leave();
    2656          201335 :     OOL_STUBCALL(stubs::Pos, REJOIN_POS);
    2657                 : 
    2658          201335 :     stubcc.rejoin(Changes(1));
    2659                 : }
    2660                 : 
    2661                 : void
    2662               0 : mjit::Compiler::jsop_initmethod()
    2663                 : {
    2664                 : #ifdef DEBUG
    2665               0 :     FrameEntry *obj = frame.peek(-2);
    2666                 : #endif
    2667               0 :     JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC));
    2668                 : 
    2669                 :     /* Initializers with INITMETHOD are not fast yet. */
    2670               0 :     JS_ASSERT(!frame.extra(obj).initObject);
    2671                 : 
    2672               0 :     prepareStubCall(Uses(2));
    2673               0 :     masm.move(ImmPtr(atom), Registers::ArgReg1);
    2674               0 :     INLINE_STUBCALL(stubs::InitMethod, REJOIN_FALLTHROUGH);
    2675               0 : }
    2676                 : 
    2677                 : void
    2678            7628 : mjit::Compiler::jsop_initprop()
    2679                 : {
    2680            7628 :     FrameEntry *obj = frame.peek(-2);
    2681            7628 :     FrameEntry *fe = frame.peek(-1);
    2682            7628 :     JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC));
    2683                 : 
    2684            7628 :     JSObject *baseobj = frame.extra(obj).initObject;
    2685                 : 
    2686            7628 :     if (!baseobj || monitored(PC)) {
    2687            3029 :         prepareStubCall(Uses(2));
    2688            3029 :         masm.move(ImmPtr(atom), Registers::ArgReg1);
    2689            3029 :         INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
    2690            3029 :         return;
    2691                 :     }
    2692                 : 
    2693                 :     JSObject *holder;
    2694            4599 :     JSProperty *prop = NULL;
    2695                 : #ifdef DEBUG
    2696                 :     bool res =
    2697                 : #endif
    2698                 :     LookupPropertyWithFlags(cx, baseobj, ATOM_TO_JSID(atom),
    2699            4599 :                             JSRESOLVE_QUALIFIED, &holder, &prop);
    2700            4599 :     JS_ASSERT(res && prop && holder == baseobj);
    2701                 : 
    2702            4599 :     RegisterID objReg = frame.copyDataIntoReg(obj);
    2703                 : 
    2704                 :     /* Perform the store. */
    2705            4599 :     Shape *shape = (Shape *) prop;
    2706            4599 :     Address address = masm.objPropAddress(baseobj, objReg, shape->slot());
    2707            4599 :     frame.storeTo(fe, address);
    2708            4599 :     frame.freeReg(objReg);
    2709                 : }
    2710                 : 
    2711                 : void
    2712           41805 : mjit::Compiler::jsop_initelem()
    2713                 : {
    2714           41805 :     FrameEntry *obj = frame.peek(-3);
    2715           41805 :     FrameEntry *id = frame.peek(-2);
    2716           41805 :     FrameEntry *fe = frame.peek(-1);
    2717                 : 
    2718                 :     /*
    2719                 :      * The initialized index is always a constant, but we won't remember which
    2720                 :      * constant if there are branches inside the code computing the initializer
    2721                 :      * expression (e.g. the expression uses the '?' operator).  Slow path those
    2722                 :      * cases, as well as those where INITELEM is used on an object initializer
    2723                 :      * or a non-fast array initializer.
    2724                 :      */
    2725           41805 :     if (!id->isConstant() || !frame.extra(obj).initArray) {
    2726             378 :         JSOp next = JSOp(PC[JSOP_INITELEM_LENGTH]);
    2727                 : 
    2728             378 :         prepareStubCall(Uses(3));
    2729             378 :         masm.move(Imm32(next == JSOP_ENDINIT ? 1 : 0), Registers::ArgReg1);
    2730             378 :         INLINE_STUBCALL(stubs::InitElem, REJOIN_FALLTHROUGH);
    2731             378 :         return;
    2732                 :     }
    2733                 : 
    2734           41427 :     int32_t idx = id->getValue().toInt32();
    2735                 : 
    2736           41427 :     RegisterID objReg = frame.copyDataIntoReg(obj);
    2737           41427 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), objReg);
    2738                 : 
    2739                 :     /* Update the initialized length. */
    2740           41427 :     masm.store32(Imm32(idx + 1), Address(objReg, ObjectElements::offsetOfInitializedLength()));
    2741                 : 
    2742                 :     /* Perform the store. */
    2743           41427 :     frame.storeTo(fe, Address(objReg, idx * sizeof(Value)));
    2744           41427 :     frame.freeReg(objReg);
    2745                 : }

Generated by: LCOV version 1.7