LCOV - code coverage report
Current view: directory - js/src/methodjit - StubCalls.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 837 687 82.1 %
Date: 2012-04-07 Functions: 94 87 92.6 %

       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            1180 : stubs::BindName(VMFrame &f, PropertyName *name)
      85                 : {
      86            1180 :     JSObject *obj = FindIdentifierBase(f.cx, &f.fp()->scopeChain(), name);
      87            1180 :     if (!obj)
      88               0 :         THROW();
      89            1180 :     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           76307 : stubs::SetName(VMFrame &f, PropertyName *name)
     101                 : {
     102           76307 :     JSContext *cx = f.cx;
     103           76307 :     const Value &rval = f.regs.sp[-1];
     104           76307 :     const Value &lval = f.regs.sp[-2];
     105                 : 
     106           76307 :     if (!SetPropertyOperation(cx, f.pc(), lval, rval))
     107              70 :         THROW();
     108                 : 
     109           76237 :     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           47724 : stubs::SetGlobalName(VMFrame &f, PropertyName *name)
     118                 : {
     119           47724 :     SetName<strict>(f, name);
     120           47724 : }
     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          157575 : stubs::Name(VMFrame &f)
     127                 : {
     128                 :     Value rval;
     129          157575 :     if (!NameOperation(f.cx, f.pc(), &rval))
     130            3298 :         THROW();
     131          154277 :     f.regs.sp[0] = rval;
     132                 : }
     133                 : 
     134                 : void JS_FASTCALL
     135          825969 : stubs::GetElem(VMFrame &f)
     136                 : {
     137          825969 :     Value &lref = f.regs.sp[-2];
     138          825969 :     Value &rref = f.regs.sp[-1];
     139          825969 :     Value &rval = f.regs.sp[-2];
     140                 : 
     141          825969 :     if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval))
     142              45 :         THROW();
     143                 : }
     144                 : 
     145                 : template<JSBool strict>
     146                 : void JS_FASTCALL
     147         1842887 : stubs::SetElem(VMFrame &f)
     148                 : {
     149         1842887 :     JSContext *cx = f.cx;
     150         1842887 :     FrameRegs &regs = f.regs;
     151                 : 
     152         1842887 :     Value &objval = regs.sp[-3];
     153         1842887 :     Value &idval  = regs.sp[-2];
     154         1842887 :     Value rval    = regs.sp[-1];
     155                 : 
     156                 :     JSObject *obj;
     157                 :     jsid id;
     158                 : 
     159         1842887 :     obj = ValueToObject(cx, objval);
     160         1842887 :     if (!obj)
     161               7 :         THROW();
     162                 : 
     163         1842880 :     if (!FetchElementId(f.cx, obj, idval, id, &regs.sp[-2]))
     164               0 :         THROW();
     165                 : 
     166         1842880 :     TypeScript::MonitorAssign(cx, obj, id);
     167                 : 
     168                 :     do {
     169         1842880 :         if (obj->isDenseArray() && JSID_IS_INT(id)) {
     170         1026676 :             uint32_t length = obj->getDenseArrayInitializedLength();
     171         1026676 :             int32_t i = JSID_TO_INT(id);
     172         1026676 :             if ((uint32_t)i < length) {
     173           19458 :                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
     174           19410 :                     if (js_PrototypeHasIndexedProperties(cx, obj))
     175               0 :                         break;
     176           19410 :                     if ((uint32_t)i >= obj->getArrayLength())
     177               0 :                         obj->setArrayLength(cx, i + 1);
     178                 :                 }
     179           19458 :                 obj->setDenseArrayElementWithType(cx, i, rval);
     180           19458 :                 goto end_setelem;
     181                 :             } else {
     182         1007218 :                 if (f.script()->hasAnalysis())
     183         1007218 :                     f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
     184                 :             }
     185                 :         }
     186                 :     } while (0);
     187         1823422 :     if (!obj->setGeneric(cx, id, &rval, strict))
     188            2905 :         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         1839975 :     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            1024 : stubs::ImplicitThis(VMFrame &f, PropertyName *name)
     220                 : {
     221                 :     JSObject *obj, *obj2;
     222                 :     JSProperty *prop;
     223            1024 :     if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
     224               0 :         THROW();
     225                 : 
     226            1024 :     if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
     227               0 :         THROW();
     228                 : }
     229                 : 
     230                 : void JS_FASTCALL
     231          407742 : stubs::BitOr(VMFrame &f)
     232                 : {
     233                 :     int32_t i, j;
     234                 : 
     235          407742 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     236              21 :         THROW();
     237                 : 
     238          407721 :     i = i | j;
     239          407721 :     f.regs.sp[-2].setInt32(i);
     240                 : }
     241                 : 
     242                 : void JS_FASTCALL
     243           20783 : stubs::BitXor(VMFrame &f)
     244                 : {
     245                 :     int32_t i, j;
     246                 : 
     247           20783 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     248               0 :         THROW();
     249                 : 
     250           20783 :     i = i ^ j;
     251           20783 :     f.regs.sp[-2].setInt32(i);
     252                 : }
     253                 : 
     254                 : void JS_FASTCALL
     255           64504 : stubs::BitAnd(VMFrame &f)
     256                 : {
     257                 :     int32_t i, j;
     258                 : 
     259           64504 :     if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
     260               0 :         THROW();
     261                 : 
     262           64504 :     i = i & j;
     263           64504 :     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             388 : stubs::Ursh(VMFrame &f)
     303                 : {
     304                 :     uint32_t u;
     305             388 :     if (!ToUint32(f.cx, f.regs.sp[-2], &u))
     306               0 :         THROW();
     307                 :     int32_t j;
     308             388 :     if (!ToInt32(f.cx, f.regs.sp[-1], &j))
     309               0 :         THROW();
     310                 : 
     311             388 :     u >>= (j & 31);
     312                 : 
     313             388 :         if (!f.regs.sp[-2].setNumber(uint32_t(u)))
     314             255 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
     315                 : }
     316                 : 
     317                 : template<JSBool strict>
     318                 : void JS_FASTCALL
     319            1739 : stubs::DefFun(VMFrame &f, JSFunction *fun)
     320                 : {
     321                 :     JSObject *obj2;
     322                 : 
     323            1739 :     JSContext *cx = f.cx;
     324            1739 :     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            1739 :     JSObject *obj = fun;
     333                 : 
     334            1739 :     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             865 :         obj2 = &fp->scopeChain();
     341                 :     } else {
     342             874 :         obj2 = GetScopeChain(cx, fp);
     343             874 :         if (!obj2)
     344               0 :             THROW();
     345                 :     }
     346                 : 
     347                 :     /*
     348                 :      * If static link is not current scope, clone fun's object to link to the
     349                 :      * current scope via parent. We do this to enable sharing of compiled
     350                 :      * functions among multiple equivalent scopes, amortizing the cost of
     351                 :      * compilation over a number of executions.  Examples include XUL scripts
     352                 :      * and event handlers shared among Firefox or other Mozilla app chrome
     353                 :      * windows, and user-defined JS functions precompiled and then shared among
     354                 :      * requests in server-side JS.
     355                 :      */
     356            1739 :     if (obj->toFunction()->environment() != obj2) {
     357             306 :         obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
     358             306 :         if (!obj)
     359               0 :             THROW();
     360             306 :         JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
     361                 :     }
     362                 : 
     363                 :     /*
     364                 :      * ECMA requires functions defined when entering Eval code to be
     365                 :      * impermanent.
     366                 :      */
     367                 :     unsigned attrs = fp->isEvalFrame()
     368                 :                   ? JSPROP_ENUMERATE
     369            1739 :                   : JSPROP_ENUMERATE | JSPROP_PERMANENT;
     370                 : 
     371                 :     /*
     372                 :      * We define the function as a property of the variable object and not the
     373                 :      * current scope chain even for the case of function expression statements
     374                 :      * and functions defined by eval inside let or with blocks.
     375                 :      */
     376            1739 :     JSObject *parent = &fp->varObj();
     377                 : 
     378                 :     /* ES5 10.5 (NB: with subsequent errata). */
     379            1739 :     PropertyName *name = fun->atom->asPropertyName();
     380            1739 :     JSProperty *prop = NULL;
     381                 :     JSObject *pobj;
     382            1739 :     if (!parent->lookupProperty(cx, name, &pobj, &prop))
     383               0 :         THROW();
     384                 : 
     385            1739 :     Value rval = ObjectValue(*obj);
     386                 : 
     387                 :     do {
     388                 :         /* Steps 5d, 5f. */
     389            1739 :         if (!prop || pobj != parent) {
     390            1114 :             if (!parent->defineProperty(cx, name, rval,
     391                 :                                         JS_PropertyStub, JS_StrictPropertyStub, attrs))
     392                 :             {
     393               0 :                 THROW();
     394                 :             }
     395            1114 :             break;
     396                 :         }
     397                 : 
     398                 :         /* Step 5e. */
     399             625 :         JS_ASSERT(parent->isNative());
     400             625 :         Shape *shape = reinterpret_cast<Shape *>(prop);
     401             625 :         if (parent->isGlobal()) {
     402             475 :             if (shape->configurable()) {
     403             130 :                 if (!parent->defineProperty(cx, name, rval,
     404                 :                                             JS_PropertyStub, JS_StrictPropertyStub, attrs))
     405                 :                 {
     406               0 :                     THROW();
     407                 :                 }
     408             130 :                 break;
     409                 :             }
     410                 : 
     411             345 :             if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
     412               8 :                 JSAutoByteString bytes;
     413               4 :                 if (js_AtomToPrintableString(cx, name, &bytes)) {
     414               4 :                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
     415                 :                                          JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
     416                 :                 }
     417               4 :                 THROW();
     418                 :             }
     419                 :         }
     420                 : 
     421                 :         /*
     422                 :          * Non-global properties, and global properties which we aren't simply
     423                 :          * redefining, must be set.  First, this preserves their attributes.
     424                 :          * Second, this will produce warnings and/or errors as necessary if the
     425                 :          * specified Call object property is not writable (const).
     426                 :          */
     427                 : 
     428                 :         /* Step 5f. */
     429             491 :         if (!parent->setProperty(cx, name, &rval, strict))
     430               0 :             THROW();
     431                 :     } while (false);
     432                 : }
     433                 : 
     434                 : template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
     435                 : template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
     436                 : 
     437                 : #define RELATIONAL(OP)                                                        \
     438                 :     JS_BEGIN_MACRO                                                            \
     439                 :         JSContext *cx = f.cx;                                                 \
     440                 :         FrameRegs &regs = f.regs;                                             \
     441                 :         Value &rval = regs.sp[-1];                                            \
     442                 :         Value &lval = regs.sp[-2];                                            \
     443                 :         bool cond;                                                            \
     444                 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                           \
     445                 :             THROWV(JS_FALSE);                                                 \
     446                 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                           \
     447                 :             THROWV(JS_FALSE);                                                 \
     448                 :         if (lval.isString() && rval.isString()) {                             \
     449                 :             JSString *l = lval.toString(), *r = rval.toString();              \
     450                 :             int32_t cmp;                                                      \
     451                 :             if (!CompareStrings(cx, l, r, &cmp))                              \
     452                 :                 THROWV(JS_FALSE);                                             \
     453                 :             cond = cmp OP 0;                                                  \
     454                 :         } else {                                                              \
     455                 :             double l, r;                                                      \
     456                 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))           \
     457                 :                 THROWV(JS_FALSE);                                             \
     458                 :             cond = (l OP r);                                                  \
     459                 :         }                                                                     \
     460                 :         regs.sp[-2].setBoolean(cond);                                         \
     461                 :         return cond;                                                          \
     462                 :     JS_END_MACRO
     463                 : 
     464                 : JSBool JS_FASTCALL
     465          402239 : stubs::LessThan(VMFrame &f)
     466                 : {
     467          402239 :     RELATIONAL(<);
     468                 : }
     469                 : 
     470                 : JSBool JS_FASTCALL
     471           17849 : stubs::LessEqual(VMFrame &f)
     472                 : {
     473           17849 :     RELATIONAL(<=);
     474                 : }
     475                 : 
     476                 : JSBool JS_FASTCALL
     477          154450 : stubs::GreaterThan(VMFrame &f)
     478                 : {
     479          154450 :     RELATIONAL(>);
     480                 : }
     481                 : 
     482                 : JSBool JS_FASTCALL
     483           17849 : stubs::GreaterEqual(VMFrame &f)
     484                 : {
     485           17849 :     RELATIONAL(>=);
     486                 : }
     487                 : 
     488                 : JSBool JS_FASTCALL
     489         3927492 : stubs::ValueToBoolean(VMFrame &f)
     490                 : {
     491         3927492 :     return js_ValueToBoolean(f.regs.sp[-1]);
     492                 : }
     493                 : 
     494                 : void JS_FASTCALL
     495          117304 : stubs::Not(VMFrame &f)
     496                 : {
     497          117304 :     JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
     498          117304 :     f.regs.sp[-1].setBoolean(b);
     499          117304 : }
     500                 : 
     501                 : template <bool EQ>
     502                 : static inline bool
     503          380895 : StubEqualityOp(VMFrame &f)
     504                 : {
     505          380895 :     JSContext *cx = f.cx;
     506          380895 :     FrameRegs &regs = f.regs;
     507                 : 
     508          380895 :     Value rval = regs.sp[-1];
     509          380895 :     Value lval = regs.sp[-2];
     510                 : 
     511                 :     bool cond;
     512                 : 
     513                 :     /* The string==string case is easily the hottest;  try it first. */
     514          380895 :     if (lval.isString() && rval.isString()) {
     515          111211 :         JSString *l = lval.toString();
     516          111211 :         JSString *r = rval.toString();
     517                 :         bool equal;
     518          111211 :         if (!EqualStrings(cx, l, r, &equal))
     519               0 :             return false;
     520          111211 :         cond = equal == EQ;
     521                 :     } else
     522                 : #if JS_HAS_XML_SUPPORT
     523          269684 :     if ((lval.isObject() && lval.toObject().isXML()) ||
     524                 :         (rval.isObject() && rval.toObject().isXML()))
     525                 :     {
     526                 :         JSBool equal;
     527               0 :         if (!js_TestXMLEquality(cx, lval, rval, &equal))
     528               0 :             return false;
     529               0 :         cond = !!equal == EQ;
     530                 :     } else
     531                 : #endif
     532                 : 
     533          269684 :     if (SameType(lval, rval)) {
     534          195312 :         JS_ASSERT(!lval.isString());    /* this case is handled above */
     535          195312 :         if (lval.isDouble()) {
     536          123658 :             double l = lval.toDouble();
     537          123658 :             double r = rval.toDouble();
     538                 :             if (EQ)
     539          115481 :                 cond = (l == r);
     540                 :             else
     541            8177 :                 cond = (l != r);
     542           71654 :         } else if (lval.isObject()) {
     543           31564 :             JSObject *l = &lval.toObject(), *r = &rval.toObject();
     544           31564 :             if (JSEqualityOp eq = l->getClass()->ext.equality) {
     545                 :                 JSBool equal;
     546               0 :                 if (!eq(cx, l, &rval, &equal))
     547               0 :                     return false;
     548               0 :                 cond = !!equal == EQ;
     549                 :             } else {
     550           31564 :                 cond = (l == r) == EQ;
     551                 :             }
     552           40090 :         } else if (lval.isNullOrUndefined()) {
     553           32936 :             cond = EQ;
     554                 :         } else {
     555            7154 :             cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
     556                 :         }
     557                 :     } else {
     558           74372 :         if (lval.isNullOrUndefined()) {
     559           15034 :             cond = rval.isNullOrUndefined() == EQ;
     560           59338 :         } else if (rval.isNullOrUndefined()) {
     561           13139 :             cond = !EQ;
     562                 :         } else {
     563           46199 :             if (!ToPrimitive(cx, &lval))
     564               4 :                 return false;
     565           46195 :             if (!ToPrimitive(cx, &rval))
     566               0 :                 return false;
     567                 : 
     568                 :             /*
     569                 :              * The string==string case is repeated because ToPrimitive can
     570                 :              * convert lval/rval to strings.
     571                 :              */
     572           46195 :             if (lval.isString() && rval.isString()) {
     573            2632 :                 JSString *l = lval.toString();
     574            2632 :                 JSString *r = rval.toString();
     575                 :                 bool equal;
     576            2632 :                 if (!EqualStrings(cx, l, r, &equal))
     577               0 :                     return false;
     578            2632 :                 cond = equal == EQ;
     579                 :             } else {
     580                 :                 double l, r;
     581           43563 :                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     582               0 :                     return false;
     583                 : 
     584                 :                 if (EQ)
     585           27989 :                     cond = (l == r);
     586                 :                 else
     587           15574 :                     cond = (l != r);
     588                 :             }
     589                 :         }
     590                 :     }
     591                 : 
     592          380891 :     regs.sp[-2].setBoolean(cond);
     593          380891 :     return true;
     594                 : }
     595                 : 
     596                 : JSBool JS_FASTCALL
     597          260674 : stubs::Equal(VMFrame &f)
     598                 : {
     599          260674 :     if (!StubEqualityOp<true>(f))
     600               4 :         THROWV(JS_FALSE);
     601          260670 :     return f.regs.sp[-2].toBoolean();
     602                 : }
     603                 : 
     604                 : JSBool JS_FASTCALL
     605          120221 : stubs::NotEqual(VMFrame &f)
     606                 : {
     607          120221 :     if (!StubEqualityOp<false>(f))
     608               0 :         THROWV(JS_FALSE);
     609          120221 :     return f.regs.sp[-2].toBoolean();
     610                 : }
     611                 : 
     612                 : void JS_FASTCALL
     613        15707038 : stubs::Add(VMFrame &f)
     614                 : {
     615        15707038 :     JSContext *cx = f.cx;
     616        15707038 :     FrameRegs &regs = f.regs;
     617        15707038 :     Value rval = regs.sp[-1];
     618        15707038 :     Value lval = regs.sp[-2];
     619                 : 
     620                 :     /* The string + string case is easily the hottest;  try it first. */
     621        15707038 :     bool lIsString = lval.isString();
     622        15707038 :     bool rIsString = rval.isString();
     623                 :     JSString *lstr, *rstr;
     624        15707038 :     if (lIsString && rIsString) {
     625        12739443 :         lstr = lval.toString();
     626        12739443 :         rstr = rval.toString();
     627        12739443 :         goto string_concat;
     628                 : 
     629                 :     } else
     630                 : #if JS_HAS_XML_SUPPORT
     631         2967595 :     if (lval.isObject() && lval.toObject().isXML() &&
     632               0 :         rval.isObject() && rval.toObject().isXML()) {
     633               0 :         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
     634               0 :             THROW();
     635               0 :         regs.sp[-2] = rval;
     636               0 :         regs.sp--;
     637               0 :         TypeScript::MonitorUnknown(cx, f.script(), f.pc());
     638                 :     } else
     639                 : #endif
     640                 :     {
     641         2967595 :         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
     642         2967595 :         if (!ToPrimitive(f.cx, &lval))
     643              16 :             THROW();
     644         2967579 :         if (!ToPrimitive(f.cx, &rval))
     645              13 :             THROW();
     646         2967566 :         if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
     647         2687059 :             if (lIsString) {
     648         2184360 :                 lstr = lval.toString();
     649                 :             } else {
     650          502699 :                 lstr = ToString(cx, lval);
     651          502699 :                 if (!lstr)
     652               0 :                     THROW();
     653          502699 :                 regs.sp[-2].setString(lstr);
     654                 :             }
     655         2687059 :             if (rIsString) {
     656          504101 :                 rstr = rval.toString();
     657                 :             } else {
     658         2182958 :                 rstr = ToString(cx, rval);
     659         2182958 :                 if (!rstr)
     660               0 :                     THROW();
     661         2182958 :                 regs.sp[-1].setString(rstr);
     662                 :             }
     663         2687059 :             if (lIsObject || rIsObject)
     664          391309 :                 TypeScript::MonitorString(cx, f.script(), f.pc());
     665         2687059 :             goto string_concat;
     666                 : 
     667                 :         } else {
     668                 :             double l, r;
     669          280507 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     670               0 :                 THROW();
     671          280507 :             l += r;
     672          837970 :             if (!regs.sp[-2].setNumber(l) &&
     673          557463 :                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
     674          278020 :                 TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     675                 :             }
     676                 :         }
     677                 :     }
     678          280507 :     return;
     679                 : 
     680                 :   string_concat:
     681        15426502 :     JSString *str = js_ConcatStrings(cx, lstr, rstr);
     682        15426502 :     if (!str)
     683               5 :         THROW();
     684        15426497 :     regs.sp[-2].setString(str);
     685        15426497 :     regs.sp--;
     686                 : }
     687                 : 
     688                 : 
     689                 : void JS_FASTCALL
     690             163 : stubs::Sub(VMFrame &f)
     691                 : {
     692             163 :     JSContext *cx = f.cx;
     693             163 :     FrameRegs &regs = f.regs;
     694                 :     double d1, d2;
     695             163 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     696               0 :         THROW();
     697             163 :     double d = d1 - d2;
     698             163 :     if (!regs.sp[-2].setNumber(d))
     699             109 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     700                 : }
     701                 : 
     702                 : void JS_FASTCALL
     703           78337 : stubs::Mul(VMFrame &f)
     704                 : {
     705           78337 :     JSContext *cx = f.cx;
     706           78337 :     FrameRegs &regs = f.regs;
     707                 :     double d1, d2;
     708           78337 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     709               0 :         THROW();
     710           78337 :     double d = d1 * d2;
     711           78337 :     if (!regs.sp[-2].setNumber(d))
     712           78199 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     713                 : }
     714                 : 
     715                 : void JS_FASTCALL
     716             730 : stubs::Div(VMFrame &f)
     717                 : {
     718             730 :     JSContext *cx = f.cx;
     719             730 :     JSRuntime *rt = cx->runtime;
     720             730 :     FrameRegs &regs = f.regs;
     721                 : 
     722                 :     double d1, d2;
     723             730 :     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     724               0 :         THROW();
     725             730 :     if (d2 == 0) {
     726                 :         const Value *vp;
     727                 : #ifdef XP_WIN
     728                 :         /* XXX MSVC miscompiles such that (NaN == 0) */
     729                 :         if (JSDOUBLE_IS_NaN(d2))
     730                 :             vp = &rt->NaNValue;
     731                 :         else
     732                 : #endif
     733               2 :         if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
     734               2 :             vp = &rt->NaNValue;
     735               0 :         else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
     736               0 :             vp = &rt->negativeInfinityValue;
     737                 :         else
     738               0 :             vp = &rt->positiveInfinityValue;
     739               2 :         regs.sp[-2] = *vp;
     740               2 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     741                 :     } else {
     742             728 :         d1 /= d2;
     743             728 :         if (!regs.sp[-2].setNumber(d1))
     744              22 :             TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     745                 :     }
     746                 : }
     747                 : 
     748                 : void JS_FASTCALL
     749           30492 : stubs::Mod(VMFrame &f)
     750                 : {
     751           30492 :     JSContext *cx = f.cx;
     752           30492 :     FrameRegs &regs = f.regs;
     753                 : 
     754           30492 :     Value &lref = regs.sp[-2];
     755           30492 :     Value &rref = regs.sp[-1];
     756                 :     int32_t l, r;
     757           30492 :     if (lref.isInt32() && rref.isInt32() &&
     758                 :         (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
     759               0 :         int32_t mod = l % r;
     760               0 :         regs.sp[-2].setInt32(mod);
     761                 :     } else {
     762                 :         double d1, d2;
     763           30492 :         if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
     764               0 :             THROW();
     765           30492 :         if (d2 == 0) {
     766              97 :             regs.sp[-2].setDouble(js_NaN);
     767                 :         } else {
     768           30395 :             d1 = js_fmod(d1, d2);
     769           30395 :             regs.sp[-2].setDouble(d1);
     770                 :         }
     771           30492 :         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     772                 :     }
     773                 : }
     774                 : 
     775                 : void JS_FASTCALL
     776            3382 : stubs::DebuggerStatement(VMFrame &f, jsbytecode *pc)
     777                 : {
     778            3382 :     JSDebuggerHandler handler = f.cx->runtime->debugHooks.debuggerHandler;
     779            3382 :     if (handler || !f.cx->compartment->getDebuggees().empty()) {
     780            3352 :         JSTrapStatus st = JSTRAP_CONTINUE;
     781                 :         Value rval;
     782            3352 :         if (handler)
     783               8 :             st = handler(f.cx, f.script(), pc, &rval, f.cx->runtime->debugHooks.debuggerHandlerData);
     784            3352 :         if (st == JSTRAP_CONTINUE)
     785            3348 :             st = Debugger::onDebuggerStatement(f.cx, &rval);
     786                 : 
     787            3352 :         switch (st) {
     788                 :           case JSTRAP_THROW:
     789              60 :             f.cx->setPendingException(rval);
     790              60 :             THROW();
     791                 : 
     792                 :           case JSTRAP_RETURN:
     793             112 :             f.cx->clearPendingException();
     794             112 :             f.cx->fp()->setReturnValue(rval);
     795             112 :             *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
     796             112 :             break;
     797                 : 
     798                 :           case JSTRAP_ERROR:
     799              80 :             f.cx->clearPendingException();
     800              80 :             THROW();
     801                 : 
     802                 :           default:
     803            3100 :             break;
     804                 :         }
     805                 :     }
     806                 : }
     807                 : 
     808                 : void JS_FASTCALL
     809             354 : stubs::Interrupt(VMFrame &f, jsbytecode *pc)
     810                 : {
     811             354 :     gc::MaybeVerifyBarriers(f.cx);
     812                 : 
     813             354 :     if (!js_HandleExecutionInterrupt(f.cx))
     814               0 :         THROW();
     815                 : }
     816                 : 
     817                 : void JS_FASTCALL
     818              93 : stubs::RecompileForInline(VMFrame &f)
     819                 : {
     820              93 :     ExpandInlineFrames(f.cx->compartment);
     821                 :     Recompiler::clearStackReferencesAndChunk(f.cx->runtime->defaultFreeOp(), f.script(), f.jit(),
     822              93 :                                              f.chunkIndex(), /* resetUses = */ false);
     823              93 : }
     824                 : 
     825                 : void JS_FASTCALL
     826             594 : stubs::Trap(VMFrame &f, uint32_t trapTypes)
     827                 : {
     828                 :     Value rval;
     829                 : 
     830                 :     /*
     831                 :      * Trap may be called for a single-step interrupt trap and/or a
     832                 :      * regular trap. Try the single-step first, and if it lets control
     833                 :      * flow through or does not exist, do the regular trap.
     834                 :      */
     835             594 :     JSTrapStatus result = JSTRAP_CONTINUE;
     836             594 :     if (trapTypes & JSTRAP_SINGLESTEP) {
     837                 :         /*
     838                 :          * single step mode may be paused without recompiling by
     839                 :          * setting the interruptHook to NULL.
     840                 :          */
     841             299 :         JSInterruptHook hook = f.cx->runtime->debugHooks.interruptHook;
     842             299 :         if (hook)
     843               0 :             result = hook(f.cx, f.script(), f.pc(), &rval, f.cx->runtime->debugHooks.interruptHookData);
     844                 : 
     845             299 :         if (result == JSTRAP_CONTINUE)
     846             299 :             result = Debugger::onSingleStep(f.cx, &rval);
     847                 :     }
     848                 : 
     849             594 :     if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP))
     850             295 :         result = Debugger::onTrap(f.cx, &rval);
     851                 : 
     852             594 :     switch (result) {
     853                 :       case JSTRAP_THROW:
     854               0 :         f.cx->setPendingException(rval);
     855               0 :         THROW();
     856                 : 
     857                 :       case JSTRAP_RETURN:
     858              24 :         f.cx->clearPendingException();
     859              24 :         f.cx->fp()->setReturnValue(rval);
     860              24 :         *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
     861              24 :         break;
     862                 : 
     863                 :       case JSTRAP_ERROR:
     864               4 :         f.cx->clearPendingException();
     865               4 :         THROW();
     866                 : 
     867                 :       default:
     868             566 :         break;
     869                 :     }
     870                 : }
     871                 : 
     872                 : void JS_FASTCALL
     873           40573 : stubs::This(VMFrame &f)
     874                 : {
     875                 :     /*
     876                 :      * We can't yet inline scripts which need to compute their 'this' object
     877                 :      * from a primitive; the frame we are computing 'this' for does not exist yet.
     878                 :      */
     879           40573 :     if (f.regs.inlined()) {
     880               0 :         f.script()->uninlineable = true;
     881               0 :         MarkTypeObjectFlags(f.cx, &f.fp()->callee(), OBJECT_FLAG_UNINLINEABLE);
     882                 :     }
     883                 : 
     884           40573 :     if (!ComputeThis(f.cx, f.fp()))
     885               0 :         THROW();
     886           40573 :     f.regs.sp[-1] = f.fp()->thisValue();
     887                 : }
     888                 : 
     889                 : void JS_FASTCALL
     890            1905 : stubs::Neg(VMFrame &f)
     891                 : {
     892                 :     double d;
     893            1905 :     if (!ToNumber(f.cx, f.regs.sp[-1], &d))
     894               0 :         THROW();
     895            1905 :     d = -d;
     896            1905 :     if (!f.regs.sp[-1].setNumber(d))
     897            1845 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
     898                 : }
     899                 : 
     900                 : void JS_FASTCALL
     901         1210617 : stubs::NewInitArray(VMFrame &f, uint32_t count)
     902                 : {
     903         1210617 :     JSObject *obj = NewDenseAllocatedArray(f.cx, count);
     904         1210617 :     if (!obj)
     905               0 :         THROW();
     906                 : 
     907         1210617 :     TypeObject *type = (TypeObject *) f.scratch;
     908         1210617 :     if (type) {
     909         1210421 :         obj->setType(type);
     910                 :     } else {
     911             196 :         if (!SetInitializerObjectType(f.cx, f.script(), f.pc(), obj))
     912               0 :             THROW();
     913                 :     }
     914                 : 
     915         1210617 :     f.regs.sp[0].setObject(*obj);
     916                 : }
     917                 : 
     918                 : void JS_FASTCALL
     919         1552128 : stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
     920                 : {
     921         1552128 :     JSContext *cx = f.cx;
     922         1552128 :     TypeObject *type = (TypeObject *) f.scratch;
     923                 : 
     924                 :     JSObject *obj;
     925                 : 
     926         1552128 :     if (baseobj) {
     927         1551601 :         obj = CopyInitializerObject(cx, baseobj);
     928                 :     } else {
     929             527 :         gc::AllocKind kind = GuessObjectGCKind(0);
     930             527 :         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     931                 :     }
     932                 : 
     933         1552128 :     if (!obj)
     934               0 :         THROW();
     935                 : 
     936         1552128 :     if (type) {
     937         1551724 :         obj->setType(type);
     938                 :     } else {
     939             404 :         if (!SetInitializerObjectType(cx, f.script(), f.pc(), obj))
     940               0 :             THROW();
     941                 :     }
     942                 : 
     943         1552128 :     f.regs.sp[0].setObject(*obj);
     944                 : }
     945                 : 
     946                 : void JS_FASTCALL
     947             638 : stubs::InitElem(VMFrame &f, uint32_t last)
     948                 : {
     949             638 :     JSContext *cx = f.cx;
     950             638 :     FrameRegs &regs = f.regs;
     951                 : 
     952                 :     /* Pop the element's value into rval. */
     953             638 :     JS_ASSERT(regs.sp - f.fp()->base() >= 3);
     954             638 :     const Value &rref = regs.sp[-1];
     955                 : 
     956                 :     /* Find the object being initialized at top of stack. */
     957             638 :     const Value &lref = regs.sp[-3];
     958             638 :     JS_ASSERT(lref.isObject());
     959             638 :     JSObject *obj = &lref.toObject();
     960                 : 
     961                 :     /* Fetch id now that we have obj. */
     962                 :     jsid id;
     963             638 :     const Value &idval = regs.sp[-2];
     964             638 :     if (!FetchElementId(f.cx, obj, idval, id, &regs.sp[-2]))
     965               0 :         THROW();
     966                 : 
     967                 :     /*
     968                 :      * If rref is a hole, do not call JSObject::defineProperty. In this case,
     969                 :      * obj must be an array, so if the current op is the last element
     970                 :      * initialiser, set the array length to one greater than id.
     971                 :      */
     972             638 :     if (rref.isMagic(JS_ARRAY_HOLE)) {
     973               0 :         JS_ASSERT(obj->isArray());
     974               0 :         JS_ASSERT(JSID_IS_INT(id));
     975               0 :         JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
     976               0 :         if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
     977               0 :             THROW();
     978                 :     } else {
     979             638 :         if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
     980               0 :             THROW();
     981                 :     }
     982                 : }
     983                 : 
     984                 : void JS_FASTCALL
     985          107872 : stubs::RegExp(VMFrame &f, JSObject *regex)
     986                 : {
     987                 :     /*
     988                 :      * Push a regexp object cloned from the regexp literal object mapped by the
     989                 :      * bytecode at pc.
     990                 :      */
     991          107872 :     JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
     992          107872 :     if (!proto)
     993               0 :         THROW();
     994          107872 :     JS_ASSERT(proto);
     995          107872 :     JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
     996          107872 :     if (!obj)
     997               0 :         THROW();
     998          107872 :     f.regs.sp[0].setObject(*obj);
     999                 : }
    1000                 : 
    1001                 : JSObject * JS_FASTCALL
    1002          733251 : stubs::Lambda(VMFrame &f, JSFunction *fun)
    1003                 : {
    1004                 :     JSObject *parent;
    1005          733251 :     if (fun->isNullClosure()) {
    1006          214137 :         parent = &f.fp()->scopeChain();
    1007                 :     } else {
    1008          519114 :         parent = GetScopeChain(f.cx, f.fp());
    1009          519114 :         if (!parent)
    1010               0 :             THROWV(NULL);
    1011                 :     }
    1012                 : 
    1013          733251 :     JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
    1014          733251 :     if (!obj)
    1015               0 :         THROWV(NULL);
    1016                 : 
    1017          733251 :     JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
    1018          733251 :     return obj;
    1019                 : }
    1020                 : 
    1021                 : void JS_FASTCALL
    1022          430799 : stubs::GetProp(VMFrame &f, PropertyName *name)
    1023                 : {
    1024          430799 :     JSContext *cx = f.cx;
    1025          430799 :     FrameRegs &regs = f.regs;
    1026                 : 
    1027                 :     Value rval;
    1028          430799 :     if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval))
    1029              19 :         THROW();
    1030                 : 
    1031          430780 :     regs.sp[-1] = rval;
    1032                 : }
    1033                 : 
    1034                 : void JS_FASTCALL
    1035               0 : stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
    1036                 : {
    1037               0 :     JSContext *cx = f.cx;
    1038               0 :     FrameRegs &regs = f.regs;
    1039                 : 
    1040               0 :     const Value &lval = f.regs.sp[-1];
    1041                 : 
    1042                 :     // Uncached lookups are only used for .prototype accesses at the start of constructors.
    1043               0 :     JS_ASSERT(lval.isObject());
    1044               0 :     JS_ASSERT(name == cx->runtime->atomState.classPrototypeAtom);
    1045                 : 
    1046               0 :     JSObject *obj = &lval.toObject();
    1047                 : 
    1048                 :     Value rval;
    1049               0 :     if (!obj->getProperty(cx, name, &rval))
    1050               0 :         THROW();
    1051                 : 
    1052               0 :     regs.sp[-1] = rval;
    1053                 : }
    1054                 : 
    1055                 : void JS_FASTCALL
    1056          301557 : stubs::Iter(VMFrame &f, uint32_t flags)
    1057                 : {
    1058          301557 :     if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
    1059              57 :         THROW();
    1060          301500 :     JS_ASSERT(!f.regs.sp[-1].isPrimitive());
    1061                 : }
    1062                 : 
    1063                 : static void
    1064            1541 : InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
    1065                 : {
    1066            1541 :     JSContext *cx = f.cx;
    1067            1541 :     FrameRegs &regs = f.regs;
    1068                 : 
    1069                 :     /* Load the property's initial value into rval. */
    1070            1541 :     JS_ASSERT(regs.sp - f.fp()->base() >= 2);
    1071                 :     Value rval;
    1072            1541 :     rval = regs.sp[-1];
    1073                 : 
    1074                 :     /* Load the object being initialized into lval/obj. */
    1075            1541 :     JSObject *obj = &regs.sp[-2].toObject();
    1076            1541 :     JS_ASSERT(obj->isNative());
    1077                 : 
    1078                 :     /* Get the immediate property name into id. */
    1079            1541 :     jsid id = ATOM_TO_JSID(name);
    1080                 : 
    1081            3082 :     if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
    1082              61 :         ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, false)
    1083                 :         : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
    1084            1480 :                                 JSPROP_ENUMERATE, 0, 0, 0)) {
    1085               0 :         THROW();
    1086                 :     }
    1087                 : }
    1088                 : 
    1089                 : void JS_FASTCALL
    1090            1541 : stubs::InitProp(VMFrame &f, PropertyName *name)
    1091                 : {
    1092            1541 :     InitPropOrMethod(f, name, JSOP_INITPROP);
    1093            1541 : }
    1094                 : 
    1095                 : void JS_FASTCALL
    1096         9307099 : stubs::IterNext(VMFrame &f, int32_t offset)
    1097                 : {
    1098         9307099 :     JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
    1099         9307099 :     JS_ASSERT(f.regs.sp[-offset].isObject());
    1100                 : 
    1101         9307099 :     JSObject *iterobj = &f.regs.sp[-offset].toObject();
    1102         9307099 :     f.regs.sp[0].setNull();
    1103         9307099 :     f.regs.sp++;
    1104         9307099 :     if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
    1105               0 :         THROW();
    1106                 : }
    1107                 : 
    1108                 : JSBool JS_FASTCALL
    1109         9420833 : stubs::IterMore(VMFrame &f)
    1110                 : {
    1111         9420833 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1112         9420833 :     JS_ASSERT(f.regs.sp[-1].isObject());
    1113                 : 
    1114                 :     Value v;
    1115         9420833 :     JSObject *iterobj = &f.regs.sp[-1].toObject();
    1116         9420833 :     if (!js_IteratorMore(f.cx, iterobj, &v))
    1117              14 :         THROWV(JS_FALSE);
    1118                 : 
    1119         9420819 :     return v.toBoolean();
    1120                 : }
    1121                 : 
    1122                 : void JS_FASTCALL
    1123             917 : stubs::EndIter(VMFrame &f)
    1124                 : {
    1125             917 :     JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
    1126             917 :     if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
    1127               0 :         THROW();
    1128                 : }
    1129                 : 
    1130                 : JSString * JS_FASTCALL
    1131           65632 : stubs::TypeOf(VMFrame &f)
    1132                 : {
    1133           65632 :     const Value &ref = f.regs.sp[-1];
    1134           65632 :     JSType type = JS_TypeOfValue(f.cx, ref);
    1135           65632 :     return f.cx->runtime->atomState.typeAtoms[type];
    1136                 : }
    1137                 : 
    1138                 : void JS_FASTCALL
    1139          701110 : stubs::StrictEq(VMFrame &f)
    1140                 : {
    1141          701110 :     const Value &rhs = f.regs.sp[-1];
    1142          701110 :     const Value &lhs = f.regs.sp[-2];
    1143                 :     bool equal;
    1144          701110 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1145               0 :         THROW();
    1146          701110 :     f.regs.sp--;
    1147          701110 :     f.regs.sp[-1].setBoolean(equal == JS_TRUE);
    1148                 : }
    1149                 : 
    1150                 : void JS_FASTCALL
    1151          236164 : stubs::StrictNe(VMFrame &f)
    1152                 : {
    1153          236164 :     const Value &rhs = f.regs.sp[-1];
    1154          236164 :     const Value &lhs = f.regs.sp[-2];
    1155                 :     bool equal;
    1156          236164 :     if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
    1157               0 :         THROW();
    1158          236164 :     f.regs.sp--;
    1159          236164 :     f.regs.sp[-1].setBoolean(equal != JS_TRUE);
    1160                 : }
    1161                 : 
    1162                 : void JS_FASTCALL
    1163             501 : stubs::Throw(VMFrame &f)
    1164                 : {
    1165             501 :     JSContext *cx = f.cx;
    1166                 : 
    1167             501 :     JS_ASSERT(!cx->isExceptionPending());
    1168             501 :     cx->setPendingException(f.regs.sp[-1]);
    1169             501 :     THROW();
    1170                 : }
    1171                 : 
    1172                 : void JS_FASTCALL
    1173          302545 : stubs::Arguments(VMFrame &f)
    1174                 : {
    1175          302545 :     if (!f.fp()->hasArgsObj()) {
    1176                 :         /*
    1177                 :          * This case occurs when checkCallApplySpeculation detects that
    1178                 :          * 'f.apply' is not actually js_fun_apply. In this case, we need to
    1179                 :          * report the mis-speculation which will bail
    1180                 :          */
    1181               1 :         if (!f.fp()->script()->applySpeculationFailed(f.cx))
    1182               0 :             THROW();
    1183                 :     }
    1184          302545 :     f.regs.sp[0] = ObjectValue(f.fp()->argsObj());
    1185                 : }
    1186                 : 
    1187                 : JSBool JS_FASTCALL
    1188           40420 : stubs::InstanceOf(VMFrame &f)
    1189                 : {
    1190           40420 :     JSContext *cx = f.cx;
    1191           40420 :     FrameRegs &regs = f.regs;
    1192                 : 
    1193           40420 :     const Value &rref = regs.sp[-1];
    1194           40420 :     if (rref.isPrimitive()) {
    1195                 :         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
    1196               0 :                             -1, rref, NULL);
    1197               0 :         THROWV(JS_FALSE);
    1198                 :     }
    1199           40420 :     JSObject *obj = &rref.toObject();
    1200           40420 :     const Value &lref = regs.sp[-2];
    1201           40420 :     JSBool cond = JS_FALSE;
    1202           40420 :     if (!HasInstance(cx, obj, &lref, &cond))
    1203               6 :         THROWV(JS_FALSE);
    1204           40414 :     f.regs.sp[-2].setBoolean(cond);
    1205           40414 :     return cond;
    1206                 : }
    1207                 : 
    1208                 : void JS_FASTCALL
    1209               2 : stubs::FastInstanceOf(VMFrame &f)
    1210                 : {
    1211               2 :     const Value &lref = f.regs.sp[-1];
    1212                 : 
    1213               2 :     if (lref.isPrimitive()) {
    1214                 :         /*
    1215                 :          * Throw a runtime error if instanceof is called on a function that
    1216                 :          * has a non-object as its .prototype value.
    1217                 :          */
    1218               2 :         js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
    1219               2 :         THROW();
    1220                 :     }
    1221                 : 
    1222               0 :     f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
    1223                 : }
    1224                 : 
    1225                 : void JS_FASTCALL
    1226           32163 : stubs::EnterBlock(VMFrame &f, JSObject *obj)
    1227                 : {
    1228           32163 :     FrameRegs &regs = f.regs;
    1229           32163 :     StackFrame *fp = f.fp();
    1230           32163 :     StaticBlockObject &blockObj = obj->asStaticBlock();
    1231                 : 
    1232           32163 :     JS_ASSERT(!f.regs.inlined());
    1233                 : 
    1234           32163 :     if (*regs.pc == JSOP_ENTERBLOCK) {
    1235           29096 :         JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp);
    1236           29096 :         Value *vp = regs.sp + blockObj.slotCount();
    1237           29096 :         JS_ASSERT(regs.sp < vp);
    1238           29096 :         JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
    1239           29096 :         SetValueRangeToUndefined(regs.sp, vp);
    1240           29096 :         regs.sp = vp;
    1241                 :     }
    1242                 : 
    1243                 : #ifdef DEBUG
    1244           32163 :     JSContext *cx = f.cx;
    1245           32163 :     JS_ASSERT(fp->maybeBlockChain() == blockObj.enclosingBlock());
    1246                 : 
    1247                 :     /*
    1248                 :      * The young end of fp->scopeChain() may omit blocks if we haven't closed
    1249                 :      * over them, but if there are any closure blocks on fp->scopeChain(), they'd
    1250                 :      * better be (clones of) ancestors of the block we're entering now;
    1251                 :      * anything else we should have popped off fp->scopeChain() when we left its
    1252                 :      * static scope.
    1253                 :      */
    1254           32163 :     JSObject *obj2 = &fp->scopeChain();
    1255           64326 :     while (obj2->isWith())
    1256               0 :         obj2 = &obj2->asWith().enclosingScope();
    1257           32589 :     if (obj2->isBlock() &&
    1258             426 :         obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
    1259               0 :         JSObject &youngestProto = obj2->asClonedBlock().staticBlock();
    1260               0 :         StaticBlockObject *parent = &blockObj;
    1261               0 :         while ((parent = parent->enclosingBlock()) != &youngestProto)
    1262               0 :             JS_ASSERT(parent);
    1263                 :     }
    1264                 : #endif
    1265                 : 
    1266           32163 :     fp->setBlockChain(&blockObj);
    1267           32163 : }
    1268                 : 
    1269                 : void JS_FASTCALL
    1270           31730 : stubs::LeaveBlock(VMFrame &f)
    1271                 : {
    1272           31730 :     JSContext *cx = f.cx;
    1273           31730 :     StackFrame *fp = f.fp();
    1274                 : 
    1275           31730 :     StaticBlockObject &blockObj = fp->blockChain();
    1276           31730 :     JS_ASSERT(blockObj.stackDepth() <= StackDepth(fp->script()));
    1277                 : 
    1278                 :     /*
    1279                 :      * If we're about to leave the dynamic scope of a block that has been
    1280                 :      * cloned onto fp->scopeChain(), clear its private data, move its locals from
    1281                 :      * the stack into the clone, and pop it off the chain.
    1282                 :      */
    1283           31730 :     JSObject &obj = fp->scopeChain();
    1284           31730 :     if (obj.getProto() == &blockObj)
    1285             252 :         obj.asClonedBlock().put(cx);
    1286                 : 
    1287           31730 :     fp->setBlockChain(blockObj.enclosingBlock());
    1288           31730 : }
    1289                 : 
    1290                 : inline void *
    1291            2119 : FindNativeCode(VMFrame &f, jsbytecode *target)
    1292                 : {
    1293            2119 :     void* native = f.fp()->script()->nativeCodeForPC(f.fp()->isConstructing(), target);
    1294            2119 :     if (native)
    1295            2119 :         return native;
    1296                 : 
    1297               0 :     uint32_t sourceOffset = f.pc() - f.script()->code;
    1298               0 :     uint32_t targetOffset = target - f.script()->code;
    1299                 : 
    1300               0 :     CrossChunkEdge *edges = f.jit()->edges();
    1301               0 :     for (size_t i = 0; i < f.jit()->nedges; i++) {
    1302               0 :         const CrossChunkEdge &edge = edges[i];
    1303               0 :         if (edge.source == sourceOffset && edge.target == targetOffset)
    1304               0 :             return edge.shimLabel;
    1305                 :     }
    1306                 : 
    1307               0 :     JS_NOT_REACHED("Missing edge");
    1308                 :     return NULL;
    1309                 : }
    1310                 : 
    1311                 : void * JS_FASTCALL
    1312            1441 : stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
    1313                 : {
    1314            1441 :     jsbytecode *jpc = pc;
    1315            1441 :     JSScript *script = f.fp()->script();
    1316                 : 
    1317                 :     /* This is correct because the compiler adjusts the stack beforehand. */
    1318            1441 :     Value lval = f.regs.sp[-1];
    1319                 : 
    1320            1441 :     if (!lval.isPrimitive())
    1321               0 :         return FindNativeCode(f, pc + GET_JUMP_OFFSET(pc));
    1322                 : 
    1323            1441 :     JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
    1324                 : 
    1325            1441 :     pc += JUMP_OFFSET_LEN;
    1326            1441 :     uint32_t npairs = GET_UINT16(pc);
    1327            1441 :     pc += UINT16_LEN;
    1328                 : 
    1329            1441 :     JS_ASSERT(npairs);
    1330                 : 
    1331            1441 :     if (lval.isString()) {
    1332            1086 :         JSLinearString *str = lval.toString()->ensureLinear(f.cx);
    1333            1086 :         if (!str)
    1334               0 :             THROWV(NULL);
    1335            4475 :         for (uint32_t i = 1; i <= npairs; i++) {
    1336            4305 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1337            4305 :             pc += UINT32_INDEX_LEN;
    1338            4305 :             if (rval.isString()) {
    1339            4305 :                 JSLinearString *rhs = &rval.toString()->asLinear();
    1340            4305 :                 if (rhs == str || EqualStrings(str, rhs))
    1341             916 :                     return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1342                 :             }
    1343            3389 :             pc += JUMP_OFFSET_LEN;
    1344                 :         }
    1345             355 :     } else if (lval.isNumber()) {
    1346               0 :         double d = lval.toNumber();
    1347               0 :         for (uint32_t i = 1; i <= npairs; i++) {
    1348               0 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1349               0 :             pc += UINT32_INDEX_LEN;
    1350               0 :             if (rval.isNumber() && d == rval.toNumber())
    1351               0 :                 return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1352               0 :             pc += JUMP_OFFSET_LEN;
    1353                 :         }
    1354                 :     } else {
    1355             710 :         for (uint32_t i = 1; i <= npairs; i++) {
    1356             355 :             Value rval = script->getConst(GET_UINT32_INDEX(pc));
    1357             355 :             pc += UINT32_INDEX_LEN;
    1358             355 :             if (lval == rval)
    1359               0 :                 return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
    1360             355 :             pc += JUMP_OFFSET_LEN;
    1361                 :         }
    1362                 :     }
    1363                 : 
    1364             525 :     return FindNativeCode(f, jpc + GET_JUMP_OFFSET(jpc));
    1365                 : }
    1366                 : 
    1367                 : void * JS_FASTCALL
    1368             678 : stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
    1369                 : {
    1370             678 :     jsbytecode * const originalPC = origPc;
    1371                 : 
    1372            1356 :     DebugOnly<JSOp> op = JSOp(*originalPC);
    1373             678 :     JS_ASSERT(op == JSOP_TABLESWITCH);
    1374                 : 
    1375             678 :     uint32_t jumpOffset = GET_JUMP_OFFSET(originalPC);
    1376             678 :     jsbytecode *pc = originalPC + JUMP_OFFSET_LEN;
    1377                 :     
    1378                 :     /* Note: compiler adjusts the stack beforehand. */
    1379             678 :     Value rval = f.regs.sp[-1];
    1380                 : 
    1381                 :     int32_t tableIdx;
    1382             678 :     if (rval.isInt32()) {
    1383               0 :         tableIdx = rval.toInt32();
    1384             678 :     } else if (rval.isDouble()) {
    1385             199 :         double d = rval.toDouble();
    1386             199 :         if (d == 0) {
    1387                 :             /* Treat -0 (double) as 0. */
    1388              93 :             tableIdx = 0;
    1389             106 :         } else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) {
    1390              88 :             goto finally;
    1391                 :         }
    1392                 :     } else {
    1393             479 :         goto finally;
    1394                 :     }
    1395                 : 
    1396                 :     {
    1397             111 :         int32_t low = GET_JUMP_OFFSET(pc);
    1398             111 :         pc += JUMP_OFFSET_LEN;
    1399             111 :         int32_t high = GET_JUMP_OFFSET(pc);
    1400             111 :         pc += JUMP_OFFSET_LEN;
    1401                 : 
    1402             111 :         tableIdx -= low;
    1403             111 :         if ((uint32_t) tableIdx < (uint32_t)(high - low + 1)) {
    1404              69 :             pc += JUMP_OFFSET_LEN * tableIdx;
    1405              69 :             if (uint32_t candidateOffset = GET_JUMP_OFFSET(pc))
    1406              69 :                 jumpOffset = candidateOffset;
    1407                 :         }
    1408                 :     }
    1409                 : 
    1410                 : finally:
    1411                 :     /* Provide the native address. */
    1412             678 :     return FindNativeCode(f, originalPC + jumpOffset);
    1413                 : }
    1414                 : 
    1415                 : void JS_FASTCALL
    1416            1105 : stubs::Pos(VMFrame &f)
    1417                 : {
    1418            1105 :     if (!ToNumber(f.cx, &f.regs.sp[-1]))
    1419               0 :         THROW();
    1420            1105 :     if (!f.regs.sp[-1].isInt32())
    1421             436 :         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
    1422                 : }
    1423                 : 
    1424                 : void JS_FASTCALL
    1425             137 : stubs::DelName(VMFrame &f, PropertyName *name)
    1426                 : {
    1427                 :     JSObject *obj, *obj2;
    1428                 :     JSProperty *prop;
    1429             137 :     if (!FindProperty(f.cx, name, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
    1430               0 :         THROW();
    1431                 : 
    1432                 :     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
    1433             137 :     JS_ASSERT(!f.script()->strictModeCode);
    1434                 : 
    1435                 :     /* ECMA says to return true if name is undefined or inherited. */
    1436             137 :     f.regs.sp++;
    1437             137 :     f.regs.sp[-1] = BooleanValue(true);
    1438             137 :     if (prop) {
    1439              85 :         if (!obj->deleteProperty(f.cx, name, &f.regs.sp[-1], false))
    1440               0 :             THROW();
    1441                 :     }
    1442                 : }
    1443                 : 
    1444                 : template<JSBool strict>
    1445                 : void JS_FASTCALL
    1446             266 : stubs::DelProp(VMFrame &f, PropertyName *name)
    1447                 : {
    1448             266 :     JSContext *cx = f.cx;
    1449                 : 
    1450             266 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
    1451             266 :     if (!obj)
    1452               0 :         THROW();
    1453                 : 
    1454                 :     Value rval;
    1455             266 :     if (!obj->deleteProperty(cx, name, &rval, strict))
    1456               0 :         THROW();
    1457                 : 
    1458             266 :     f.regs.sp[-1] = rval;
    1459                 : }
    1460                 : 
    1461                 : template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, PropertyName *name);
    1462                 : template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
    1463                 : 
    1464                 : template<JSBool strict>
    1465                 : void JS_FASTCALL
    1466            1351 : stubs::DelElem(VMFrame &f)
    1467                 : {
    1468            1351 :     JSContext *cx = f.cx;
    1469                 : 
    1470            1351 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
    1471            1351 :     if (!obj)
    1472               0 :         THROW();
    1473                 : 
    1474            1351 :     const Value &propval = f.regs.sp[-1];
    1475            1351 :     Value &rval = f.regs.sp[-2];
    1476                 : 
    1477            1351 :     if (!obj->deleteByValue(cx, propval, &rval, strict))
    1478               2 :         THROW();
    1479                 : }
    1480                 : 
    1481                 : void JS_FASTCALL
    1482           26250 : stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
    1483                 : {
    1484           26250 :     unsigned attrs = JSPROP_ENUMERATE;
    1485           26250 :     if (!f.fp()->isEvalFrame())
    1486           25488 :         attrs |= JSPROP_PERMANENT;
    1487           26250 :     if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
    1488           25076 :         attrs |= JSPROP_READONLY;
    1489                 : 
    1490           26250 :     JSObject &obj = f.fp()->varObj();
    1491                 : 
    1492           26250 :     if (!DefVarOrConstOperation(f.cx, obj, dn, attrs))
    1493               0 :         THROW();
    1494                 : }
    1495                 : 
    1496                 : void JS_FASTCALL
    1497           25062 : stubs::SetConst(VMFrame &f, PropertyName *name)
    1498                 : {
    1499           25062 :     JSContext *cx = f.cx;
    1500                 : 
    1501           25062 :     JSObject *obj = &f.fp()->varObj();
    1502           25062 :     const Value &ref = f.regs.sp[-1];
    1503                 : 
    1504           25062 :     if (!obj->defineProperty(cx, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
    1505           25062 :                              JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
    1506                 :     {
    1507               0 :         THROW();
    1508                 :     }
    1509                 : }
    1510                 : 
    1511                 : JSBool JS_FASTCALL
    1512          383951 : stubs::In(VMFrame &f)
    1513                 : {
    1514          383951 :     JSContext *cx = f.cx;
    1515                 : 
    1516          383951 :     const Value &rref = f.regs.sp[-1];
    1517          383951 :     if (!rref.isObject()) {
    1518               7 :         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
    1519               7 :         THROWV(JS_FALSE);
    1520                 :     }
    1521                 : 
    1522          383944 :     JSObject *obj = &rref.toObject();
    1523                 :     jsid id;
    1524          383944 :     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
    1525               0 :         THROWV(JS_FALSE);
    1526                 : 
    1527                 :     JSObject *obj2;
    1528                 :     JSProperty *prop;
    1529          383944 :     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
    1530               0 :         THROWV(JS_FALSE);
    1531                 : 
    1532          383944 :     return !!prop;
    1533                 : }
    1534                 : 
    1535                 : template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
    1536                 : template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
    1537                 : 
    1538                 : void JS_FASTCALL
    1539           14673 : stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
    1540                 : {
    1541           14673 :     JS_ASSERT(which == 0 || which == 1);
    1542                 : 
    1543                 :     /* The actual pushed value is at sp[0], fix up the stack. See finishBarrier. */
    1544           14673 :     Value &result = f.regs.sp[-1 - (int)which];
    1545           14673 :     result = f.regs.sp[0];
    1546                 : 
    1547                 :     /*
    1548                 :      * Break type barriers at this bytecode if we have added many objects to
    1549                 :      * the target already. This isn't needed if inference results for the
    1550                 :      * script have been destroyed, as we will reanalyze and prune type barriers
    1551                 :      * as they are regenerated.
    1552                 :      */
    1553           14673 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1554           29346 :         AutoEnterTypeInference enter(f.cx);
    1555           14673 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1556                 :     }
    1557                 : 
    1558           14673 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1559           14673 : }
    1560                 : 
    1561                 : void JS_FASTCALL
    1562           13298 : stubs::StubTypeHelper(VMFrame &f, int32_t which)
    1563                 : {
    1564           13298 :     const Value &result = f.regs.sp[which];
    1565                 : 
    1566           13298 :     if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
    1567           26596 :         AutoEnterTypeInference enter(f.cx);
    1568           13298 :         f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
    1569                 :     }
    1570                 : 
    1571           13298 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
    1572           13298 : }
    1573                 : 
    1574                 : /*
    1575                 :  * Variant of TypeBarrierHelper for checking types after making a native call.
    1576                 :  * The stack is already correct, and no fixup should be performed.
    1577                 :  */
    1578                 : void JS_FASTCALL
    1579             287 : stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
    1580                 : {
    1581             287 :     TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
    1582             287 : }
    1583                 : 
    1584                 : void JS_FASTCALL
    1585             100 : stubs::NegZeroHelper(VMFrame &f)
    1586                 : {
    1587             100 :     f.regs.sp[-1].setDouble(-0.0);
    1588             100 :     TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
    1589             100 : }
    1590                 : 
    1591                 : void JS_FASTCALL
    1592             916 : stubs::CheckArgumentTypes(VMFrame &f)
    1593                 : {
    1594             916 :     StackFrame *fp = f.fp();
    1595             916 :     JSFunction *fun = fp->fun();
    1596             916 :     JSScript *script = fun->script();
    1597             916 :     RecompilationMonitor monitor(f.cx);
    1598                 : 
    1599                 :     {
    1600                 :         /* Postpone recompilations until all args have been updated. */
    1601            1832 :         types::AutoEnterTypeInference enter(f.cx);
    1602                 : 
    1603             916 :         if (!f.fp()->isConstructing())
    1604             898 :             TypeScript::SetThis(f.cx, script, fp->thisValue());
    1605            2337 :         for (unsigned i = 0; i < fun->nargs; i++)
    1606            1421 :             TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i));
    1607                 :     }
    1608                 : 
    1609             916 :     if (monitor.recompiled())
    1610              23 :         return;
    1611                 : 
    1612                 : #ifdef JS_MONOIC
    1613             893 :     ic::GenerateArgumentCheckStub(f);
    1614                 : #endif
    1615                 : }
    1616                 : 
    1617                 : #ifdef DEBUG
    1618                 : void JS_FASTCALL
    1619        14134094 : stubs::AssertArgumentTypes(VMFrame &f)
    1620                 : {
    1621        14134094 :     StackFrame *fp = f.fp();
    1622        14134094 :     JSFunction *fun = fp->fun();
    1623        14134094 :     JSScript *script = fun->script();
    1624                 : 
    1625                 :     /*
    1626                 :      * Don't check the type of 'this' for constructor frames, the 'this' value
    1627                 :      * has not been constructed yet.
    1628                 :      */
    1629        14134094 :     if (!fp->isConstructing()) {
    1630        12397874 :         Type type = GetValueType(f.cx, fp->thisValue());
    1631        12397874 :         if (!TypeScript::ThisTypes(script)->hasType(type))
    1632               0 :             TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
    1633                 :     }
    1634                 : 
    1635        38256008 :     for (unsigned i = 0; i < fun->nargs; i++) {
    1636        24121914 :         Type type = GetValueType(f.cx, fp->formalArg(i));
    1637        24121914 :         if (!TypeScript::ArgTypes(script, i)->hasType(type))
    1638               0 :             TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
    1639                 :     }
    1640        14134094 : }
    1641                 : #endif
    1642                 : 
    1643                 : /*
    1644                 :  * These two are never actually called, they just give us a place to rejoin if
    1645                 :  * there is an invariant failure when initially entering a loop.
    1646                 :  */
    1647               0 : void JS_FASTCALL stubs::MissedBoundsCheckEntry(VMFrame &f) {}
    1648               0 : void JS_FASTCALL stubs::MissedBoundsCheckHead(VMFrame &f) {}
    1649                 : 
    1650                 : void * JS_FASTCALL
    1651              66 : stubs::InvariantFailure(VMFrame &f, void *rval)
    1652                 : {
    1653                 :     /*
    1654                 :      * Patch this call to the return site of the call triggering the invariant
    1655                 :      * failure (or a MissedBoundsCheck* function if the failure occurred on
    1656                 :      * initial loop entry), and trigger a recompilation which will then
    1657                 :      * redirect to the rejoin point for that call. We want to make things look
    1658                 :      * to the recompiler like we are still inside that call, and that after
    1659                 :      * recompilation we will return to the call's rejoin point.
    1660                 :      */
    1661              66 :     void *repatchCode = f.scratch;
    1662              66 :     JS_ASSERT(repatchCode);
    1663              66 :     void **frameAddr = f.returnAddressLocation();
    1664              66 :     *frameAddr = repatchCode;
    1665                 : 
    1666                 :     /* Recompile the outermost script, and don't hoist any bounds checks. */
    1667              66 :     JSScript *script = f.fp()->script();
    1668              66 :     JS_ASSERT(!script->failedBoundsCheck);
    1669              66 :     script->failedBoundsCheck = true;
    1670                 : 
    1671              66 :     ExpandInlineFrames(f.cx->compartment);
    1672                 : 
    1673              66 :     mjit::Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), script);
    1674              66 :     mjit::ReleaseScriptCode(f.cx->runtime->defaultFreeOp(), script);
    1675                 : 
    1676                 :     /* Return the same value (if any) as the call triggering the invariant failure. */
    1677              66 :     return rval;
    1678                 : }
    1679                 : 
    1680                 : void JS_FASTCALL
    1681               0 : stubs::Exception(VMFrame &f)
    1682                 : {
    1683                 :     // Check the interrupt flag to allow interrupting deeply nested exception
    1684                 :     // handling.
    1685               0 :     if (f.cx->runtime->interrupt && !js_HandleExecutionInterrupt(f.cx))
    1686               0 :         THROW();
    1687                 : 
    1688               0 :     f.regs.sp[0] = f.cx->getPendingException();
    1689               0 :     f.cx->clearPendingException();
    1690                 : }
    1691                 : 
    1692                 : void JS_FASTCALL
    1693          369352 : stubs::FunctionFramePrologue(VMFrame &f)
    1694                 : {
    1695          369352 :     if (!f.fp()->functionPrologue(f.cx))
    1696               0 :         THROW();
    1697                 : }
    1698                 : 
    1699                 : void JS_FASTCALL
    1700          687190 : stubs::FunctionFrameEpilogue(VMFrame &f)
    1701                 : {
    1702          687190 :     f.fp()->functionEpilogue();
    1703          687190 : }
    1704                 : 
    1705                 : void JS_FASTCALL
    1706             202 : stubs::AnyFrameEpilogue(VMFrame &f)
    1707                 : {
    1708                 :     /*
    1709                 :      * On the normal execution path, emitReturn calls ScriptDebugEpilogue
    1710                 :      * and inlines ScriptEpilogue. This function implements forced early
    1711                 :      * returns, so it must have the same effect.
    1712                 :      */
    1713             202 :     bool ok = true;
    1714             202 :     if (f.cx->compartment->debugMode())
    1715             202 :         ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok);
    1716             202 :     ok = ScriptEpilogue(f.cx, f.fp(), ok);
    1717             202 :     if (!ok)
    1718               0 :         THROW();
    1719             202 :     if (f.fp()->isNonEvalFunctionFrame())
    1720             162 :         f.fp()->functionEpilogue();
    1721                 : }
    1722                 : 
    1723                 : template <bool Clamped>
    1724                 : int32_t JS_FASTCALL
    1725             489 : stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
    1726                 : {
    1727             489 :     JS_ASSERT(!vp->isInt32());
    1728                 : 
    1729             489 :     if (vp->isDouble()) {
    1730                 :         if (Clamped)
    1731              93 :             return js_TypedArray_uint8_clamp_double(vp->toDouble());
    1732             276 :         return js_DoubleToECMAInt32(vp->toDouble());
    1733                 :     }
    1734                 : 
    1735             120 :     if (vp->isNull() || vp->isObject() || vp->isUndefined())
    1736             120 :         return 0;
    1737                 : 
    1738               0 :     if (vp->isBoolean())
    1739               0 :         return vp->toBoolean() ? 1 : 0;
    1740                 : 
    1741               0 :     JS_ASSERT(vp->isString());
    1742                 : 
    1743               0 :     int32_t i32 = 0;
    1744                 : #ifdef DEBUG
    1745                 :     bool success = 
    1746                 : #endif
    1747               0 :         StringToNumberType<int32_t>(cx, vp->toString(), &i32);
    1748               0 :     JS_ASSERT(success);
    1749                 : 
    1750               0 :     return i32;
    1751                 : }
    1752                 : 
    1753                 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<true>(JSContext *, Value *);
    1754                 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<false>(JSContext *, Value *);
    1755                 : 
    1756                 : void JS_FASTCALL
    1757              56 : stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
    1758                 : {
    1759              56 :     JS_ASSERT(!vp->isDouble() && !vp->isInt32());
    1760                 : 
    1761              56 :     if (vp->isNull()) {
    1762               0 :         vp->setDouble(0);
    1763              56 :     } else if (vp->isObject() || vp->isUndefined()) {
    1764              28 :         vp->setDouble(js_NaN);
    1765              28 :     } else if (vp->isBoolean()) {
    1766               0 :         vp->setDouble(vp->toBoolean() ? 1 : 0);
    1767                 :     } else {
    1768              28 :         JS_ASSERT(vp->isString());
    1769              28 :         double d = 0;
    1770                 : #ifdef DEBUG
    1771                 :         bool success = 
    1772                 : #endif
    1773              28 :             StringToNumberType<double>(cx, vp->toString(), &d);
    1774              28 :         JS_ASSERT(success);
    1775              28 :         vp->setDouble(d);
    1776                 :     }
    1777              56 : }
    1778                 : 
    1779                 : void JS_FASTCALL
    1780              48 : stubs::WriteBarrier(VMFrame &f, Value *addr)
    1781                 : {
    1782              48 :     gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
    1783              48 : }
    1784                 : 
    1785                 : void JS_FASTCALL
    1786               2 : stubs::GCThingWriteBarrier(VMFrame &f, Value *addr)
    1787                 : {
    1788               2 :     gc::Cell *cell = (gc::Cell *)addr->toGCThing();
    1789               2 :     if (cell && !cell->isMarked())
    1790               2 :         gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
    1791               2 : }

Generated by: LCOV version 1.7