LCOV - app.info - js/src/methodjit/FastOps.cpp

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - FastOps.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1428 | 1363 | 95.4 %
| Date: | 2012-04-07 | Functions: | 32 | 32 | 100.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   David Anderson <danderson@mozilla.com>
          25                 :  *   David Mandelin <dmandelin@mozilla.com>
          26                 :  *
          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           23084 : mjit::Compiler::ensureInteger(FrameEntry *fe, Uses uses)
          65                 : {
          66           23084 :     if (fe->isConstant()) {
          67            7695 :         if (!fe->isType(JSVAL_TYPE_INT32)) {
          68             456 :             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
          69             456 :             fe->convertConstantDoubleToInt32(cx);
          70                 :         }
          71           15389 :     } 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           15099 :     } else if (!fe->isType(JSVAL_TYPE_INT32)) {
         104            4796 :         if (masm.supportsFloatingPoint()) {
         105            4796 :             FPRegisterID fptemp = frame.allocFPReg();
         106            4796 :             RegisterID typeReg = frame.tempRegForType(fe);
         107            4796 :             frame.pinReg(typeReg);
         108            4796 :             RegisterID dataReg = frame.copyDataIntoReg(fe);
         109            4796 :             frame.unpinReg(typeReg);
         110                 :
         111            4796 :             Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
         112                 :
         113            4796 :             Label syncPath = stubcc.syncExitAndJump(uses);
         114            4796 :             stubcc.linkExitDirect(intGuard, stubcc.masm.label());
         115                 :
         116                 :             /* Try an OOL path to truncate doubles representing int32s. */
         117            4796 :             Jump doubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, typeReg);
         118            4796 :             doubleGuard.linkTo(syncPath, &stubcc.masm);
         119                 :
         120            4796 :             frame.loadDouble(fe, fptemp, stubcc.masm);
         121            4796 :             Jump truncateGuard = stubcc.masm.branchTruncateDoubleToInt32(fptemp, dataReg);
         122            4796 :             truncateGuard.linkTo(syncPath, &stubcc.masm);
         123            4796 :             stubcc.crossJump(stubcc.masm.jump(), masm.label());
         124                 :
         125            4796 :             frame.freeReg(fptemp);
         126            4796 :             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           23084 : }
         142                 :
         143                 : void
         144             166 : mjit::Compiler::jsop_bitnot()
         145                 : {
         146             166 :     FrameEntry *top = frame.peek(-1);
         147                 :
         148                 :     /* We only want to handle integers here. */
         149             166 :     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             166 :     ensureInteger(top, Uses(1));
         158                 :
         159             166 :     stubcc.leave();
         160             166 :     OOL_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
         161                 :
         162             166 :     RegisterID reg = frame.ownRegForData(top);
         163             166 :     masm.not32(reg);
         164             166 :     frame.pop();
         165             166 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         166                 :
         167             166 :     stubcc.rejoin(Changes(1));
         168                 : }
         169                 :
         170                 : void
         171           12302 : mjit::Compiler::jsop_bitop(JSOp op)
         172                 : {
         173           12302 :     FrameEntry *rhs = frame.peek(-1);
         174           12302 :     FrameEntry *lhs = frame.peek(-2);
         175                 :
         176                 :     /* The operands we ensure are integers cannot be copied by each other. */
         177           12302 :     frame.separateBinaryEntries(lhs, rhs);
         178                 :
         179                 :     VoidStub stub;
         180           12302 :     switch (op) {
         181                 :       case JSOP_BITOR:
         182            1564 :         stub = stubs::BitOr;
         183            1564 :         break;
         184                 :       case JSOP_BITAND:
         185            3605 :         stub = stubs::BitAnd;
         186            3605 :         break;
         187                 :       case JSOP_BITXOR:
         188            1478 :         stub = stubs::BitXor;
         189            1478 :         break;
         190                 :       case JSOP_LSH:
         191            2011 :         stub = stubs::Lsh;
         192            2011 :         break;
         193                 :       case JSOP_RSH:
         194            2812 :         stub = stubs::Rsh;
         195            2812 :         break;
         196                 :       case JSOP_URSH:
         197             832 :         stub = stubs::Ursh;
         198             832 :         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           12302 :     if (rhs->isConstant() && rhs->getValue().isDouble())
         206             630 :         rhs->convertConstantDoubleToInt32(cx);
         207                 :
         208                 :     /* We only want to handle integers here. */
         209           25626 :     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
         210           12270 :         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
         211            1054 :         (op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) {
         212             843 :         prepareStubCall(Uses(2));
         213             843 :         INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
         214             843 :         frame.popn(2);
         215             843 :         frame.pushSynced(op != JSOP_URSH ? JSVAL_TYPE_INT32 : knownPushedType(0));
         216             843 :         return;
         217                 :     }
         218                 :
         219           11459 :     ensureInteger(lhs, Uses(2));
         220           11459 :     ensureInteger(rhs, Uses(2));
         221                 :
         222           11459 :     if (lhs->isConstant() && rhs->isConstant()) {
         223             193 :         int32_t L = lhs->getValue().toInt32();
         224             193 :         int32_t R = rhs->getValue().toInt32();
         225                 :
         226             193 :         frame.popn(2);
         227             193 :         switch (op) {
         228                 :           case JSOP_BITOR:
         229               6 :             frame.push(Int32Value(L | R));
         230               6 :             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           11266 :     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            6024 :         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            6024 :         reg = frame.ownRegForData(lhs);
         273            6024 :         if (rhs->isConstant()) {
         274            3210 :             int32_t rhsInt = rhs->getValue().toInt32();
         275            3210 :             if (op == JSOP_BITAND)
         276            2461 :                 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            2814 :         } 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            2794 :             RegisterID rhsReg = frame.tempRegForData(rhs);
         291            2794 :             if (op == JSOP_BITAND)
         292             888 :                 masm.and32(rhsReg, reg);
         293            1906 :             else if (op == JSOP_BITXOR)
         294             919 :                 masm.xor32(rhsReg, reg);
         295                 :             else
         296             987 :                 masm.or32(rhsReg, reg);
         297                 :         }
         298                 :
         299            6024 :         break;
         300                 :       }
         301                 :
         302                 :       case JSOP_LSH:
         303                 :       case JSOP_RSH:
         304                 :       case JSOP_URSH:
         305                 :       {
         306                 :         /* Not commutative. */
         307            5242 :         if (rhs->isConstant()) {
         308            2869 :             RegisterID reg = frame.ownRegForData(lhs);
         309            2869 :             int shift = rhs->getValue().toInt32() & 0x1F;
         310                 :
         311            2869 :             stubcc.leave();
         312            2869 :             OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
         313                 :
         314            2869 :             if (shift) {
         315            2757 :                 if (op == JSOP_LSH)
         316             809 :                     masm.lshift32(Imm32(shift), reg);
         317            1948 :                 else if (op == JSOP_RSH)
         318            1701 :                     masm.rshift32(Imm32(shift), reg);
         319                 :                 else
         320             247 :                     masm.urshift32(Imm32(shift), reg);
         321                 :             }
         322            2869 :             frame.popn(2);
         323                 :
         324                 :             /* x >>> 0 may result in a double, handled above. */
         325            2869 :             JS_ASSERT_IF(op == JSOP_URSH, shift >= 1);
         326            2869 :             frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         327                 :
         328            2869 :             stubcc.rejoin(Changes(1));
         329            2869 :             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            2373 :                                                    Registers::maskReg(JSC::X86Registers::ecx)).reg();
         335                 : #else
         336                 :         RegisterID rr = frame.tempRegForData(rhs);
         337                 : #endif
         338                 :
         339            2373 :         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            2369 :             frame.pinReg(rr);
         347            2369 :             if (lhs->isConstant()) {
         348            1230 :                 reg = frame.allocReg();
         349            1230 :                 masm.move(Imm32(lhs->getValue().toInt32()), reg);
         350                 :             } else {
         351            1139 :                 reg = frame.copyDataIntoReg(lhs);
         352                 :             }
         353            2369 :             frame.unpinReg(rr);
         354                 :         }
         355                 :
         356            2373 :         if (op == JSOP_LSH) {
         357            1061 :             masm.lshift32(rr, reg);
         358            1312 :         } else if (op == JSOP_RSH) {
         359             884 :             masm.rshift32(rr, reg);
         360                 :         } else {
         361             428 :             masm.urshift32(rr, reg);
         362                 :
         363             428 :             Jump isNegative = masm.branch32(Assembler::LessThan, reg, Imm32(0));
         364             428 :             stubcc.linkExit(isNegative, Uses(2));
         365                 :         }
         366            2373 :         break;
         367                 :       }
         368                 :
         369                 :       default:
         370               0 :         JS_NOT_REACHED("NYI");
         371                 :         return;
         372                 :     }
         373                 :
         374            8397 :     stubcc.leave();
         375            8397 :     OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
         376                 :
         377            8397 :     frame.pop();
         378            8397 :     frame.pop();
         379                 :
         380            8397 :     JSValueType type = knownPushedType(0);
         381                 :
         382            8397 :     if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE)
         383            6661 :         frame.pushTypedPayload(type, reg);
         384            1736 :     else if (op == JSOP_URSH)
         385             157 :         frame.pushNumber(reg, true);
         386                 :     else
         387            1579 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         388                 :
         389            8397 :     stubcc.rejoin(Changes(1));
         390                 : }
         391                 :
         392                 : static inline bool
         393            2218 : CheckNullOrUndefined(FrameEntry *fe)
         394                 : {
         395            2218 :     if (!fe->isTypeKnown())
         396             691 :         return false;
         397            1527 :     JSValueType type = fe->getKnownType();
         398            1527 :     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            1203 : mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
         455                 : {
         456            1203 :     FrameEntry *rhs = frame.peek(-1);
         457            1203 :     FrameEntry *lhs = frame.peek(-2);
         458                 :
         459                 :     /* The compiler should have handled constant folding. */
         460            1203 :     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
         461                 :
         462                 :     bool lhsTest;
         463            1203 :     if ((lhsTest = CheckNullOrUndefined(lhs)) || CheckNullOrUndefined(rhs)) {
         464                 :         /* What's the other mask? */
         465             999 :         FrameEntry *test = lhsTest ? rhs : lhs;
         466                 :
         467             999 :         if (test->isType(JSVAL_TYPE_NULL) || test->isType(JSVAL_TYPE_UNDEFINED)) {
         468             138 :             return emitStubCmpOp(stub, target, fused);
         469             861 :         } else if (test->isTypeKnown()) {
         470                 :             /* The test will not succeed, constant fold the compare. */
         471             214 :             bool result = GetCompareCondition(op, fused) == Assembler::NotEqual;
         472             214 :             frame.pop();
         473             214 :             frame.pop();
         474             214 :             if (target)
         475             147 :                 return constantFoldBranch(target, result);
         476              67 :             frame.push(BooleanValue(result));
         477              67 :             return true;
         478                 :         }
         479                 :
         480                 :         /* The other side must be null or undefined. */
         481             647 :         RegisterID reg = frame.ownRegForType(test);
         482             647 :         frame.pop();
         483             647 :         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             647 :         if (target) {
         491             476 :             frame.syncAndKillEverything();
         492             476 :             frame.freeReg(reg);
         493                 :
         494                 :             Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
         495             476 :                                                Registers::ReturnReg, Registers::ReturnReg);
         496                 :
         497             476 :             if ((op == JSOP_EQ && fused == JSOP_IFNE) ||
         498                 :                 (op == JSOP_NE && fused == JSOP_IFEQ)) {
         499             153 :                 Jump b1 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
         500             153 :                 Jump b2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL));
         501             153 :                 Jump j1 = masm.jump();
         502             153 :                 b1.linkTo(masm.label(), &masm);
         503             153 :                 b2.linkTo(masm.label(), &masm);
         504             153 :                 Jump j2 = masm.jump();
         505             153 :                 if (!jumpAndRun(j2, target, &sj))
         506               0 :                     return false;
         507             153 :                 j1.linkTo(masm.label(), &masm);
         508                 :             } else {
         509             323 :                 Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
         510             323 :                 Jump j2 = masm.branchPtr(Assembler::NotEqual, reg, ImmType(JSVAL_TYPE_NULL));
         511             323 :                 if (!jumpAndRun(j2, target, &sj))
         512               0 :                     return false;
         513             323 :                 j.linkTo(masm.label(), &masm);
         514                 :             }
         515                 :         } else {
         516             171 :             Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED));
         517             171 :             Jump j2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL));
         518             171 :             masm.move(Imm32(op == JSOP_NE), reg);
         519             171 :             Jump j3 = masm.jump();
         520             171 :             j2.linkTo(masm.label(), &masm);
         521             171 :             j.linkTo(masm.label(), &masm);
         522             171 :             masm.move(Imm32(op == JSOP_EQ), reg);
         523             171 :             j3.linkTo(masm.label(), &masm);
         524             171 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
         525                 :         }
         526             647 :         return true;
         527                 :     }
         528                 :
         529             490 :     if (cx->typeInferenceEnabled() &&
         530             286 :         lhs->isType(JSVAL_TYPE_OBJECT) && rhs->isType(JSVAL_TYPE_OBJECT))
         531                 :     {
         532              90 :         CompileStatus status = jsop_equality_obj_obj(op, target, fused);
         533              90 :         if (status == Compile_Okay) return true;
         534               1 :         else if (status == Compile_Error) return false;
         535                 :     }
         536                 :
         537             115 :     return emitStubCmpOp(stub, target, fused);
         538                 : }
         539                 :
         540                 : bool
         541           53595 : mjit::Compiler::jsop_relational(JSOp op, BoolStub stub,
         542                 :                                 jsbytecode *target, JSOp fused)
         543                 : {
         544           53595 :     FrameEntry *rhs = frame.peek(-1);
         545           53595 :     FrameEntry *lhs = frame.peek(-2);
         546                 :
         547                 :     /* The compiler should have handled constant folding. */
         548           53595 :     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
         549           53595 :     JS_ASSERT(fused == JSOP_NOP || fused == JSOP_IFEQ || fused == JSOP_IFNE);
         550                 :
         551                 :     /* Always slow path... */
         552          112263 :     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE) &&
         553            1098 :          lhs->isNotType(JSVAL_TYPE_STRING)) ||
         554           56002 :         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE) &&
         555            1568 :          rhs->isNotType(JSVAL_TYPE_STRING))) {
         556            1502 :         if (op == JSOP_EQ || op == JSOP_NE)
         557            1203 :             return jsop_equality(op, stub, target, fused);
         558             299 :         return emitStubCmpOp(stub, target, fused);
         559                 :     }
         560                 :
         561           52093 :     if (op == JSOP_EQ || op == JSOP_NE) {
         562           16605 :         if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_STRING)) ||
         563            8466 :             (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_STRING))) {
         564             534 :             return emitStubCmpOp(stub, target, fused);
         565            7605 :         } else if (!target && (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING))) {
         566             285 :             return emitStubCmpOp(stub, target, fused);
         567            7320 :         } else if (frame.haveSameBacking(lhs, rhs)) {
         568              21 :             return emitStubCmpOp(stub, target, fused);
         569                 :         } else {
         570            7299 :             return jsop_equality_int_string(op, stub, target, fused);
         571                 :         }
         572                 :     }
         573                 :
         574           43954 :     if (frame.haveSameBacking(lhs, rhs)) {
         575               0 :         return emitStubCmpOp(stub, target, fused);
         576           43954 :     } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
         577              60 :         return emitStubCmpOp(stub, target, fused);
         578           43894 :     } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
         579            1579 :         if (!masm.supportsFloatingPoint())
         580               0 :             return emitStubCmpOp(stub, target, fused);
         581            1579 :         return jsop_relational_double(op, stub, target, fused);
         582           92789 :     } else if (cx->typeInferenceEnabled() &&
         583           50474 :                lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
         584           16134 :         return jsop_relational_int(op, target, fused);
         585                 :     } else {
         586           26181 :         return jsop_relational_full(op, stub, target, fused);
         587                 :     }
         588                 : }
         589                 :
         590                 : void
         591           35607 : mjit::Compiler::jsop_not()
         592                 : {
         593           35607 :     FrameEntry *top = frame.peek(-1);
         594                 :
         595           35607 :     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           35600 :     if (top->isTypeKnown()) {
         603           34607 :         JSValueType type = top->getKnownType();
         604           34607 :         switch (type) {
         605                 :           case JSVAL_TYPE_INT32:
         606                 :           {
         607              10 :             RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
         608              10 :             if (frame.shouldAvoidDataRemat(top))
         609               0 :                 masm.loadPayload(frame.addressOf(top), data);
         610                 :             else
         611              10 :                 masm.move(frame.tempRegForData(top), data);
         612                 :
         613              10 :             masm.set32(Assembler::Equal, data, Imm32(0), data);
         614                 :
         615              10 :             frame.pop();
         616              10 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data);
         617              10 :             break;
         618                 :           }
         619                 :
         620                 :           case JSVAL_TYPE_BOOLEAN:
         621                 :           {
         622           34280 :             RegisterID reg = frame.ownRegForData(top);
         623                 :
         624           34280 :             masm.xor32(Imm32(1), reg);
         625                 :
         626           34280 :             frame.pop();
         627           34280 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
         628           34280 :             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           34607 :         return;
         657                 :     }
         658                 :
         659             993 :     RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
         660             993 :     if (frame.shouldAvoidDataRemat(top))
         661             133 :         masm.loadPayload(frame.addressOf(top), data);
         662                 :     else
         663             860 :         masm.move(frame.tempRegForData(top), data);
         664             993 :     RegisterID type = frame.tempRegForType(top);
         665             993 :     Label syncTarget = stubcc.syncExitAndJump(Uses(1));
         666                 :
         667                 :
         668                 :     /* Inline path is for booleans. */
         669             993 :     Jump jmpNotBool = masm.testBoolean(Assembler::NotEqual, type);
         670             993 :     masm.xor32(Imm32(1), data);
         671                 :
         672                 :
         673                 :     /* OOL path is for int + object. */
         674             993 :     Label lblMaybeInt32 = stubcc.masm.label();
         675                 :
         676             993 :     Jump jmpNotInt32 = stubcc.masm.testInt32(Assembler::NotEqual, type);
         677             993 :     stubcc.masm.set32(Assembler::Equal, data, Imm32(0), data);
         678             993 :     Jump jmpInt32Exit = stubcc.masm.jump();
         679                 :
         680             993 :     Label lblMaybeObject = stubcc.masm.label();
         681             993 :     Jump jmpNotObject = stubcc.masm.testPrimitive(Assembler::Equal, type);
         682             993 :     stubcc.masm.move(Imm32(0), data);
         683             993 :     Jump jmpObjectExit = stubcc.masm.jump();
         684                 :
         685                 :
         686                 :     /* Rejoin location. */
         687             993 :     Label lblRejoin = masm.label();
         688                 :
         689                 :     /* Patch up jumps. */
         690             993 :     stubcc.linkExitDirect(jmpNotBool, lblMaybeInt32);
         691                 :
         692             993 :     jmpNotInt32.linkTo(lblMaybeObject, &stubcc.masm);
         693             993 :     stubcc.crossJump(jmpInt32Exit, lblRejoin);
         694                 :
         695             993 :     jmpNotObject.linkTo(syncTarget, &stubcc.masm);
         696             993 :     stubcc.crossJump(jmpObjectExit, lblRejoin);
         697                 :
         698                 :
         699                 :     /* Leave. */
         700             993 :     stubcc.leave();
         701             993 :     OOL_STUBCALL(stubs::Not, REJOIN_FALLTHROUGH);
         702                 :
         703             993 :     frame.pop();
         704             993 :     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data);
         705                 :
         706             993 :     stubcc.rejoin(Changes(1));
         707                 : }
         708                 :
         709                 : void
         710            1792 : mjit::Compiler::jsop_typeof()
         711                 : {
         712            1792 :     FrameEntry *fe = frame.peek(-1);
         713                 :
         714            1792 :     if (fe->isTypeKnown()) {
         715             582 :         JSRuntime *rt = cx->runtime;
         716                 :
         717             582 :         JSAtom *atom = NULL;
         718             582 :         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             403 :             atom = rt->atomState.typeAtoms[JSTYPE_VOID];
         724             403 :             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             582 :         if (atom) {
         740             477 :             frame.pop();
         741             477 :             frame.push(StringValue(atom));
         742             477 :             return;
         743                 :         }
         744                 :     }
         745                 :
         746            1315 :     JSOp fused = JSOp(PC[JSOP_TYPEOF_LENGTH]);
         747            1315 :     if (fused == JSOP_STRING && !fe->isTypeKnown()) {
         748             928 :         JSOp op = JSOp(PC[JSOP_TYPEOF_LENGTH + JSOP_STRING_LENGTH]);
         749                 :
         750             928 :         if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) {
         751             737 :             JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH));
         752             737 :             JSRuntime *rt = cx->runtime;
         753             737 :             JSValueType type = JSVAL_TYPE_UNKNOWN;
         754                 :             Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ)
         755                 :                                         ? Assembler::Equal
         756             737 :                                         : Assembler::NotEqual;
         757                 :
         758             737 :             if (atom == rt->atomState.typeAtoms[JSTYPE_VOID]) {
         759             337 :                 type = JSVAL_TYPE_UNDEFINED;
         760             400 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_STRING]) {
         761             227 :                 type = JSVAL_TYPE_STRING;
         762             173 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_BOOLEAN]) {
         763               0 :                 type = JSVAL_TYPE_BOOLEAN;
         764             173 :             } else if (atom == rt->atomState.typeAtoms[JSTYPE_NUMBER]) {
         765              18 :                 type = JSVAL_TYPE_INT32;
         766                 :
         767                 :                 /* JSVAL_TYPE_DOUBLE is 0x0 and JSVAL_TYPE_INT32 is 0x1, use <= or > to match both */
         768              18 :                 cond = (cond == Assembler::Equal) ? Assembler::BelowOrEqual : Assembler::Above;
         769                 :             }
         770                 :
         771             737 :             jsbytecode *afterPC = PC + JSOP_STRING_LENGTH + JSOP_EQ_LENGTH;
         772                 :
         773             737 :             if (type != JSVAL_TYPE_UNKNOWN && bytecodeInChunk(afterPC)) {
         774             582 :                 PC = afterPC;
         775                 :
         776             582 :                 RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
         777                 :
         778                 : #if defined JS_NUNBOX32
         779             582 :                 if (frame.shouldAvoidTypeRemat(fe))
         780               0 :                     masm.set32(cond, masm.tagOf(frame.addressOf(fe)), ImmType(type), result);
         781                 :                 else
         782             582 :                     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             582 :                 frame.pop();
         788             582 :                 frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
         789             582 :                 return;
         790                 :             }
         791                 :         }
         792                 :     }
         793                 :
         794             733 :     prepareStubCall(Uses(1));
         795             733 :     INLINE_STUBCALL(stubs::TypeOf, REJOIN_NONE);
         796             733 :     frame.pop();
         797             733 :     frame.takeReg(Registers::ReturnReg);
         798             733 :     frame.pushTypedPayload(JSVAL_TYPE_STRING, Registers::ReturnReg);
         799                 : }
         800                 :
         801                 : bool
         802           50329 : 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           50329 :     if (op == JSOP_AND || op == JSOP_OR) {
         807            3598 :         frame.syncForBranch(target, Uses(0));
         808                 :     } else {
         809           46731 :         JS_ASSERT(op == JSOP_IFEQ || op == JSOP_IFNE);
         810           46731 :         frame.syncForBranch(target, Uses(1));
         811                 :     }
         812                 :
         813           50329 :     FrameEntry *fe = frame.peek(-1);
         814                 :     Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR)
         815                 :                                 ? Assembler::NonZero
         816           50329 :                                 : Assembler::Zero;
         817                 :
         818                 :     // Load data register and pin it so that frame.testBoolean
         819                 :     // below cannot evict it.
         820           50329 :     MaybeRegisterID data;
         821           50329 :     if (!fe->isType(JSVAL_TYPE_DOUBLE)) {
         822           50312 :         data = frame.tempRegForData(fe);
         823           50312 :         frame.pinReg(data.reg());
         824                 :     }
         825                 :
         826                 :     // Test for boolean if needed.
         827           50329 :     bool needStub = false;
         828           50329 :     if (!fe->isType(JSVAL_TYPE_BOOLEAN) && !fe->isType(JSVAL_TYPE_INT32)) {
         829           24759 :         Jump notBool;
         830           24759 :         if (fe->mightBeType(JSVAL_TYPE_BOOLEAN))
         831           24115 :             notBool = frame.testBoolean(Assembler::NotEqual, fe);
         832                 :         else
         833             644 :             notBool = masm.jump();
         834                 :
         835           24759 :         stubcc.linkExitForBranch(notBool);
         836           24759 :         needStub = true;
         837                 :     }
         838           50329 :     if (data.isSet())
         839           50312 :         frame.unpinReg(data.reg());
         840                 :
         841                 :     // Test + branch.
         842           50329 :     Jump branch;
         843           50329 :     if (!fe->isType(JSVAL_TYPE_DOUBLE))
         844           50312 :         branch = masm.branchTest32(cond, data.reg());
         845                 :     else
         846              17 :         branch = masm.jump(); // dummy jump
         847                 :
         848                 :     // OOL path: call ValueToBoolean and branch.
         849           50329 :     if (needStub) {
         850           24759 :         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           24759 :                                      frame.totalDepth());
         855                 :     }
         856                 :
         857           50329 :     Jump stubBranch = stubcc.masm.branchTest32(cond, Registers::ReturnReg);
         858                 :
         859                 :     // Rejoin from the stub call fallthrough.
         860           50329 :     if (needStub)
         861           24759 :         stubcc.rejoin(Changes(0));
         862                 :
         863           50329 :     frame.pop();
         864                 :
         865           50329 :     return jumpAndRun(branch, target, &stubBranch);
         866                 : }
         867                 :
         868                 : bool
         869           47541 : mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target)
         870                 : {
         871           47541 :     FrameEntry *fe = frame.peek(-1);
         872                 :
         873           47541 :     if (fe->isConstant()) {
         874             810 :         JSBool b = js_ValueToBoolean(fe->getValue());
         875                 :
         876             810 :         frame.pop();
         877                 :
         878             810 :         if (op == JSOP_IFEQ)
         879             314 :             b = !b;
         880             810 :         if (b) {
         881             500 :             if (!frame.syncForBranch(target, Uses(0)))
         882               0 :                 return false;
         883             500 :             if (!jumpAndRun(masm.jump(), target))
         884               0 :                 return false;
         885                 :         } else {
         886             310 :             if (target < PC && !finishLoop(target))
         887               0 :                 return false;
         888                 :         }
         889             810 :         return true;
         890                 :     }
         891                 :
         892           46731 :     return booleanJumpScript(op, target);
         893                 : }
         894                 :
         895                 : bool
         896            4712 : mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target)
         897                 : {
         898            4712 :     FrameEntry *fe = frame.peek(-1);
         899                 :
         900            4712 :     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            3598 :     return booleanJumpScript(op, target);
         917                 : }
         918                 :
         919                 : bool
         920           29396 : mjit::Compiler::jsop_localinc(JSOp op, uint32_t slot)
         921                 : {
         922           29396 :     restoreVarType();
         923                 :
         924           29396 :     types::TypeSet *types = pushedTypeSet(0);
         925           29396 :     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
         926                 :
         927           29396 :     int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1;
         928                 :
         929           29396 :     if (!analysis->incrementInitialValueObserved(PC)) {
         930                 :         // Before:
         931                 :         // After:  V
         932           28478 :         frame.pushLocal(slot);
         933                 :
         934                 :         // Before: V
         935                 :         // After:  V 1
         936           28478 :         frame.push(Int32Value(-amt));
         937                 :
         938                 :         // Note, SUB will perform integer conversion for us.
         939                 :         // Before: V 1
         940                 :         // After:  N+1
         941           28478 :         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
         942               1 :             return false;
         943                 :
         944                 :         // Before: N+1
         945                 :         // After:  N+1
         946           28477 :         frame.storeLocal(slot, analysis->popGuaranteed(PC));
         947                 :     } else {
         948                 :         // Before:
         949                 :         // After: V
         950             918 :         frame.pushLocal(slot);
         951                 :
         952                 :         // Before: V
         953                 :         // After:  N
         954             918 :         jsop_pos();
         955                 :
         956                 :         // Before: N
         957                 :         // After:  N N
         958             918 :         frame.dup();
         959                 :
         960                 :         // Before: N N
         961                 :         // After:  N N 1
         962             918 :         frame.push(Int32Value(amt));
         963                 :
         964                 :         // Before: N N 1
         965                 :         // After:  N N+1
         966             918 :         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             918 :         frame.storeLocal(slot, true);
         972                 :
         973                 :         // Before: N N+1
         974                 :         // After:  N
         975             918 :         frame.pop();
         976                 :     }
         977                 :
         978           29395 :     updateVarType();
         979           29395 :     return true;
         980                 : }
         981                 :
         982                 : bool
         983             433 : mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
         984                 : {
         985             433 :     restoreVarType();
         986                 :
         987             433 :     types::TypeSet *types = pushedTypeSet(0);
         988             433 :     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
         989                 :
         990             433 :     int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
         991                 :
         992             433 :     if (!analysis->incrementInitialValueObserved(PC)) {
         993                 :         // Before:
         994                 :         // After:  V
         995             246 :         frame.pushArg(slot);
         996                 :
         997                 :         // Before: V
         998                 :         // After:  V 1
         999             246 :         frame.push(Int32Value(-amt));
        1000                 :
        1001                 :         // Note, SUB will perform integer conversion for us.
        1002                 :         // Before: V 1
        1003                 :         // After:  N+1
        1004             246 :         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
        1005               0 :             return false;
        1006                 :
        1007                 :         // Before: N+1
        1008                 :         // After:  N+1
        1009             246 :         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             433 :     updateVarType();
        1042             433 :     return true;
        1043                 : }
        1044                 :
        1045                 : static inline bool
        1046           16178 : IsCacheableSetElem(FrameEntry *obj, FrameEntry *id, FrameEntry *value)
        1047                 : {
        1048           16178 :     if (obj->isNotType(JSVAL_TYPE_OBJECT))
        1049             498 :         return false;
        1050           15680 :     if (id->isNotType(JSVAL_TYPE_INT32) && id->isNotType(JSVAL_TYPE_DOUBLE))
        1051            1217 :         return false;
        1052           14463 :     if (id->isConstant()) {
        1053            3417 :         if (id->isNotType(JSVAL_TYPE_INT32))
        1054              16 :             return false;
        1055            3401 :         if (id->getValue().toInt32() < 0)
        1056               6 :             return false;
        1057            3395 :         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           14437 :     if (obj->hasSameBacking(id))
        1065               1 :         return false;
        1066                 :
        1067           14436 :     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           26054 : GetDenseArrayShape(JSContext *cx, JSObject *globalObj)
        1518                 : {
        1519           26054 :     JS_ASSERT(globalObj);
        1520                 :
        1521           26054 :     JSObject *proto = globalObj->global().getOrCreateArrayPrototype(cx);
        1522           26054 :     if (!proto)
        1523               0 :         return NULL;
        1524                 :
        1525                 :     return EmptyShape::getInitialShape(cx, &ArrayClass, proto,
        1526           26054 :                                        proto->getParent(), gc::FINALIZE_OBJECT0);
        1527                 : }
        1528                 :
        1529                 : bool
        1530           16178 : mjit::Compiler::jsop_setelem(bool popGuaranteed)
        1531                 : {
        1532           16178 :     FrameEntry *obj = frame.peek(-3);
        1533           16178 :     FrameEntry *id = frame.peek(-2);
        1534           16178 :     FrameEntry *value = frame.peek(-1);
        1535                 :
        1536           16178 :     if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
        1537            1906 :         jsop_setelem_slow();
        1538            1906 :         return true;
        1539                 :     }
        1540                 :
        1541           14272 :     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           14272 :     if (cx->typeInferenceEnabled()) {
        1546           10996 :         types::TypeSet *types = analysis->poppedTypes(PC, 2);
        1547                 :
        1548           18823 :         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            5477 :         if ((value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE)) &&
        1557            2296 :             !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            5705 :     if (id->isType(JSVAL_TYPE_DOUBLE) || !globalObj) {
        1569               0 :         jsop_setelem_slow();
        1570               0 :         return true;
        1571                 :     }
        1572                 :
        1573                 : #ifdef JSGC_INCREMENTAL_MJ
        1574                 :     // Write barrier.
        1575            5705 :     if (cx->compartment->needsBarrier()) {
        1576               2 :         jsop_setelem_slow();
        1577               2 :         return true;
        1578                 :     }
        1579                 : #endif
        1580                 :
        1581            5703 :     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            5703 :     MaybeRegisterID pinnedValueType = frame.maybePinType(value);
        1587            5703 :     MaybeRegisterID pinnedValueData = frame.maybePinData(value);
        1588                 :
        1589                 :     // Pin |obj| if it doesn't share a backing with |value|.
        1590            5703 :     MaybeRegisterID pinnedObjData;
        1591            5703 :     if (!obj->hasSameBacking(value))
        1592            5637 :         pinnedObjData = frame.maybePinData(obj);
        1593                 :
        1594                 :     // Pin |id| if it doesn't share a backing with |value|.
        1595            5703 :     MaybeRegisterID pinnedIdData;
        1596            5703 :     if (!id->hasSameBacking(value))
        1597            5656 :         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            5703 :     if (!obj->isTypeKnown()) {
        1608            4946 :         Jump j = frame.testObject(Assembler::NotEqual, obj);
        1609            4946 :         stubcc.linkExit(j, Uses(3));
        1610                 :     }
        1611                 :
        1612                 :     // Guard that the id is int32.
        1613            5703 :     if (!id->isTypeKnown()) {
        1614            2901 :         Jump j = frame.testInt32(Assembler::NotEqual, id);
        1615            2901 :         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            5703 :     frame.maybeUnpinReg(pinnedObjData);
        1623            5703 :     if (obj->hasSameBacking(value) && pinnedValueData.isSet()) {
        1624              61 :         ic.objReg = frame.allocReg();
        1625              61 :         masm.move(pinnedValueData.reg(), ic.objReg);
        1626                 :     } else {
        1627            5642 :         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            5703 :     frame.maybeUnpinReg(pinnedValueType);
        1633            5703 :     frame.maybeUnpinReg(pinnedValueData);
        1634            5703 :     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            5703 :     frame.maybeUnpinReg(pinnedIdData);
        1642            5703 :     if (id->isConstant())
        1643            1784 :         ic.key = Int32Key::FromConstant(id->getValue().toInt32());
        1644                 :     else
        1645            3919 :         ic.key = Int32Key::FromRegister(frame.tempRegForData(id));
        1646                 :
        1647                 :     // Unpin the value since register allocation is complete.
        1648            5703 :     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            5703 :     ic.objRemat = frame.dataRematInfo(obj);
        1653                 :
        1654                 :     // All patchable guards must occur after this point.
        1655                 :     RESERVE_IC_SPACE(masm);
        1656            5703 :     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            5703 :     ic.slowPathStart = stubcc.syncExit(Uses(3));
        1662                 :
        1663                 :     // Guard obj is a dense array.
        1664            5703 :     Shape *shape = GetDenseArrayShape(cx, globalObj);
        1665            5703 :     if (!shape)
        1666               0 :         return false;
        1667            5703 :     ic.shapeGuard = masm.guardShape(ic.objReg, shape);
        1668            5703 :     stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
        1669                 :
        1670                 :     // Load the dynamic elements vector.
        1671            5703 :     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            5703 :                                               ic.objReg, ic.key, Assembler::BelowOrEqual);
        1676            5703 :     stubcc.linkExitDirect(initlenGuard, ic.slowPathStart);
        1677                 :
        1678                 :     // Guard there's no hole, then store directly to the slot.
        1679            5703 :     if (ic.key.isConstant()) {
        1680            1784 :         Address slot(ic.objReg, ic.key.index() * sizeof(Value));
        1681            1784 :         ic.holeGuard = masm.guardNotHole(slot);
        1682            1784 :         masm.storeValue(ic.vr, slot);
        1683                 :     } else {
        1684            3919 :         BaseIndex slot(ic.objReg, ic.key.reg(), Assembler::JSVAL_SCALE);
        1685            3919 :         ic.holeGuard = masm.guardNotHole(slot);
        1686            3919 :         masm.storeValue(ic.vr, slot);
        1687                 :     }
        1688            5703 :     stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
        1689                 :
        1690            5703 :     stubcc.leave();
        1691                 : #if defined JS_POLYIC
        1692            5703 :     passICAddress(&ic);
        1693            5703 :     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            5703 :     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            5703 :     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           21558 :     if (popGuaranteed &&
        1715            5487 :         !ic.vr.isConstant() &&
        1716            3664 :         !value->isCopy() &&
        1717            3352 :         !frame.haveSameBacking(value, obj) &&
        1718            3352 :         !frame.haveSameBacking(value, id))
        1719                 :     {
        1720            3352 :         ic.volatileMask &= ~Registers::maskReg(ic.vr.dataReg());
        1721            3352 :         if (!ic.vr.isTypeKnown())
        1722            2419 :             ic.volatileMask &= ~Registers::maskReg(ic.vr.typeReg());
        1723            2351 :     } else if (!ic.vr.isConstant()) {
        1724             470 :         ic.volatileMask |= Registers::maskReg(ic.vr.dataReg());
        1725                 :     }
        1726                 :
        1727            5703 :     frame.freeReg(ic.objReg);
        1728            5703 :     frame.shimmy(2);
        1729            5703 :     stubcc.rejoin(Changes(2));
        1730                 :
        1731                 : #if defined JS_POLYIC
        1732            5703 :     if (!setElemICs.append(ic))
        1733               0 :         return false;
        1734                 : #endif
        1735                 :
        1736            5703 :     return true;
        1737                 : }
        1738                 :
        1739                 : static inline bool
        1740           48555 : IsCacheableGetElem(FrameEntry *obj, FrameEntry *id)
        1741                 : {
        1742           79193 :     if (id->isTypeKnown() &&
        1743           31967 :         !(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           48492 :     if (id->isType(JSVAL_TYPE_DOUBLE) && id->isConstant())
        1752              20 :         return false;
        1753                 :
        1754           67285 :     if (id->isType(JSVAL_TYPE_INT32) && id->isConstant() &&
        1755           18813 :         id->getValue().toInt32() < 0) {
        1756               6 :         return false;
        1757                 :     }
        1758                 :
        1759                 :     // obj[obj] is not allowed, since it will never optimize.
        1760           48466 :     if (obj->hasSameBacking(id))
        1761               5 :         return false;
        1762                 :
        1763           48461 :     return true;
        1764                 : }
        1765                 :
        1766                 : void
        1767           24598 : mjit::Compiler::jsop_getelem_dense(bool isPacked)
        1768                 : {
        1769           24598 :     FrameEntry *obj = frame.peek(-2);
        1770           24598 :     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           24598 :     if (!obj->isTypeKnown()) {
        1775            3250 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
        1776            3250 :         stubcc.linkExit(guard, Uses(2));
        1777                 :     }
        1778                 :
        1779           24598 :     if (id->isType(JSVAL_TYPE_DOUBLE))
        1780               2 :         tryConvertInteger(id, Uses(2));
        1781                 :
        1782                 :     // Test for integer index.
        1783           24598 :     if (!id->isTypeKnown()) {
        1784            9664 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
        1785            9664 :         stubcc.linkExit(guard, Uses(2));
        1786                 :     }
        1787                 :
        1788           24598 :     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           24598 :     bool allowUndefined = mayPushUndefined(0);
        1796                 :
        1797           24598 :     analyze::CrossSSAValue objv(a->inlineIndex, analysis->poppedValue(PC, 1));
        1798           24598 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
        1799           20055 :     bool hoisted = loop && id->isType(JSVAL_TYPE_INT32) &&
        1800           44653 :         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           24598 :     if (hoisted) {
        1806             858 :         FrameEntry *slotsFe = loop->invariantArraySlots(objv);
        1807             858 :         baseReg = frame.tempRegForData(slotsFe);
        1808                 :     } else {
        1809           23740 :         baseReg = frame.tempRegForData(obj);
        1810                 :     }
        1811           24598 :     frame.pinReg(baseReg);
        1812                 :
        1813           24598 :     Int32Key key = id->isConstant()
        1814            6688 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
        1815           31286 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
        1816           24598 :     bool pinKey = !key.isConstant() && key.reg() != baseReg;
        1817           24598 :     if (pinKey)
        1818           17910 :         frame.pinReg(key.reg());
        1819                 :
        1820           24598 :     RegisterID dataReg = frame.allocReg();
        1821                 :
        1822           24598 :     MaybeRegisterID typeReg;
        1823           24598 :     if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE || hasTypeBarriers(PC))
        1824           19863 :         typeReg = frame.allocReg();
        1825                 :
        1826           24598 :     frame.unpinReg(baseReg);
        1827           24598 :     if (pinKey)
        1828           17910 :         frame.unpinReg(key.reg());
        1829                 :
        1830                 :     RegisterID slotsReg;
        1831           24598 :     if (hoisted) {
        1832             858 :         slotsReg = baseReg;
        1833                 :     } else {
        1834           23740 :         masm.loadPtr(Address(baseReg, JSObject::offsetOfElements()), dataReg);
        1835           23740 :         slotsReg = dataReg;
        1836                 :     }
        1837                 :
        1838                 :     // Guard on the array's initialized length.
        1839           24598 :     MaybeJump initlenGuard;
        1840           24598 :     if (!hoisted) {
        1841                 :         initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
        1842           23740 :                                              slotsReg, key, Assembler::BelowOrEqual);
        1843           23740 :         if (!allowUndefined)
        1844           22728 :             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           24598 :     Jump holeCheck;
        1849           24598 :     if (key.isConstant()) {
        1850            6688 :         Address slot(slotsReg, key.index() * sizeof(Value));
        1851            6688 :         holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg);
        1852                 :     } else {
        1853           17910 :         JS_ASSERT(key.reg() != dataReg);
        1854           17910 :         BaseIndex slot(slotsReg, key.reg(), masm.JSVAL_SCALE);
        1855           17910 :         holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg);
        1856                 :     }
        1857                 :
        1858           24598 :     if (!isPacked && !allowUndefined)
        1859            1897 :         stubcc.linkExit(holeCheck, Uses(2));
        1860                 :
        1861           24598 :     stubcc.leave();
        1862           24598 :     OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
        1863           24598 :     testPushedType(REJOIN_FALLTHROUGH, -2);
        1864                 :
        1865           24598 :     frame.popn(2);
        1866                 :
        1867           24598 :     BarrierState barrier;
        1868           24598 :     if (typeReg.isSet()) {
        1869           19863 :         frame.pushRegs(typeReg.reg(), dataReg, type);
        1870           19863 :         barrier = testBarrier(typeReg.reg(), dataReg, false);
        1871                 :     } else {
        1872            4735 :         frame.pushTypedPayload(type, dataReg);
        1873                 :     }
        1874                 :
        1875           24598 :     stubcc.rejoin(Changes(2));
        1876                 :
        1877           24598 :     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           24598 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
        1891           24598 : }
        1892                 :
        1893                 : void
        1894             380 : mjit::Compiler::jsop_getelem_args()
        1895                 : {
        1896             380 :     FrameEntry *id = frame.peek(-1);
        1897                 :
        1898             380 :     if (id->isType(JSVAL_TYPE_DOUBLE))
        1899               0 :         tryConvertInteger(id, Uses(2));
        1900                 :
        1901                 :     // Test for integer index.
        1902             380 :     if (!id->isTypeKnown()) {
        1903              37 :         Jump guard = frame.testInt32(Assembler::NotEqual, id);
        1904              37 :         stubcc.linkExit(guard, Uses(2));
        1905                 :     }
        1906                 :
        1907                 :     // Allocate registers.
        1908                 :
        1909             380 :     analyze::CrossSSAValue indexv(a->inlineIndex, analysis->poppedValue(PC, 0));
        1910              99 :     bool hoistedLength = loop && id->isType(JSVAL_TYPE_INT32) &&
        1911             479 :         loop->hoistArgsLengthCheck(indexv);
        1912             380 :     FrameEntry *actualsFe = loop ? loop->invariantArguments() : NULL;
        1913                 :
        1914             380 :     Int32Key key = id->isConstant()
        1915             279 :                  ? Int32Key::FromConstant(id->getValue().toInt32())
        1916             659 :                  : Int32Key::FromRegister(frame.tempRegForData(id));
        1917             380 :     if (!key.isConstant())
        1918             101 :         frame.pinReg(key.reg());
        1919                 :
        1920             380 :     RegisterID dataReg = frame.allocReg();
        1921             380 :     RegisterID typeReg = frame.allocReg();
        1922                 :
        1923                 :     // Guard on nactual.
        1924             380 :     if (!hoistedLength) {
        1925             378 :         Address nactualAddr(JSFrameReg, StackFrame::offsetOfNumActual());
        1926             378 :         MaybeJump rangeGuard;
        1927             378 :         if (key.isConstant()) {
        1928             279 :             JS_ASSERT(key.index() >= 0);
        1929             279 :             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, Imm32(key.index()));
        1930                 :         } else {
        1931              99 :             rangeGuard = masm.branch32(Assembler::BelowOrEqual, nactualAddr, key.reg());
        1932                 :         }
        1933             378 :         stubcc.linkExit(rangeGuard.get(), Uses(2));
        1934                 :     }
        1935                 :
        1936                 :     RegisterID actualsReg;
        1937             380 :     if (actualsFe) {
        1938              39 :         actualsReg = frame.tempRegForData(actualsFe);
        1939                 :     } else {
        1940             341 :         actualsReg = dataReg;
        1941             341 :         masm.loadFrameActuals(outerScript->function(), actualsReg);
        1942                 :     }
        1943                 :
        1944             380 :     if (!key.isConstant())
        1945             101 :         frame.unpinReg(key.reg());
        1946                 :
        1947             380 :     if (key.isConstant()) {
        1948             279 :         Address arg(actualsReg, key.index() * sizeof(Value));
        1949             279 :         masm.loadValueAsComponents(arg, typeReg, dataReg);
        1950                 :     } else {
        1951             101 :         JS_ASSERT(key.reg() != dataReg);
        1952             101 :         BaseIndex arg(actualsReg, key.reg(), masm.JSVAL_SCALE);
        1953             101 :         masm.loadValueAsComponents(arg, typeReg, dataReg);
        1954                 :     }
        1955                 :
        1956             380 :     stubcc.leave();
        1957             380 :     OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
        1958             380 :     testPushedType(REJOIN_FALLTHROUGH, -2);
        1959                 :
        1960             380 :     frame.popn(2);
        1961             380 :     frame.pushRegs(typeReg, dataReg, knownPushedType(0));
        1962             380 :     BarrierState barrier = testBarrier(typeReg, dataReg, false);
        1963                 :
        1964             380 :     stubcc.rejoin(Changes(2));
        1965                 :
        1966             380 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
        1967             380 : }
        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           48555 : mjit::Compiler::jsop_getelem()
        2117                 : {
        2118           48555 :     FrameEntry *obj = frame.peek(-2);
        2119           48555 :     FrameEntry *id = frame.peek(-1);
        2120                 :
        2121           48555 :     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           48461 :     if (cx->typeInferenceEnabled() && !id->isType(JSVAL_TYPE_STRING)) {
        2129           37655 :         types::TypeSet *types = analysis->poppedTypes(PC, 1);
        2130           37655 :         if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
        2131                 :             // Inline arguments path.
        2132             380 :             jsop_getelem_args();
        2133             380 :             return true;
        2134                 :         }
        2135                 :
        2136           98191 :         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
        2137           36272 :             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
        2138           24644 :             !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
        2139                 :             // Inline dense array path.
        2140           24598 :             bool packed = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
        2141           24598 :             jsop_getelem_dense(packed);
        2142           24598 :             return true;
        2143                 :         }
        2144                 :
        2145                 : #ifdef JS_METHODJIT_TYPED_ARRAY
        2146           24351 :         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
        2147           11674 :             !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           22506 :     frame.forgetMismatchedObject(obj);
        2160                 :
        2161           22506 :     if (id->isType(JSVAL_TYPE_DOUBLE) || !globalObj) {
        2162             850 :         jsop_getelem_slow();
        2163             850 :         return true;
        2164                 :     }
        2165                 :
        2166           21656 :     GetElementICInfo ic = GetElementICInfo(JSOp(*PC));
        2167                 :
        2168                 :     // Pin the top of the stack to avoid spills, before allocating registers.
        2169           21656 :     MaybeRegisterID pinnedIdData = frame.maybePinData(id);
        2170           21656 :     MaybeRegisterID pinnedIdType = frame.maybePinType(id);
        2171                 :
        2172           21656 :     MaybeJump objTypeGuard;
        2173           21656 :     if (!obj->isTypeKnown()) {
        2174                 :         // Test the type of the object without spilling the payload.
        2175           17634 :         MaybeRegisterID pinnedObjData = frame.maybePinData(obj);
        2176           17634 :         Jump guard = frame.testObject(Assembler::NotEqual, obj);
        2177           17634 :         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           17634 :         stubcc.linkExit(guard, Uses(2));
        2184           17634 :         objTypeGuard = stubcc.masm.jump();
        2185                 :     }
        2186                 :
        2187                 :     // Get a mutable register for the object. This will be the data reg.
        2188           21656 :     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           21656 :     frame.maybeUnpinReg(pinnedIdType);
        2194           21656 :     if (id->isConstant() || id->isTypeKnown())
        2195           13435 :         ic.typeReg = frame.allocReg();
        2196                 :     else
        2197            8221 :         ic.typeReg = frame.copyTypeIntoReg(id);
        2198                 :
        2199                 :     // Fill in the id value.
        2200           21656 :     frame.maybeUnpinReg(pinnedIdData);
        2201           21656 :     if (id->isConstant()) {
        2202           10207 :         ic.id = ValueRemat::FromConstant(id->getValue());
        2203                 :     } else {
        2204           11449 :         RegisterID dataReg = frame.tempRegForData(id);
        2205           11449 :         if (id->isTypeKnown())
        2206            3228 :             ic.id = ValueRemat::FromKnownType(id->getKnownType(), dataReg);
        2207                 :         else
        2208            8221 :             ic.id = ValueRemat::FromRegisters(ic.typeReg, dataReg);
        2209                 :     }
        2210                 :
        2211                 :     RESERVE_IC_SPACE(masm);
        2212           21656 :     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           21656 :     ic.slowPathStart = stubcc.masm.label();
        2217           21656 :     frame.sync(stubcc.masm, Uses(2));
        2218                 :
        2219           21656 :     if (id->mightBeType(JSVAL_TYPE_INT32)) {
        2220                 :         // Always test the type first (see comment in PolyIC.h).
        2221           20351 :         if (!id->isTypeKnown()) {
        2222            8221 :             ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
        2223            8221 :             stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
        2224                 :         }
        2225                 :
        2226                 :         // Guard obj is a dense array.
        2227           20351 :         Shape *shape = GetDenseArrayShape(cx, globalObj);
        2228           20351 :         if (!shape)
        2229               0 :             return false;
        2230           20351 :         ic.shapeGuard = masm.guardShape(ic.objReg, shape);
        2231           20351 :         stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
        2232                 :
        2233           20351 :         Int32Key key = id->isConstant()
        2234           10180 :                        ? Int32Key::FromConstant(id->getValue().toInt32())
        2235           30531 :                        : Int32Key::FromRegister(ic.id.dataReg());
        2236                 :
        2237                 :         Assembler::FastArrayLoadFails fails =
        2238           20351 :             masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg);
        2239                 :
        2240           20351 :         stubcc.linkExitDirect(fails.rangeCheck, ic.slowPathStart);
        2241           20351 :         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            1305 :         ic.shapeGuard = masm.jump();
        2246            1305 :         stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
        2247                 :     }
        2248                 :
        2249           21656 :     stubcc.leave();
        2250           21656 :     if (objTypeGuard.isSet())
        2251           17634 :         objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
        2252                 : #ifdef JS_POLYIC
        2253           21656 :     passICAddress(&ic);
        2254           21656 :     ic.slowPathCall = OOL_STUBCALL(ic::GetElement, REJOIN_FALLTHROUGH);
        2255                 : #else
        2256                 :     ic.slowPathCall = OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
        2257                 : #endif
        2258                 :
        2259           21656 :     testPushedType(REJOIN_FALLTHROUGH, -2);
        2260                 :
        2261           21656 :     ic.fastPathRejoin = masm.label();
        2262           21656 :     ic.forcedTypeBarrier = analysis->getCode(PC).getStringElement;
        2263                 :
        2264                 :     CHECK_IC_SPACE();
        2265                 :
        2266           21656 :     frame.popn(2);
        2267           21656 :     frame.pushRegs(ic.typeReg, ic.objReg, knownPushedType(0));
        2268                 :     BarrierState barrier = testBarrier(ic.typeReg, ic.objReg, false, false,
        2269           21656 :                                        /* force = */ ic.forcedTypeBarrier);
        2270                 :
        2271           21656 :     stubcc.rejoin(Changes(1));
        2272                 :
        2273                 : #ifdef JS_POLYIC
        2274           21656 :     if (!getElemICs.append(ic))
        2275               0 :         return false;
        2276                 : #endif
        2277                 :
        2278           21656 :     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
        2279           21656 :     return true;
        2280                 : }
        2281                 :
        2282                 : static inline bool
        2283           16393 : ReallySimpleStrictTest(FrameEntry *fe)
        2284                 : {
        2285           16393 :     if (!fe->isTypeKnown())
        2286            7642 :         return false;
        2287            8751 :     JSValueType type = fe->getKnownType();
        2288            8751 :     return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED;
        2289                 : }
        2290                 :
        2291                 : static inline bool
        2292           13072 : BooleanStrictTest(FrameEntry *fe)
        2293                 : {
        2294           13072 :     return fe->isConstant() && fe->getKnownType() == JSVAL_TYPE_BOOLEAN;
        2295                 : }
        2296                 :
        2297                 : void
        2298            9074 : mjit::Compiler::jsop_stricteq(JSOp op)
        2299                 : {
        2300            9074 :     FrameEntry *rhs = frame.peek(-1);
        2301            9074 :     FrameEntry *lhs = frame.peek(-2);
        2302                 :
        2303            9074 :     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            9074 :     if (lhs->isConstant() && rhs->isConstant()) {
        2312                 :         bool b;
        2313             414 :         StrictlyEqual(cx, lhs->getValue(), rhs->getValue(), &b);
        2314             414 :         frame.popn(2);
        2315             414 :         frame.push(BooleanValue((op == JSOP_STRICTEQ) ? b : !b));
        2316             414 :         return;
        2317                 :     }
        2318                 :
        2319            8660 :     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            8391 :     if ((lhsTest = ReallySimpleStrictTest(lhs)) || ReallySimpleStrictTest(rhs)) {
        2377            1855 :         FrameEntry *test = lhsTest ? rhs : lhs;
        2378            1855 :         FrameEntry *known = lhsTest ? lhs : rhs;
        2379            1855 :         RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
        2380                 :
        2381            1855 :         if (test->isTypeKnown()) {
        2382             589 :             masm.move(Imm32((test->getKnownType() == known->getKnownType()) ==
        2383             589 :                             (op == JSOP_STRICTEQ)), result);
        2384             589 :             frame.popn(2);
        2385             589 :             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
        2386             589 :             return;
        2387                 :         }
        2388                 :
        2389                 :         /* This is only true if the other side is |null|. */
        2390                 : #ifndef JS_CPU_X64
        2391            1266 :         JSValueTag mask = known->getKnownTag();
        2392            1266 :         if (frame.shouldAvoidTypeRemat(test))
        2393               1 :             masm.set32(cond, masm.tagOf(frame.addressOf(test)), Imm32(mask), result);
        2394                 :         else
        2395            1265 :             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            1266 :         frame.popn(2);
        2406            1266 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
        2407            1266 :         return;
        2408                 :     }
        2409                 :
        2410                 :     /* Hardcoded booleans are easy too. */
        2411            6536 :     if ((lhsTest = BooleanStrictTest(lhs)) || BooleanStrictTest(rhs)) {
        2412             933 :         FrameEntry *test = lhsTest ? rhs : lhs;
        2413                 :
        2414             933 :         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             907 :         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             907 :         RegisterID data = frame.copyDataIntoReg(test);
        2432                 :
        2433             907 :         RegisterID result = data;
        2434             907 :         if (!(Registers::maskReg(data) & Registers::SingleByteRegs))
        2435             284 :             result = frame.allocReg(Registers::SingleByteRegs).reg();
        2436                 :
        2437             907 :         Jump notBoolean;
        2438             907 :         if (!test->isTypeKnown())
        2439             805 :            notBoolean = frame.testBoolean(Assembler::NotEqual, test);
        2440                 :
        2441                 :         /* Do a dynamic test. */
        2442             907 :         bool val = lhsTest ? lhs->getValue().toBoolean() : rhs->getValue().toBoolean();
        2443             907 :         masm.set32(cond, data, Imm32(val), result);
        2444                 :
        2445             907 :         if (!test->isTypeKnown()) {
        2446             805 :             Jump done = masm.jump();
        2447             805 :             notBoolean.linkTo(masm.label(), &masm);
        2448             805 :             masm.move(Imm32((op == JSOP_STRICTNE)), result);
        2449             805 :             done.linkTo(masm.label(), &masm);
        2450                 :         }
        2451                 :
        2452             907 :         if (data != result)
        2453             284 :             frame.freeReg(data);
        2454                 :
        2455             907 :         frame.popn(2);
        2456             907 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
        2457             907 :         return;
        2458                 :     }
        2459                 :
        2460            5603 :     if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
        2461             529 :         FrameEntry *maybeNotStr = lhs->isType(JSVAL_TYPE_STRING) ? rhs : lhs;
        2462                 :
        2463             529 :         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             446 :         if (!maybeNotStr->isTypeKnown()) {
        2470             158 :             JS_ASSERT(!maybeNotStr->isConstant());
        2471             158 :             Jump j = frame.testString(Assembler::NotEqual, maybeNotStr);
        2472             158 :             stubcc.linkExit(j, Uses(2));
        2473                 :         }
        2474                 :
        2475             446 :         FrameEntry *op1 = lhs->isConstant() ? rhs : lhs;
        2476             446 :         FrameEntry *op2 = lhs->isConstant() ? lhs : rhs;
        2477             446 :         JS_ASSERT(!op1->isConstant());
        2478                 :
        2479                 :         /* ReturnReg is safely usable with set32, since %ah can be accessed. */
        2480             446 :         RegisterID resultReg = Registers::ReturnReg;
        2481             446 :         frame.takeReg(resultReg);
        2482             446 :         RegisterID tmpReg = frame.allocReg();
        2483             446 :         RegisterID reg1 = frame.tempRegForData(op1);
        2484             446 :         frame.pinReg(reg1);
        2485                 :
        2486                 :         RegisterID reg2;
        2487             446 :         if (op2->isConstant()) {
        2488             235 :             reg2 = frame.allocReg();
        2489             235 :             JSString *str = op2->getValue().toString();
        2490             235 :             JS_ASSERT(str->isAtom());
        2491             235 :             masm.move(ImmPtr(str), reg2);
        2492                 :         } else {
        2493             211 :             reg2 = frame.tempRegForData(op2);
        2494             211 :             frame.pinReg(reg2);
        2495                 :         }
        2496                 :
        2497             446 :         JS_ASSERT(reg1 != resultReg);
        2498             446 :         JS_ASSERT(reg1 != tmpReg);
        2499             446 :         JS_ASSERT(reg2 != resultReg);
        2500             446 :         JS_ASSERT(reg2 != tmpReg);
        2501                 :
        2502                 :         /* JSString::isAtom === (lengthAndFlags & ATOM_MASK == 0) */
        2503                 :         JS_STATIC_ASSERT(JSString::ATOM_FLAGS == 0);
        2504             446 :         Imm32 atomMask(JSString::ATOM_MASK);
        2505                 :
        2506             446 :         masm.load32(Address(reg1, JSString::offsetOfLengthAndFlags()), tmpReg);
        2507             446 :         Jump op1NotAtomized = masm.branchTest32(Assembler::NonZero, tmpReg, atomMask);
        2508             446 :         stubcc.linkExit(op1NotAtomized, Uses(2));
        2509                 :
        2510             446 :         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             446 :         masm.set32(cond, reg1, reg2, resultReg);
        2517                 :
        2518             446 :         frame.unpinReg(reg1);
        2519             446 :         if (op2->isConstant())
        2520             235 :             frame.freeReg(reg2);
        2521                 :         else
        2522             211 :             frame.unpinReg(reg2);
        2523             446 :         frame.freeReg(tmpReg);
        2524                 :
        2525             446 :         stubcc.leave();
        2526             446 :         if (op == JSOP_STRICTEQ)
        2527             286 :             OOL_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
        2528                 :         else
        2529             160 :             OOL_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
        2530                 :
        2531             446 :         frame.popn(2);
        2532             446 :         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
        2533                 :
        2534             446 :         stubcc.rejoin(Changes(1));
        2535             446 :         return;
        2536                 :     }
        2537                 :
        2538            8818 :     if (cx->typeInferenceEnabled() &&
        2539            3744 :         lhs->isType(JSVAL_TYPE_OBJECT) && rhs->isType(JSVAL_TYPE_OBJECT))
        2540                 :     {
        2541             119 :         CompileStatus status = jsop_equality_obj_obj(op, NULL, JSOP_NOP);
        2542             119 :         if (status == Compile_Okay) return;
        2543              10 :         JS_ASSERT(status == Compile_Skipped);
        2544                 :     }
        2545                 :
        2546                 :     /* Is it impossible that both Values are ints? */
        2547           11656 :     if ((lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_INT32)) ||
        2548            6691 :         (rhs->isTypeKnown() && rhs->isNotType(JSVAL_TYPE_INT32))) {
        2549             689 :         prepareStubCall(Uses(2));
        2550                 :
        2551             689 :         if (op == JSOP_STRICTEQ)
        2552             359 :             INLINE_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
        2553                 :         else
        2554             330 :             INLINE_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
        2555                 :
        2556             689 :         frame.popn(2);
        2557             689 :         frame.pushSynced(JSVAL_TYPE_BOOLEAN);
        2558             689 :         return;
        2559                 :     }
        2560                 :
        2561                 : #if !defined JS_CPU_ARM && !defined JS_CPU_SPARC
        2562                 :     /* Try an integer fast-path. */
        2563            4276 :     bool needStub = false;
        2564            4276 :     if (!lhs->isTypeKnown()) {
        2565            3250 :         Jump j = frame.testInt32(Assembler::NotEqual, lhs);
        2566            3250 :         stubcc.linkExit(j, Uses(2));
        2567            3250 :         needStub = true;
        2568                 :     }
        2569                 :
        2570            4276 :     if (!rhs->isTypeKnown() && !frame.haveSameBacking(lhs, rhs)) {
        2571            2099 :         Jump j = frame.testInt32(Assembler::NotEqual, rhs);
        2572            2099 :         stubcc.linkExit(j, Uses(2));
        2573            2099 :         needStub = true;
        2574                 :     }
        2575                 :
        2576            4276 :     FrameEntry *test  = lhs->isConstant() ? rhs : lhs;
        2577            4276 :     FrameEntry *other = lhs->isConstant() ? lhs : rhs;
        2578                 :
        2579                 :     /* ReturnReg is safely usable with set32, since %ah can be accessed. */
        2580            4276 :     RegisterID resultReg = Registers::ReturnReg;
        2581            4276 :     frame.takeReg(resultReg);
        2582            4276 :     RegisterID testReg = frame.tempRegForData(test);
        2583            4276 :     frame.pinReg(testReg);
        2584                 :
        2585            4276 :     JS_ASSERT(resultReg != testReg);
        2586                 :
        2587                 :     /* Set boolean in resultReg. */
        2588            4276 :     if (other->isConstant()) {
        2589            1886 :         masm.set32(cond, testReg, Imm32(other->getValue().toInt32()), resultReg);
        2590            2390 :     } else if (frame.shouldAvoidDataRemat(other)) {
        2591             803 :         masm.set32(cond, testReg, frame.addressOf(other), resultReg);
        2592                 :     } else {
        2593            1587 :         RegisterID otherReg = frame.tempRegForData(other);
        2594                 :
        2595            1587 :         JS_ASSERT(otherReg != resultReg);
        2596            1587 :         JS_ASSERT(otherReg != testReg);
        2597                 :
        2598            1587 :         masm.set32(cond, testReg, otherReg, resultReg);
        2599                 :     }
        2600                 :
        2601            4276 :     frame.unpinReg(testReg);
        2602                 :
        2603            4276 :     if (needStub) {
        2604            3342 :         stubcc.leave();
        2605            3342 :         if (op == JSOP_STRICTEQ)
        2606            2007 :             OOL_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
        2607                 :         else
        2608            1335 :             OOL_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
        2609                 :     }
        2610                 :
        2611            4276 :     frame.popn(2);
        2612            4276 :     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
        2613                 :
        2614            4276 :     if (needStub)
        2615            3342 :         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           13066 : mjit::Compiler::jsop_pos()
        2633                 : {
        2634           13066 :     FrameEntry *top = frame.peek(-1);
        2635                 :
        2636           13066 :     if (top->isTypeKnown()) {
        2637            5188 :         if (top->getKnownType() <= JSVAL_TYPE_INT32)
        2638            5020 :             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            7878 :     frame.giveOwnRegs(top);
        2647                 :
        2648            7878 :     Jump j;
        2649            7878 :     if (frame.shouldAvoidTypeRemat(top))
        2650              15 :         j = masm.testNumber(Assembler::NotEqual, frame.addressOf(top));
        2651                 :     else
        2652            7863 :         j = masm.testNumber(Assembler::NotEqual, frame.tempRegForType(top));
        2653            7878 :     stubcc.linkExit(j, Uses(1));
        2654                 :
        2655            7878 :     stubcc.leave();
        2656            7878 :     OOL_STUBCALL(stubs::Pos, REJOIN_POS);
        2657                 :
        2658            7878 :     stubcc.rejoin(Changes(1));
        2659                 : }
        2660                 :
        2661                 : void
        2662            7381 : mjit::Compiler::jsop_initprop()
        2663                 : {
        2664            7381 :     FrameEntry *obj = frame.peek(-2);
        2665            7381 :     FrameEntry *fe = frame.peek(-1);
        2666            7381 :     JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC));
        2667                 :
        2668            7381 :     JSObject *baseobj = frame.extra(obj).initObject;
        2669                 :
        2670            7381 :     if (!baseobj || monitored(PC)) {
        2671            2041 :         prepareStubCall(Uses(2));
        2672            2041 :         masm.move(ImmPtr(atom), Registers::ArgReg1);
        2673            2041 :         INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
        2674            2041 :         return;
        2675                 :     }
        2676                 :
        2677                 :     JSObject *holder;
        2678            5340 :     JSProperty *prop = NULL;
        2679                 : #ifdef DEBUG
        2680                 :     bool res =
        2681                 : #endif
        2682                 :     LookupPropertyWithFlags(cx, baseobj, ATOM_TO_JSID(atom),
        2683            5340 :                             JSRESOLVE_QUALIFIED, &holder, &prop);
        2684            5340 :     JS_ASSERT(res && prop && holder == baseobj);
        2685                 :
        2686            5340 :     RegisterID objReg = frame.copyDataIntoReg(obj);
        2687                 :
        2688                 :     /* Perform the store. */
        2689            5340 :     Shape *shape = (Shape *) prop;
        2690            5340 :     Address address = masm.objPropAddress(baseobj, objReg, shape->slot());
        2691            5340 :     frame.storeTo(fe, address);
        2692            5340 :     frame.freeReg(objReg);
        2693                 : }
        2694                 :
        2695                 : void
        2696           40156 : mjit::Compiler::jsop_initelem()
        2697                 : {
        2698           40156 :     FrameEntry *obj = frame.peek(-3);
        2699           40156 :     FrameEntry *id = frame.peek(-2);
        2700           40156 :     FrameEntry *fe = frame.peek(-1);
        2701                 :
        2702                 :     /*
        2703                 :      * The initialized index is always a constant, but we won't remember which
        2704                 :      * constant if there are branches inside the code computing the initializer
        2705                 :      * expression (e.g. the expression uses the '?' operator).  Slow path those
        2706                 :      * cases, as well as those where INITELEM is used on an object initializer
        2707                 :      * or a non-fast array initializer.
        2708                 :      */
        2709           40156 :     if (!id->isConstant() || !frame.extra(obj).initArray) {
        2710             375 :         JSOp next = JSOp(PC[JSOP_INITELEM_LENGTH]);
        2711                 :
        2712             375 :         prepareStubCall(Uses(3));
        2713             375 :         masm.move(Imm32(next == JSOP_ENDINIT ? 1 : 0), Registers::ArgReg1);
        2714             375 :         INLINE_STUBCALL(stubs::InitElem, REJOIN_FALLTHROUGH);
        2715             375 :         return;
        2716                 :     }
        2717                 :
        2718           39781 :     int32_t idx = id->getValue().toInt32();
        2719                 :
        2720           39781 :     RegisterID objReg = frame.copyDataIntoReg(obj);
        2721           39781 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), objReg);
        2722                 :
        2723                 :     /* Update the initialized length. */
        2724           39781 :     masm.store32(Imm32(idx + 1), Address(objReg, ObjectElements::offsetOfInitializedLength()));
        2725                 :
        2726                 :     /* Perform the store. */
        2727           39781 :     frame.storeTo(fe, Address(objReg, idx * sizeof(Value)));
        2728           39781 :     frame.freeReg(objReg);
        2729                 : }

Generated by: LCOV version 1.7