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

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - FastBuiltins.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 560 | 532 | 95.0 %
| Date: | 2012-04-07 | Functions: | 16 | 16 | 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                 :  *   Jan de Mooij <jandemooij@gmail.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 : #include "jsbool.h"
          40                 : #include "jslibmath.h"
          41                 : #include "jsmath.h"
          42                 : #include "jsnum.h"
          43                 : #include "methodjit/MethodJIT.h"
          44                 : #include "methodjit/Compiler.h"
          45                 : #include "methodjit/StubCalls.h"
          46                 : #include "methodjit/FrameState-inl.h"
          47                 :
          48                 : using namespace js;
          49                 : using namespace js::mjit;
          50                 : using namespace JSC;
          51                 :
          52                 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
          53                 :
          54                 : CompileStatus
          55              36 : mjit::Compiler::compileMathAbsInt(FrameEntry *arg)
          56                 : {
          57                 :     RegisterID reg;
          58              36 :     if (arg->isConstant()) {
          59               0 :         reg = frame.allocReg();
          60               0 :         masm.move(Imm32(arg->getValue().toInt32()), reg);
          61                 :     } else {
          62              36 :         reg = frame.copyDataIntoReg(arg);
          63                 :     }
          64                 :
          65              36 :     Jump isPositive = masm.branch32(Assembler::GreaterThanOrEqual, reg, Imm32(0));
          66                 :
          67                 :     /* Math.abs(INT32_MIN) results in a double */
          68              36 :     Jump isMinInt = masm.branch32(Assembler::Equal, reg, Imm32(INT32_MIN));
          69              36 :     stubcc.linkExit(isMinInt, Uses(3));
          70                 :
          71              36 :     masm.neg32(reg);
          72                 :
          73              36 :     isPositive.linkTo(masm.label(), &masm);
          74                 :
          75              36 :     stubcc.leave();
          76              36 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
          77              36 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
          78                 :
          79              36 :     frame.popn(3);
          80              36 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
          81                 :
          82              36 :     stubcc.rejoin(Changes(1));
          83              36 :     return Compile_Okay;
          84                 : }
          85                 :
          86                 : CompileStatus
          87              85 : mjit::Compiler::compileMathAbsDouble(FrameEntry *arg)
          88                 : {
          89              85 :     FPRegisterID fpResultReg = frame.allocFPReg();
          90                 :
          91                 :     FPRegisterID fpReg;
          92                 :     bool allocate;
          93                 :
          94             170 :     DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
          95              85 :     JS_ASSERT(!((MaybeJump)notNumber).isSet());
          96                 :
          97              85 :     masm.absDouble(fpReg, fpResultReg);
          98                 :
          99              85 :     if (allocate)
         100               0 :         frame.freeReg(fpReg);
         101                 :
         102              85 :     frame.popn(3);
         103              85 :     frame.pushDouble(fpResultReg);
         104                 :
         105              85 :     return Compile_Okay;
         106                 : }
         107                 :
         108                 : CompileStatus
         109             184 : mjit::Compiler::compileRound(FrameEntry *arg, RoundingMode mode)
         110                 : {
         111             184 :     FPRegisterID fpScratchReg = frame.allocFPReg();
         112                 :
         113                 :     FPRegisterID fpReg;
         114                 :     bool allocate;
         115                 :
         116             368 :     DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
         117             184 :     JS_ASSERT(!((MaybeJump)notNumber).isSet());
         118                 :
         119             184 :     masm.zeroDouble(fpScratchReg);
         120                 :
         121                 :     /* Slow path for NaN and numbers <= 0. */
         122             184 :     Jump negOrNan = masm.branchDouble(Assembler::DoubleLessThanOrEqualOrUnordered, fpReg, fpScratchReg);
         123             184 :     stubcc.linkExit(negOrNan, Uses(3));
         124                 :
         125                 :     /* For round add 0.5 and floor. */
         126                 :     FPRegisterID fpSourceReg;
         127             184 :     if (mode == Round) {
         128              51 :         masm.slowLoadConstantDouble(0.5, fpScratchReg);
         129              51 :         masm.addDouble(fpReg, fpScratchReg);
         130              51 :         fpSourceReg = fpScratchReg;
         131                 :     } else {
         132             133 :         fpSourceReg = fpReg;
         133                 :     }
         134                 :
         135                 :     /* Truncate to integer, slow path if this overflows. */
         136             184 :     RegisterID reg = frame.allocReg();
         137             184 :     Jump overflow = masm.branchTruncateDoubleToInt32(fpSourceReg, reg);
         138             184 :     stubcc.linkExit(overflow, Uses(3));
         139                 :
         140             184 :     if (allocate)
         141               6 :         frame.freeReg(fpReg);
         142             184 :     frame.freeReg(fpScratchReg);
         143                 :
         144             184 :     stubcc.leave();
         145             184 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
         146             184 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         147                 :
         148             184 :     frame.popn(3);
         149             184 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         150                 :
         151             184 :     stubcc.rejoin(Changes(1));
         152             184 :     return Compile_Okay;
         153                 : }
         154                 :
         155                 : CompileStatus
         156             178 : mjit::Compiler::compileMathSqrt(FrameEntry *arg)
         157                 : {
         158             178 :     FPRegisterID fpResultReg = frame.allocFPReg();
         159                 :
         160                 :     FPRegisterID fpReg;
         161                 :     bool allocate;
         162                 :
         163             356 :     DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
         164             178 :     JS_ASSERT(!((MaybeJump)notNumber).isSet());
         165                 :
         166             178 :     masm.sqrtDouble(fpReg, fpResultReg);
         167                 :
         168             178 :     if (allocate)
         169              56 :         frame.freeReg(fpReg);
         170                 :
         171             178 :     frame.popn(3);
         172             178 :     frame.pushDouble(fpResultReg);
         173                 :
         174             178 :     return Compile_Okay;
         175                 : }
         176                 :
         177                 : CompileStatus
         178             174 : mjit::Compiler::compileMathMinMaxDouble(FrameEntry *arg1, FrameEntry *arg2,
         179                 :                                         Assembler::DoubleCondition cond)
         180                 : {
         181                 :     FPRegisterID fpReg1;
         182                 :     FPRegisterID fpReg2;
         183                 :     bool allocate;
         184                 :
         185             348 :     DebugOnly<MaybeJump> notNumber = loadDouble(arg1, &fpReg1, &allocate);
         186             174 :     JS_ASSERT(!((MaybeJump)notNumber).isSet());
         187                 :
         188             174 :     if (!allocate) {
         189             136 :         FPRegisterID fpResultReg = frame.allocFPReg();
         190             136 :         masm.moveDouble(fpReg1, fpResultReg);
         191             136 :         fpReg1 = fpResultReg;
         192                 :     }
         193                 :
         194             348 :     DebugOnly<MaybeJump> notNumber2 = loadDouble(arg2, &fpReg2, &allocate);
         195             174 :     JS_ASSERT(!((MaybeJump)notNumber2).isSet());
         196                 :
         197                 :
         198                 :     /* Slow path for 0 and NaN, because they have special requriments. */
         199             174 :     masm.zeroDouble(Registers::FPConversionTemp);
         200                 :     Jump zeroOrNan = masm.branchDouble(Assembler::DoubleEqualOrUnordered, fpReg1,
         201             174 :                                        Registers::FPConversionTemp);
         202             174 :     stubcc.linkExit(zeroOrNan, Uses(4));
         203                 :     Jump zeroOrNan2 = masm.branchDouble(Assembler::DoubleEqualOrUnordered, fpReg2,
         204             174 :                                         Registers::FPConversionTemp);
         205             174 :     stubcc.linkExit(zeroOrNan2, Uses(4));
         206                 :
         207                 :
         208             174 :     Jump ifTrue = masm.branchDouble(cond, fpReg1, fpReg2);
         209             174 :     masm.moveDouble(fpReg2, fpReg1);
         210                 :
         211             174 :     ifTrue.linkTo(masm.label(), &masm);
         212                 :
         213             174 :     if (allocate)
         214              66 :         frame.freeReg(fpReg2);
         215                 :
         216             174 :     stubcc.leave();
         217             174 :     stubcc.masm.move(Imm32(2), Registers::ArgReg1);
         218             174 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         219                 :
         220             174 :     frame.popn(4);
         221             174 :     frame.pushDouble(fpReg1);
         222                 :
         223             174 :     stubcc.rejoin(Changes(1));
         224             174 :     return Compile_Okay;
         225                 : }
         226                 :
         227                 : CompileStatus
         228              87 : mjit::Compiler::compileMathMinMaxInt(FrameEntry *arg1, FrameEntry *arg2, Assembler::Condition cond)
         229                 : {
         230                 :     /* Get this case out of the way */
         231              87 :     if (arg1->isConstant() && arg2->isConstant()) {
         232              16 :         int32_t a = arg1->getValue().toInt32();
         233              16 :         int32_t b = arg2->getValue().toInt32();
         234                 :
         235              16 :         frame.popn(4);
         236              16 :         if (cond == Assembler::LessThan)
         237               8 :             frame.push(Int32Value(a < b ? a : b));
         238                 :         else
         239               8 :             frame.push(Int32Value(a > b ? a : b));
         240              16 :         return Compile_Okay;
         241                 :     }
         242                 :
         243              71 :     Jump ifTrue;
         244                 :     RegisterID reg;
         245              71 :     if (arg1->isConstant()) {
         246               8 :         reg = frame.copyDataIntoReg(arg2);
         247               8 :         int32_t v = arg1->getValue().toInt32();
         248                 :
         249               8 :         ifTrue = masm.branch32(cond, reg, Imm32(v));
         250               8 :         masm.move(Imm32(v), reg);
         251              63 :     } else if (arg2->isConstant()) {
         252              14 :         reg = frame.copyDataIntoReg(arg1);
         253              14 :         int32_t v = arg2->getValue().toInt32();
         254                 :
         255              14 :         ifTrue = masm.branch32(cond, reg, Imm32(v));
         256              14 :         masm.move(Imm32(v), reg);
         257                 :     } else {
         258              49 :         reg = frame.copyDataIntoReg(arg1);
         259              49 :         RegisterID regB = frame.tempRegForData(arg2);
         260                 :
         261              49 :         ifTrue = masm.branch32(cond, reg, regB);
         262              49 :         masm.move(regB, reg);
         263                 :     }
         264                 :
         265              71 :     ifTrue.linkTo(masm.label(), &masm);
         266              71 :     frame.popn(4);
         267              71 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         268              71 :     return Compile_Okay;
         269                 : }
         270                 :
         271                 : CompileStatus
         272              10 : mjit::Compiler::compileMathPowSimple(FrameEntry *arg1, FrameEntry *arg2)
         273                 : {
         274              10 :     FPRegisterID fpScratchReg = frame.allocFPReg();
         275              10 :     FPRegisterID fpResultReg = frame.allocFPReg();
         276                 :
         277                 :     FPRegisterID fpReg;
         278                 :     bool allocate;
         279                 :
         280              20 :     DebugOnly<MaybeJump> notNumber = loadDouble(arg1, &fpReg, &allocate);
         281              10 :     JS_ASSERT(!((MaybeJump)notNumber).isSet());
         282                 :
         283                 :     /* Slow path for -Infinity (must return Infinity, not NaN). */
         284              10 :     masm.slowLoadConstantDouble(js_NegativeInfinity, fpResultReg);
         285              10 :     Jump isNegInfinity = masm.branchDouble(Assembler::DoubleEqual, fpReg, fpResultReg);
         286              10 :     stubcc.linkExit(isNegInfinity, Uses(4));
         287                 :
         288                 :     /* Convert -0 to +0. */
         289              10 :     masm.zeroDouble(fpResultReg);
         290              10 :     masm.moveDouble(fpReg, fpScratchReg);
         291              10 :     masm.addDouble(fpResultReg, fpScratchReg);
         292                 :
         293              10 :     double y = arg2->getValue().toDouble();
         294              10 :     if (y == 0.5) {
         295                 :         /* pow(x, 0.5) => sqrt(x) */
         296               1 :         masm.sqrtDouble(fpScratchReg, fpResultReg);
         297                 :
         298               9 :     } else if (y == -0.5) {
         299                 :         /* pow(x, -0.5) => 1/sqrt(x) */
         300               9 :         masm.sqrtDouble(fpScratchReg, fpScratchReg);
         301               9 :         masm.slowLoadConstantDouble(1, fpResultReg);
         302               9 :         masm.divDouble(fpScratchReg, fpResultReg);
         303                 :     }
         304                 :
         305              10 :     frame.freeReg(fpScratchReg);
         306                 :
         307              10 :     if (allocate)
         308               9 :         frame.freeReg(fpReg);
         309                 :
         310              10 :     stubcc.leave();
         311              10 :     stubcc.masm.move(Imm32(2), Registers::ArgReg1);
         312              10 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         313                 :
         314              10 :     frame.popn(4);
         315              10 :     frame.pushDouble(fpResultReg);
         316                 :
         317              10 :     stubcc.rejoin(Changes(1));
         318              10 :     return Compile_Okay;
         319                 : }
         320                 :
         321                 : CompileStatus
         322             105 : mjit::Compiler::compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode)
         323                 : {
         324             105 :     RegisterID reg1 = frame.allocReg();
         325             105 :     RegisterID reg2 = frame.allocReg();
         326                 :
         327                 :     /* Load string in strReg. */
         328                 :     RegisterID strReg;
         329             105 :     if (thisValue->isConstant()) {
         330               2 :         strReg = frame.allocReg();
         331               2 :         masm.move(ImmPtr(thisValue->getValue().toString()), strReg);
         332                 :     } else {
         333             103 :         strReg = frame.tempRegForData(thisValue);
         334             103 :         frame.pinReg(strReg);
         335                 :     }
         336                 :
         337                 :     /* Load index in argReg. */
         338                 :     RegisterID argReg;
         339             105 :     if (arg->isConstant()) {
         340              11 :         argReg = frame.allocReg();
         341              11 :         masm.move(Imm32(arg->getValue().toInt32()), argReg);
         342                 :     } else {
         343              94 :         argReg = frame.tempRegForData(arg);
         344                 :     }
         345             105 :     if (!thisValue->isConstant())
         346             103 :         frame.unpinReg(strReg);
         347                 :
         348             105 :     Address lengthAndFlagsAddr(strReg, JSString::offsetOfLengthAndFlags());
         349                 :
         350                 :     /* Load lengthAndFlags in reg1 and reg2 */
         351             105 :     masm.loadPtr(lengthAndFlagsAddr, reg1);
         352             105 :     masm.move(reg1, reg2);
         353                 :
         354                 :     /* Slow path if string is a rope */
         355             105 :     masm.andPtr(ImmPtr((void *)JSString::ROPE_BIT), reg1);
         356             105 :     Jump isRope = masm.branchTestPtr(Assembler::NonZero, reg1);
         357             105 :     stubcc.linkExit(isRope, Uses(3));
         358                 :
         359                 :     /* Slow path if out-of-range. */
         360             105 :     masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), reg2);
         361             105 :     Jump outOfRange = masm.branchPtr(Assembler::AboveOrEqual, argReg, reg2);
         362             105 :     stubcc.linkExit(outOfRange, Uses(3));
         363                 :
         364                 :     /* Load char code in reg2. */
         365             105 :     masm.move(argReg, reg1);
         366             105 :     masm.loadPtr(Address(strReg, JSString::offsetOfChars()), reg2);
         367             105 :     masm.lshiftPtr(Imm32(1), reg1);
         368             105 :     masm.addPtr(reg1, reg2);
         369             105 :     masm.load16(Address(reg2), reg2);
         370                 :
         371                 :     /* Convert char code to string. */
         372             105 :     if (mode == GetChar) {
         373                 :         /* Slow path if there's no unit string for this character. */
         374                 :         Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, reg2,
         375              22 :                                            Imm32(StaticStrings::UNIT_STATIC_LIMIT));
         376              22 :         stubcc.linkExit(notUnitString, Uses(3));
         377                 :
         378                 :         /* Load unit string in reg2. */
         379              22 :         masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), reg2);
         380              22 :         masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), reg2);
         381              22 :         masm.loadPtr(Address(reg2), reg2);
         382                 :     }
         383                 :
         384             105 :     if (thisValue->isConstant())
         385               2 :         frame.freeReg(strReg);
         386             105 :     if (arg->isConstant())
         387              11 :         frame.freeReg(argReg);
         388             105 :     frame.freeReg(reg1);
         389                 :
         390             105 :     stubcc.leave();
         391             105 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
         392             105 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         393                 :
         394             105 :     frame.popn(3);
         395             105 :     switch(mode) {
         396                 :       case GetCharCode:
         397              83 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg2);
         398              83 :         break;
         399                 :       case GetChar:
         400              22 :         frame.pushTypedPayload(JSVAL_TYPE_STRING, reg2);
         401              22 :         break;
         402                 :       default:
         403               0 :         JS_NOT_REACHED("unknown getchar mode");
         404                 :     }
         405                 :
         406             105 :     stubcc.rejoin(Changes(1));
         407             105 :     return Compile_Okay;
         408                 : }
         409                 :
         410                 : CompileStatus
         411              72 : mjit::Compiler::compileStringFromCode(FrameEntry *arg)
         412                 : {
         413                 :     /* Load Char-Code into argReg */
         414                 :     RegisterID argReg;
         415              72 :     if (arg->isConstant()) {
         416               0 :         argReg = frame.allocReg();
         417               0 :         masm.move(Imm32(arg->getValue().toInt32()), argReg);
         418                 :     } else {
         419              72 :         argReg = frame.copyDataIntoReg(arg);
         420                 :     }
         421                 :
         422                 :     /* Slow path if there's no unit string for this character. */
         423                 :     Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, argReg,
         424              72 :                                        Imm32(StaticStrings::UNIT_STATIC_LIMIT));
         425              72 :     stubcc.linkExit(notUnitString, Uses(3));
         426                 :
         427                 :     /* Load unit string in reg. */
         428              72 :     masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), argReg);
         429              72 :     masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), argReg);
         430              72 :     masm.loadPtr(Address(argReg), argReg);
         431                 :
         432              72 :     stubcc.leave();
         433              72 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
         434              72 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         435                 :
         436              72 :     frame.popn(3);
         437              72 :     frame.pushTypedPayload(JSVAL_TYPE_STRING, argReg);
         438                 :
         439              72 :     stubcc.rejoin(Changes(1));
         440              72 :     return Compile_Okay;
         441                 : }
         442                 :
         443                 : CompileStatus
         444            1232 : mjit::Compiler::compileArrayPush(FrameEntry *thisValue, FrameEntry *arg)
         445                 : {
         446                 :     /* This behaves like an assignment this[this.length] = arg; */
         447                 :
         448                 :     /* Filter out silly cases. */
         449            1232 :     if (frame.haveSameBacking(thisValue, arg) || thisValue->isConstant())
         450               0 :         return Compile_InlineAbort;
         451                 :
         452                 :     /* Allocate registers. */
         453                 :     ValueRemat vr;
         454            1232 :     frame.pinEntry(arg, vr, /* breakDouble = */ false);
         455                 :
         456            1232 :     RegisterID objReg = frame.tempRegForData(thisValue);
         457            1232 :     frame.pinReg(objReg);
         458                 :
         459            1232 :     RegisterID slotsReg = frame.allocReg();
         460            1232 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
         461                 :
         462            1232 :     RegisterID lengthReg = frame.allocReg();
         463            1232 :     masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg);
         464                 :
         465            1232 :     frame.unpinReg(objReg);
         466                 :
         467            1232 :     Int32Key key = Int32Key::FromRegister(lengthReg);
         468                 :
         469                 :     /* Test for 'length == initializedLength' */
         470                 :     Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
         471            1232 :                                               slotsReg, key, Assembler::NotEqual);
         472            1232 :     stubcc.linkExit(initlenGuard, Uses(3));
         473                 :
         474                 :     /* Test for 'length < capacity' */
         475                 :     Jump capacityGuard = masm.guardArrayExtent(ObjectElements::offsetOfCapacity(),
         476            1232 :                                                slotsReg, key, Assembler::BelowOrEqual);
         477            1232 :     stubcc.linkExit(capacityGuard, Uses(3));
         478                 :
         479            1232 :     masm.storeValue(vr, BaseIndex(slotsReg, lengthReg, masm.JSVAL_SCALE));
         480                 :
         481            1232 :     masm.bumpKey(key, 1);
         482            1232 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength()));
         483            1232 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
         484                 :
         485            1232 :     stubcc.leave();
         486            1232 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
         487            1232 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         488                 :
         489            1232 :     frame.unpinEntry(vr);
         490            1232 :     frame.freeReg(slotsReg);
         491            1232 :     frame.popn(3);
         492                 :
         493            1232 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, lengthReg);
         494                 :
         495            1232 :     stubcc.rejoin(Changes(1));
         496            1232 :     return Compile_Okay;
         497                 : }
         498                 :
         499                 : CompileStatus
         500              76 : mjit::Compiler::compileArrayPopShift(FrameEntry *thisValue, bool isPacked, bool isArrayPop)
         501                 : {
         502                 :     /* Filter out silly cases. */
         503              76 :     if (thisValue->isConstant())
         504               0 :         return Compile_InlineAbort;
         505                 :
         506                 : #ifdef JSGC_INCREMENTAL_MJ
         507                 :     /* Write barrier. */
         508              76 :     if (cx->compartment->needsBarrier())
         509               6 :         return Compile_InlineAbort;
         510                 : #endif
         511                 :
         512              70 :     RegisterID objReg = frame.tempRegForData(thisValue);
         513              70 :     frame.pinReg(objReg);
         514                 :
         515              70 :     RegisterID lengthReg = frame.allocReg();
         516              70 :     RegisterID slotsReg = frame.allocReg();
         517                 :
         518              70 :     JSValueType type = knownPushedType(0);
         519                 :
         520              70 :     MaybeRegisterID dataReg, typeReg;
         521              70 :     if (!analysis->popGuaranteed(PC)) {
         522              64 :         dataReg = frame.allocReg();
         523              64 :         if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE)
         524               9 :             typeReg = frame.allocReg();
         525                 :     }
         526                 :
         527              70 :     if (isArrayPop) {
         528              49 :         frame.unpinReg(objReg);
         529                 :     } else {
         530                 :         /*
         531                 :          * Sync up front for shift() so we can jump over the inline stub.
         532                 :          * The result will be stored in memory rather than registers.
         533                 :          */
         534              21 :         frame.syncAndKillEverything();
         535              21 :         frame.unpinKilledReg(objReg);
         536                 :     }
         537                 :
         538              70 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
         539              70 :     masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg);
         540                 :
         541                 :     /* Test for 'length == initializedLength' */
         542              70 :     Int32Key key = Int32Key::FromRegister(lengthReg);
         543                 :     Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
         544              70 :                                               slotsReg, key, Assembler::NotEqual);
         545              70 :     stubcc.linkExit(initlenGuard, Uses(3));
         546                 :
         547                 :     /*
         548                 :      * Test for length != 0. On zero length either take a slow call or generate
         549                 :      * an undefined value, depending on whether the call is known to produce
         550                 :      * undefined.
         551                 :      */
         552              70 :     bool maybeUndefined = pushedTypeSet(0)->hasType(types::Type::UndefinedType());
         553              70 :     Jump emptyGuard = masm.branch32(Assembler::Equal, lengthReg, Imm32(0));
         554              70 :     if (!maybeUndefined)
         555              56 :         stubcc.linkExit(emptyGuard, Uses(3));
         556                 :
         557              70 :     masm.bumpKey(key, -1);
         558                 :
         559              70 :     if (dataReg.isSet()) {
         560              64 :         Jump holeCheck;
         561              64 :         if (isArrayPop) {
         562              45 :             BaseIndex slot(slotsReg, lengthReg, masm.JSVAL_SCALE);
         563              45 :             holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg.reg());
         564                 :         } else {
         565              19 :             holeCheck = masm.fastArrayLoadSlot(Address(slotsReg), !isPacked, typeReg, dataReg.reg());
         566              19 :             Address addr = frame.addressOf(frame.peek(-2));
         567              19 :             if (typeReg.isSet())
         568               2 :                 masm.storeValueFromComponents(typeReg.reg(), dataReg.reg(), addr);
         569                 :             else
         570              17 :                 masm.storeValueFromComponents(ImmType(type), dataReg.reg(), addr);
         571                 :         }
         572              64 :         if (!isPacked)
         573              47 :             stubcc.linkExit(holeCheck, Uses(3));
         574                 :     }
         575                 :
         576              70 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength()));
         577              70 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
         578                 :
         579              70 :     if (!isArrayPop)
         580              21 :         INLINE_STUBCALL(stubs::ArrayShift, REJOIN_NONE);
         581                 :
         582              70 :     stubcc.leave();
         583              70 :     stubcc.masm.move(Imm32(0), Registers::ArgReg1);
         584              70 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         585                 :
         586              70 :     frame.freeReg(slotsReg);
         587              70 :     frame.freeReg(lengthReg);
         588              70 :     frame.popn(2);
         589                 :
         590              70 :     if (dataReg.isSet()) {
         591              64 :         if (isArrayPop) {
         592              45 :             if (typeReg.isSet())
         593               7 :                 frame.pushRegs(typeReg.reg(), dataReg.reg(), type);
         594                 :             else
         595              38 :                 frame.pushTypedPayload(type, dataReg.reg());
         596                 :         } else {
         597              19 :             frame.pushSynced(type);
         598              19 :             if (typeReg.isSet())
         599               2 :                 frame.freeReg(typeReg.reg());
         600              19 :             frame.freeReg(dataReg.reg());
         601                 :         }
         602                 :     } else {
         603               6 :         frame.push(UndefinedValue());
         604                 :     }
         605                 :
         606              70 :     stubcc.rejoin(Changes(1));
         607                 :
         608              70 :     if (maybeUndefined) {
         609                 :         /* Generate an OOL path to push an undefined value, and rejoin. */
         610              14 :         if (dataReg.isSet()) {
         611              12 :             stubcc.linkExitDirect(emptyGuard, stubcc.masm.label());
         612              12 :             if (isArrayPop) {
         613               6 :                 if (typeReg.isSet()) {
         614               6 :                     stubcc.masm.loadValueAsComponents(UndefinedValue(), typeReg.reg(), dataReg.reg());
         615                 :                 } else {
         616               0 :                     JS_ASSERT(type == JSVAL_TYPE_UNDEFINED);
         617               0 :                     stubcc.masm.loadValuePayload(UndefinedValue(), dataReg.reg());
         618                 :                 }
         619                 :             } else {
         620               6 :                 stubcc.masm.storeValue(UndefinedValue(), frame.addressOf(frame.peek(-1)));
         621                 :             }
         622              12 :             stubcc.crossJump(stubcc.masm.jump(), masm.label());
         623                 :         } else {
         624               2 :             emptyGuard.linkTo(masm.label(), &masm);
         625                 :         }
         626                 :     }
         627                 :
         628              70 :     return Compile_Okay;
         629                 : }
         630                 :
         631                 : CompileStatus
         632              24 : mjit::Compiler::compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *argTypes,
         633                 :                                    FrameEntry *thisValue, FrameEntry *argValue)
         634                 : {
         635                 :     /*
         636                 :      * Require the 'this' types to have a specific type matching the current
         637                 :      * global, so we can create the result object inline.
         638                 :      */
         639              24 :     if (thisTypes->getObjectCount() != 1)
         640               0 :         return Compile_InlineAbort;
         641              24 :     types::TypeObject *thisType = thisTypes->getTypeObject(0);
         642              24 :     if (!thisType || &thisType->proto->global() != globalObj)
         643               0 :         return Compile_InlineAbort;
         644                 :
         645                 :     /*
         646                 :      * Constraints modeling this concat have not been generated by inference,
         647                 :      * so check that type information already reflects possible side effects of
         648                 :      * this call.
         649                 :      */
         650              24 :     thisTypes->addFreeze(cx);
         651              24 :     argTypes->addFreeze(cx);
         652              24 :     types::TypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID, false);
         653              24 :     if (!thisElemTypes)
         654               0 :         return Compile_Error;
         655              24 :     if (!pushedTypeSet(0)->hasType(types::Type::ObjectType(thisType)))
         656               0 :         return Compile_InlineAbort;
         657              46 :     for (unsigned i = 0; i < argTypes->getObjectCount(); i++) {
         658              24 :         if (argTypes->getSingleObject(i))
         659               0 :             return Compile_InlineAbort;
         660              24 :         types::TypeObject *argType = argTypes->getTypeObject(i);
         661              24 :         if (!argType)
         662               0 :             continue;
         663              24 :         types::TypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
         664              24 :         if (!elemTypes)
         665               0 :             return Compile_Error;
         666              24 :         if (!elemTypes->knownSubset(cx, thisElemTypes))
         667               2 :             return Compile_InlineAbort;
         668                 :     }
         669                 :
         670                 :     /* Test for 'length == initializedLength' on both arrays. */
         671                 :
         672              22 :     RegisterID slotsReg = frame.allocReg();
         673              22 :     RegisterID reg = frame.allocReg();
         674                 :
         675              22 :     Int32Key key = Int32Key::FromRegister(reg);
         676                 :
         677              22 :     RegisterID objReg = frame.tempRegForData(thisValue);
         678              22 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
         679              22 :     masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), reg);
         680                 :     Jump initlenOneGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
         681              22 :                                                  slotsReg, key, Assembler::NotEqual);
         682              22 :     stubcc.linkExit(initlenOneGuard, Uses(3));
         683                 :
         684              22 :     objReg = frame.tempRegForData(argValue);
         685              22 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
         686              22 :     masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), reg);
         687                 :     Jump initlenTwoGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
         688              22 :                                                  slotsReg, key, Assembler::NotEqual);
         689              22 :     stubcc.linkExit(initlenTwoGuard, Uses(3));
         690                 :
         691              22 :     frame.freeReg(reg);
         692              22 :     frame.freeReg(slotsReg);
         693              22 :     frame.syncAndForgetEverything();
         694                 :
         695                 :     /*
         696                 :      * The current stack layout is 'CALLEE THIS ARG'. Allocate the result and
         697                 :      * scribble it over the callee, which will be its final position after the
         698                 :      * call.
         699                 :      */
         700                 :
         701              22 :     JSObject *templateObject = NewDenseEmptyArray(cx, thisType->proto);
         702              22 :     if (!templateObject)
         703               0 :         return Compile_Error;
         704              22 :     templateObject->setType(thisType);
         705                 :
         706              22 :     RegisterID result = Registers::ReturnReg;
         707              22 :     Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
         708              22 :     stubcc.linkExit(emptyFreeList, Uses(3));
         709                 :
         710              22 :     masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), result, frame.addressOf(frame.peek(-3)));
         711              22 :     INLINE_STUBCALL(stubs::ArrayConcatTwoArrays, REJOIN_FALLTHROUGH);
         712                 :
         713              22 :     stubcc.leave();
         714              22 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
         715              22 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         716                 :
         717              22 :     frame.popn(3);
         718              22 :     frame.pushSynced(JSVAL_TYPE_OBJECT);
         719                 :
         720              22 :     stubcc.rejoin(Changes(1));
         721              22 :     return Compile_Okay;
         722                 : }
         723                 :
         724                 : CompileStatus
         725             965 : mjit::Compiler::compileArrayWithLength(uint32_t argc)
         726                 : {
         727                 :     /* Match Array() or Array(n) for constant n. */
         728             965 :     JS_ASSERT(argc == 0 || argc == 1);
         729                 :
         730             965 :     int32_t length = 0;
         731             965 :     if (argc == 1) {
         732             620 :         FrameEntry *arg = frame.peek(-1);
         733             620 :         if (!arg->isConstant() || !arg->getValue().isInt32())
         734             301 :             return Compile_InlineAbort;
         735             319 :         length = arg->getValue().toInt32();
         736             319 :         if (length < 0)
         737               0 :             return Compile_InlineAbort;
         738                 :     }
         739                 :
         740             664 :     types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
         741             664 :     if (!type)
         742               0 :         return Compile_Error;
         743                 :
         744             664 :     JSObject *templateObject = NewDenseUnallocatedArray(cx, length, type->proto);
         745             664 :     if (!templateObject)
         746               0 :         return Compile_Error;
         747             664 :     templateObject->setType(type);
         748                 :
         749             664 :     RegisterID result = frame.allocReg();
         750             664 :     Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
         751                 :
         752             664 :     stubcc.linkExit(emptyFreeList, Uses(0));
         753             664 :     stubcc.leave();
         754                 :
         755             664 :     stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
         756             664 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         757                 :
         758             664 :     frame.popn(argc + 2);
         759             664 :     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
         760                 :
         761             664 :     stubcc.rejoin(Changes(1));
         762             664 :     return Compile_Okay;
         763                 : }
         764                 :
         765                 : CompileStatus
         766              61 : mjit::Compiler::compileArrayWithArgs(uint32_t argc)
         767                 : {
         768                 :     /*
         769                 :      * Match Array(x, y, z) with at least two arguments. Don't inline the case
         770                 :      * where a non-number argument is passed, so we don't need to care about
         771                 :      * the types of the arguments.
         772                 :      */
         773              61 :     JS_ASSERT(argc >= 2);
         774                 :
         775                 :     size_t maxArraySlots =
         776              61 :         gc::GetGCKindSlots(gc::FINALIZE_OBJECT_LAST) - ObjectElements::VALUES_PER_HEADER;
         777                 :
         778              61 :     if (argc > maxArraySlots)
         779               0 :         return Compile_InlineAbort;
         780                 :
         781              61 :     types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
         782              61 :     if (!type)
         783               0 :         return Compile_Error;
         784                 :
         785              61 :     JSObject *templateObject = NewDenseUnallocatedArray(cx, argc, type->proto);
         786              61 :     if (!templateObject)
         787               0 :         return Compile_Error;
         788              61 :     templateObject->setType(type);
         789                 :
         790              61 :     JS_ASSERT(templateObject->getDenseArrayCapacity() >= argc);
         791                 :
         792              61 :     RegisterID result = frame.allocReg();
         793              61 :     Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
         794              61 :     stubcc.linkExit(emptyFreeList, Uses(0));
         795                 :
         796              61 :     int offset = JSObject::offsetOfFixedElements();
         797                 :     masm.store32(Imm32(argc),
         798              61 :                  Address(result, offset + ObjectElements::offsetOfInitializedLength()));
         799                 :
         800             259 :     for (unsigned i = 0; i < argc; i++) {
         801             198 :         FrameEntry *arg = frame.peek(-(int32_t)argc + i);
         802             198 :         frame.storeTo(arg, Address(result, offset), /* popped = */ true);
         803             198 :         offset += sizeof(Value);
         804                 :     }
         805                 :
         806              61 :     stubcc.leave();
         807                 :
         808              61 :     stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
         809              61 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         810                 :
         811              61 :     frame.popn(argc + 2);
         812              61 :     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
         813                 :
         814              61 :     stubcc.rejoin(Changes(1));
         815              61 :     return Compile_Okay;
         816                 : }
         817                 :
         818                 : CompileStatus
         819             199 : mjit::Compiler::compileParseInt(JSValueType argType, uint32_t argc)
         820                 : {
         821             199 :     bool needStubCall = false;
         822                 :
         823             199 :     if (argc > 1) {
         824              30 :         FrameEntry *arg = frame.peek(-(int32_t)argc + 1);
         825                 :
         826              30 :         if (!arg->isTypeKnown() || arg->getKnownType() != JSVAL_TYPE_INT32)
         827               2 :             return Compile_InlineAbort;
         828                 :
         829              28 :         if (arg->isConstant()) {
         830              20 :             int32_t base = arg->getValue().toInt32();
         831              20 :             if (base != 0 && base != 10)
         832               0 :                 return Compile_InlineAbort;
         833                 :         } else {
         834               8 :             RegisterID baseReg = frame.tempRegForData(arg);
         835               8 :             needStubCall = true;
         836                 :
         837               8 :             Jump isTen = masm.branch32(Assembler::Equal, baseReg, Imm32(10));
         838               8 :             Jump isNotZero = masm.branch32(Assembler::NotEqual, baseReg, Imm32(0));
         839               8 :             stubcc.linkExit(isNotZero, Uses(2 + argc));
         840                 :
         841               8 :             isTen.linkTo(masm.label(), &masm);
         842                 :         }
         843                 :     }
         844                 :
         845             197 :     if (argType == JSVAL_TYPE_INT32) {
         846              24 :         if (needStubCall) {
         847               3 :             stubcc.leave();
         848               3 :             stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
         849               3 :             OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         850                 :         }
         851                 :
         852                 :         /*
         853                 :          * Stack looks like callee, this, arg1, arg2, argN.
         854                 :          * First pop all args other than arg1.
         855                 :          */
         856              24 :         frame.popn(argc - 1);
         857                 :         /* "Shimmy" arg1 to the callee slot and pop this + arg1. */
         858              24 :         frame.shimmy(2);
         859                 :
         860              24 :         if (needStubCall) {
         861               3 :             stubcc.rejoin(Changes(1));
         862                 :         }
         863                 :     } else {
         864             173 :         FrameEntry *arg = frame.peek(-(int32_t)argc);
         865             173 :         FPRegisterID fpScratchReg = frame.allocFPReg();
         866                 :         FPRegisterID fpReg;
         867                 :         bool allocate;
         868                 :
         869             346 :         DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate);
         870             173 :         JS_ASSERT(!((MaybeJump)notNumber).isSet());
         871                 :
         872             173 :         masm.slowLoadConstantDouble(1, fpScratchReg);
         873                 :
         874                 :         /* Slow path for NaN and numbers < 1. */
         875                 :         Jump lessThanOneOrNan = masm.branchDouble(Assembler::DoubleLessThanOrUnordered,
         876             173 :                                                   fpReg, fpScratchReg);
         877             173 :         stubcc.linkExit(lessThanOneOrNan, Uses(2 + argc));
         878                 :
         879             173 :         frame.freeReg(fpScratchReg);
         880                 :
         881                 :         /* Truncate to integer, slow path if this overflows. */
         882             173 :         RegisterID reg = frame.allocReg();
         883             173 :         Jump overflow = masm.branchTruncateDoubleToInt32(fpReg, reg);
         884             173 :         stubcc.linkExit(overflow, Uses(2 + argc));
         885                 :
         886             173 :         if (allocate)
         887             112 :             frame.freeReg(fpReg);
         888                 :
         889             173 :         stubcc.leave();
         890             173 :         stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
         891             173 :         OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
         892                 :
         893             173 :         frame.popn(2 + argc);
         894             173 :         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
         895                 :
         896             173 :         stubcc.rejoin(Changes(1));
         897                 :     }
         898                 :
         899             197 :     return Compile_Okay;
         900                 : }
         901                 :
         902                 : CompileStatus
         903          172875 : mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
         904                 : {
         905          172875 :     if (!cx->typeInferenceEnabled())
         906           52391 :         return Compile_InlineAbort;
         907                 :
         908          120484 :     if (applyTricks == LazyArgsObj)
         909               0 :         return Compile_InlineAbort;
         910                 :
         911          120484 :     FrameEntry *origCallee = frame.peek(-((int)argc + 2));
         912          120484 :     FrameEntry *thisValue = frame.peek(-((int)argc + 1));
         913          120484 :     types::TypeSet *thisTypes = analysis->poppedTypes(PC, argc);
         914                 :
         915          120484 :     if (!origCallee->isConstant() || !origCallee->isType(JSVAL_TYPE_OBJECT))
         916           68037 :         return Compile_InlineAbort;
         917                 :
         918           52447 :     JSObject *callee = &origCallee->getValue().toObject();
         919           52447 :     if (!callee->isFunction())
         920               0 :         return Compile_InlineAbort;
         921                 :
         922                 :     /*
         923                 :      * The callee must have the same parent as the script's global, otherwise
         924                 :      * inference may not have accounted for any side effects correctly.
         925                 :      */
         926           52447 :     if (!globalObj || globalObj != &callee->global())
         927             288 :         return Compile_InlineAbort;
         928                 :
         929           52159 :     Native native = callee->toFunction()->maybeNative();
         930                 :
         931           52159 :     if (!native)
         932           12681 :         return Compile_InlineAbort;
         933                 :
         934           39478 :     JSValueType type = knownPushedType(0);
         935           39478 :     JSValueType thisType = thisValue->isTypeKnown()
         936                 :                            ? thisValue->getKnownType()
         937           39478 :                            : JSVAL_TYPE_UNKNOWN;
         938                 :
         939                 :     /*
         940                 :      * Note: when adding new natives which operate on properties, add relevant
         941                 :      * constraint generation to the behavior of TypeConstraintCall.
         942                 :      */
         943                 :
         944                 :     /* Handle natives that can be called either with or without 'new'. */
         945                 :
         946           39478 :     if (native == js_Array && type == JSVAL_TYPE_OBJECT && globalObj) {
         947            1026 :         if (argc == 0 || argc == 1)
         948             965 :             return compileArrayWithLength(argc);
         949              61 :         return compileArrayWithArgs(argc);
         950                 :     }
         951                 :
         952                 :     /* Remaining natives must not be called with 'new'. */
         953           38452 :     if (callingNew)
         954            1768 :         return Compile_InlineAbort;
         955                 :
         956           36684 :     if (native == js::num_parseInt && argc >= 1) {
         957             323 :         FrameEntry *arg = frame.peek(-(int32_t)argc);
         958             323 :         JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
         959                 :
         960             323 :         if ((argType == JSVAL_TYPE_DOUBLE || argType == JSVAL_TYPE_INT32) &&
         961                 :             type == JSVAL_TYPE_INT32) {
         962             199 :             return compileParseInt(argType, argc);
         963                 :         }
         964                 :     }
         965                 :
         966           36485 :     if (argc == 0) {
         967            2317 :         if ((native == js::array_pop || native == js::array_shift) && thisType == JSVAL_TYPE_OBJECT) {
         968                 :             /*
         969                 :              * Only handle pop/shift on dense arrays which have never been used
         970                 :              * in an iterator --- when popping elements we don't account for
         971                 :              * suppressing deleted properties in active iterators.
         972                 :              *
         973                 :              * Constraints propagating properties directly into the result
         974                 :              * type set are generated by TypeConstraintCall during inference.
         975                 :              */
         976             160 :             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY |
         977              84 :                                            types::OBJECT_FLAG_ITERATED) &&
         978              76 :                 !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
         979              76 :                 bool packed = !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
         980              76 :                 return compileArrayPopShift(thisValue, packed, native == js::array_pop);
         981                 :             }
         982                 :         }
         983           34168 :     } else if (argc == 1) {
         984           17016 :         FrameEntry *arg = frame.peek(-1);
         985           17016 :         types::TypeSet *argTypes = frame.extra(arg).types;
         986           17016 :         if (!argTypes)
         987               0 :             return Compile_InlineAbort;
         988           17016 :         JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
         989                 :
         990           17016 :         if (native == js_math_abs) {
         991             270 :             if (argType == JSVAL_TYPE_INT32 && type == JSVAL_TYPE_INT32)
         992              36 :                 return compileMathAbsInt(arg);
         993                 :
         994             234 :             if (argType == JSVAL_TYPE_DOUBLE && type == JSVAL_TYPE_DOUBLE)
         995              85 :                 return compileMathAbsDouble(arg);
         996                 :         }
         997           16895 :         if (native == js_math_floor && argType == JSVAL_TYPE_DOUBLE &&
         998                 :             type == JSVAL_TYPE_INT32) {
         999             133 :             return compileRound(arg, Floor);
        1000                 :         }
        1001           16762 :         if (native == js_math_round && argType == JSVAL_TYPE_DOUBLE &&
        1002                 :             type == JSVAL_TYPE_INT32) {
        1003              51 :             return compileRound(arg, Round);
        1004                 :         }
        1005           16892 :         if (native == js_math_sqrt && type == JSVAL_TYPE_DOUBLE &&
        1006             181 :              masm.supportsFloatingPointSqrt() &&
        1007                 :             (argType == JSVAL_TYPE_INT32 || argType == JSVAL_TYPE_DOUBLE)) {
        1008             178 :             return compileMathSqrt(arg);
        1009                 :         }
        1010           16533 :         if (native == js_str_charCodeAt && argType == JSVAL_TYPE_INT32 &&
        1011                 :             thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_INT32) {
        1012              83 :             return compileGetChar(thisValue, arg, GetCharCode);
        1013                 :         }
        1014           16450 :         if (native == js_str_charAt && argType == JSVAL_TYPE_INT32 &&
        1015                 :             thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_STRING) {
        1016              22 :             return compileGetChar(thisValue, arg, GetChar);
        1017                 :         }
        1018           16428 :         if (native == js::str_fromCharCode && argType == JSVAL_TYPE_INT32 &&
        1019                 :             type == JSVAL_TYPE_STRING) {
        1020              72 :             return compileStringFromCode(arg);
        1021                 :         }
        1022           16356 :         if (native == js::array_push &&
        1023                 :             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_INT32) {
        1024                 :             /*
        1025                 :              * Constraints propagating properties into the 'this' object are
        1026                 :              * generated by TypeConstraintCall during inference.
        1027                 :              */
        1028            2491 :             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
        1029            1244 :                 !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
        1030            1232 :                 return compileArrayPush(thisValue, arg);
        1031                 :             }
        1032                 :         }
        1033           15278 :         if (native == js::array_concat && argType == JSVAL_TYPE_OBJECT &&
        1034                 :             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_OBJECT &&
        1035              77 :             !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
        1036              77 :             !argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
        1037              24 :             return compileArrayConcat(thisTypes, argTypes, thisValue, arg);
        1038                 :         }
        1039           17152 :     } else if (argc == 2) {
        1040           16466 :         FrameEntry *arg1 = frame.peek(-2);
        1041           16466 :         FrameEntry *arg2 = frame.peek(-1);
        1042                 :
        1043           16466 :         JSValueType arg1Type = arg1->isTypeKnown() ? arg1->getKnownType() : JSVAL_TYPE_UNKNOWN;
        1044           16466 :         JSValueType arg2Type = arg2->isTypeKnown() ? arg2->getKnownType() : JSVAL_TYPE_UNKNOWN;
        1045                 :
        1046           16825 :         if (native == js_math_pow && type == JSVAL_TYPE_DOUBLE &&
        1047             211 :              masm.supportsFloatingPointSqrt() &&
        1048                 :             (arg1Type == JSVAL_TYPE_DOUBLE || arg1Type == JSVAL_TYPE_INT32) &&
        1049             148 :             arg2Type == JSVAL_TYPE_DOUBLE && arg2->isConstant())
        1050                 :         {
        1051              10 :             Value arg2Value = arg2->getValue();
        1052              10 :             if (arg2Value.toDouble() == -0.5 || arg2Value.toDouble() == 0.5)
        1053              10 :                 return compileMathPowSimple(arg1, arg2);
        1054                 :         }
        1055           16456 :         if ((native == js_math_min || native == js_math_max)) {
        1056             337 :             if (arg1Type == JSVAL_TYPE_INT32 && arg2Type == JSVAL_TYPE_INT32 &&
        1057                 :                 type == JSVAL_TYPE_INT32) {
        1058                 :                 return compileMathMinMaxInt(arg1, arg2,
        1059              87 :                         native == js_math_min ? Assembler::LessThan : Assembler::GreaterThan);
        1060                 :             }
        1061             250 :             if ((arg1Type == JSVAL_TYPE_INT32 || arg1Type == JSVAL_TYPE_DOUBLE) &&
        1062                 :                 (arg2Type == JSVAL_TYPE_INT32 || arg2Type == JSVAL_TYPE_DOUBLE) &&
        1063                 :                 type == JSVAL_TYPE_DOUBLE) {
        1064                 :                 return compileMathMinMaxDouble(arg1, arg2,
        1065                 :                         (native == js_math_min)
        1066                 :                         ? Assembler::DoubleLessThan
        1067             174 :                         : Assembler::DoubleGreaterThan);
        1068                 :             }
        1069                 :         }
        1070                 :     }
        1071           34222 :     return Compile_InlineAbort;
        1072                 : }
        1073                 :

Generated by: LCOV version 1.7