LCOV - code coverage report
Current view: directory - js/src - jsinterpinlines.h (source / functions) Found Hit Coverage
Test: app.info Lines: 371 334 90.0 %
Date: 2012-04-07 Functions: 28 28 100.0 %

       1                 : /* -*- Mode: C; tab-width: 8; 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 SpiderMonkey code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Mozilla Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Luke Wagner <lw@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                 : #ifndef jsinterpinlines_h__
      42                 : #define jsinterpinlines_h__
      43                 : 
      44                 : #include "jsapi.h"
      45                 : #include "jsbool.h"
      46                 : #include "jscompartment.h"
      47                 : #include "jsinfer.h"
      48                 : #include "jsinterp.h"
      49                 : #include "jslibmath.h"
      50                 : #include "jsnum.h"
      51                 : #include "jsprobes.h"
      52                 : #include "jsstr.h"
      53                 : #include "methodjit/MethodJIT.h"
      54                 : 
      55                 : #include "jsfuninlines.h"
      56                 : #include "jsinferinlines.h"
      57                 : #include "jspropertycacheinlines.h"
      58                 : #include "jstypedarrayinlines.h"
      59                 : 
      60                 : #include "vm/Stack-inl.h"
      61                 : 
      62                 : namespace js {
      63                 : 
      64                 : /*
      65                 :  * Compute the implicit |this| parameter for a call expression where the callee
      66                 :  * funval was resolved from an unqualified name reference to a property on obj
      67                 :  * (an object on the scope chain).
      68                 :  *
      69                 :  * We can avoid computing |this| eagerly and push the implicit callee-coerced
      70                 :  * |this| value, undefined, if any of these conditions hold:
      71                 :  *
      72                 :  * 1. The nominal |this|, obj, is a global object.
      73                 :  *
      74                 :  * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
      75                 :  *    is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
      76                 :  *    censored with undefined.
      77                 :  *
      78                 :  * Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
      79                 :  * statements and embedding-specific scope objects fall into this category.
      80                 :  *
      81                 :  * If the callee is a strict mode function, then code implementing JSOP_THIS
      82                 :  * in the interpreter and JITs will leave undefined as |this|. If funval is a
      83                 :  * function not in strict mode, JSOP_THIS code replaces undefined with funval's
      84                 :  * global.
      85                 :  *
      86                 :  * We set *vp to undefined early to reduce code size and bias this code for the
      87                 :  * common and future-friendly cases.
      88                 :  */
      89                 : inline bool
      90           97473 : ComputeImplicitThis(JSContext *cx, JSObject *obj, Value *vp)
      91                 : {
      92           97473 :     vp->setUndefined();
      93                 : 
      94           97473 :     if (obj->isGlobal())
      95           97392 :         return true;
      96                 : 
      97              81 :     if (IsCacheableNonGlobalScope(obj))
      98              63 :         return true;
      99                 : 
     100              18 :     obj = obj->thisObject(cx);
     101              18 :     if (!obj)
     102               0 :         return false;
     103                 : 
     104              18 :     vp->setObject(*obj);
     105              18 :     return true;
     106                 : }
     107                 : 
     108                 : inline bool
     109         7644062 : ComputeThis(JSContext *cx, StackFrame *fp)
     110                 : {
     111         7644062 :     Value &thisv = fp->thisValue();
     112         7644062 :     if (thisv.isObject())
     113         7582825 :         return true;
     114           61237 :     if (fp->isFunctionFrame()) {
     115           61237 :         if (fp->fun()->inStrictMode())
     116            1890 :             return true;
     117                 :         /*
     118                 :          * Eval function frames have their own |this| slot, which is a copy of the function's
     119                 :          * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
     120                 :          * eval's frame will get the wrapper, but the function's frame will not. To prevent
     121                 :          * this, we always wrap a function's |this| before pushing an eval frame, and should
     122                 :          * thus never see an unwrapped primitive in a non-strict eval function frame.
     123                 :          */
     124           59347 :         JS_ASSERT(!fp->isEvalFrame());
     125                 :     }
     126           59347 :     return BoxNonStrictThis(cx, fp->callReceiver());
     127                 : }
     128                 : 
     129                 : /*
     130                 :  * Return an object on which we should look for the properties of |value|.
     131                 :  * This helps us implement the custom [[Get]] method that ES5's GetValue
     132                 :  * algorithm uses for primitive values, without actually constructing the
     133                 :  * temporary object that the specification does.
     134                 :  * 
     135                 :  * For objects, return the object itself. For string, boolean, and number
     136                 :  * primitive values, return the appropriate constructor's prototype. For
     137                 :  * undefined and null, throw an error and return NULL, attributing the
     138                 :  * problem to the value at |spindex| on the stack.
     139                 :  */
     140                 : JS_ALWAYS_INLINE JSObject *
     141                 : ValuePropertyBearer(JSContext *cx, StackFrame *fp, const Value &v, int spindex)
     142                 : {
     143                 :     if (v.isObject())
     144                 :         return &v.toObject();
     145                 : 
     146                 :     GlobalObject &global = fp->scopeChain().global();
     147                 : 
     148                 :     if (v.isString())
     149                 :         return global.getOrCreateStringPrototype(cx);
     150                 :     if (v.isNumber())
     151                 :         return global.getOrCreateNumberPrototype(cx);
     152                 :     if (v.isBoolean())
     153                 :         return global.getOrCreateBooleanPrototype(cx);
     154                 : 
     155                 :     JS_ASSERT(v.isNull() || v.isUndefined());
     156                 :     js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
     157                 :     return NULL;
     158                 : }
     159                 : 
     160                 : inline bool
     161        77112435 : NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow, Value *vp)
     162                 : {
     163        77112435 :     if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
     164                 :         /* Fast path for Object instance properties. */
     165        76256420 :         JS_ASSERT(shape->hasSlot());
     166        76256420 :         *vp = pobj->nativeGetSlot(shape->slot());
     167                 :     } else {
     168          856015 :         if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))
     169            3286 :             return false;
     170                 :     }
     171        77109149 :     return true;
     172                 : }
     173                 : 
     174                 : #if defined(DEBUG) && !defined(JS_THREADSAFE)
     175                 : extern void
     176                 : AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
     177                 :                             PropertyCacheEntry *entry);
     178                 : #else
     179                 : inline void
     180        76166115 : AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
     181                 :                             PropertyCacheEntry *entry)
     182        76166115 : {}
     183                 : #endif
     184                 : 
     185                 : inline bool
     186         2132976 : GetPropertyGenericMaybeCallXML(JSContext *cx, JSOp op, JSObject *obj, jsid id, Value *vp)
     187                 : {
     188                 :     /*
     189                 :      * Various XML properties behave differently when accessed in a
     190                 :      * call vs. normal context, and getGeneric will not work right.
     191                 :      */
     192                 : #if JS_HAS_XML_SUPPORT
     193         2132976 :     if (op == JSOP_CALLPROP && obj->isXML())
     194              81 :         return js_GetXMLMethod(cx, obj, id, vp);
     195                 : #endif
     196                 : 
     197         2132895 :     return obj->getGeneric(cx, id, vp);
     198                 : }
     199                 : 
     200                 : inline bool
     201        64801185 : GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp)
     202                 : {
     203        64801185 :     JS_ASSERT(vp != &lval);
     204                 : 
     205        64801185 :     JSOp op = JSOp(*pc);
     206                 : 
     207        64801185 :     if (op == JSOP_LENGTH) {
     208                 :         /* Optimize length accesses on strings, arrays, and arguments. */
     209        42479932 :         if (lval.isString()) {
     210          216338 :             *vp = Int32Value(lval.toString()->length());
     211          216338 :             return true;
     212                 :         }
     213        42263594 :         if (lval.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
     214           95803 :             *vp = Int32Value(cx->fp()->numActualArgs());
     215           95803 :             return true;
     216                 :         }
     217        42167791 :         if (lval.isObject()) {
     218        42167629 :             JSObject *obj = &lval.toObject();
     219        42167629 :             if (obj->isArray()) {
     220        22043988 :                 uint32_t length = obj->getArrayLength();
     221        22043988 :                 *vp = NumberValue(length);
     222        22043988 :                 return true;
     223                 :             }
     224                 : 
     225        20123641 :             if (obj->isArguments()) {
     226           16226 :                 ArgumentsObject *argsobj = &obj->asArguments();
     227           16226 :                 if (!argsobj->hasOverriddenLength()) {
     228           15750 :                     uint32_t length = argsobj->initialLength();
     229           15750 :                     JS_ASSERT(length < INT32_MAX);
     230           15750 :                     *vp = Int32Value(int32_t(length));
     231           15750 :                     return true;
     232                 :                 }
     233                 :             }
     234                 : 
     235        20107891 :             if (js_IsTypedArray(obj)) {
     236            6983 :                 JSObject *tarray = TypedArray::getTypedArray(obj);
     237            6983 :                 *vp = Int32Value(TypedArray::getLength(tarray));
     238            6983 :                 return true;
     239                 :             }
     240                 :         }
     241                 :     }
     242                 : 
     243        42422323 :     JSObject *obj = ValueToObject(cx, lval);
     244        42422323 :     if (!obj)
     245             126 :         return false;
     246                 : 
     247                 :     PropertyCacheEntry *entry;
     248                 :     JSObject *obj2;
     249                 :     PropertyName *name;
     250        42422197 :     JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
     251        42422197 :     if (!name) {
     252        39776767 :         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
     253        39776767 :         if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
     254               0 :             return false;
     255        39776767 :         return true;
     256                 :     }
     257                 : 
     258         2645430 :     jsid id = ATOM_TO_JSID(name);
     259                 : 
     260         2645430 :     if (obj->getOps()->getProperty) {
     261         2132976 :         if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
     262               0 :             return false;
     263                 :     } else {
     264          512454 :         if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
     265             108 :             return false;
     266                 :     }
     267                 : 
     268                 : #if JS_HAS_NO_SUCH_METHOD
     269         5050607 :     if (op == JSOP_CALLPROP &&
     270         2404902 :         JS_UNLIKELY(vp->isPrimitive()) &&
     271             383 :         lval.isObject())
     272                 :     {
     273             286 :         if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
     274               0 :             return false;
     275                 :     }
     276                 : #endif
     277                 : 
     278         2645322 :     return true;
     279                 : }
     280                 : 
     281                 : inline bool
     282        16214551 : SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Value &rval)
     283                 : {
     284        16214551 :     JSObject *obj = ValueToObject(cx, lval);
     285        16214551 :     if (!obj)
     286              18 :         return false;
     287                 : 
     288        16214533 :     JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject());
     289        16214533 :     JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->scopeChain().global());
     290                 : 
     291                 :     PropertyCacheEntry *entry;
     292                 :     JSObject *obj2;
     293                 :     PropertyName *name;
     294        16214533 :     if (JS_PROPERTY_CACHE(cx).testForSet(cx, pc, obj, &entry, &obj2, &name)) {
     295                 :         /*
     296                 :          * Property cache hit, only partially confirmed by testForSet. We
     297                 :          * know that the entry applies to regs.pc and that obj's shape
     298                 :          * matches.
     299                 :          *
     300                 :          * The entry predicts a set either an existing "own" property, or
     301                 :          * on a prototype property that has a setter.
     302                 :          */
     303        14771734 :         const Shape *shape = entry->prop;
     304        14771734 :         JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable());
     305        14771734 :         JS_ASSERT_IF(shape->hasSlot(), entry->isOwnPropertyHit());
     306                 : 
     307        14779618 :         if (entry->isOwnPropertyHit() ||
     308            7884 :             ((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
     309                 : #ifdef DEBUG
     310        14771729 :             if (entry->isOwnPropertyHit()) {
     311        14767792 :                 JS_ASSERT(obj->nativeContains(cx, *shape));
     312                 :             } else {
     313            3937 :                 JS_ASSERT(obj2->nativeContains(cx, *shape));
     314            3937 :                 JS_ASSERT(entry->isPrototypePropertyHit());
     315            3937 :                 JS_ASSERT(entry->kshape != entry->pshape);
     316            3937 :                 JS_ASSERT(!shape->hasSlot());
     317                 :             }
     318                 : #endif
     319                 : 
     320        14771729 :             if (shape->hasDefaultSetter() && shape->hasSlot()) {
     321                 :                 /* Fast path for, e.g., plain Object instance properties. */
     322        14750119 :                 obj->nativeSetSlotWithType(cx, shape, rval);
     323                 :             } else {
     324           21610 :                 Value rref = rval;
     325           21610 :                 bool strict = cx->stack.currentScript()->strictModeCode;
     326           21610 :                 if (!js_NativeSet(cx, obj, shape, false, strict, &rref))
     327              72 :                     return false;
     328                 :             }
     329        14771657 :             return true;
     330                 :         }
     331                 : 
     332               5 :         GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name);
     333                 :     }
     334                 : 
     335         1442804 :     bool strict = cx->stack.currentScript()->strictModeCode;
     336         1442804 :     Value rref = rval;
     337                 : 
     338         1442804 :     JSOp op = JSOp(*pc);
     339                 : 
     340         1442804 :     jsid id = ATOM_TO_JSID(name);
     341         1442804 :     if (JS_LIKELY(!obj->getOps()->setProperty)) {
     342                 :         unsigned defineHow = (op == JSOP_SETNAME)
     343                 :                              ? DNP_CACHE_RESULT | DNP_UNQUALIFIED
     344         1431828 :                              : DNP_CACHE_RESULT;
     345         1431828 :         if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict))
     346             136 :             return false;
     347                 :     } else {
     348           10976 :         if (!obj->setGeneric(cx, id, &rref, strict))
     349              36 :             return false;
     350                 :     }
     351                 : 
     352         1442632 :     return true;
     353                 : }
     354                 : 
     355                 : inline bool
     356        37337139 : NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
     357                 : {
     358        37337139 :     JSObject *obj = cx->stack.currentScriptedScopeChain();
     359                 : 
     360                 :     /*
     361                 :      * Skip along the scope chain to the enclosing global object. This is
     362                 :      * used for GNAME opcodes where the bytecode emitter has determined a
     363                 :      * name access must be on the global. It also insulates us from bugs
     364                 :      * in the emitter: type inference will assume that GNAME opcodes are
     365                 :      * accessing the global object, and the inferred behavior should match
     366                 :      * the actual behavior even if the id could be found on the scope chain
     367                 :      * before the global object.
     368                 :      */
     369        37337139 :     if (js_CodeSpec[*pc].format & JOF_GNAME)
     370        36150086 :         obj = &obj->global();
     371                 : 
     372                 :     PropertyCacheEntry *entry;
     373                 :     JSObject *obj2;
     374                 :     PropertyName *name;
     375        37337139 :     JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
     376        37337139 :     if (!name) {
     377        36389348 :         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
     378        36389348 :         if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp))
     379            3259 :             return false;
     380        36386089 :         return true;
     381                 :     }
     382                 : 
     383          947791 :     jsid id = ATOM_TO_JSID(name);
     384                 : 
     385                 :     JSProperty *prop;
     386          947791 :     if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &prop))
     387               0 :         return false;
     388          947791 :     if (!prop) {
     389                 :         /* Kludge to allow (typeof foo == "undefined") tests. */
     390            1444 :         JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
     391            1444 :         if (op2 == JSOP_TYPEOF) {
     392              79 :             vp->setUndefined();
     393              79 :             return true;
     394                 :         }
     395            2730 :         JSAutoByteString printable;
     396            1365 :         if (js_AtomToPrintableString(cx, name, &printable))
     397            1365 :             js_ReportIsNotDefined(cx, printable.ptr());
     398            1365 :         return false;
     399                 :     }
     400                 : 
     401                 :     /* Take the slow path if prop was not found in a native object. */
     402          946347 :     if (!obj->isNative() || !obj2->isNative()) {
     403              27 :         if (!obj->getGeneric(cx, id, vp))
     404               0 :             return false;
     405                 :     } else {
     406          946320 :         Shape *shape = (Shape *)prop;
     407          946320 :         JSObject *normalized = obj;
     408          946320 :         if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
     409              28 :             normalized = &normalized->asWith().object();
     410          946320 :         if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
     411              27 :             return false;
     412                 :     }
     413                 : 
     414          946320 :     return true;
     415                 : }
     416                 : 
     417                 : inline bool
     418           58937 : DefVarOrConstOperation(JSContext *cx, JSObject &varobj, PropertyName *dn, unsigned attrs)
     419                 : {
     420           58937 :     JS_ASSERT(varobj.isVarObj());
     421           58937 :     JS_ASSERT(!varobj.getOps()->defineProperty);
     422                 : 
     423                 :     JSProperty *prop;
     424                 :     JSObject *obj2;
     425           58937 :     if (!varobj.lookupProperty(cx, dn, &obj2, &prop))
     426               0 :         return false;
     427                 : 
     428                 :     /* Steps 8c, 8d. */
     429           58937 :     if (!prop || (obj2 != &varobj && varobj.isGlobal())) {
     430           57810 :         if (!DefineNativeProperty(cx, &varobj, dn, UndefinedValue(),
     431           57810 :                                   JS_PropertyStub, JS_StrictPropertyStub, attrs, 0, 0))
     432                 :         {
     433               0 :             return false;
     434                 :         }
     435                 :     } else {
     436                 :         /*
     437                 :          * Extension: ordinarily we'd be done here -- but for |const|.  If we
     438                 :          * see a redeclaration that's |const|, we consider it a conflict.
     439                 :          */
     440                 :         unsigned oldAttrs;
     441            1127 :         if (!varobj.getPropertyAttributes(cx, dn, &oldAttrs))
     442               0 :             return false;
     443            1127 :         if (attrs & JSPROP_READONLY) {
     444               0 :             JSAutoByteString bytes;
     445               0 :             if (js_AtomToPrintableString(cx, dn, &bytes)) {
     446               0 :                 JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
     447                 :                                                              js_GetErrorMessage,
     448                 :                                                              NULL, JSMSG_REDECLARED_VAR,
     449                 :                                                              (oldAttrs & JSPROP_READONLY)
     450                 :                                                              ? "const"
     451                 :                                                              : "var",
     452               0 :                                                              bytes.ptr()));
     453                 :             }
     454               0 :             return false;
     455                 :         }
     456                 :     }
     457                 : 
     458           58937 :     return true;
     459                 : }
     460                 : 
     461                 : inline bool
     462                 : FunctionNeedsPrologue(JSContext *cx, JSFunction *fun)
     463                 : {
     464                 :     /* Heavyweight functions need call objects created. */
     465                 :     if (fun->isHeavyweight())
     466                 :         return true;
     467                 : 
     468                 :     /* Outer and inner functions need to preserve nesting invariants. */
     469                 :     if (cx->typeInferenceEnabled() && fun->script()->nesting())
     470                 :         return true;
     471                 : 
     472                 :     return false;
     473                 : }
     474                 : 
     475                 : inline bool
     476         9685721 : ScriptPrologue(JSContext *cx, StackFrame *fp, bool newType)
     477                 : {
     478         9685721 :     JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj());
     479                 : 
     480         9685721 :     if (fp->isConstructing()) {
     481          872149 :         JSObject *obj = js_CreateThisForFunction(cx, &fp->callee(), newType);
     482          872149 :         if (!obj)
     483               0 :             return false;
     484          872149 :         fp->functionThis().setObject(*obj);
     485                 :     }
     486                 : 
     487         9685721 :     Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
     488                 : 
     489         9685721 :     return true;
     490                 : }
     491                 : 
     492                 : inline bool
     493        11773210 : ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok)
     494                 : {
     495        11773210 :     Probes::exitJSFun(cx, fp->maybeFun(), fp->script());
     496                 : 
     497                 :     /*
     498                 :      * If inline-constructing, replace primitive rval with the new object
     499                 :      * passed in via |this|, and instrument this constructor invocation.
     500                 :      */
     501        11773210 :     if (fp->isConstructing() && ok) {
     502          808831 :         if (fp->returnValue().isPrimitive())
     503          808789 :             fp->setReturnValue(ObjectValue(fp->constructorThis()));
     504                 :     }
     505                 : 
     506        11773210 :     return ok;
     507                 : }
     508                 : 
     509                 : inline bool
     510          502154 : ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp, bool newType)
     511                 : {
     512          502154 :     if (!fp->isGeneratorFrame())
     513          484528 :         return ScriptPrologue(cx, fp, newType);
     514           17626 :     return true;
     515                 : }
     516                 : 
     517                 : inline bool
     518          517069 : ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok)
     519                 : {
     520          517069 :     if (!fp->isYielding())
     521          501643 :         return ScriptEpilogue(cx, fp, ok);
     522           15426 :     return ok;
     523                 : }
     524                 : 
     525                 : inline void
     526            2541 : InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
     527                 : {
     528            2541 :     if (script == regs->fp()->script())
     529             588 :         enabler.enableInterrupts();
     530            2541 : }
     531                 : 
     532                 : static JS_ALWAYS_INLINE bool
     533        50410500 : AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     534                 : {
     535        50410500 :     Value lval = lhs;
     536        50410500 :     Value rval = rhs;
     537                 : 
     538        50410500 :     if (lval.isInt32() && rval.isInt32()) {
     539        40807759 :         int32_t l = lval.toInt32(), r = rval.toInt32();
     540        40807759 :         int32_t sum = l + r;
     541        40807759 :         if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
     542          179633 :             res->setDouble(double(l) + double(r));
     543          179633 :             types::TypeScript::MonitorOverflow(cx);
     544                 :         } else {
     545        40628126 :             res->setInt32(sum);
     546                 :         }
     547                 :     } else
     548                 : #if JS_HAS_XML_SUPPORT
     549         9602741 :     if (IsXML(lval) && IsXML(rval)) {
     550               0 :         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), res))
     551               0 :             return false;
     552               0 :         types::TypeScript::MonitorUnknown(cx);
     553                 :     } else
     554                 : #endif
     555                 :     {
     556                 :         /*
     557                 :          * If either operand is an object, any non-integer result must be
     558                 :          * reported to inference.
     559                 :          */
     560         9602741 :         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
     561                 : 
     562         9602741 :         if (!ToPrimitive(cx, &lval))
     563              11 :             return false;
     564         9602730 :         if (!ToPrimitive(cx, &rval))
     565              32 :             return false;
     566                 :         bool lIsString, rIsString;
     567         9602698 :         if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
     568        13442124 :             js::AutoStringRooter lstr(cx), rstr(cx);
     569         4480708 :             if (lIsString) {
     570         4329485 :                 lstr.setString(lval.toString());
     571                 :             } else {
     572          151223 :                 lstr.setString(ToString(cx, lval));
     573          151223 :                 if (!lstr.string())
     574               0 :                     return false;
     575                 :             }
     576         4480708 :             if (rIsString) {
     577         3887772 :                 rstr.setString(rval.toString());
     578                 :             } else {
     579          592936 :                 rstr.setString(ToString(cx, rval));
     580          592936 :                 if (!rstr.string())
     581               0 :                     return false;
     582                 :             }
     583         4480708 :             JSString *str = js_ConcatStrings(cx, lstr.string(), rstr.string());
     584         4480708 :             if (!str)
     585              13 :                 return false;
     586         4480695 :             if (lIsObject || rIsObject)
     587          118047 :                 types::TypeScript::MonitorString(cx);
     588         8961403 :             res->setString(str);
     589                 :         } else {
     590                 :             double l, r;
     591         5121990 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     592               0 :                 return false;
     593         5121990 :             l += r;
     594        10390198 :             if (!res->setNumber(l) &&
     595         5268208 :                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
     596            3238 :                 types::TypeScript::MonitorOverflow(cx);
     597                 :             }
     598                 :         }
     599                 :     }
     600        50410444 :     return true;
     601                 : }
     602                 : 
     603                 : static JS_ALWAYS_INLINE bool
     604         6564664 : SubOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     605                 : {
     606                 :     double d1, d2;
     607         6564664 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     608               0 :         return false;
     609         6564664 :     double d = d1 - d2;
     610         6564664 :     if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
     611             112 :         types::TypeScript::MonitorOverflow(cx);
     612         6564664 :     return true;
     613                 : }
     614                 : 
     615                 : static JS_ALWAYS_INLINE bool
     616        24958944 : MulOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     617                 : {
     618                 :     double d1, d2;
     619        24958944 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     620               0 :         return false;
     621        24958944 :     double d = d1 * d2;
     622        24958944 :     if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
     623           80969 :         types::TypeScript::MonitorOverflow(cx);
     624        24958944 :     return true;
     625                 : }
     626                 : 
     627                 : static JS_ALWAYS_INLINE bool
     628         1388305 : DivOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     629                 : {
     630                 :     double d1, d2;
     631         1388305 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     632               0 :         return false;
     633         1388305 :     res->setNumber(NumberDiv(d1, d2));
     634                 : 
     635         1388305 :     if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
     636          725596 :         types::TypeScript::MonitorOverflow(cx);
     637         1388305 :     return true;
     638                 : }
     639                 : 
     640                 : static JS_ALWAYS_INLINE bool
     641          457306 : ModOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     642                 : {
     643                 :     int32_t l, r;
     644          457306 :     if (lhs.isInt32() && rhs.isInt32() &&
     645                 :         (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
     646          447280 :         int32_t mod = l % r;
     647          447280 :         res->setInt32(mod);
     648          447280 :         return true;
     649                 :     }
     650                 : 
     651                 :     double d1, d2;
     652           10026 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     653               0 :         return false;
     654                 : 
     655           10026 :     if (d2 == 0)
     656             145 :         res->setDouble(js_NaN);
     657                 :     else
     658            9881 :         res->setDouble(js_fmod(d1, d2));
     659           10026 :     types::TypeScript::MonitorOverflow(cx);
     660           10026 :     return true;
     661                 : }
     662                 : 
     663                 : static inline bool
     664         2229128 : FetchElementId(JSContext *cx, JSObject *obj, const Value &idval, jsid &id, Value *vp)
     665                 : {
     666                 :     int32_t i_;
     667         2229128 :     if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
     668         1607492 :         id = INT_TO_JSID(i_);
     669         1607492 :         return true;
     670                 :     }
     671          621636 :     return !!js_InternNonIntElementId(cx, obj, idval, &id, vp);
     672                 : }
     673                 : 
     674                 : static JS_ALWAYS_INLINE bool
     675           83249 : ToIdOperation(JSContext *cx, const Value &objval, const Value &idval, Value *res)
     676                 : {
     677           83249 :     if (idval.isInt32()) {
     678           82375 :         *res = idval;
     679           82375 :         return true;
     680                 :     }
     681                 : 
     682             874 :     JSObject *obj = ValueToObject(cx, objval);
     683             874 :     if (!obj)
     684               0 :         return false;
     685                 : 
     686                 :     jsid dummy;
     687             874 :     if (!js_InternNonIntElementId(cx, obj, idval, &dummy, res))
     688               0 :         return false;
     689                 : 
     690             874 :     if (!res->isInt32())
     691             874 :         types::TypeScript::MonitorUnknown(cx);
     692             874 :     return true;
     693                 : }
     694                 : 
     695                 : static JS_ALWAYS_INLINE bool
     696        27729996 : GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *obj, const Value &rref, Value *res)
     697                 : {
     698                 : #if JS_HAS_XML_SUPPORT
     699        27729996 :     if (op == JSOP_CALLELEM && JS_UNLIKELY(obj->isXML())) {
     700                 :         jsid id;
     701             540 :         if (!FetchElementId(cx, obj, rref, id, res))
     702               0 :             return false;
     703             540 :         return js_GetXMLMethod(cx, obj, id, res);
     704                 :     }
     705                 : #endif
     706                 : 
     707                 :     uint32_t index;
     708        27729456 :     if (IsDefinitelyIndex(rref, &index)) {
     709                 :         do {
     710        26903584 :             if (obj->isDenseArray()) {
     711        26341581 :                 if (index < obj->getDenseArrayInitializedLength()) {
     712        26245726 :                     *res = obj->getDenseArrayElement(index);
     713        26245726 :                     if (!res->isMagic())
     714        26244530 :                         break;
     715                 :                 }
     716          562003 :             } else if (obj->isArguments()) {
     717          114425 :                 if (obj->asArguments().getElement(index, res))
     718          111854 :                     break;
     719                 :             }
     720          547200 :             if (!obj->getElement(cx, index, res))
     721              27 :                 return false;
     722                 :         } while(0);
     723                 :     } else {
     724                 :         JSScript *script;
     725                 :         jsbytecode *pc;
     726          825872 :         types::TypeScript::GetPcScript(cx, &script, &pc);
     727                 : 
     728          825872 :         if (script->hasAnalysis())
     729          825839 :             script->analysis()->getCode(pc).getStringElement = true;
     730                 : 
     731          825872 :         SpecialId special;
     732          825872 :         *res = rref;
     733          825872 :         if (ValueIsSpecial(obj, res, &special, cx)) {
     734               0 :             if (!obj->getSpecial(cx, obj, special, res))
     735               0 :                 return false;
     736                 :         } else {
     737                 :             JSAtom *name;
     738          825872 :             if (!js_ValueToAtom(cx, *res, &name))
     739               0 :                 return false;
     740                 : 
     741          825872 :             if (name->isIndex(&index)) {
     742          187646 :                 if (!obj->getElement(cx, index, res))
     743               0 :                     return false;
     744                 :             } else {
     745          638226 :                 if (!obj->getProperty(cx, name->asPropertyName(), res))
     746               0 :                     return false;
     747                 :             }
     748                 :         }
     749                 :     }
     750                 : 
     751        27729429 :     assertSameCompartment(cx, *res);
     752        27729429 :     return true;
     753                 : }
     754                 : 
     755                 : static JS_ALWAYS_INLINE bool
     756        27828053 : GetElementOperation(JSContext *cx, JSOp op, const Value &lref, const Value &rref, Value *res)
     757                 : {
     758        27828053 :     JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
     759                 : 
     760        27828053 :     if (lref.isString() && rref.isInt32()) {
     761            2259 :         JSString *str = lref.toString();
     762            2259 :         int32_t i = rref.toInt32();
     763            2259 :         if (size_t(i) < str->length()) {
     764            2088 :             str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
     765            2088 :             if (!str)
     766               0 :                 return false;
     767            2088 :             res->setString(str);
     768            2088 :             return true;
     769                 :         }
     770                 :     }
     771                 : 
     772        27825965 :     if (lref.isMagic(JS_OPTIMIZED_ARGUMENTS))
     773           95906 :         return NormalArgumentsObject::optimizedGetElem(cx, cx->fp(), rref, res);
     774                 : 
     775        27730059 :     bool isObject = lref.isObject();
     776        27730059 :     JSObject *obj = ValueToObject(cx, lref);
     777        27730059 :     if (!obj)
     778              63 :         return false;
     779        27729996 :     if (!GetObjectElementOperation(cx, op, obj, rref, res))
     780              27 :         return false;
     781                 : 
     782                 : #if JS_HAS_NO_SUCH_METHOD
     783        27729969 :     if (op == JSOP_CALLELEM && JS_UNLIKELY(res->isPrimitive()) && isObject) {
     784             527 :         if (!OnUnknownMethod(cx, obj, rref, res))
     785               0 :             return false;
     786                 :     }
     787                 : #endif
     788        27729969 :     return true;
     789                 : }
     790                 : 
     791                 : static JS_ALWAYS_INLINE bool
     792        11318786 : SetObjectElementOperation(JSContext *cx, JSObject *obj, jsid id, const Value &value, bool strict)
     793                 : {
     794        11318786 :     types::TypeScript::MonitorAssign(cx, obj, id);
     795                 : 
     796                 :     do {
     797        11318786 :         if (obj->isDenseArray() && JSID_IS_INT(id)) {
     798        11061995 :             uint32_t length = obj->getDenseArrayInitializedLength();
     799        11061995 :             int32_t i = JSID_TO_INT(id);
     800        11061995 :             if ((uint32_t)i < length) {
     801        10386841 :                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
     802           14202 :                     if (js_PrototypeHasIndexedProperties(cx, obj))
     803               0 :                         break;
     804           14202 :                     if ((uint32_t)i >= obj->getArrayLength())
     805               0 :                         obj->setArrayLength(cx, i + 1);
     806                 :                 }
     807        10386841 :                 obj->setDenseArrayElementWithType(cx, i, value);
     808        10386841 :                 return true;
     809                 :             } else {
     810                 :                 JSScript *script;
     811                 :                 jsbytecode *pc;
     812          675154 :                 types::TypeScript::GetPcScript(cx, &script, &pc);
     813                 : 
     814          675154 :                 if (script->hasAnalysis())
     815          675154 :                     script->analysis()->getCode(pc).arrayWriteHole = true;
     816                 :             }
     817                 :         }
     818                 :     } while (0);
     819                 : 
     820          931945 :     Value tmp = value;
     821          931945 :     return obj->setGeneric(cx, id, &tmp, strict);
     822                 : }
     823                 : 
     824                 : #define RELATIONAL_OP(OP)                                                     \
     825                 :     JS_BEGIN_MACRO                                                            \
     826                 :         Value lval = lhs;                                                     \
     827                 :         Value rval = rhs;                                                     \
     828                 :         /* Optimize for two int-tagged operands (typical loop control). */    \
     829                 :         if (lval.isInt32() && rval.isInt32()) {                               \
     830                 :             *res = lval.toInt32() OP rval.toInt32();                          \
     831                 :         } else {                                                              \
     832                 :             if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                       \
     833                 :                 return false;                                                 \
     834                 :             if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                       \
     835                 :                 return false;                                                 \
     836                 :             if (lval.isString() && rval.isString()) {                         \
     837                 :                 JSString *l = lval.toString(), *r = rval.toString();          \
     838                 :                 int32_t result;                                               \
     839                 :                 if (!CompareStrings(cx, l, r, &result))                       \
     840                 :                     return false;                                             \
     841                 :                 *res = result OP 0;                                           \
     842                 :             } else {                                                          \
     843                 :                 double l, r;                                                  \
     844                 :                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))       \
     845                 :                     return false;;                                            \
     846                 :                 *res = (l OP r);                                              \
     847                 :             }                                                                 \
     848                 :         }                                                                     \
     849                 :         return true;                                                          \
     850                 :     JS_END_MACRO
     851                 : 
     852                 : static JS_ALWAYS_INLINE bool
     853       156837398 : LessThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     854       156837398 :     RELATIONAL_OP(<);
     855                 : }
     856                 : 
     857                 : static JS_ALWAYS_INLINE bool
     858         1705631 : LessThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     859         1705631 :     RELATIONAL_OP(<=);
     860                 : }
     861                 : 
     862                 : static JS_ALWAYS_INLINE bool
     863         1539957 : GreaterThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     864         1539957 :     RELATIONAL_OP(>);
     865                 : }
     866                 : 
     867                 : static JS_ALWAYS_INLINE bool
     868         6143501 : GreaterThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     869         6143501 :     RELATIONAL_OP(>=);
     870                 : }
     871                 : 
     872                 : #undef RELATIONAL_OP
     873                 : 
     874                 : }  /* namespace js */
     875                 : 
     876                 : #endif /* jsinterpinlines_h__ */

Generated by: LCOV version 1.7