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

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

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

Generated by: LCOV version 1.7