LCOV - code coverage report
Current view: directory - js/src/methodjit - StubCalls.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 899 745 82.9 %
Date: 2012-04-21 Functions: 103 94 91.3 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Brendan Eich <brendan@mozilla.org>
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   David Anderson <danderson@mozilla.com>
      25                 :  *   David Mandelin <dmandelin@mozilla.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "jscntxt.h"
      42                 : #include "jsscope.h"
      43                 : #include "jsobj.h"
      44                 : #include "jslibmath.h"
      45                 : #include "jsiter.h"
      46                 : #include "jsgcmark.h"
      47                 : #include "jsnum.h"
      48                 : #include "jsxml.h"
      49                 : #include "jsbool.h"
      50                 : #include "assembler/assembler/MacroAssemblerCodeRef.h"
      51                 : #include "jstypes.h"
      52                 : #include "vm/Debugger.h"
      53                 : #include "vm/String.h"
      54                 : #include "methodjit/Compiler.h"
      55                 : #include "methodjit/StubCalls.h"
      56                 : #include "methodjit/Retcon.h"
      57                 : 
      58                 : #include "jsinterpinlines.h"
      59                 : #include "jsscopeinlines.h"
      60                 : #include "jsscriptinlines.h"
      61                 : #include "jsnuminlines.h"
      62                 : #include "jsobjinlines.h"
      63                 : #include "jscntxtinlines.h"
      64                 : #include "jsatominlines.h"
      65                 : #include "StubCalls-inl.h"
      66                 : #include "jsfuninlines.h"
      67                 : #include "jstypedarray.h"
      68                 : 
      69                 : #include "vm/RegExpObject-inl.h"
      70                 : #include "vm/String-inl.h"
      71                 : 
      72                 : #ifdef XP_WIN
      73                 : # include "jswin.h"
      74                 : #endif
      75                 : 
      76                 : #include "jsautooplen.h"
      77                 : 
      78                 : using namespace js;
      79                 : using namespace js::mjit;
      80                 : using namespace js::types;
      81                 : using namespace JSC;
      82                 : 
      83                 : void JS_FASTCALL
      84            1439 : stubs::BindName(VMFrame &f, PropertyName *name)
      85                 : {
      86            1439 :     JSObject *obj = FindIdentifierBase(f.cx, &f.fp()->scopeChain(), name);
      87            1439 :     if (!obj)
      88               0 :         THROW();
      89            1439 :     f.regs.sp[0].setObject(*obj);
      90                 : }
      91                 : 
      92                 : JSObject * JS_FASTCALL
      93               0 : stubs::BindGlobalName(VMFrame &f)
      94                 : {
      95               0 :     return &f.fp()->scopeChain().global();
      96                 : }
      97                 : 
      98                 : template<JSBool strict>
      99                 : void JS_FASTCALL
     100          136598 : stubs::SetName(VMFrame &f, PropertyName *name)
     101                 : {
     102          136598 :     JSContext *cx = f.cx;
     103          136598 :     const Value &rval = f.regs.sp[-1];
     104          136598 :     const Value &lval = f.regs.sp[-2];
     105                 : 
     106          136598 :     if (!SetPropertyOperation(cx, f.pc(), lval, rval))
     107             425 :         THROW();
     108                 : 
     109          136173 :     f.regs.sp[-2] = f.regs.sp[-1];
     110                 : }
     111                 : 
     112                 : template void JS_FASTCALL stubs::SetName<true>(VMFrame &f, PropertyName *origName);
     113                 : template void JS_FASTCALL stubs::SetName<false>(VMFrame &f, PropertyName *origName);
     114                 : 
     115                 : template<JSBool strict>
     116                 : void JS_FASTCALL
     117           47468 : stubs::SetGlobalName(VMFrame &f, PropertyName *name)
     118                 : {
     119           47468 :     SetName<strict>(f, name);
     120           47468 : }
     121                 : 
     122                 : template void JS_FASTCALL stubs::SetGlobalName<true>(VMFrame &f, PropertyName *name);
     123                 : template void JS_FASTCALL stubs::SetGlobalName<false>(VMFrame &f, PropertyName *name);
     124                 : 
     125                 : void JS_FASTCALL
     126          825402 : stubs::Name(VMFrame &f)
     127                 : {
     128                 :     Value rval;
     129          825402 :     if (!NameOperation(f.cx, f.pc(), &rval))
     130            3369 :         THROW();
     131          822033 :     f.regs.sp[0] = rval;
     132                 : }
     133                 : 
     134                 : void JS_FASTCALL
     135         9494311 : stubs::GetElem(VMFrame &f)
     136                 : {
     137         9494311 :     Value &lref = f.regs.sp[-2];
     138         9494311 :     Value &rref = f.regs.sp[-1];
     139         9494311 :     Value &rval = f.regs.sp[-2];
     140                 : 
     141         9494311 :     if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval))
     142              45 :         THROW();
     143                 : }
     144                 : 
     145                 : template<JSBool strict>
     146                 : void JS_FASTCALL
     147         8739135 : stubs::SetElem(VMFrame &f)
     148                 : {
     149         8739135 :     JSContext *cx = f.cx;
     150         8739135 :     FrameRegs &regs = f.regs;
     151                 : 
     152         8739135 :     Value &objval = regs.sp[-3];
     153         8739135 :     Value &idval  = regs.sp[-2];
     154         8739135 :     Value rval    = regs.sp[-1];
     155                 : 
     156                 :     JSObject *obj;
     157                 :     jsid id;
     158                 : 
     159         8739135 :     obj = ValueToObject(cx, objval);
     160         8739135 :     if (!obj)
     161               7 :         THROW();
     162                 : 
     163         8739128 :     if (!FetchElementId(f.cx, obj, idval, id, &regs.sp[-2]))
     164               0 :         THROW();
     165                 : 
     166         8739128 :     TypeScript::MonitorAssign(cx, obj, id);
     167                 : 
     168                 :     do {
     169         8739128 :         if (obj->isDenseArray() && JSID_IS_INT(id)) {
     170         1529028 :             uint32_t length = obj->getDenseArrayInitializedLength();
     171         1529028 :             int32_t i = JSID_TO_INT(id);
     172         1529028 :             if ((uint32_t)i < length) {
     173           23520 :                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
     174           19469 :                     if (js_PrototypeHasIndexedProperties(cx, obj))
     175               0 :                         break;
     176           19469 :                     if ((uint32_t)i >= obj->getArrayLength())
     177               0 :                         obj->setArrayLength(cx, i + 1);
     178                 :                 }
     179           23520 :                 obj->setDenseArrayElementWithType(cx, i, rval);
     180           23520 :                 goto end_setelem;
     181                 :             } else {
     182         1505508 :                 if (f.script()->hasAnalysis())
     183         1505508 :                     f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
     184                 :             }
     185                 :         }
     186                 :     } while (0);
     187         8715608 :     if (!obj->setGeneric(cx, id, &rval, strict))
     188            2436 :         THROW();
     189                 :   end_setelem:
     190                 :     /* :FIXME: Moving the assigned object into the lowest stack slot
     191                 :      * is a temporary hack. What we actually want is an implementation
     192                 :      * of popAfterSet() that allows popping more than one value;
     193                 :      * this logic can then be handled in Compiler.cpp. */
     194         8736692 :     regs.sp[-3] = regs.sp[-1];
     195                 : }
     196                 : 
     197                 : template void JS_FASTCALL stubs::SetElem<true>(VMFrame &f);
     198                 : template void JS_FASTCALL stubs::SetElem<false>(VMFrame &f);
     199                 : 
     200                 : void JS_FASTCALL
     201            1126 : stubs::ToId(VMFrame &f)
     202                 : {
     203            1126 :     Value &objval = f.regs.sp[-2];
     204            1126 :     Value &idval  = f.regs.sp[-1];
     205                 : 
     206            1126 :     JSObject *obj = ValueToObject(f.cx, objval);
     207            1126 :     if (!obj)
     208               0 :         THROW();
     209                 : 
     210                 :     jsid id;
     211            1126 :     if (!FetchElementId(f.cx, obj, idval, id, &idval))
     212               0 :         THROW();
     213                 : 
     214            1126 :     if (!idval.isInt32())
     215            1126 :         TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
     216                 : }
     217                 : 
     218                 : void JS_FASTCALL
     219         2092388 : stubs::ImplicitThis(VMFrame &f, PropertyName *name)
     220                 : {
     221                 :     JSObject *obj, *obj2;
     222                 :     JSProperty *prop;
     223         2092388 :     if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
     224               0 :         THROW();
     225                 : 
     226         2092388 :     if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
     227               0 :         THROW();
     228                 : }
     229                 : 
     230                 : void JS_FASTCALL
     231          409108 : stubs::BitOr(VMFrame &f)
     232                 : {
     233                 :     int32_t i, j;
     234                 : 
     235          409108 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     236              21 :         THROW();
     237                 : 
     238          409087 :     i = i | j;
     239          409087 :     f.regs.sp[-2].setInt32(i);
     240                 : }
     241                 : 
     242                 : void JS_FASTCALL
     243           22237 : stubs::BitXor(VMFrame &f)
     244                 : {
     245                 :     int32_t i, j;
     246                 : 
     247           22237 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     248               0 :         THROW();
     249                 : 
     250           22237 :     i = i ^ j;
     251           22237 :     f.regs.sp[-2].setInt32(i);
     252                 : }
     253                 : 
     254                 : void JS_FASTCALL
     255           64598 : stubs::BitAnd(VMFrame &f)
     256                 : {
     257                 :     int32_t i, j;
     258                 : 
     259           64598 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     260               0 :         THROW();
     261                 : 
     262           64598 :     i = i & j;
     263           64598 :     f.regs.sp[-2].setInt32(i);
     264                 : }
     265                 : 
     266                 : void JS_FASTCALL
     267               2 : stubs::BitNot(VMFrame &f)
     268                 : {
     269                 :     int32_t i;
     270                 : 
     271               2 :     if (!ToInt32(f.cx, f.regs.sp[-1], &i))
     272               0 :         THROW();
     273               2 :     i = ~i;
     274               2 :     f.regs.sp[-1].setInt32(i);
     275                 : }
     276                 : 
     277                 : void JS_FASTCALL
     278             453 : stubs::Lsh(VMFrame &f)
     279                 : {
     280                 :     int32_t i, j;
     281             453 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i))
     282               0 :         THROW();
     283             453 :     if (!ToInt32(f.cx, f.regs.sp[-1], &j))
     284               0 :         THROW();
     285             453 :     i = i << (j & 31);
     286             453 :     f.regs.sp[-2].setInt32(i);
     287                 : }
     288                 : 
     289                 : void JS_FASTCALL
     290             509 : stubs::Rsh(VMFrame &f)
     291                 : {
     292                 :     int32_t i, j;
     293             509 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i))
     294               0 :         THROW();
     295             509 :     if (!ToInt32(f.cx, f.regs.sp[-1], &j))
     296               0 :         THROW();
     297             509 :     i = i >> (j & 31);
     298             509 :     f.regs.sp[-2].setInt32(i);
     299                 : }
     300                 : 
     301                 : void JS_FASTCALL
     302             750 : stubs::Ursh(VMFrame &f)
     303                 : {
     304                 :     uint32_t u;
     305             750 :     if (!ToUint32(f.cx, f.regs.sp[-2], &u))
     306               0 :         THROW();
     307                 :     int32_t j;
     308             750 :     if (!ToInt32(f.cx, f.regs.sp[-1], &j))
     309               0 :         THROW();
     310                 : 
     311             750 :     u >>= (j & 31);
     312                 : 
     313             750 :         if (!f.regs.sp[-2].setNumber(uint32_t(u)))
     314             447 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
     315                 : }
     316                 : 
     317                 : template<JSBool strict>
     318                 : void JS_FASTCALL
     319            1755 : stubs::DefFun(VMFrame &f, JSFunction *fun)
     320                 : {
     321                 :     JSObject *obj2;
     322                 : 
     323            1755 :     JSContext *cx = f.cx;
     324            1755 :     StackFrame *fp = f.fp();
     325                 : 
     326                 :     /*
     327                 :      * A top-level function defined in Global or Eval code (see ECMA-262
     328                 :      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
     329                 :      * a compound statement (not at the top statement level of global code, or
     330                 :      * at the top level of a function body).
     331                 :      */
     332            1755 :     JSObject *obj = fun;
     333                 : 
     334            1755 :     if (fun->isNullClosure()) {
     335                 :         /*
     336                 :          * Even a null closure needs a parent for principals finding.
     337                 :          * FIXME: bug 476950, although debugger users may also demand some kind
     338                 :          * of scope link for debugger-assisted eval-in-frame.
     339                 :          */
     340             867 :         obj2 = &fp->scopeChain();
     341                 :     } else {
     342             888 :         JS_ASSERT(!fun->isFlatClosure());
     343                 : 
     344             888 :         obj2 = GetScopeChain(cx, fp);
     345             888 :         if (!obj2)
     346               0 :             THROW();
     347                 :     }
     348                 : 
     349                 :     /*
     350                 :      * If static link is not current scope, clone fun's object to link to the
     351                 :      * current scope via parent. We do this to enable sharing of compiled
     352                 :      * functions among multiple equivalent scopes, amortizing the cost of
     353                 :      * compilation over a number of executions.  Examples include XUL scripts
     354                 :      * and event handlers shared among Firefox or other Mozilla app chrome
     355                 :      * windows, and user-defined JS functions precompiled and then shared among
     356                 :      * requests in server-side JS.
     357                 :      */
     358            1755 :     if (obj->toFunction()->environment() != obj2) {
     359             356 :         obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
     360             356 :         if (!obj)
     361               0 :             THROW();
     362             356 :         JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
     363                 :     }
     364                 : 
     365                 :     /*
     366                 :      * ECMA requires functions defined when entering Eval code to be
     367                 :      * impermanent.
     368                 :      */
     369                 :     unsigned attrs = fp->isEvalFrame()
     370                 :                   ? JSPROP_ENUMERATE
     371            1755 :                   : JSPROP_ENUMERATE | JSPROP_PERMANENT;
     372                 : 
     373                 :     /*
     374                 :      * We define the function as a property of the variable object and not the
     375                 :      * current scope chain even for the case of function expression statements
     376                 :      * and functions defined by eval inside let or with blocks.
     377                 :      */
     378            1755 :     JSObject *parent = &fp->varObj();
     379                 : 
     380                 :     /* ES5 10.5 (NB: with subsequent errata). */
     381            1755 :     PropertyName *name = fun->atom->asPropertyName();
     382            1755 :     JSProperty *prop = NULL;
     383                 :     JSObject *pobj;
     384            1755 :     if (!parent->lookupProperty(cx, name, &pobj, &prop))
     385               0 :         THROW();
     386                 : 
     387            1755 :     Value rval = ObjectValue(*obj);
     388                 : 
     389                 :     do {
     390                 :         /* Steps 5d, 5f. */
     391            1755 :         if (!prop || pobj != parent) {
     392            1115 :             if (!parent->defineProperty(cx, name, rval,
     393                 :                                         JS_PropertyStub, JS_StrictPropertyStub, attrs))
     394                 :             {
     395               0 :                 THROW();
     396                 :             }
     397            1115 :             break;
     398                 :         }
     399                 : 
     400                 :         /* Step 5e. */
     401             640 :         JS_ASSERT(parent->isNative());
     402             640 :         Shape *shape = reinterpret_cast<Shape *>(prop);
     403             640 :         if (parent->isGlobal()) {
     404             475 :             if (shape->configurable()) {
     405             130 :                 if (!parent->defineProperty(cx, name, rval,
     406                 :                                             JS_PropertyStub, JS_StrictPropertyStub, attrs))
     407                 :                 {
     408               0 :                     THROW();
     409                 :                 }
     410             130 :                 break;
     411                 :             }
     412                 : 
     413             345 :             if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
     414               8 :                 JSAutoByteString bytes;
     415               4 :                 if (js_AtomToPrintableString(cx, name, &bytes)) {
     416               4 :                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
     417                 :                                          JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
     418                 :                 }
     419               4 :                 THROW();
     420                 :             }
     421                 :         }
     422                 : 
     423                 :         /*
     424                 :          * Non-global properties, and global properties which we aren't simply
     425                 :          * redefining, must be set.  First, this preserves their attributes.
     426                 :          * Second, this will produce warnings and/or errors as necessary if the
     427                 :          * specified Call object property is not writable (const).
     428                 :          */
     429                 : 
     430                 :         /* Step 5f. */
     431             506 :         if (!parent->setProperty(cx, name, &rval, strict))
     432               0 :             THROW();
     433                 :     } while (false);
     434                 : }
     435                 : 
     436                 : template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
     437                 : template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
     438                 : 
     439                 : #define RELATIONAL(OP)                                                        \
     440                 :     JS_BEGIN_MACRO                                                            \
     441                 :         JSContext *cx = f.cx;                                                 \
     442                 :         FrameRegs &regs = f.regs;                                             \
     443                 :         Value &rval = regs.sp[-1];                                            \
     444                 :         Value &lval = regs.sp[-2];                                            \
     445                 :         bool cond;                                                            \
     446                 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                           \
     447                 :             THROWV(JS_FALSE);                                                 \
     448                 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                           \
     449                 :             THROWV(JS_FALSE);                                                 \
     450                 :         if (lval.isString() && rval.isString()) {                             \
     451                 :             JSString *l = lval.toString(), *r = rval.toString();              \
     452                 :             int32_t cmp;                                                      \
     453                 :             if (!CompareStrings(cx, l, r, &cmp))                              \
     454                 :                 THROWV(JS_FALSE);                                             \
     455                 :             cond = cmp OP 0;                                                  \
     456                 :         } else {                                                              \
     457                 :             double l, r;                                                      \
     458                 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))           \
     459                 :                 THROWV(JS_FALSE);                                             \
     460                 :             cond = (l OP r);                                                  \
     461                 :         }                                                                     \
     462                 :         regs.sp[-2].setBoolean(cond);                                         \
     463                 :         return cond;                                                          \
     464                 :     JS_END_MACRO
     465                 : 
     466                 : JSBool JS_FASTCALL
     467          402825 : stubs::LessThan(VMFrame &f)
     468                 : {
     469          402825 :     RELATIONAL(<);
     470                 : }
     471                 : 
     472                 : JSBool JS_FASTCALL
     473           17849 : stubs::LessEqual(VMFrame &f)
     474                 : {
     475           17849 :     RELATIONAL(<=);
     476                 : }
     477                 : 
     478                 : JSBool JS_FASTCALL
     479          154668 : stubs::GreaterThan(VMFrame &f)
     480                 : {
     481          154668 :     RELATIONAL(>);
     482                 : }
     483                 : 
     484                 : JSBool JS_FASTCALL
     485           17861 : stubs::GreaterEqual(VMFrame &f)
     486                 : {
     487           17861 :     RELATIONAL(>=);
     488                 : }
     489                 : 
     490                 : JSBool JS_FASTCALL
     491         4467117 : stubs::ValueToBoolean(VMFrame &f)
     492                 : {
     493         4467117 :     return js_ValueToBoolean(f.regs.sp[-1]);
     494                 : }
     495                 : 
     496                 : void JS_FASTCALL
     497          300850 : stubs::Not(VMFrame &f)
     498                 : {
     499          300850 :     JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
     500          300850 :     f.regs.sp[-1].setBoolean(b);
     501          300850 : }
     502                 : 
     503                 : template <bool EQ>
     504                 : static inline bool
     505         2319475 : StubEqualityOp(VMFrame &f)
     506                 : {
     507         2319475 :     JSContext *cx = f.cx;
     508         2319475 :     FrameRegs &regs = f.regs;
     509                 : 
     510         2319475 :     Value rval = regs.sp[-1];
     511         2319475 :     Value lval = regs.sp[-2];
     512                 : 
     513                 :     bool cond;
     514                 : 
     515                 :     /* The string==string case is easily the hottest;  try it first. */
     516         2319475 :     if (lval.isString() && rval.isString()) {
     517         1920163 :         JSString *l = lval.toString();
     518         1920163 :         JSString *r = rval.toString();
     519                 :         bool equal;
     520         1920163 :         if (!EqualStrings(cx, l, r, &equal))
     521               0 :             return false;
     522         1920163 :         cond = equal == EQ;
     523                 :     } else
     524                 : #if JS_HAS_XML_SUPPORT
     525          399312 :     if ((lval.isObject() && lval.toObject().isXML()) ||
     526                 :         (rval.isObject() && rval.toObject().isXML()))
     527                 :     {
     528                 :         JSBool equal;
     529               0 :         if (!js_TestXMLEquality(cx, lval, rval, &equal))
     530               0 :             return false;
     531               0 :         cond = !!equal == EQ;
     532                 :     } else
     533                 : #endif
     534                 : 
     535          399312 :     if (SameType(lval, rval)) {
     536          310362 :         JS_ASSERT(!lval.isString());    /* this case is handled above */
     537          310362 :         if (lval.isDouble()) {
     538          128532 :             double l = lval.toDouble();
     539          128532 :             double r = rval.toDouble();
     540                 :             if (EQ)
     541          116946 :                 cond = (l == r);
     542                 :             else
     543           11586 :                 cond = (l != r);
     544          181830 :         } else if (lval.isObject()) {
     545           35833 :             JSObject *l = &lval.toObject(), *r = &rval.toObject();
     546           35833 :             if (JSEqualityOp eq = l->getClass()->ext.equality) {
     547                 :                 JSBool equal;
     548              49 :                 if (!eq(cx, l, &rval, &equal))
     549               0 :                     return false;
     550              49 :                 cond = !!equal == EQ;
     551                 :             } else {
     552           35784 :                 cond = (l == r) == EQ;
     553                 :             }
     554          145997 :         } else if (lval.isNullOrUndefined()) {
     555           98260 :             cond = EQ;
     556                 :         } else {
     557           47737 :             cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
     558                 :         }
     559                 :     } else {
     560           88950 :         if (lval.isNullOrUndefined()) {
     561           15398 :             cond = rval.isNullOrUndefined() == EQ;
     562           73552 :         } else if (rval.isNullOrUndefined()) {
     563           18914 :             cond = !EQ;
     564                 :         } else {
     565           54638 :             if (!ToPrimitive(cx, &lval))
     566               4 :                 return false;
     567           54634 :             if (!ToPrimitive(cx, &rval))
     568               0 :                 return false;
     569                 : 
     570                 :             /*
     571                 :              * The string==string case is repeated because ToPrimitive can
     572                 :              * convert lval/rval to strings.
     573                 :              */
     574           54634 :             if (lval.isString() && rval.isString()) {
     575            2850 :                 JSString *l = lval.toString();
     576            2850 :                 JSString *r = rval.toString();
     577                 :                 bool equal;
     578            2850 :                 if (!EqualStrings(cx, l, r, &equal))
     579               0 :                     return false;
     580            2850 :                 cond = equal == EQ;
     581                 :             } else {
     582                 :                 double l, r;
     583           51784 :                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     584               0 :                     return false;
     585                 : 
     586                 :                 if (EQ)
     587           28842 :                     cond = (l == r);
     588                 :                 else
     589           22942 :                     cond = (l != r);
     590                 :             }
     591                 :         }
     592                 :     }
     593                 : 
     594         2319471 :     regs.sp[-2].setBoolean(cond);
     595         2319471 :     return true;
     596                 : }
     597                 : 
     598                 : JSBool JS_FASTCALL
     599          663880 : stubs::Equal(VMFrame &f)
     600                 : {
     601          663880 :     if (!StubEqualityOp<true>(f))
     602               4 :         THROWV(JS_FALSE);
     603          663876 :     return f.regs.sp[-2].toBoolean();
     604                 : }
     605                 : 
     606                 : JSBool JS_FASTCALL
     607         1655595 : stubs::NotEqual(VMFrame &f)
     608                 : {
     609         1655595 :     if (!StubEqualityOp<false>(f))
     610               0 :         THROWV(JS_FALSE);
     611         1655595 :     return f.regs.sp[-2].toBoolean();
     612                 : }
     613                 : 
     614                 : void JS_FASTCALL
     615        19058831 : stubs::Add(VMFrame &f)
     616                 : {
     617        19058831 :     JSContext *cx = f.cx;
     618        19058831 :     FrameRegs &regs = f.regs;
     619        19058831 :     Value rval = regs.sp[-1];
     620        19058831 :     Value lval = regs.sp[-2];
     621                 : 
     622                 :     /* The string + string case is easily the hottest;  try it first. */
     623        19058831 :     bool lIsString = lval.isString();
     624        19058831 :     bool rIsString = rval.isString();
     625                 :     JSString *lstr, *rstr;
     626        19058831 :     if (lIsString && rIsString) {
     627        15720509 :         lstr = lval.toString();
     628        15720509 :         rstr = rval.toString();
     629        15720509 :         goto string_concat;
     630                 : 
     631                 :     } else
     632                 : #if JS_HAS_XML_SUPPORT
     633         3338322 :     if (lval.isObject() && lval.toObject().isXML() &&
     634               0 :         rval.isObject() && rval.toObject().isXML()) {
     635               0 :         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
     636               0 :             THROW();
     637               0 :         regs.sp[-2] = rval;
     638               0 :         regs.sp--;
     639               0 :         TypeScript::MonitorUnknown(cx, f.script(), f.pc());
     640                 :     } else
     641                 : #endif
     642                 :     {
     643         3338322 :         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
     644         3338322 :         if (!ToPrimitive(f.cx, &lval))
     645              16 :             THROW();
     646         3338306 :         if (!ToPrimitive(f.cx, &rval))
     647              11 :             THROW();
     648         3338295 :         if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
     649         3057785 :             if (lIsString) {
     650         2465790 :                 lstr = lval.toString();
     651                 :             } else {
     652          591995 :                 lstr = ToString(cx, lval);
     653          591995 :                 if (!lstr)
     654               0 :                     THROW();
     655          591995 :                 regs.sp[-2].setString(lstr);
     656                 :             }
     657         3057785 :             if (rIsString) {
     658          594071 :                 rstr = rval.toString();
     659                 :             } else {
     660         2463714 :                 rstr = ToString(cx, rval);
     661         2463714 :                 if (!rstr)
     662               0 :                     THROW();
     663         2463714 :                 regs.sp[-1].setString(rstr);
     664                 :             }
     665         3057785 :             if (lIsObject || rIsObject)
     666          394482 :                 TypeScript::MonitorString(cx, f.script(), f.pc());
     667         3057785 :             goto string_concat;
     668                 : 
     669                 :         } else {
     670                 :             double l, r;
     671          280510 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     672               0 :                 THROW();
     673          280510 :             l += r;
     674          837979 :             if (!regs.sp[-2].setNumber(l) &&
     675          557469 :                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
     676          278023 :                 TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     677                 :             }
     678                 :         }
     679                 :     }
     680          280510 :     return;
     681                 : 
     682                 :   string_concat:
     683        18778294 :     JSString *str = js_ConcatStrings(cx, lstr, rstr);
     684        18778294 :     if (!str)
     685               5 :         THROW();
     686        18778289 :     regs.sp[-2].setString(str);
     687        18778289 :     regs.sp--;
     688                 : }
     689                 : 
     690                 : 
     691                 : void JS_FASTCALL
     692             213 : stubs::Sub(VMFrame &f)
     693                 : {
     694             213 :     JSContext *cx = f.cx;
     695             213 :     FrameRegs &regs = f.regs;
     696                 :     double d1, d2;
     697             213 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     698               0 :         THROW();
     699             213 :     double d = d1 - d2;
     700             213 :     if (!regs.sp[-2].setNumber(d))
     701             159 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     702                 : }
     703                 : 
     704                 : void JS_FASTCALL
     705           78369 : stubs::Mul(VMFrame &f)
     706                 : {
     707           78369 :     JSContext *cx = f.cx;
     708           78369 :     FrameRegs &regs = f.regs;
     709                 :     double d1, d2;
     710           78369 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     711               0 :         THROW();
     712           78369 :     double d = d1 * d2;
     713           78369 :     if (!regs.sp[-2].setNumber(d))
     714           78231 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     715                 : }
     716                 : 
     717                 : void JS_FASTCALL
     718             739 : stubs::Div(VMFrame &f)
     719                 : {
     720             739 :     JSContext *cx = f.cx;
     721             739 :     JSRuntime *rt = cx->runtime;
     722             739 :     FrameRegs &regs = f.regs;
     723                 : 
     724                 :     double d1, d2;
     725             739 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     726               0 :         THROW();
     727             739 :     if (d2 == 0) {
     728                 :         const Value *vp;
     729                 : #ifdef XP_WIN
     730                 :         /* XXX MSVC miscompiles such that (NaN == 0) */
     731                 :         if (JSDOUBLE_IS_NaN(d2))
     732                 :             vp = &rt->NaNValue;
     733                 :         else
     734                 : #endif
     735              11 :         if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
     736               2 :             vp = &rt->NaNValue;
     737               9 :         else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
     738               0 :             vp = &rt->negativeInfinityValue;
     739                 :         else
     740               9 :             vp = &rt->positiveInfinityValue;
     741              11 :         regs.sp[-2] = *vp;
     742              11 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     743                 :     } else {
     744             728 :         d1 /= d2;
     745             728 :         if (!regs.sp[-2].setNumber(d1))
     746              22 :             TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     747                 :     }
     748                 : }
     749                 : 
     750                 : void JS_FASTCALL
     751           30492 : stubs::Mod(VMFrame &f)
     752                 : {
     753           30492 :     JSContext *cx = f.cx;
     754           30492 :     FrameRegs &regs = f.regs;
     755                 : 
     756           30492 :     Value &lref = regs.sp[-2];
     757           30492 :     Value &rref = regs.sp[-1];
     758                 :     int32_t l, r;
     759           30492 :     if (lref.isInt32() && rref.isInt32() &&
     760                 :         (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
     761               0 :         int32_t mod = l % r;
     762               0 :         regs.sp[-2].setInt32(mod);
     763                 :     } else {
     764                 :         double d1, d2;
     765           30492 :         if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     766               0 :             THROW();
     767           30492 :         if (d2 == 0) {
     768              97 :             regs.sp[-2].setDouble(js_NaN);
     769                 :         } else {
     770           30395 :             d1 = js_fmod(d1, d2);
     771           30395 :             regs.sp[-2].setDouble(d1);
     772                 :         }
     773           30492 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     774                 :     }
     775                 : }
     776                 : 
     777                 : void JS_FASTCALL
     778            3378 : stubs::DebuggerStatement(VMFrame &f, jsbytecode *pc)
     779                 : {
     780            3378 :     JSDebuggerHandler handler = f.cx->runtime->debugHooks.debuggerHandler;
     781            3378 :     if (handler || !f.cx->compartment->getDebuggees().empty()) {
     782            3348 :         JSTrapStatus st = JSTRAP_CONTINUE;
     783                 :         Value rval;
     784            3348 :         if (handler)
     785               8 :             st = handler(f.cx, f.script(), pc, &rval, f.cx->runtime->debugHooks.debuggerHandlerData);
     786            3348 :         if (st == JSTRAP_CONTINUE)
     787            3344 :             st = Debugger::onDebuggerStatement(f.cx, &rval);
     788                 : 
     789            3348 :         switch (st) {
     790                 :           case JSTRAP_THROW:
     791              60 :             f.cx->setPendingException(rval);
     792              60 :             THROW();
     793                 : 
     794                 :           case JSTRAP_RETURN:
     795             112 :             f.cx->clearPendingException();
     796             112 :             f.cx->fp()->setReturnValue(rval);
     797             112 :             *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
     798             112 :             break;
     799                 : 
     800                 :           case JSTRAP_ERROR:
     801              80 :             f.cx->clearPendingException();
     802              80 :             THROW();
     803                 : 
     804                 :           default:
     805            3096 :             break;
     806                 :         }
     807                 :     }
     808                 : }
     809                 : 
     810                 : void JS_FASTCALL
     811            1252 : stubs::Interrupt(VMFrame &f, jsbytecode *pc)
     812                 : {
     813            1252 :     gc::MaybeVerifyBarriers(f.cx);
     814                 : 
     815            1252 :     if (!js_HandleExecutionInterrupt(f.cx))
     816               0 :         THROW();
     817                 : }
     818                 : 
     819                 : void JS_FASTCALL
     820              95 : stubs::RecompileForInline(VMFrame &f)
     821                 : {
     822              95 :     ExpandInlineFrames(f.cx->compartment);
     823                 :     Recompiler::clearStackReferencesAndChunk(f.cx, f.script(), f.jit(), f.chunkIndex(),
     824              95 :                                              /* resetUses = */ false);
     825              95 : }
     826                 : 
     827                 : void JS_FASTCALL
     828             594 : stubs::Trap(VMFrame &f, uint32_t trapTypes)
     829                 : {
     830                 :     Value rval;
     831                 : 
     832                 :     /*
     833                 :      * Trap may be called for a single-step interrupt trap and/or a
     834                 :      * regular trap. Try the single-step first, and if it lets control
     835                 :      * flow through or does not exist, do the regular trap.
     836                 :      */
     837             594 :     JSTrapStatus result = JSTRAP_CONTINUE;
     838             594 :     if (trapTypes & JSTRAP_SINGLESTEP) {
     839                 :         /*
     840                 :          * single step mode may be paused without recompiling by
     841                 :          * setting the interruptHook to NULL.
     842                 :          */
     843             299 :         JSInterruptHook hook = f.cx->runtime->debugHooks.interruptHook;
     844             299 :         if (hook)
     845               0 :             result = hook(f.cx, f.script(), f.pc(), &rval, f.cx->runtime->debugHooks.interruptHookData);
     846                 : 
     847             299 :         if (result == JSTRAP_CONTINUE)
     848             299 :             result = Debugger::onSingleStep(f.cx, &rval);
     849                 :     }
     850                 : 
     851             594 :     if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP))
     852             295 :         result = Debugger::onTrap(f.cx, &rval);
     853                 : 
     854             594 :     switch (result) {
     855                 :       case JSTRAP_THROW:
     856               0 :         f.cx->setPendingException(rval);
     857               0 :         THROW();
     858                 : 
     859                 :       case JSTRAP_RETURN:
     860              24 :         f.cx->clearPendingException();
     861              24 :         f.cx->fp()->setReturnValue(rval);
     862              24 :         *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
     863              24 :         break;
     864                 : 
     865                 :       case JSTRAP_ERROR:
     866               4 :         f.cx->clearPendingException();
     867               4 :         THROW();
     868                 : 
     869                 :       default:
     870             566 :         break;
     871                 :     }
     872                 : }
     873                 : 
     874                 : void JS_FASTCALL
     875           40583 : stubs::This(VMFrame &f)
     876                 : {
     877                 :     /*
     878                 :      * We can't yet inline scripts which need to compute their 'this' object
     879                 :      * from a primitive; the frame we are computing 'this' for does not exist yet.
     880                 :      */
     881           40583 :     if (f.regs.inlined()) {
     882               0 :         f.script()->uninlineable = true;
     883               0 :         MarkTypeObjectFlags(f.cx, &f.fp()->callee(), OBJECT_FLAG_UNINLINEABLE);
     884                 :     }
     885                 : 
     886           40583 :     if (!ComputeThis(f.cx, f.fp()))
     887               0 :         THROW();
     888           40583 :     f.regs.sp[-1] = f.fp()->thisValue();
     889                 : }
     890                 : 
     891                 : void JS_FASTCALL
     892            1915 : stubs::Neg(VMFrame &f)
     893                 : {
     894                 :     double d;
     895            1915 :     if (!ToNumber(f.cx, f.regs.sp[-1], &d))
     896               0 :         THROW();
     897            1915 :     d = -d;
     898            1915 :     if (!f.regs.sp[-1].setNumber(d))
     899            1855 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
     900                 : }
     901                 : 
     902                 : void JS_FASTCALL
     903         1256683 : stubs::NewInitArray(VMFrame &f, uint32_t count)
     904                 : {
     905         1256683 :     JSObject *obj = NewDenseAllocatedArray(f.cx, count);
     906         1256683 :     if (!obj)
     907               0 :         THROW();
     908                 : 
     909         1256683 :     TypeObject *type = (TypeObject *) f.scratch;
     910         1256683 :     if (type)
     911         1207349 :         obj->setType(type);
     912                 : 
     913         1256683 :     f.regs.sp[0].setObject(*obj);
     914                 : }
     915                 : 
     916                 : void JS_FASTCALL
     917         1600219 : stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
     918                 : {
     919         1600219 :     JSContext *cx = f.cx;
     920         1600219 :     TypeObject *type = (TypeObject *) f.scratch;
     921                 : 
     922         1600219 :     if (!baseobj) {
     923           53161 :         gc::AllocKind kind = GuessObjectGCKind(0);
     924           53161 :         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     925           53161 :         if (!obj)
     926               0 :             THROW();
     927           53161 :         if (type)
     928            9083 :             obj->setType(type);
     929           53161 :         f.regs.sp[0].setObject(*obj);
     930           53161 :         return;
     931                 :     }
     932                 : 
     933         1547058 :     JS_ASSERT(type);
     934         1547058 :     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
     935                 : 
     936         1547058 :     if (!obj)
     937               0 :         THROW();
     938         1547058 :     f.regs.sp[0].setObject(*obj);
     939                 : }
     940                 : 
     941                 : void JS_FASTCALL
     942            1316 : stubs::InitElem(VMFrame &f, uint32_t last)
     943                 : {
     944            1316 :     JSContext *cx = f.cx;
     945            1316 :     FrameRegs &regs = f.regs;
     946                 : 
     947                 :     /* Pop the element's value into rval. */
     948            1316 :     JS_ASSERT(regs.sp - f.fp()->base() >= 3);
     949            1316 :     const Value &rref = regs.sp[-1];
     950                 : 
     951                 :     /* Find the object being initialized at top of stack. */
     952            1316 :     const Value &lref = regs.sp[-3];
     953            1316 :     JS_ASSERT(lref.isObject());
     954            1316 :     JSObject *obj = &lref.toObject();
     955                 : 
     956                 :     /* Fetch id now that we have obj. */
     957                 :     jsid id;
     958            1316 :     const Value &idval = regs.sp[-2];
     959            1316 :     if (!FetchElementId(f.cx, obj, idval, id, &regs.sp[-2]))
     960               0 :         THROW();
     961                 : 
     962                 :     /*
     963                 :      * If rref is a hole, do not call JSObject::defineProperty. In this case,
     964                 :      * obj must be an array, so if the current op is the last element
     965                 :      * initialiser, set the array length to one greater than id.
     966                 :      */
     967            1316 :     if (rref.isMagic(JS_ARRAY_HOLE)) {
     968               0 :         JS_ASSERT(obj->isArray());
     969               0 :         JS_ASSERT(JSID_IS_INT(id));
     970               0 :         JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
     971               0 :         if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
     972               0 :             THROW();
     973                 :     } else {
     974            1316 :         if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
     975               0 :             THROW();
     976                 :     }
     977                 : }
     978                 : 
     979                 : void JS_FASTCALL
     980               0 : stubs::GetUpvar(VMFrame &f, uint32_t ck)
     981                 : {
     982                 :     /* :FIXME: We can do better, this stub isn't needed. */
     983               0 :     uint32_t staticLevel = f.script()->staticLevel;
     984                 :     UpvarCookie cookie;
     985               0 :     cookie.fromInteger(ck);
     986               0 :     f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
     987               0 : }
     988                 : 
     989                 : JSObject * JS_FASTCALL
     990          207673 : stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
     991                 : {
     992                 :     /*
     993                 :      * Define a local function (i.e., one nested at the top level of another
     994                 :      * function), parented by the current scope chain, stored in a local
     995                 :      * variable slot that the compiler allocated.  This is an optimization over
     996                 :      * JSOP_DEFFUN that avoids requiring a call object for the outer function's
     997                 :      * activation.
     998                 :      */
     999          207673 :     JS_ASSERT(fun->isInterpreted());
    1000          207673 :     JS_ASSERT(!fun->isFlatClosure());
    1001                 : 
    1002                 :     JSObject *parent;
    1003          207673 :     if (fun->isNullClosure()) {
    1004            2948 :         parent = &f.fp()->scopeChain();
    1005                 :     } else {
    1006          204725 :         parent = GetScopeChain(f.cx, f.fp());
    1007          204725 :         if (!parent)
    1008               0 :             THROWV(NULL);
    1009                 :     }
    1010          207673 :     JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
    1011          207673 :     if (!obj)
    1012               0 :         THROWV(NULL);
    1013                 : 
    1014          207673 :     JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
    1015                 : 
    1016          207673 :     return obj;
    1017                 : }
    1018                 : 
    1019                 : JSObject * JS_FASTCALL
    1020            7182 : stubs::DefLocalFun_FC(VMFrame &f, JSFunction *fun)
    1021                 : {
    1022            7182 :     JSObject *obj = js_NewFlatClosure(f.cx, fun);
    1023            7182 :     if (!obj)
    1024               0 :         THROWV(NULL);
    1025            7182 :     return obj;
    1026                 : }
    1027                 : 
    1028                 : void JS_FASTCALL
    1029          392452 : stubs::RegExp(VMFrame &f, JSObject *regex)
    1030                 : {
    1031                 :     /*
    1032                 :      * Push a regexp object cloned from the regexp literal object mapped by the
    1033                 :      * bytecode at pc.
    1034                 :      */
    1035          392452 :     JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
    1036          392452 :     if (!proto)
    1037               0 :         THROW();
    1038          392452 :     JS_ASSERT(proto);
    1039          392452 :     JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
    1040          392452 :     if (!obj)
    1041               0 :         THROW();
    1042          392452 :     f.regs.sp[0].setObject(*obj);
    1043                 : }
    1044                 : 
    1045                 : JSObject * JS_FASTCALL
    1046            9066 : stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun)
    1047                 : {
    1048            9066 :     JS_ASSERT(fun->joinable());
    1049           18132 :     DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
    1050            9066 :     JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
    1051            9066 :     return fun;
    1052                 : }
    1053                 : 
    1054                 : JSObject * JS_FASTCALL
    1055            4005 : stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun)
    1056                 : {
    1057            4005 :     JS_ASSERT(fun->joinable());
    1058            4005 :     const Value &lref = f.regs.sp[-1];
    1059            4005 :     if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
    1060            4158 :         DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
    1061            2079 :         JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
    1062            2079 :         return fun;
    1063                 :     }
    1064            1926 :     return Lambda(f, fun);
    1065                 : }
    1066                 : 
    1067                 : JSObject * JS_FASTCALL
    1068            9653 : stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
    1069                 : {
    1070            9653 :     JS_ASSERT(fun->joinable());
    1071                 : 
    1072                 :     /*
    1073                 :      * Array.prototype.sort and String.prototype.replace are optimized as if
    1074                 :      * they are special form. We know that they won't leak the joined function
    1075                 :      * object fun, therefore we don't need to clone that compiler-created
    1076                 :      * function object for identity/mutation reasons.
    1077                 :      */
    1078            9653 :     int iargc = GET_ARGC(f.regs.pc + JSOP_LAMBDA_LENGTH);
    1079                 : 
    1080                 :     /*
    1081                 :      * Note that we have not yet pushed fun as the final argument, so
    1082                 :      * regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], is the callee
    1083                 :      * for this JSOP_CALL.
    1084                 :      */
    1085            9653 :     const Value &cref = f.regs.sp[1 - (iargc + 2)];
    1086                 :     JSFunction *callee;
    1087                 : 
    1088            9653 :     if (IsFunctionObject(cref, &callee)) {
    1089            9647 :         Native native = callee->maybeNative();
    1090                 : 
    1091            9647 :         if (native) {
    1092            9467 :             if (iargc == 1 && native == array_sort)
    1093               2 :                 return fun;
    1094            9465 :             if (iargc == 2 && native == str_replace)
    1095            1014 :                 return fun;
    1096                 :         }
    1097                 :     }
    1098            8637 :     return Lambda(f, fun);
    1099                 : }
    1100                 : 
    1101                 : JSObject * JS_FASTCALL
    1102               0 : stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
    1103                 : {
    1104               0 :     JS_ASSERT(fun->joinable());
    1105               0 :     return fun;
    1106                 : }
    1107                 : 
    1108                 : JSObject * JS_FASTCALL
    1109          293607 : stubs::Lambda(VMFrame &f, JSFunction *fun)
    1110                 : {
    1111                 :     JSObject *parent;
    1112          293607 :     if (fun->isNullClosure()) {
    1113          209795 :         parent = &f.fp()->scopeChain();
    1114                 :     } else {
    1115           83812 :         parent = GetScopeChain(f.cx, f.fp());
    1116           83812 :         if (!parent)
    1117               0 :             THROWV(NULL);
    1118                 :     }
    1119                 : 
    1120          293607 :     JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
    1121          293607 :     if (!obj)
    1122               0 :         THROWV(NULL);
    1123                 : 
    1124          293607 :     JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
    1125          293607 :     return obj;
    1126                 : }
    1127                 : 
    1128                 : void JS_FASTCALL
    1129         5436159 : stubs::GetProp(VMFrame &f, PropertyName *name)
    1130                 : {
    1131         5436159 :     JSContext *cx = f.cx;
    1132         5436159 :     FrameRegs &regs = f.regs;
    1133                 : 
    1134                 :     Value rval;
    1135         5436159 :     if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval))
    1136              19 :         THROW();
    1137                 : 
    1138         5436140 :     regs.sp[-1] = rval;
    1139                 : }
    1140                 : 
    1141                 : void JS_FASTCALL
    1142               0 : stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
    1143                 : {
    1144               0 :     JSContext *cx = f.cx;
    1145               0 :     FrameRegs &regs = f.regs;
    1146                 : 
    1147               0 :     const Value &lval = f.regs.sp[-1];
    1148                 : 
    1149                 :     // Uncached lookups are only used for .prototype accesses at the start of constructors.
    1150               0 :     JS_ASSERT(lval.isObject());
    1151               0 :     JS_ASSERT(name == cx->runtime->atomState.classPrototypeAtom);
    1152                 : 
    1153               0 :     JSObject *obj = &lval.toObject();
    1154                 : 
    1155                 :     Value rval;
    1156               0 :     if (!obj->getProperty(cx, name, &rval))
    1157               0 :         THROW();
    1158                 : 
    1159               0 :     regs.sp[-1] = rval;
    1160                 : }
    1161                 : 
    1162                 : void JS_FASTCALL
    1163          306772 : stubs::Iter(VMFrame &f, uint32_t flags)
    1164                 : {
    1165          306772 :     if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
    1166              57 :         THROW();
    1167          306715 :     JS_ASSERT(!f.regs.sp[-1].isPrimitive());
    1168                 : }
    1169                 : 
    1170                 : static void
    1171           52940 : InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
    1172                 : {
    1173           52940 :     JSContext *cx = f.cx;
    1174           52940 :     FrameRegs &regs = f.regs;
    1175                 : 
    1176                 :     /* Load the property's initial value into rval. */
    1177           52940 :     JS_ASSERT(regs.sp - f.fp()->base() >= 2);
    1178                 :     Value rval;
    1179           52940 :     rval = regs.sp[-1];
    1180                 : 
    1181                 :     /* Load the object being initialized into lval/obj. */
    1182           52940 :     JSObject *obj = &regs.sp[-2].toObject();
    1183           52940 :     JS_ASSERT(obj->isNative());
    1184                 : 
    1185                 :     /* Get the immediate property name into id. */
    1186           52940 :     jsid id = ATOM_TO_JSID(name);
    1187                 : 
    1188           52940 :     unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
    1189          105880 :     if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
    1190              61 :         ? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false)
    1191                 :         : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
    1192           52879 :                                 JSPROP_ENUMERATE, 0, 0, defineHow)) {
    1193               0 :         THROW();
    1194                 :     }
    1195                 : }
    1196                 : 
    1197                 : void JS_FASTCALL
    1198           43874 : stubs::InitProp(VMFrame &f, PropertyName *name)
    1199                 : {
    1200           43874 :     InitPropOrMethod(f, name, JSOP_INITPROP);
    1201           43874 : }
    1202                 : 
    1203                 : void JS_FASTCALL
    1204            9066 : stubs::InitMethod(VMFrame &f, PropertyName *name)
    1205                 : {
    1206            9066 :     InitPropOrMethod(f, name, JSOP_INITMETHOD);
    1207            9066 : }
    1208                 : 
    1209                 : void JS_FASTCALL
    1210         9090684 : stubs::IterNext(VMFrame &f, int32_t offset)
    1211                 : {
    1212         9090684 :     JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
    1213         9090684 :     JS_ASSERT(f.regs.sp[-offset].isObject());
    1214                 : 
    1215         9090684 :     JSObject *iterobj = &f.regs.sp[-offset].toObject();
    1216         9090684 :     f.regs.sp[0].setNull();
    1217         9090684 :     f.regs.sp++;
    1218         9090684 :     if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
    1219               0 :         THROW();
    1220                 : }
    1221                 : 
    1222                 : JSBool JS_FASTCALL
    1223         9207379 : stubs::IterMore(VMFrame &f)
    1224                 : {
    1225         9207379 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1226         9207379 :     JS_ASSERT(f.regs.sp[-1].isObject());
    1227                 : 
    1228                 :     Value v;
    1229         9207379 :     JSObject *iterobj = &f.regs.sp[-1].toObject();
    1230         9207379 :     if (!js_IteratorMore(f.cx, iterobj, &v))
    1231              11 :         THROWV(JS_FALSE);
    1232                 : 
    1233         9207368 :     return v.toBoolean();
    1234                 : }
    1235                 : 
    1236                 : void JS_FASTCALL
    1237            1188 : stubs::EndIter(VMFrame &f)
    1238                 : {
    1239            1188 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1240            1188 :     if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
    1241               0 :         THROW();
    1242                 : }
    1243                 : 
    1244                 : JSString * JS_FASTCALL
    1245           81219 : stubs::TypeOf(VMFrame &f)
    1246                 : {
    1247           81219 :     const Value &ref = f.regs.sp[-1];
    1248           81219 :     JSType type = JS_TypeOfValue(f.cx, ref);
    1249           81219 :     return f.cx->runtime->atomState.typeAtoms[type];
    1250                 : }
    1251                 : 
    1252                 : void JS_FASTCALL
    1253          730578 : stubs::StrictEq(VMFrame &f)
    1254                 : {
    1255          730578 :     const Value &rhs = f.regs.sp[-1];
    1256          730578 :     const Value &lhs = f.regs.sp[-2];
    1257                 :     bool equal;
    1258          730578 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1259               0 :         THROW();
    1260          730578 :     f.regs.sp--;
    1261          730578 :     f.regs.sp[-1].setBoolean(equal == JS_TRUE);
    1262                 : }
    1263                 : 
    1264                 : void JS_FASTCALL
    1265          240221 : stubs::StrictNe(VMFrame &f)
    1266                 : {
    1267          240221 :     const Value &rhs = f.regs.sp[-1];
    1268          240221 :     const Value &lhs = f.regs.sp[-2];
    1269                 :     bool equal;
    1270          240221 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1271               0 :         THROW();
    1272          240221 :     f.regs.sp--;
    1273          240221 :     f.regs.sp[-1].setBoolean(equal != JS_TRUE);
    1274                 : }
    1275                 : 
    1276                 : void JS_FASTCALL
    1277            1036 : stubs::Throw(VMFrame &f)
    1278                 : {
    1279            1036 :     JSContext *cx = f.cx;
    1280                 : 
    1281            1036 :     JS_ASSERT(!cx->isExceptionPending());
    1282            1036 :     cx->setPendingException(f.regs.sp[-1]);
    1283            1036 :     THROW();
    1284                 : }
    1285                 : 
    1286                 : JSObject * JS_FASTCALL
    1287          265985 : stubs::FlatLambda(VMFrame &f, JSFunction *fun)
    1288                 : {
    1289          265985 :     JSObject *obj = js_NewFlatClosure(f.cx, fun);
    1290          265985 :     if (!obj)
    1291               0 :         THROWV(NULL);
    1292          265985 :     return obj;
    1293                 : }
    1294                 : 
    1295                 : void JS_FASTCALL
    1296          428393 : stubs::Arguments(VMFrame &f)
    1297                 : {
    1298          428393 :     ArgumentsObject *arguments = js_GetArgsObject(f.cx, f.fp());
    1299          428393 :     if (!arguments)
    1300               0 :         THROW();
    1301          428393 :     f.regs.sp[0] = ObjectValue(*arguments);
    1302                 : }
    1303                 : 
    1304                 : JSBool JS_FASTCALL
    1305           91679 : stubs::InstanceOf(VMFrame &f)
    1306                 : {
    1307           91679 :     JSContext *cx = f.cx;
    1308           91679 :     FrameRegs &regs = f.regs;
    1309                 : 
    1310           91679 :     const Value &rref = regs.sp[-1];
    1311           91679 :     if (rref.isPrimitive()) {
    1312                 :         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
    1313               0 :                             -1, rref, NULL);
    1314               0 :         THROWV(JS_FALSE);
    1315                 :     }
    1316           91679 :     JSObject *obj = &rref.toObject();
    1317           91679 :     const Value &lref = regs.sp[-2];
    1318           91679 :     JSBool cond = JS_FALSE;
    1319           91679 :     if (!HasInstance(cx, obj, &lref, &cond))
    1320               6 :         THROWV(JS_FALSE);
    1321           91673 :     f.regs.sp[-2].setBoolean(cond);
    1322           91673 :     return cond;
    1323                 : }
    1324                 : 
    1325                 : void JS_FASTCALL
    1326               2 : stubs::FastInstanceOf(VMFrame &f)
    1327                 : {
    1328               2 :     const Value &lref = f.regs.sp[-1];
    1329                 : 
    1330               2 :     if (lref.isPrimitive()) {
    1331                 :         /*
    1332                 :          * Throw a runtime error if instanceof is called on a function that
    1333                 :          * has a non-object as its .prototype value.
    1334                 :          */
    1335               2 :         js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
    1336               2 :         THROW();
    1337                 :     }
    1338                 : 
    1339               0 :     f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
    1340                 : }
    1341                 : 
    1342                 : void JS_FASTCALL
    1343          244478 : stubs::EnterBlock(VMFrame &f, JSObject *obj)
    1344                 : {
    1345          244478 :     FrameRegs &regs = f.regs;
    1346          244478 :     StackFrame *fp = f.fp();
    1347          244478 :     StaticBlockObject &blockObj = obj->asStaticBlock();
    1348                 : 
    1349          244478 :     JS_ASSERT(!f.regs.inlined());
    1350                 : 
    1351          244478 :     if (*regs.pc == JSOP_ENTERBLOCK) {
    1352          162995 :         JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp);
    1353          162995 :         Value *vp = regs.sp + blockObj.slotCount();
    1354          162995 :         JS_ASSERT(regs.sp < vp);
    1355          162995 :         JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
    1356          162995 :         SetValueRangeToUndefined(regs.sp, vp);
    1357          162995 :         regs.sp = vp;
    1358                 :     }
    1359                 : 
    1360                 : #ifdef DEBUG
    1361          244478 :     JSContext *cx = f.cx;
    1362          244478 :     JS_ASSERT(fp->maybeBlockChain() == blockObj.enclosingBlock());
    1363                 : 
    1364                 :     /*
    1365                 :      * The young end of fp->scopeChain() may omit blocks if we haven't closed
    1366                 :      * over them, but if there are any closure blocks on fp->scopeChain(), they'd
    1367                 :      * better be (clones of) ancestors of the block we're entering now;
    1368                 :      * anything else we should have popped off fp->scopeChain() when we left its
    1369                 :      * static scope.
    1370                 :      */
    1371          244478 :     JSObject *obj2 = &fp->scopeChain();
    1372          488956 :     while (obj2->isWith())
    1373               0 :         obj2 = &obj2->asWith().enclosingScope();
    1374          247549 :     if (obj2->isBlock() &&
    1375            3071 :         obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
    1376             985 :         JSObject &youngestProto = obj2->asClonedBlock().staticBlock();
    1377             985 :         StaticBlockObject *parent = &blockObj;
    1378            1970 :         while ((parent = parent->enclosingBlock()) != &youngestProto)
    1379               0 :             JS_ASSERT(parent);
    1380                 :     }
    1381                 : #endif
    1382                 : 
    1383          244478 :     fp->setBlockChain(&blockObj);
    1384          244478 : }
    1385                 : 
    1386                 : void JS_FASTCALL
    1387          245147 : stubs::LeaveBlock(VMFrame &f)
    1388                 : {
    1389          245147 :     JSContext *cx = f.cx;
    1390          245147 :     StackFrame *fp = f.fp();
    1391                 : 
    1392          245147 :     StaticBlockObject &blockObj = fp->blockChain();
    1393          245147 :     JS_ASSERT(blockObj.stackDepth() <= StackDepth(fp->script()));
    1394                 : 
    1395                 :     /*
    1396                 :      * If we're about to leave the dynamic scope of a block that has been
    1397                 :      * cloned onto fp->scopeChain(), clear its private data, move its locals from
    1398                 :      * the stack into the clone, and pop it off the chain.
    1399                 :      */
    1400          245147 :     JSObject &obj = fp->scopeChain();
    1401          245147 :     if (obj.getProto() == &blockObj)
    1402            1328 :         obj.asClonedBlock().put(cx);
    1403                 : 
    1404          245147 :     fp->setBlockChain(blockObj.enclosingBlock());
    1405          245147 : }
    1406                 : 
    1407                 : inline void *
    1408            6788 : FindNativeCode(VMFrame &f, jsbytecode *target)
    1409                 : {
    1410            6788 :     void* native = f.fp()->script()->nativeCodeForPC(f.fp()->isConstructing(), target);
    1411            6788 :     if (native)
    1412            6788 :         return native;
    1413                 : 
    1414               0 :     uint32_t sourceOffset = f.pc() - f.script()->code;
    1415               0 :     uint32_t targetOffset = target - f.script()->code;
    1416                 : 
    1417               0 :     CrossChunkEdge *edges = f.jit()->edges();
    1418               0 :     for (size_t i = 0; i < f.jit()->nedges; i++) {
    1419               0 :         const CrossChunkEdge &edge = edges[i];
    1420               0 :         if (edge.source == sourceOffset && edge.target == targetOffset)
    1421               0 :             return edge.shimLabel;
    1422                 :     }
    1423                 : 
    1424               0 :     JS_NOT_REACHED("Missing edge");
    1425                 :     return NULL;
    1426                 : }
    1427                 : 
    1428                 : void * JS_FASTCALL
    1429            6110 : stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
    1430                 : {
    1431            6110 :     jsbytecode *jpc = pc;
    1432            6110 :     JSScript *script = f.fp()->script();
    1433                 : 
    1434                 :     /* This is correct because the compiler adjusts the stack beforehand. */
    1435            6110 :     Value lval = f.regs.sp[-1];
    1436                 : 
    1437            6110 :     if (!lval.isPrimitive())
    1438               0 :         return FindNativeCode(f, pc + GET_JUMP_OFFSET(pc));
    1439                 : 
    1440            6110 :     JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
    1441                 : 
    1442            6110 :     pc += JUMP_OFFSET_LEN;
    1443            6110 :     uint32_t npairs = GET_UINT16(pc);
    1444            6110 :     pc += UINT16_LEN;
    1445                 : 
    1446            6110 :     JS_ASSERT(npairs);
    1447                 : 
    1448            6110 :     if (lval.isString()) {
    1449            5696 :         JSLinearString *str = lval.toString()->ensureLinear(f.cx);
    1450            5696 :         if (!str)
    1451               0 :             THROWV(NULL);
    1452           36152 :         for (uint32_t i = 1; i <= npairs; i++) {
    1453           34956 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1454           34956 :             pc += UINT32_INDEX_LEN;
    1455           34956 :             if (rval.isString()) {
    1456           34956 :                 JSLinearString *rhs = &rval.toString()->asLinear();
    1457           34956 :                 if (rhs == str || EqualStrings(str, rhs))
    1458            4500 :                     return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1459                 :             }
    1460           30456 :             pc += JUMP_OFFSET_LEN;
    1461                 :         }
    1462             414 :     } else if (lval.isNumber()) {
    1463               0 :         double d = lval.toNumber();
    1464               0 :         for (uint32_t i = 1; i <= npairs; i++) {
    1465               0 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1466               0 :             pc += UINT32_INDEX_LEN;
    1467               0 :             if (rval.isNumber() && d == rval.toNumber())
    1468               0 :                 return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1469               0 :             pc += JUMP_OFFSET_LEN;
    1470                 :         }
    1471                 :     } else {
    1472            1300 :         for (uint32_t i = 1; i <= npairs; i++) {
    1473             886 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1474             886 :             pc += UINT32_INDEX_LEN;
    1475             886 :             if (lval == rval)
    1476               0 :                 return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1477             886 :             pc += JUMP_OFFSET_LEN;
    1478                 :         }
    1479                 :     }
    1480                 : 
    1481            1610 :     return FindNativeCode(f, jpc + GET_JUMP_OFFSET(jpc));
    1482                 : }
    1483                 : 
    1484                 : void * JS_FASTCALL
    1485             678 : stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
    1486                 : {
    1487             678 :     jsbytecode * const originalPC = origPc;
    1488                 : 
    1489            1356 :     DebugOnly<JSOp> op = JSOp(*originalPC);
    1490             678 :     JS_ASSERT(op == JSOP_TABLESWITCH);
    1491                 : 
    1492             678 :     uint32_t jumpOffset = GET_JUMP_OFFSET(originalPC);
    1493             678 :     jsbytecode *pc = originalPC + JUMP_OFFSET_LEN;
    1494                 :     
    1495                 :     /* Note: compiler adjusts the stack beforehand. */
    1496             678 :     Value rval = f.regs.sp[-1];
    1497                 : 
    1498                 :     int32_t tableIdx;
    1499             678 :     if (rval.isInt32()) {
    1500               0 :         tableIdx = rval.toInt32();
    1501             678 :     } else if (rval.isDouble()) {
    1502             199 :         double d = rval.toDouble();
    1503             199 :         if (d == 0) {
    1504                 :             /* Treat -0 (double) as 0. */
    1505              93 :             tableIdx = 0;
    1506             106 :         } else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) {
    1507              88 :             goto finally;
    1508                 :         }
    1509                 :     } else {
    1510             479 :         goto finally;
    1511                 :     }
    1512                 : 
    1513                 :     {
    1514             111 :         int32_t low = GET_JUMP_OFFSET(pc);
    1515             111 :         pc += JUMP_OFFSET_LEN;
    1516             111 :         int32_t high = GET_JUMP_OFFSET(pc);
    1517             111 :         pc += JUMP_OFFSET_LEN;
    1518                 : 
    1519             111 :         tableIdx -= low;
    1520             111 :         if ((uint32_t) tableIdx < (uint32_t)(high - low + 1)) {
    1521              69 :             pc += JUMP_OFFSET_LEN * tableIdx;
    1522              69 :             if (uint32_t candidateOffset = GET_JUMP_OFFSET(pc))
    1523              69 :                 jumpOffset = candidateOffset;
    1524                 :         }
    1525                 :     }
    1526                 : 
    1527                 : finally:
    1528                 :     /* Provide the native address. */
    1529             678 :     return FindNativeCode(f, originalPC + jumpOffset);
    1530                 : }
    1531                 : 
    1532                 : void JS_FASTCALL
    1533            1105 : stubs::Pos(VMFrame &f)
    1534                 : {
    1535            1105 :     if (!ToNumber(f.cx, &f.regs.sp[-1]))
    1536               0 :         THROW();
    1537            1105 :     if (!f.regs.sp[-1].isInt32())
    1538             436 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
    1539                 : }
    1540                 : 
    1541                 : void JS_FASTCALL
    1542             137 : stubs::DelName(VMFrame &f, PropertyName *name)
    1543                 : {
    1544                 :     JSObject *obj, *obj2;
    1545                 :     JSProperty *prop;
    1546             137 :     if (!FindProperty(f.cx, name, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
    1547               0 :         THROW();
    1548                 : 
    1549                 :     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
    1550             137 :     JS_ASSERT(!f.script()->strictModeCode);
    1551                 : 
    1552                 :     /* ECMA says to return true if name is undefined or inherited. */
    1553             137 :     f.regs.sp++;
    1554             137 :     f.regs.sp[-1] = BooleanValue(true);
    1555             137 :     if (prop) {
    1556              85 :         if (!obj->deleteProperty(f.cx, name, &f.regs.sp[-1], false))
    1557               0 :             THROW();
    1558                 :     }
    1559                 : }
    1560                 : 
    1561                 : template<JSBool strict>
    1562                 : void JS_FASTCALL
    1563             653 : stubs::DelProp(VMFrame &f, PropertyName *name)
    1564                 : {
    1565             653 :     JSContext *cx = f.cx;
    1566                 : 
    1567             653 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
    1568             653 :     if (!obj)
    1569               0 :         THROW();
    1570                 : 
    1571                 :     Value rval;
    1572             653 :     if (!obj->deleteProperty(cx, name, &rval, strict))
    1573               0 :         THROW();
    1574                 : 
    1575             653 :     f.regs.sp[-1] = rval;
    1576                 : }
    1577                 : 
    1578                 : template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, PropertyName *name);
    1579                 : template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
    1580                 : 
    1581                 : template<JSBool strict>
    1582                 : void JS_FASTCALL
    1583            1619 : stubs::DelElem(VMFrame &f)
    1584                 : {
    1585            1619 :     JSContext *cx = f.cx;
    1586                 : 
    1587            1619 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
    1588            1619 :     if (!obj)
    1589               0 :         THROW();
    1590                 : 
    1591            1619 :     const Value &propval = f.regs.sp[-1];
    1592            1619 :     Value &rval = f.regs.sp[-2];
    1593                 : 
    1594            1619 :     if (!obj->deleteByValue(cx, propval, &rval, strict))
    1595               2 :         THROW();
    1596                 : }
    1597                 : 
    1598                 : void JS_FASTCALL
    1599           17666 : stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
    1600                 : {
    1601           17666 :     unsigned attrs = JSPROP_ENUMERATE;
    1602           17666 :     if (!f.fp()->isEvalFrame())
    1603           16916 :         attrs |= JSPROP_PERMANENT;
    1604           17666 :     if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
    1605           16500 :         attrs |= JSPROP_READONLY;
    1606                 : 
    1607           17666 :     JSObject &obj = f.fp()->varObj();
    1608                 : 
    1609           17666 :     if (!DefVarOrConstOperation(f.cx, obj, dn, attrs))
    1610               0 :         THROW();
    1611                 : }
    1612                 : 
    1613                 : void JS_FASTCALL
    1614           16486 : stubs::SetConst(VMFrame &f, PropertyName *name)
    1615                 : {
    1616           16486 :     JSContext *cx = f.cx;
    1617                 : 
    1618           16486 :     JSObject *obj = &f.fp()->varObj();
    1619           16486 :     const Value &ref = f.regs.sp[-1];
    1620                 : 
    1621           16486 :     if (!obj->defineProperty(cx, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
    1622           16486 :                              JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
    1623                 :     {
    1624               0 :         THROW();
    1625                 :     }
    1626                 : }
    1627                 : 
    1628                 : JSBool JS_FASTCALL
    1629          403311 : stubs::In(VMFrame &f)
    1630                 : {
    1631          403311 :     JSContext *cx = f.cx;
    1632                 : 
    1633          403311 :     const Value &rref = f.regs.sp[-1];
    1634          403311 :     if (!rref.isObject()) {
    1635               7 :         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
    1636               7 :         THROWV(JS_FALSE);
    1637                 :     }
    1638                 : 
    1639          403304 :     JSObject *obj = &rref.toObject();
    1640                 :     jsid id;
    1641          403304 :     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
    1642               0 :         THROWV(JS_FALSE);
    1643                 : 
    1644                 :     JSObject *obj2;
    1645                 :     JSProperty *prop;
    1646          403304 :     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
    1647               0 :         THROWV(JS_FALSE);
    1648                 : 
    1649          403304 :     return !!prop;
    1650                 : }
    1651                 : 
    1652                 : template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
    1653                 : template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
    1654                 : 
    1655                 : void JS_FASTCALL
    1656           14528 : stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
    1657                 : {
    1658           14528 :     JS_ASSERT(which == 0 || which == 1);
    1659                 : 
    1660                 :     /* The actual pushed value is at sp[0], fix up the stack. See finishBarrier. */
    1661           14528 :     Value &result = f.regs.sp[-1 - (int)which];
    1662           14528 :     result = f.regs.sp[0];
    1663                 : 
    1664                 :     /*
    1665                 :      * Break type barriers at this bytecode if we have added many objects to
    1666                 :      * the target already. This isn't needed if inference results for the
    1667                 :      * script have been destroyed, as we will reanalyze and prune type barriers
    1668                 :      * as they are regenerated.
    1669                 :      */
    1670           14528 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1671           29056 :         AutoEnterTypeInference enter(f.cx);
    1672           14528 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1673                 :     }
    1674                 : 
    1675           14528 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1676           14528 : }
    1677                 : 
    1678                 : void JS_FASTCALL
    1679           13209 : stubs::StubTypeHelper(VMFrame &f, int32_t which)
    1680                 : {
    1681           13209 :     const Value &result = f.regs.sp[which];
    1682                 : 
    1683           13209 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1684           26418 :         AutoEnterTypeInference enter(f.cx);
    1685           13209 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1686                 :     }
    1687                 : 
    1688           13209 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1689           13209 : }
    1690                 : 
    1691                 : /*
    1692                 :  * Variant of TypeBarrierHelper for checking types after making a native call.
    1693                 :  * The stack is already correct, and no fixup should be performed.
    1694                 :  */
    1695                 : void JS_FASTCALL
    1696             287 : stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
    1697                 : {
    1698             287 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
    1699             287 : }
    1700                 : 
    1701                 : void JS_FASTCALL
    1702             100 : stubs::NegZeroHelper(VMFrame &f)
    1703                 : {
    1704             100 :     f.regs.sp[-1].setDouble(-0.0);
    1705             100 :     TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
    1706             100 : }
    1707                 : 
    1708                 : void JS_FASTCALL
    1709             912 : stubs::CheckArgumentTypes(VMFrame &f)
    1710                 : {
    1711             912 :     StackFrame *fp = f.fp();
    1712             912 :     JSFunction *fun = fp->fun();
    1713             912 :     JSScript *script = fun->script();
    1714             912 :     RecompilationMonitor monitor(f.cx);
    1715                 : 
    1716                 :     {
    1717                 :         /* Postpone recompilations until all args have been updated. */
    1718            1824 :         types::AutoEnterTypeInference enter(f.cx);
    1719                 : 
    1720             912 :         if (!f.fp()->isConstructing())
    1721             894 :             TypeScript::SetThis(f.cx, script, fp->thisValue());
    1722            2326 :         for (unsigned i = 0; i < fun->nargs; i++)
    1723            1414 :             TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i));
    1724                 :     }
    1725                 : 
    1726             912 :     if (monitor.recompiled())
    1727              22 :         return;
    1728                 : 
    1729                 : #ifdef JS_MONOIC
    1730             890 :     ic::GenerateArgumentCheckStub(f);
    1731                 : #endif
    1732                 : }
    1733                 : 
    1734                 : #ifdef DEBUG
    1735                 : void JS_FASTCALL
    1736        14165571 : stubs::AssertArgumentTypes(VMFrame &f)
    1737                 : {
    1738        14165571 :     StackFrame *fp = f.fp();
    1739        14165571 :     JSFunction *fun = fp->fun();
    1740        14165571 :     JSScript *script = fun->script();
    1741                 : 
    1742                 :     /*
    1743                 :      * Don't check the type of 'this' for constructor frames, the 'this' value
    1744                 :      * has not been constructed yet.
    1745                 :      */
    1746        14165571 :     if (!fp->isConstructing()) {
    1747        12429353 :         Type type = GetValueType(f.cx, fp->thisValue());
    1748        12429353 :         if (!TypeScript::ThisTypes(script)->hasType(type))
    1749               0 :             TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
    1750                 :     }
    1751                 : 
    1752        38310247 :     for (unsigned i = 0; i < fun->nargs; i++) {
    1753        24144676 :         Type type = GetValueType(f.cx, fp->formalArg(i));
    1754        24144676 :         if (!TypeScript::ArgTypes(script, i)->hasType(type))
    1755               0 :             TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
    1756                 :     }
    1757        14165571 : }
    1758                 : #endif
    1759                 : 
    1760                 : /*
    1761                 :  * These two are never actually called, they just give us a place to rejoin if
    1762                 :  * there is an invariant failure when initially entering a loop.
    1763                 :  */
    1764               0 : void JS_FASTCALL stubs::MissedBoundsCheckEntry(VMFrame &f) {}
    1765               0 : void JS_FASTCALL stubs::MissedBoundsCheckHead(VMFrame &f) {}
    1766                 : 
    1767                 : void * JS_FASTCALL
    1768              66 : stubs::InvariantFailure(VMFrame &f, void *rval)
    1769                 : {
    1770                 :     /*
    1771                 :      * Patch this call to the return site of the call triggering the invariant
    1772                 :      * failure (or a MissedBoundsCheck* function if the failure occurred on
    1773                 :      * initial loop entry), and trigger a recompilation which will then
    1774                 :      * redirect to the rejoin point for that call. We want to make things look
    1775                 :      * to the recompiler like we are still inside that call, and that after
    1776                 :      * recompilation we will return to the call's rejoin point.
    1777                 :      */
    1778              66 :     void *repatchCode = f.scratch;
    1779              66 :     JS_ASSERT(repatchCode);
    1780              66 :     void **frameAddr = f.returnAddressLocation();
    1781              66 :     *frameAddr = repatchCode;
    1782                 : 
    1783                 :     /* Recompile the outermost script, and don't hoist any bounds checks. */
    1784              66 :     JSScript *script = f.fp()->script();
    1785              66 :     JS_ASSERT(!script->failedBoundsCheck);
    1786              66 :     script->failedBoundsCheck = true;
    1787                 : 
    1788              66 :     ExpandInlineFrames(f.cx->compartment);
    1789                 : 
    1790              66 :     mjit::Recompiler::clearStackReferences(f.cx, script);
    1791              66 :     mjit::ReleaseScriptCode(f.cx, script);
    1792                 : 
    1793                 :     /* Return the same value (if any) as the call triggering the invariant failure. */
    1794              66 :     return rval;
    1795                 : }
    1796                 : 
    1797                 : void JS_FASTCALL
    1798               0 : stubs::Exception(VMFrame &f)
    1799                 : {
    1800                 :     // Check the interrupt flag to allow interrupting deeply nested exception
    1801                 :     // handling.
    1802               0 :     if (f.cx->runtime->interrupt && !js_HandleExecutionInterrupt(f.cx))
    1803               0 :         THROW();
    1804                 : 
    1805               0 :     f.regs.sp[0] = f.cx->getPendingException();
    1806               0 :     f.cx->clearPendingException();
    1807                 : }
    1808                 : 
    1809                 : void JS_FASTCALL
    1810          188736 : stubs::FunctionFramePrologue(VMFrame &f)
    1811                 : {
    1812          188736 :     if (!f.fp()->functionPrologue(f.cx))
    1813               0 :         THROW();
    1814                 : }
    1815                 : 
    1816                 : void JS_FASTCALL
    1817          535303 : stubs::FunctionFrameEpilogue(VMFrame &f)
    1818                 : {
    1819          535303 :     f.fp()->functionEpilogue();
    1820          535303 : }
    1821                 : 
    1822                 : void JS_FASTCALL
    1823             202 : stubs::AnyFrameEpilogue(VMFrame &f)
    1824                 : {
    1825                 :     /*
    1826                 :      * On the normal execution path, emitReturn calls ScriptDebugEpilogue
    1827                 :      * and inlines ScriptEpilogue. This function implements forced early
    1828                 :      * returns, so it must have the same effect.
    1829                 :      */
    1830             202 :     bool ok = true;
    1831             202 :     if (f.cx->compartment->debugMode())
    1832             202 :         ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok);
    1833             202 :     ok = ScriptEpilogue(f.cx, f.fp(), ok);
    1834             202 :     if (!ok)
    1835               0 :         THROW();
    1836             202 :     if (f.fp()->isNonEvalFunctionFrame())
    1837             162 :         f.fp()->functionEpilogue();
    1838                 : }
    1839                 : 
    1840                 : template <bool Clamped>
    1841                 : int32_t JS_FASTCALL
    1842             489 : stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
    1843                 : {
    1844             489 :     JS_ASSERT(!vp->isInt32());
    1845                 : 
    1846             489 :     if (vp->isDouble()) {
    1847                 :         if (Clamped)
    1848              93 :             return js_TypedArray_uint8_clamp_double(vp->toDouble());
    1849             276 :         return js_DoubleToECMAInt32(vp->toDouble());
    1850                 :     }
    1851                 : 
    1852             120 :     if (vp->isNull() || vp->isObject() || vp->isUndefined())
    1853             120 :         return 0;
    1854                 : 
    1855               0 :     if (vp->isBoolean())
    1856               0 :         return vp->toBoolean() ? 1 : 0;
    1857                 : 
    1858               0 :     JS_ASSERT(vp->isString());
    1859                 : 
    1860               0 :     int32_t i32 = 0;
    1861                 : #ifdef DEBUG
    1862                 :     bool success = 
    1863                 : #endif
    1864               0 :         StringToNumberType<int32_t>(cx, vp->toString(), &i32);
    1865               0 :     JS_ASSERT(success);
    1866                 : 
    1867               0 :     return i32;
    1868                 : }
    1869                 : 
    1870                 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<true>(JSContext *, Value *);
    1871                 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<false>(JSContext *, Value *);
    1872                 : 
    1873                 : void JS_FASTCALL
    1874              56 : stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
    1875                 : {
    1876              56 :     JS_ASSERT(!vp->isDouble() && !vp->isInt32());
    1877                 : 
    1878              56 :     if (vp->isNull()) {
    1879               0 :         vp->setDouble(0);
    1880              56 :     } else if (vp->isObject() || vp->isUndefined()) {
    1881              28 :         vp->setDouble(js_NaN);
    1882              28 :     } else if (vp->isBoolean()) {
    1883               0 :         vp->setDouble(vp->toBoolean() ? 1 : 0);
    1884                 :     } else {
    1885              28 :         JS_ASSERT(vp->isString());
    1886              28 :         double d = 0;
    1887                 : #ifdef DEBUG
    1888                 :         bool success = 
    1889                 : #endif
    1890              28 :             StringToNumberType<double>(cx, vp->toString(), &d);
    1891              28 :         JS_ASSERT(success);
    1892              28 :         vp->setDouble(d);
    1893                 :     }
    1894              56 : }
    1895                 : 
    1896                 : void JS_FASTCALL
    1897              48 : stubs::WriteBarrier(VMFrame &f, Value *addr)
    1898                 : {
    1899              48 :     gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
    1900              48 : }
    1901                 : 
    1902                 : void JS_FASTCALL
    1903               2 : stubs::GCThingWriteBarrier(VMFrame &f, Value *addr)
    1904                 : {
    1905               2 :     gc::Cell *cell = (gc::Cell *)addr->toGCThing();
    1906               2 :     if (cell && !cell->isMarked())
    1907               2 :         gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
    1908               2 : }

Generated by: LCOV version 1.7