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-06-02 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            1226 : 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            1226 :     if (frame.haveSameBacking(thisValue, arg) || thisValue->isConstant())
     450               0 :         return Compile_InlineAbort;
     451                 : 
     452                 :     /* Allocate registers. */
     453                 :     ValueRemat vr;
     454            1226 :     frame.pinEntry(arg, vr, /* breakDouble = */ false);
     455                 : 
     456            1226 :     RegisterID objReg = frame.tempRegForData(thisValue);
     457            1226 :     frame.pinReg(objReg);
     458                 : 
     459            1226 :     RegisterID slotsReg = frame.allocReg();
     460            1226 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg);
     461                 : 
     462            1226 :     RegisterID lengthReg = frame.allocReg();
     463            1226 :     masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg);
     464                 : 
     465            1226 :     frame.unpinReg(objReg);
     466                 : 
     467            1226 :     Int32Key key = Int32Key::FromRegister(lengthReg);
     468                 : 
     469                 :     /* Test for 'length == initializedLength' */
     470                 :     Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
     471            1226 :                                               slotsReg, key, Assembler::NotEqual);
     472            1226 :     stubcc.linkExit(initlenGuard, Uses(3));
     473                 : 
     474                 :     /* Test for 'length < capacity' */
     475                 :     Jump capacityGuard = masm.guardArrayExtent(ObjectElements::offsetOfCapacity(),
     476            1226 :                                                slotsReg, key, Assembler::BelowOrEqual);
     477            1226 :     stubcc.linkExit(capacityGuard, Uses(3));
     478                 : 
     479            1226 :     masm.storeValue(vr, BaseIndex(slotsReg, lengthReg, masm.JSVAL_SCALE));
     480                 : 
     481            1226 :     masm.bumpKey(key, 1);
     482            1226 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength()));
     483            1226 :     masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength()));
     484                 : 
     485            1226 :     stubcc.leave();
     486            1226 :     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
     487            1226 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
     488                 : 
     489            1226 :     frame.unpinEntry(vr);
     490            1226 :     frame.freeReg(slotsReg);
     491            1226 :     frame.popn(3);
     492                 : 
     493            1226 :     frame.pushTypedPayload(JSVAL_TYPE_INT32, lengthReg);
     494                 : 
     495            1226 :     stubcc.rejoin(Changes(1));
     496            1226 :     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             124 : 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             124 :     JS_ASSERT(argc >= 2);
     774                 : 
     775                 :     size_t maxArraySlots =
     776             124 :         gc::GetGCKindSlots(gc::FINALIZE_OBJECT_LAST) - ObjectElements::VALUES_PER_HEADER;
     777                 : 
     778             124 :     if (argc > maxArraySlots)
     779               0 :         return Compile_InlineAbort;
     780                 : 
     781             124 :     types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
     782             124 :     if (!type)
     783               0 :         return Compile_Error;
     784                 : 
     785             124 :     JSObject *templateObject = NewDenseUnallocatedArray(cx, argc, type->proto);
     786             124 :     if (!templateObject)
     787               0 :         return Compile_Error;
     788             124 :     templateObject->setType(type);
     789                 : 
     790             124 :     JS_ASSERT(templateObject->getDenseArrayCapacity() >= argc);
     791                 : 
     792             124 :     RegisterID result = frame.allocReg();
     793             124 :     Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
     794             124 :     stubcc.linkExit(emptyFreeList, Uses(0));
     795                 : 
     796             124 :     int offset = JSObject::offsetOfFixedElements();
     797                 :     masm.store32(Imm32(argc),
     798             124 :                  Address(result, offset + ObjectElements::offsetOfInitializedLength()));
     799                 : 
     800             511 :     for (unsigned i = 0; i < argc; i++) {
     801             387 :         FrameEntry *arg = frame.peek(-(int32_t)argc + i);
     802             387 :         frame.storeTo(arg, Address(result, offset), /* popped = */ true);
     803             387 :         offset += sizeof(Value);
     804                 :     }
     805                 : 
     806             124 :     stubcc.leave();
     807                 : 
     808             124 :     stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
     809             124 :     OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
     810                 : 
     811             124 :     frame.popn(argc + 2);
     812             124 :     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
     813                 : 
     814             124 :     stubcc.rejoin(Changes(1));
     815             124 :     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          287828 : mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
     904                 : {
     905          287828 :     if (!cx->typeInferenceEnabled())
     906          168723 :         return Compile_InlineAbort;
     907                 : 
     908          119105 :     if (applyTricks == LazyArgsObj)
     909               0 :         return Compile_InlineAbort;
     910                 : 
     911          119105 :     FrameEntry *origCallee = frame.peek(-((int)argc + 2));
     912          119105 :     FrameEntry *thisValue = frame.peek(-((int)argc + 1));
     913          119105 :     types::TypeSet *thisTypes = analysis->poppedTypes(PC, argc);
     914                 : 
     915          119105 :     if (!origCallee->isConstant() || !origCallee->isType(JSVAL_TYPE_OBJECT))
     916           67400 :         return Compile_InlineAbort;
     917                 : 
     918           51705 :     JSObject *callee = &origCallee->getValue().toObject();
     919           51705 :     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           51705 :     if (!globalObj || globalObj != &callee->global())
     927             284 :         return Compile_InlineAbort;
     928                 : 
     929           51421 :     Native native = callee->toFunction()->maybeNative();
     930                 : 
     931           51421 :     if (!native)
     932           12250 :         return Compile_InlineAbort;
     933                 : 
     934           39171 :     JSValueType type = knownPushedType(0);
     935           39171 :     JSValueType thisType = thisValue->isTypeKnown()
     936                 :                            ? thisValue->getKnownType()
     937           39171 :                            : 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           39171 :     if (native == js_Array && type == JSVAL_TYPE_OBJECT && globalObj) {
     947            1089 :         if (argc == 0 || argc == 1)
     948             965 :             return compileArrayWithLength(argc);
     949             124 :         return compileArrayWithArgs(argc);
     950                 :     }
     951                 : 
     952                 :     /* Remaining natives must not be called with 'new'. */
     953           38082 :     if (callingNew)
     954            1766 :         return Compile_InlineAbort;
     955                 : 
     956           36316 :     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           36117 :     if (argc == 0) {
     967            2267 :         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           33850 :     } else if (argc == 1) {
     984           16706 :         FrameEntry *arg = frame.peek(-1);
     985           16706 :         types::TypeSet *argTypes = frame.extra(arg).types;
     986           16706 :         if (!argTypes)
     987               0 :             return Compile_InlineAbort;
     988           16706 :         JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
     989                 : 
     990           16706 :         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           16585 :         if (native == js_math_floor && argType == JSVAL_TYPE_DOUBLE &&
     998                 :             type == JSVAL_TYPE_INT32) {
     999             133 :             return compileRound(arg, Floor);
    1000                 :         }
    1001           16452 :         if (native == js_math_round && argType == JSVAL_TYPE_DOUBLE &&
    1002                 :             type == JSVAL_TYPE_INT32) {
    1003              51 :             return compileRound(arg, Round);
    1004                 :         }
    1005           16582 :         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           16223 :         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           16140 :         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           16118 :         if (native == js::str_fromCharCode && argType == JSVAL_TYPE_INT32 &&
    1019                 :             type == JSVAL_TYPE_STRING) {
    1020              72 :             return compileStringFromCode(arg);
    1021                 :         }
    1022           16046 :         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            2479 :             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
    1029            1238 :                 !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
    1030            1226 :                 return compileArrayPush(thisValue, arg);
    1031                 :             }
    1032                 :         }
    1033           14974 :         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           17144 :     } else if (argc == 2) {
    1040           16460 :         FrameEntry *arg1 = frame.peek(-2);
    1041           16460 :         FrameEntry *arg2 = frame.peek(-1);
    1042                 : 
    1043           16460 :         JSValueType arg1Type = arg1->isTypeKnown() ? arg1->getKnownType() : JSVAL_TYPE_UNKNOWN;
    1044           16460 :         JSValueType arg2Type = arg2->isTypeKnown() ? arg2->getKnownType() : JSVAL_TYPE_UNKNOWN;
    1045                 : 
    1046           16819 :         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           16450 :         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           33860 :     return Compile_InlineAbort;
    1072                 : }
    1073                 : 

Generated by: LCOV version 1.7