LCOV - code coverage report
Current view: directory - js/src/methodjit - StubCalls.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 899 717 79.8 %
Date: 2012-06-02 Functions: 103 90 87.4 %

       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          135441 : stubs::SetName(VMFrame &f, PropertyName *name)
     101                 : {
     102          135441 :     JSContext *cx = f.cx;
     103          135441 :     const Value &rval = f.regs.sp[-1];
     104          135441 :     const Value &lval = f.regs.sp[-2];
     105                 : 
     106          135441 :     if (!SetPropertyOperation(cx, f.pc(), lval, rval))
     107             425 :         THROW();
     108                 : 
     109          135016 :     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           47472 : stubs::SetGlobalName(VMFrame &f, PropertyName *name)
     118                 : {
     119           47472 :     SetName<strict>(f, name);
     120           47472 : }
     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          781215 : stubs::Name(VMFrame &f)
     127                 : {
     128                 :     Value rval;
     129          781215 :     if (!NameOperation(f.cx, f.pc(), &rval))
     130            3359 :         THROW();
     131          777856 :     f.regs.sp[0] = rval;
     132                 : }
     133                 : 
     134                 : void JS_FASTCALL
     135         9431373 : stubs::GetElem(VMFrame &f)
     136                 : {
     137         9431373 :     Value &lref = f.regs.sp[-2];
     138         9431373 :     Value &rref = f.regs.sp[-1];
     139         9431373 :     Value &rval = f.regs.sp[-2];
     140                 : 
     141         9431373 :     if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval))
     142              45 :         THROW();
     143                 : }
     144                 : 
     145                 : template<JSBool strict>
     146                 : void JS_FASTCALL
     147         8713438 : stubs::SetElem(VMFrame &f)
     148                 : {
     149         8713438 :     JSContext *cx = f.cx;
     150         8713438 :     FrameRegs &regs = f.regs;
     151                 : 
     152         8713438 :     Value &objval = regs.sp[-3];
     153         8713438 :     Value &idval  = regs.sp[-2];
     154         8713438 :     Value rval    = regs.sp[-1];
     155                 : 
     156                 :     JSObject *obj;
     157                 :     jsid id;
     158                 : 
     159         8713438 :     obj = ValueToObject(cx, objval);
     160         8713438 :     if (!obj)
     161               7 :         THROW();
     162                 : 
     163         8713431 :     if (!FetchElementId(f.cx, obj, idval, id, &regs.sp[-2]))
     164               0 :         THROW();
     165                 : 
     166         8713431 :     TypeScript::MonitorAssign(cx, obj, id);
     167                 : 
     168                 :     do {
     169         8713431 :         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         8689911 :     if (!obj->setGeneric(cx, id, &rval, strict))
     188            2428 :         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         8711003 :     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         1950398 : stubs::ImplicitThis(VMFrame &f, PropertyName *name)
     220                 : {
     221                 :     JSObject *obj, *obj2;
     222                 :     JSProperty *prop;
     223         1950398 :     if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
     224               0 :         THROW();
     225                 : 
     226         1950398 :     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           22203 : stubs::BitXor(VMFrame &f)
     244                 : {
     245                 :     int32_t i, j;
     246                 : 
     247           22203 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     248               0 :         THROW();
     249                 : 
     250           22203 :     i = i ^ j;
     251           22203 :     f.regs.sp[-2].setInt32(i);
     252                 : }
     253                 : 
     254                 : void JS_FASTCALL
     255           64586 : stubs::BitAnd(VMFrame &f)
     256                 : {
     257                 :     int32_t i, j;
     258                 : 
     259           64586 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     260               0 :         THROW();
     261                 : 
     262           64586 :     i = i & j;
     263           64586 :     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             705 : stubs::Ursh(VMFrame &f)
     303                 : {
     304                 :     uint32_t u;
     305             705 :     if (!ToUint32(f.cx, f.regs.sp[-2], &u))
     306               0 :         THROW();
     307                 :     int32_t j;
     308             705 :     if (!ToInt32(f.cx, f.regs.sp[-1], &j))
     309               0 :         THROW();
     310                 : 
     311             705 :     u >>= (j & 31);
     312                 : 
     313             705 :         if (!f.regs.sp[-2].setNumber(uint32_t(u)))
     314             423 :         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          402822 : stubs::LessThan(VMFrame &f)
     468                 : {
     469          402822 :     RELATIONAL(<);
     470                 : }
     471                 : 
     472                 : JSBool JS_FASTCALL
     473           17849 : stubs::LessEqual(VMFrame &f)
     474                 : {
     475           17849 :     RELATIONAL(<=);
     476                 : }
     477                 : 
     478                 : JSBool JS_FASTCALL
     479          154681 : stubs::GreaterThan(VMFrame &f)
     480                 : {
     481          154681 :     RELATIONAL(>);
     482                 : }
     483                 : 
     484                 : JSBool JS_FASTCALL
     485           17862 : stubs::GreaterEqual(VMFrame &f)
     486                 : {
     487           17862 :     RELATIONAL(>=);
     488                 : }
     489                 : 
     490                 : JSBool JS_FASTCALL
     491         4444661 : stubs::ValueToBoolean(VMFrame &f)
     492                 : {
     493         4444661 :     return js_ValueToBoolean(f.regs.sp[-1]);
     494                 : }
     495                 : 
     496                 : void JS_FASTCALL
     497          299978 : stubs::Not(VMFrame &f)
     498                 : {
     499          299978 :     JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
     500          299978 :     f.regs.sp[-1].setBoolean(b);
     501          299978 : }
     502                 : 
     503                 : template <bool EQ>
     504                 : static inline bool
     505         2318588 : StubEqualityOp(VMFrame &f)
     506                 : {
     507         2318588 :     JSContext *cx = f.cx;
     508         2318588 :     FrameRegs &regs = f.regs;
     509                 : 
     510         2318588 :     Value rval = regs.sp[-1];
     511         2318588 :     Value lval = regs.sp[-2];
     512                 : 
     513                 :     bool cond;
     514                 : 
     515                 :     /* The string==string case is easily the hottest;  try it first. */
     516         2318588 :     if (lval.isString() && rval.isString()) {
     517         1919593 :         JSString *l = lval.toString();
     518         1919593 :         JSString *r = rval.toString();
     519                 :         bool equal;
     520         1919593 :         if (!EqualStrings(cx, l, r, &equal))
     521               0 :             return false;
     522         1919593 :         cond = equal == EQ;
     523                 :     } else
     524                 : #if JS_HAS_XML_SUPPORT
     525          398995 :     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          398995 :     if (SameType(lval, rval)) {
     536          310060 :         JS_ASSERT(!lval.isString());    /* this case is handled above */
     537          310060 :         if (lval.isDouble()) {
     538          128020 :             double l = lval.toDouble();
     539          128020 :             double r = rval.toDouble();
     540                 :             if (EQ)
     541          116941 :                 cond = (l == r);
     542                 :             else
     543           11079 :                 cond = (l != r);
     544          182040 :         } else if (lval.isObject()) {
     545           35832 :             JSObject *l = &lval.toObject(), *r = &rval.toObject();
     546           35832 :             if (JSEqualityOp eq = l->getClass()->ext.equality) {
     547                 :                 JSBool equal;
     548              42 :                 if (!eq(cx, l, &rval, &equal))
     549               0 :                     return false;
     550              42 :                 cond = !!equal == EQ;
     551                 :             } else {
     552           35790 :                 cond = (l == r) == EQ;
     553                 :             }
     554          146208 :         } else if (lval.isNullOrUndefined()) {
     555           98260 :             cond = EQ;
     556                 :         } else {
     557           47948 :             cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
     558                 :         }
     559                 :     } else {
     560           88935 :         if (lval.isNullOrUndefined()) {
     561           15389 :             cond = rval.isNullOrUndefined() == EQ;
     562           73546 :         } else if (rval.isNullOrUndefined()) {
     563           18914 :             cond = !EQ;
     564                 :         } else {
     565           54632 :             if (!ToPrimitive(cx, &lval))
     566               4 :                 return false;
     567           54628 :             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           54628 :             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           51778 :                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     584               0 :                     return false;
     585                 : 
     586                 :                 if (EQ)
     587           28838 :                     cond = (l == r);
     588                 :                 else
     589           22940 :                     cond = (l != r);
     590                 :             }
     591                 :         }
     592                 :     }
     593                 : 
     594         2318584 :     regs.sp[-2].setBoolean(cond);
     595         2318584 :     return true;
     596                 : }
     597                 : 
     598                 : JSBool JS_FASTCALL
     599          663664 : stubs::Equal(VMFrame &f)
     600                 : {
     601          663664 :     if (!StubEqualityOp<true>(f))
     602               4 :         THROWV(JS_FALSE);
     603          663660 :     return f.regs.sp[-2].toBoolean();
     604                 : }
     605                 : 
     606                 : JSBool JS_FASTCALL
     607         1654924 : stubs::NotEqual(VMFrame &f)
     608                 : {
     609         1654924 :     if (!StubEqualityOp<false>(f))
     610               0 :         THROWV(JS_FALSE);
     611         1654924 :     return f.regs.sp[-2].toBoolean();
     612                 : }
     613                 : 
     614                 : void JS_FASTCALL
     615        18873754 : stubs::Add(VMFrame &f)
     616                 : {
     617        18873754 :     JSContext *cx = f.cx;
     618        18873754 :     FrameRegs &regs = f.regs;
     619        18873754 :     Value rval = regs.sp[-1];
     620        18873754 :     Value lval = regs.sp[-2];
     621                 : 
     622                 :     /* The string + string case is easily the hottest;  try it first. */
     623        18873754 :     bool lIsString = lval.isString();
     624        18873754 :     bool rIsString = rval.isString();
     625                 :     JSString *lstr, *rstr;
     626        18873754 :     if (lIsString && rIsString) {
     627        15592648 :         lstr = lval.toString();
     628        15592648 :         rstr = rval.toString();
     629        15592648 :         goto string_concat;
     630                 : 
     631                 :     } else
     632                 : #if JS_HAS_XML_SUPPORT
     633         3281106 :     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         3281106 :         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
     644         3281106 :         if (!ToPrimitive(f.cx, &lval))
     645              16 :             THROW();
     646         3281090 :         if (!ToPrimitive(f.cx, &rval))
     647              11 :             THROW();
     648         3281079 :         if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
     649         3000569 :             if (lIsString) {
     650         2420542 :                 lstr = lval.toString();
     651                 :             } else {
     652          580027 :                 lstr = ToString(cx, lval);
     653          580027 :                 if (!lstr)
     654               0 :                     THROW();
     655          580027 :                 regs.sp[-2].setString(lstr);
     656                 :             }
     657         3000569 :             if (rIsString) {
     658          582096 :                 rstr = rval.toString();
     659                 :             } else {
     660         2418473 :                 rstr = ToString(cx, rval);
     661         2418473 :                 if (!rstr)
     662               0 :                     THROW();
     663         2418473 :                 regs.sp[-1].setString(rstr);
     664                 :             }
     665         3000569 :             if (lIsObject || rIsObject)
     666          394405 :                 TypeScript::MonitorString(cx, f.script(), f.pc());
     667         3000569 :             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        18593217 :     JSString *str = js_ConcatStrings(cx, lstr, rstr);
     684        18593217 :     if (!str)
     685               5 :         THROW();
     686        18593212 :     regs.sp[-2].setString(str);
     687        18593212 :     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             878 : stubs::Interrupt(VMFrame &f, jsbytecode *pc)
     812                 : {
     813             878 :     gc::MaybeVerifyBarriers(f.cx);
     814                 : 
     815             878 :     if (!js_HandleExecutionInterrupt(f.cx))
     816               0 :         THROW();
     817                 : }
     818                 : 
     819                 : void JS_FASTCALL
     820              93 : stubs::RecompileForInline(VMFrame &f)
     821                 : {
     822              93 :     ExpandInlineFrames(f.cx->compartment);
     823                 :     Recompiler::clearStackReferencesAndChunk(f.cx, f.script(), f.jit(), f.chunkIndex(),
     824              93 :                                              /* resetUses = */ false);
     825              93 : }
     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         1256740 : stubs::NewInitArray(VMFrame &f, uint32_t count)
     904                 : {
     905         1256740 :     JSObject *obj = NewDenseAllocatedArray(f.cx, count);
     906         1256740 :     if (!obj)
     907               0 :         THROW();
     908                 : 
     909         1256740 :     TypeObject *type = (TypeObject *) f.scratch;
     910         1256740 :     if (type)
     911         1207426 :         obj->setType(type);
     912                 : 
     913         1256740 :     f.regs.sp[0].setObject(*obj);
     914                 : }
     915                 : 
     916                 : void JS_FASTCALL
     917         1573985 : stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
     918                 : {
     919         1573985 :     JSContext *cx = f.cx;
     920         1573985 :     TypeObject *type = (TypeObject *) f.scratch;
     921                 : 
     922         1573985 :     if (!baseobj) {
     923           22883 :         gc::AllocKind kind = GuessObjectGCKind(0);
     924           22883 :         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     925           22883 :         if (!obj)
     926               0 :             THROW();
     927           22883 :         if (type)
     928             395 :             obj->setType(type);
     929           22883 :         f.regs.sp[0].setObject(*obj);
     930           22883 :         return;
     931                 :     }
     932                 : 
     933         1551102 :     JS_ASSERT(type);
     934         1551102 :     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
     935                 : 
     936         1551102 :     if (!obj)
     937               0 :         THROW();
     938         1551102 :     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          207700 : 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          207700 :     JS_ASSERT(fun->isInterpreted());
    1000          207700 :     JS_ASSERT(!fun->isFlatClosure());
    1001                 : 
    1002                 :     JSObject *parent;
    1003          207700 :     if (fun->isNullClosure()) {
    1004            2959 :         parent = &f.fp()->scopeChain();
    1005                 :     } else {
    1006          204741 :         parent = GetScopeChain(f.cx, f.fp());
    1007          204741 :         if (!parent)
    1008               0 :             THROWV(NULL);
    1009                 :     }
    1010          207700 :     JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
    1011          207700 :     if (!obj)
    1012               0 :         THROWV(NULL);
    1013                 : 
    1014          207700 :     JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
    1015                 : 
    1016          207700 :     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          347887 : 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          347887 :     JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
    1036          347887 :     if (!proto)
    1037               0 :         THROW();
    1038          347887 :     JS_ASSERT(proto);
    1039          347887 :     JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
    1040          347887 :     if (!obj)
    1041               0 :         THROW();
    1042          347887 :     f.regs.sp[0].setObject(*obj);
    1043                 : }
    1044                 : 
    1045                 : JSObject * JS_FASTCALL
    1046               0 : stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun)
    1047                 : {
    1048               0 :     JS_ASSERT(fun->joinable());
    1049               0 :     DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
    1050               0 :     JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
    1051               0 :     return fun;
    1052                 : }
    1053                 : 
    1054                 : JSObject * JS_FASTCALL
    1055               0 : stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun)
    1056                 : {
    1057               0 :     JS_ASSERT(fun->joinable());
    1058               0 :     const Value &lref = f.regs.sp[-1];
    1059               0 :     if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
    1060               0 :         DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
    1061               0 :         JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
    1062               0 :         return fun;
    1063                 :     }
    1064               0 :     return Lambda(f, fun);
    1065                 : }
    1066                 : 
    1067                 : JSObject * JS_FASTCALL
    1068               0 : stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
    1069                 : {
    1070               0 :     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               0 :     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               0 :     const Value &cref = f.regs.sp[1 - (iargc + 2)];
    1086                 :     JSFunction *callee;
    1087                 : 
    1088               0 :     if (IsFunctionObject(cref, &callee)) {
    1089               0 :         Native native = callee->maybeNative();
    1090                 : 
    1091               0 :         if (native) {
    1092               0 :             if (iargc == 1 && native == array_sort)
    1093               0 :                 return fun;
    1094               0 :             if (iargc == 2 && native == str_replace)
    1095               0 :                 return fun;
    1096                 :         }
    1097                 :     }
    1098               0 :     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          305808 : stubs::Lambda(VMFrame &f, JSFunction *fun)
    1110                 : {
    1111                 :     JSObject *parent;
    1112          305808 :     if (fun->isNullClosure()) {
    1113          221995 :         parent = &f.fp()->scopeChain();
    1114                 :     } else {
    1115           83813 :         parent = GetScopeChain(f.cx, f.fp());
    1116           83813 :         if (!parent)
    1117               0 :             THROWV(NULL);
    1118                 :     }
    1119                 : 
    1120          305808 :     JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
    1121          305808 :     if (!obj)
    1122               0 :         THROWV(NULL);
    1123                 : 
    1124          305808 :     JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
    1125          305808 :     return obj;
    1126                 : }
    1127                 : 
    1128                 : void JS_FASTCALL
    1129         5184112 : stubs::GetProp(VMFrame &f, PropertyName *name)
    1130                 : {
    1131         5184112 :     JSContext *cx = f.cx;
    1132         5184112 :     FrameRegs &regs = f.regs;
    1133                 : 
    1134                 :     Value rval;
    1135         5184112 :     if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval))
    1136              19 :         THROW();
    1137                 : 
    1138         5184093 :     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          306710 : stubs::Iter(VMFrame &f, uint32_t flags)
    1164                 : {
    1165          306710 :     if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
    1166              57 :         THROW();
    1167          306653 :     JS_ASSERT(!f.regs.sp[-1].isPrimitive());
    1168                 : }
    1169                 : 
    1170                 : static void
    1171           15740 : InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
    1172                 : {
    1173           15740 :     JSContext *cx = f.cx;
    1174           15740 :     FrameRegs &regs = f.regs;
    1175                 : 
    1176                 :     /* Load the property's initial value into rval. */
    1177           15740 :     JS_ASSERT(regs.sp - f.fp()->base() >= 2);
    1178                 :     Value rval;
    1179           15740 :     rval = regs.sp[-1];
    1180                 : 
    1181                 :     /* Load the object being initialized into lval/obj. */
    1182           15740 :     JSObject *obj = &regs.sp[-2].toObject();
    1183           15740 :     JS_ASSERT(obj->isNative());
    1184                 : 
    1185                 :     /* Get the immediate property name into id. */
    1186           15740 :     jsid id = ATOM_TO_JSID(name);
    1187                 : 
    1188           15740 :     unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
    1189           31480 :     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           15679 :                                 JSPROP_ENUMERATE, 0, 0, defineHow)) {
    1193               0 :         THROW();
    1194                 :     }
    1195                 : }
    1196                 : 
    1197                 : void JS_FASTCALL
    1198           15740 : stubs::InitProp(VMFrame &f, PropertyName *name)
    1199                 : {
    1200           15740 :     InitPropOrMethod(f, name, JSOP_INITPROP);
    1201           15740 : }
    1202                 : 
    1203                 : void JS_FASTCALL
    1204               0 : stubs::InitMethod(VMFrame &f, PropertyName *name)
    1205                 : {
    1206               0 :     InitPropOrMethod(f, name, JSOP_INITMETHOD);
    1207               0 : }
    1208                 : 
    1209                 : void JS_FASTCALL
    1210         9090683 : stubs::IterNext(VMFrame &f, int32_t offset)
    1211                 : {
    1212         9090683 :     JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
    1213         9090683 :     JS_ASSERT(f.regs.sp[-offset].isObject());
    1214                 : 
    1215         9090683 :     JSObject *iterobj = &f.regs.sp[-offset].toObject();
    1216         9090683 :     f.regs.sp[0].setNull();
    1217         9090683 :     f.regs.sp++;
    1218         9090683 :     if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
    1219               0 :         THROW();
    1220                 : }
    1221                 : 
    1222                 : JSBool JS_FASTCALL
    1223         9207390 : stubs::IterMore(VMFrame &f)
    1224                 : {
    1225         9207390 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1226         9207390 :     JS_ASSERT(f.regs.sp[-1].isObject());
    1227                 : 
    1228                 :     Value v;
    1229         9207390 :     JSObject *iterobj = &f.regs.sp[-1].toObject();
    1230         9207390 :     if (!js_IteratorMore(f.cx, iterobj, &v))
    1231              12 :         THROWV(JS_FALSE);
    1232                 : 
    1233         9207378 :     return v.toBoolean();
    1234                 : }
    1235                 : 
    1236                 : void JS_FASTCALL
    1237            1187 : stubs::EndIter(VMFrame &f)
    1238                 : {
    1239            1187 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1240            1187 :     if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
    1241               0 :         THROW();
    1242                 : }
    1243                 : 
    1244                 : JSString * JS_FASTCALL
    1245           70160 : stubs::TypeOf(VMFrame &f)
    1246                 : {
    1247           70160 :     const Value &ref = f.regs.sp[-1];
    1248           70160 :     JSType type = JS_TypeOfValue(f.cx, ref);
    1249           70160 :     return f.cx->runtime->atomState.typeAtoms[type];
    1250                 : }
    1251                 : 
    1252                 : void JS_FASTCALL
    1253          730550 : stubs::StrictEq(VMFrame &f)
    1254                 : {
    1255          730550 :     const Value &rhs = f.regs.sp[-1];
    1256          730550 :     const Value &lhs = f.regs.sp[-2];
    1257                 :     bool equal;
    1258          730550 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1259               0 :         THROW();
    1260          730550 :     f.regs.sp--;
    1261          730550 :     f.regs.sp[-1].setBoolean(equal == JS_TRUE);
    1262                 : }
    1263                 : 
    1264                 : void JS_FASTCALL
    1265          240223 : stubs::StrictNe(VMFrame &f)
    1266                 : {
    1267          240223 :     const Value &rhs = f.regs.sp[-1];
    1268          240223 :     const Value &lhs = f.regs.sp[-2];
    1269                 :     bool equal;
    1270          240223 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1271               0 :         THROW();
    1272          240223 :     f.regs.sp--;
    1273          240223 :     f.regs.sp[-1].setBoolean(equal != JS_TRUE);
    1274                 : }
    1275                 : 
    1276                 : void JS_FASTCALL
    1277            1042 : stubs::Throw(VMFrame &f)
    1278                 : {
    1279            1042 :     JSContext *cx = f.cx;
    1280                 : 
    1281            1042 :     JS_ASSERT(!cx->isExceptionPending());
    1282            1042 :     cx->setPendingException(f.regs.sp[-1]);
    1283            1042 :     THROW();
    1284                 : }
    1285                 : 
    1286                 : JSObject * JS_FASTCALL
    1287          244438 : stubs::FlatLambda(VMFrame &f, JSFunction *fun)
    1288                 : {
    1289          244438 :     JSObject *obj = js_NewFlatClosure(f.cx, fun);
    1290          244438 :     if (!obj)
    1291               0 :         THROWV(NULL);
    1292          244438 :     return obj;
    1293                 : }
    1294                 : 
    1295                 : void JS_FASTCALL
    1296          428382 : stubs::Arguments(VMFrame &f)
    1297                 : {
    1298          428382 :     ArgumentsObject *arguments = js_GetArgsObject(f.cx, f.fp());
    1299          428382 :     if (!arguments)
    1300               0 :         THROW();
    1301          428382 :     f.regs.sp[0] = ObjectValue(*arguments);
    1302                 : }
    1303                 : 
    1304                 : JSBool JS_FASTCALL
    1305           91701 : stubs::InstanceOf(VMFrame &f)
    1306                 : {
    1307           91701 :     JSContext *cx = f.cx;
    1308           91701 :     FrameRegs &regs = f.regs;
    1309                 : 
    1310           91701 :     const Value &rref = regs.sp[-1];
    1311           91701 :     if (rref.isPrimitive()) {
    1312                 :         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
    1313               0 :                             -1, rref, NULL);
    1314               0 :         THROWV(JS_FALSE);
    1315                 :     }
    1316           91701 :     JSObject *obj = &rref.toObject();
    1317           91701 :     const Value &lref = regs.sp[-2];
    1318           91701 :     JSBool cond = JS_FALSE;
    1319           91701 :     if (!HasInstance(cx, obj, &lref, &cond))
    1320               6 :         THROWV(JS_FALSE);
    1321           91695 :     f.regs.sp[-2].setBoolean(cond);
    1322           91695 :     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          246072 : stubs::EnterBlock(VMFrame &f, JSObject *obj)
    1344                 : {
    1345          246072 :     FrameRegs &regs = f.regs;
    1346          246072 :     StackFrame *fp = f.fp();
    1347          246072 :     StaticBlockObject &blockObj = obj->asStaticBlock();
    1348                 : 
    1349          246072 :     JS_ASSERT(!f.regs.inlined());
    1350                 : 
    1351          246072 :     if (*regs.pc == JSOP_ENTERBLOCK) {
    1352          164469 :         JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp);
    1353          164469 :         Value *vp = regs.sp + blockObj.slotCount();
    1354          164469 :         JS_ASSERT(regs.sp < vp);
    1355          164469 :         JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
    1356          164469 :         SetValueRangeToUndefined(regs.sp, vp);
    1357          164469 :         regs.sp = vp;
    1358                 :     }
    1359                 : 
    1360                 : #ifdef DEBUG
    1361          246072 :     JSContext *cx = f.cx;
    1362          246072 :     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          246072 :     JSObject *obj2 = &fp->scopeChain();
    1372          492144 :     while (obj2->isWith())
    1373               0 :         obj2 = &obj2->asWith().enclosingScope();
    1374          249143 :     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          246072 :     fp->setBlockChain(&blockObj);
    1384          246072 : }
    1385                 : 
    1386                 : void JS_FASTCALL
    1387          246744 : stubs::LeaveBlock(VMFrame &f)
    1388                 : {
    1389          246744 :     JSContext *cx = f.cx;
    1390          246744 :     StackFrame *fp = f.fp();
    1391                 : 
    1392          246744 :     StaticBlockObject &blockObj = fp->blockChain();
    1393          246744 :     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          246744 :     JSObject &obj = fp->scopeChain();
    1401          246744 :     if (obj.getProto() == &blockObj)
    1402            1328 :         obj.asClonedBlock().put(cx);
    1403                 : 
    1404          246744 :     fp->setBlockChain(blockObj.enclosingBlock());
    1405          246744 : }
    1406                 : 
    1407                 : inline void *
    1408            6789 : FindNativeCode(VMFrame &f, jsbytecode *target)
    1409                 : {
    1410            6789 :     void* native = f.fp()->script()->nativeCodeForPC(f.fp()->isConstructing(), target);
    1411            6789 :     if (native)
    1412            6789 :         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            6111 : stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
    1430                 : {
    1431            6111 :     jsbytecode *jpc = pc;
    1432            6111 :     JSScript *script = f.fp()->script();
    1433                 : 
    1434                 :     /* This is correct because the compiler adjusts the stack beforehand. */
    1435            6111 :     Value lval = f.regs.sp[-1];
    1436                 : 
    1437            6111 :     if (!lval.isPrimitive())
    1438               0 :         return FindNativeCode(f, pc + GET_JUMP_OFFSET(pc));
    1439                 : 
    1440            6111 :     JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
    1441                 : 
    1442            6111 :     pc += JUMP_OFFSET_LEN;
    1443            6111 :     uint32_t npairs = GET_UINT16(pc);
    1444            6111 :     pc += UINT16_LEN;
    1445                 : 
    1446            6111 :     JS_ASSERT(npairs);
    1447                 : 
    1448            6111 :     if (lval.isString()) {
    1449            5696 :         JSLinearString *str = lval.toString()->ensureLinear(f.cx);
    1450            5696 :         if (!str)
    1451               0 :             THROWV(NULL);
    1452           35885 :         for (uint32_t i = 1; i <= npairs; i++) {
    1453           34397 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1454           34397 :             pc += UINT32_INDEX_LEN;
    1455           34397 :             if (rval.isString()) {
    1456           34397 :                 JSLinearString *rhs = &rval.toString()->asLinear();
    1457           34397 :                 if (rhs == str || EqualStrings(str, rhs))
    1458            4208 :                     return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1459                 :             }
    1460           30189 :             pc += JUMP_OFFSET_LEN;
    1461                 :         }
    1462             415 :     } 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            1310 :         for (uint32_t i = 1; i <= npairs; i++) {
    1473             895 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1474             895 :             pc += UINT32_INDEX_LEN;
    1475             895 :             if (lval == rval)
    1476               0 :                 return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1477             895 :             pc += JUMP_OFFSET_LEN;
    1478                 :         }
    1479                 :     }
    1480                 : 
    1481            1903 :     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            1631 : stubs::DelElem(VMFrame &f)
    1584                 : {
    1585            1631 :     JSContext *cx = f.cx;
    1586                 : 
    1587            1631 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
    1588            1631 :     if (!obj)
    1589               0 :         THROW();
    1590                 : 
    1591            1631 :     const Value &propval = f.regs.sp[-1];
    1592            1631 :     Value &rval = f.regs.sp[-2];
    1593                 : 
    1594            1631 :     if (!obj->deleteByValue(cx, propval, &rval, strict))
    1595               2 :         THROW();
    1596                 : }
    1597                 : 
    1598                 : void JS_FASTCALL
    1599           17662 : stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
    1600                 : {
    1601           17662 :     unsigned attrs = JSPROP_ENUMERATE;
    1602           17662 :     if (!f.fp()->isEvalFrame())
    1603           16912 :         attrs |= JSPROP_PERMANENT;
    1604           17662 :     if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
    1605           16500 :         attrs |= JSPROP_READONLY;
    1606                 : 
    1607           17662 :     JSObject &obj = f.fp()->varObj();
    1608                 : 
    1609           17662 :     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          403280 : stubs::In(VMFrame &f)
    1630                 : {
    1631          403280 :     JSContext *cx = f.cx;
    1632                 : 
    1633          403280 :     const Value &rref = f.regs.sp[-1];
    1634          403280 :     if (!rref.isObject()) {
    1635               7 :         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
    1636               7 :         THROWV(JS_FALSE);
    1637                 :     }
    1638                 : 
    1639          403273 :     JSObject *obj = &rref.toObject();
    1640                 :     jsid id;
    1641          403273 :     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          403273 :     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
    1647               0 :         THROWV(JS_FALSE);
    1648                 : 
    1649          403273 :     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           14553 : stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
    1657                 : {
    1658           14553 :     JS_ASSERT(which == 0 || which == 1);
    1659                 : 
    1660                 :     /* The actual pushed value is at sp[0], fix up the stack. See finishBarrier. */
    1661           14553 :     Value &result = f.regs.sp[-1 - (int)which];
    1662           14553 :     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           14553 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1671           29106 :         AutoEnterTypeInference enter(f.cx);
    1672           14553 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1673                 :     }
    1674                 : 
    1675           14553 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1676           14553 : }
    1677                 : 
    1678                 : void JS_FASTCALL
    1679           13172 : stubs::StubTypeHelper(VMFrame &f, int32_t which)
    1680                 : {
    1681           13172 :     const Value &result = f.regs.sp[which];
    1682                 : 
    1683           13172 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1684           26344 :         AutoEnterTypeInference enter(f.cx);
    1685           13172 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1686                 :     }
    1687                 : 
    1688           13172 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1689           13172 : }
    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            2330 :         for (unsigned i = 0; i < fun->nargs; i++)
    1723            1418 :             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        14122535 : stubs::AssertArgumentTypes(VMFrame &f)
    1737                 : {
    1738        14122535 :     StackFrame *fp = f.fp();
    1739        14122535 :     JSFunction *fun = fp->fun();
    1740        14122535 :     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        14122535 :     if (!fp->isConstructing()) {
    1747        12386317 :         Type type = GetValueType(f.cx, fp->thisValue());
    1748        12386317 :         if (!TypeScript::ThisTypes(script)->hasType(type))
    1749               0 :             TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
    1750                 :     }
    1751                 : 
    1752        38229237 :     for (unsigned i = 0; i < fun->nargs; i++) {
    1753        24106702 :         Type type = GetValueType(f.cx, fp->formalArg(i));
    1754        24106702 :         if (!TypeScript::ArgTypes(script, i)->hasType(type))
    1755               0 :             TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
    1756                 :     }
    1757        14122535 : }
    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          535260 : stubs::FunctionFrameEpilogue(VMFrame &f)
    1818                 : {
    1819          535260 :     f.fp()->functionEpilogue();
    1820          535260 : }
    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