LCOV - code coverage report
Current view: directory - js/src - jsinterpinlines.h (source / functions) Found Hit Coverage
Test: app.info Lines: 381 345 90.6 %
Date: 2012-06-02 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         3217867 : ComputeImplicitThis(JSContext *cx, JSObject *obj, Value *vp)
      91                 : {
      92         3217867 :     vp->setUndefined();
      93                 : 
      94         3217867 :     if (obj->isGlobal())
      95         3189072 :         return true;
      96                 : 
      97           28795 :     if (IsCacheableNonGlobalScope(obj))
      98           28777 :         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        12152873 : ComputeThis(JSContext *cx, StackFrame *fp)
     110                 : {
     111        12152873 :     Value &thisv = fp->thisValue();
     112        12152873 :     if (thisv.isObject())
     113        12090876 :         return true;
     114           61997 :     if (fp->isFunctionFrame()) {
     115           61997 :         if (fp->fun()->inStrictMode())
     116            1976 :             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           60021 :         JS_ASSERT(!fp->isEvalFrame());
     125                 :     }
     126           60021 :     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       107021630 : NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow, Value *vp)
     162                 : {
     163       107021630 :     if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
     164                 :         /* Fast path for Object instance properties. */
     165       104037204 :         JS_ASSERT(shape->hasSlot());
     166       104037204 :         *vp = pobj->nativeGetSlot(shape->slot());
     167                 :     } else {
     168         2984426 :         if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))
     169            3384 :             return false;
     170                 :     }
     171       107018246 :     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        99500702 : AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
     181                 :                             PropertyCacheEntry *entry)
     182        99500702 : {}
     183                 : #endif
     184                 : 
     185                 : inline bool
     186         2586902 : 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         2586902 :     if (op == JSOP_CALLPROP && obj->isXML())
     194              81 :         return js_GetXMLMethod(cx, obj, id, vp);
     195                 : #endif
     196                 : 
     197         2586821 :     return obj->getGeneric(cx, id, vp);
     198                 : }
     199                 : 
     200                 : inline bool
     201        90980582 : GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp)
     202                 : {
     203        90980582 :     JS_ASSERT(vp != &lval);
     204                 : 
     205        90980582 :     JSOp op = JSOp(*pc);
     206                 : 
     207        90980582 :     if (op == JSOP_LENGTH) {
     208                 :         /* Optimize length accesses on strings, arrays, and arguments. */
     209        43033004 :         if (lval.isString()) {
     210          336345 :             *vp = Int32Value(lval.toString()->length());
     211          336345 :             return true;
     212                 :         }
     213        42696659 :         if (lval.isMagic(JS_LAZY_ARGUMENTS)) {
     214           36138 :             *vp = Int32Value(cx->fp()->numActualArgs());
     215           36138 :             return true;
     216                 :         }
     217        42660521 :         if (lval.isObject()) {
     218        42660354 :             JSObject *obj = &lval.toObject();
     219        42660354 :             if (obj->isArray()) {
     220        22514426 :                 uint32_t length = obj->getArrayLength();
     221        22514426 :                 *vp = NumberValue(length);
     222        22514426 :                 return true;
     223                 :             }
     224                 : 
     225        20145928 :             if (obj->isArguments()) {
     226           24442 :                 ArgumentsObject *argsobj = &obj->asArguments();
     227           24442 :                 if (!argsobj->hasOverriddenLength()) {
     228           23937 :                     uint32_t length = argsobj->initialLength();
     229           23937 :                     JS_ASSERT(length < INT32_MAX);
     230           23937 :                     *vp = Int32Value(int32_t(length));
     231           23937 :                     return true;
     232                 :                 }
     233                 :             }
     234                 : 
     235        20121991 :             if (js_IsTypedArray(obj)) {
     236            7010 :                 JSObject *tarray = TypedArray::getTypedArray(obj);
     237            7010 :                 *vp = Int32Value(TypedArray::getLength(tarray));
     238            7010 :                 return true;
     239                 :             }
     240                 :         }
     241                 :     }
     242                 : 
     243        68062726 :     JSObject *obj = ValueToObject(cx, lval);
     244        68062726 :     if (!obj)
     245             293 :         return false;
     246                 : 
     247                 :     unsigned flags = (op == JSOP_CALLPROP)
     248                 :                   ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
     249        68062433 :                   : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER;
     250                 : 
     251                 :     PropertyCacheEntry *entry;
     252                 :     JSObject *obj2;
     253                 :     PropertyName *name;
     254        68062433 :     JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
     255        68062433 :     if (!name) {
     256        54673693 :         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
     257        54673693 :         if (!NativeGet(cx, obj, obj2, entry->prop, flags, vp))
     258              57 :             return false;
     259        54673636 :         return true;
     260                 :     }
     261                 : 
     262        13388740 :     jsid id = ATOM_TO_JSID(name);
     263                 : 
     264        13388740 :     if (obj->getOps()->getProperty) {
     265         2586902 :         if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
     266               0 :             return false;
     267                 :     } else {
     268        10801838 :         if (!GetPropertyHelper(cx, obj, id, flags, vp))
     269             421 :             return false;
     270                 :     }
     271                 : 
     272                 : #if JS_HAS_NO_SUCH_METHOD
     273        18383326 :     if (op == JSOP_CALLPROP &&
     274         4994222 :         JS_UNLIKELY(vp->isPrimitive()) &&
     275             785 :         lval.isObject())
     276                 :     {
     277             687 :         if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
     278               0 :             return false;
     279                 :     }
     280                 : #endif
     281                 : 
     282        13388319 :     return true;
     283                 : }
     284                 : 
     285                 : inline bool
     286        17694237 : SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Value &rval)
     287                 : {
     288        17694237 :     JSObject *obj = ValueToObject(cx, lval);
     289        17694237 :     if (!obj)
     290               9 :         return false;
     291                 : 
     292        17694228 :     JS_ASSERT_IF(*pc == JSOP_SETMETHOD, IsFunctionObject(rval));
     293        17694228 :     JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject());
     294        17694228 :     JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->scopeChain().global());
     295                 : 
     296                 :     PropertyCacheEntry *entry;
     297                 :     JSObject *obj2;
     298                 :     PropertyName *name;
     299        17694228 :     if (JS_PROPERTY_CACHE(cx).testForSet(cx, pc, obj, &entry, &obj2, &name)) {
     300                 :         /*
     301                 :          * Property cache hit, only partially confirmed by testForSet. We
     302                 :          * know that the entry applies to regs.pc and that obj's shape
     303                 :          * matches.
     304                 :          *
     305                 :          * The entry predicts a set either an existing "own" property, or
     306                 :          * on a prototype property that has a setter.
     307                 :          */
     308        15016855 :         const Shape *shape = entry->prop;
     309        15016855 :         JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable());
     310        15016855 :         JS_ASSERT_IF(shape->hasSlot(), entry->isOwnPropertyHit());
     311                 : 
     312        15042481 :         if (entry->isOwnPropertyHit() ||
     313           25626 :             ((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
     314                 : #ifdef DEBUG
     315        15016845 :             if (entry->isOwnPropertyHit()) {
     316        15004042 :                 JS_ASSERT(obj->nativeContains(cx, *shape));
     317                 :             } else {
     318           12803 :                 JS_ASSERT(obj2->nativeContains(cx, *shape));
     319           12803 :                 JS_ASSERT(entry->isPrototypePropertyHit());
     320           12803 :                 JS_ASSERT(entry->kshape != entry->pshape);
     321           12803 :                 JS_ASSERT(!shape->hasSlot());
     322                 :             }
     323                 : #endif
     324                 : 
     325        15016845 :             if (shape->hasDefaultSetter() && shape->hasSlot() && !shape->isMethod()) {
     326                 :                 /* Fast path for, e.g., plain Object instance properties. */
     327        14929174 :                 obj->nativeSetSlotWithType(cx, shape, rval);
     328                 :             } else {
     329           87671 :                 Value rref = rval;
     330           87671 :                 bool strict = cx->stack.currentScript()->strictModeCode;
     331           87671 :                 if (!js_NativeSet(cx, obj, shape, false, strict, &rref))
     332             121 :                     return false;
     333                 :             }
     334        15016724 :             return true;
     335                 :         }
     336                 : 
     337              10 :         GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name);
     338                 :     }
     339                 : 
     340         2677383 :     bool strict = cx->stack.currentScript()->strictModeCode;
     341         2677383 :     Value rref = rval;
     342                 : 
     343         2677383 :     JSOp op = JSOp(*pc);
     344                 : 
     345         2677383 :     jsid id = ATOM_TO_JSID(name);
     346         2677383 :     if (JS_LIKELY(!obj->getOps()->setProperty)) {
     347                 :         unsigned defineHow;
     348         2661099 :         if (op == JSOP_SETMETHOD)
     349               0 :             defineHow = DNP_CACHE_RESULT | DNP_SET_METHOD;
     350         2661099 :         else if (op == JSOP_SETNAME)
     351          154104 :             defineHow = DNP_CACHE_RESULT | DNP_UNQUALIFIED;
     352                 :         else
     353         2506995 :             defineHow = DNP_CACHE_RESULT;
     354         2661099 :         if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict))
     355             655 :             return false;
     356                 :     } else {
     357           16284 :         if (!obj->setGeneric(cx, id, &rref, strict))
     358              18 :             return false;
     359                 :     }
     360                 : 
     361         2676710 :     return true;
     362                 : }
     363                 : 
     364                 : inline bool
     365        52501662 : NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
     366                 : {
     367        52501662 :     JSObject *obj = cx->stack.currentScriptedScopeChain();
     368                 : 
     369                 :     /*
     370                 :      * Skip along the scope chain to the enclosing global object. This is
     371                 :      * used for GNAME opcodes where the bytecode emitter has determined a
     372                 :      * name access must be on the global. It also insulates us from bugs
     373                 :      * in the emitter: type inference will assume that GNAME opcodes are
     374                 :      * accessing the global object, and the inferred behavior should match
     375                 :      * the actual behavior even if the id could be found on the scope chain
     376                 :      * before the global object.
     377                 :      */
     378        52501662 :     if (js_CodeSpec[*pc].format & JOF_GNAME)
     379        36124468 :         obj = &obj->global();
     380                 : 
     381                 :     PropertyCacheEntry *entry;
     382                 :     JSObject *obj2;
     383                 :     PropertyName *name;
     384        52501662 :     JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
     385        52501662 :     if (!name) {
     386        44827009 :         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
     387        44827009 :         if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_METHOD_BARRIER, vp))
     388            3293 :             return false;
     389        44823716 :         return true;
     390                 :     }
     391                 : 
     392         7674653 :     jsid id = ATOM_TO_JSID(name);
     393                 : 
     394                 :     JSProperty *prop;
     395         7674653 :     if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &prop))
     396               0 :         return false;
     397         7674653 :     if (!prop) {
     398                 :         /* Kludge to allow (typeof foo == "undefined") tests. */
     399          153698 :         JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
     400          153698 :         if (op2 == JSOP_TYPEOF) {
     401          152352 :             vp->setUndefined();
     402          152352 :             return true;
     403                 :         }
     404            2692 :         JSAutoByteString printable;
     405            1346 :         if (js_AtomToPrintableString(cx, name, &printable))
     406            1346 :             js_ReportIsNotDefined(cx, printable.ptr());
     407            1346 :         return false;
     408                 :     }
     409                 : 
     410                 :     /* Take the slow path if prop was not found in a native object. */
     411         7520955 :     if (!obj->isNative() || !obj2->isNative()) {
     412              27 :         if (!obj->getGeneric(cx, id, vp))
     413               0 :             return false;
     414                 :     } else {
     415         7520928 :         Shape *shape = (Shape *)prop;
     416         7520928 :         JSObject *normalized = obj;
     417         7520928 :         if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
     418              28 :             normalized = &normalized->asWith().object();
     419         7520928 :         if (!NativeGet(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, vp))
     420              34 :             return false;
     421                 :     }
     422                 : 
     423         7520921 :     return true;
     424                 : }
     425                 : 
     426                 : inline bool
     427          303904 : DefVarOrConstOperation(JSContext *cx, JSObject &varobj, PropertyName *dn, unsigned attrs)
     428                 : {
     429          303904 :     JS_ASSERT(varobj.isVarObj());
     430          303904 :     JS_ASSERT(!varobj.getOps()->defineProperty);
     431                 : 
     432                 :     JSProperty *prop;
     433                 :     JSObject *obj2;
     434          303904 :     if (!varobj.lookupProperty(cx, dn, &obj2, &prop))
     435               0 :         return false;
     436                 : 
     437                 :     /* Steps 8c, 8d. */
     438          303904 :     if (!prop || (obj2 != &varobj && varobj.isGlobal())) {
     439          302687 :         if (!DefineNativeProperty(cx, &varobj, dn, UndefinedValue(),
     440          302687 :                                   JS_PropertyStub, JS_StrictPropertyStub, attrs, 0, 0))
     441                 :         {
     442               0 :             return false;
     443                 :         }
     444                 :     } else {
     445                 :         /*
     446                 :          * Extension: ordinarily we'd be done here -- but for |const|.  If we
     447                 :          * see a redeclaration that's |const|, we consider it a conflict.
     448                 :          */
     449                 :         unsigned oldAttrs;
     450            1217 :         if (!varobj.getPropertyAttributes(cx, dn, &oldAttrs))
     451               0 :             return false;
     452            1217 :         if (attrs & JSPROP_READONLY) {
     453               0 :             JSAutoByteString bytes;
     454               0 :             if (js_AtomToPrintableString(cx, dn, &bytes)) {
     455               0 :                 JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
     456                 :                                                              js_GetErrorMessage,
     457                 :                                                              NULL, JSMSG_REDECLARED_VAR,
     458                 :                                                              (oldAttrs & JSPROP_READONLY)
     459                 :                                                              ? "const"
     460                 :                                                              : "var",
     461               0 :                                                              bytes.ptr()));
     462                 :             }
     463               0 :             return false;
     464                 :         }
     465                 :     }
     466                 : 
     467          303904 :     return true;
     468                 : }
     469                 : 
     470                 : inline bool
     471                 : FunctionNeedsPrologue(JSContext *cx, JSFunction *fun)
     472                 : {
     473                 :     /* Heavyweight functions need call objects created. */
     474                 :     if (fun->isHeavyweight())
     475                 :         return true;
     476                 : 
     477                 :     /* Outer and inner functions need to preserve nesting invariants. */
     478                 :     if (cx->typeInferenceEnabled() && fun->script()->nesting())
     479                 :         return true;
     480                 : 
     481                 :     return false;
     482                 : }
     483                 : 
     484                 : inline bool
     485        13185783 : ScriptPrologue(JSContext *cx, StackFrame *fp, bool newType)
     486                 : {
     487        13185783 :     JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(), fp->hasCallObj());
     488                 : 
     489        13185783 :     if (fp->isConstructing()) {
     490          996775 :         JSObject *obj = js_CreateThisForFunction(cx, &fp->callee(), newType);
     491          996775 :         if (!obj)
     492               0 :             return false;
     493          996775 :         fp->functionThis().setObject(*obj);
     494                 :     }
     495                 : 
     496        13185783 :     Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
     497                 : 
     498        13185783 :     return true;
     499                 : }
     500                 : 
     501                 : inline bool
     502        15272726 : ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok)
     503                 : {
     504        15272726 :     Probes::exitJSFun(cx, fp->maybeFun(), fp->script());
     505                 : 
     506                 :     /*
     507                 :      * If inline-constructing, replace primitive rval with the new object
     508                 :      * passed in via |this|, and instrument this constructor invocation.
     509                 :      */
     510        15272726 :     if (fp->isConstructing() && ok) {
     511          933442 :         if (fp->returnValue().isPrimitive())
     512          933370 :             fp->setReturnValue(ObjectValue(fp->constructorThis()));
     513                 :     }
     514                 : 
     515        15272726 :     return ok;
     516                 : }
     517                 : 
     518                 : inline bool
     519         1962019 : ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp, bool newType)
     520                 : {
     521         1962019 :     if (!fp->isGeneratorFrame())
     522         1932690 :         return ScriptPrologue(cx, fp, newType);
     523           29329 :     return true;
     524                 : }
     525                 : 
     526                 : inline bool
     527         1977034 : ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok)
     528                 : {
     529         1977034 :     if (!fp->isYielding())
     530         1953903 :         return ScriptEpilogue(cx, fp, ok);
     531           23131 :     return ok;
     532                 : }
     533                 : 
     534                 : inline void
     535            2607 : InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
     536                 : {
     537            2607 :     if (script == regs->fp()->script())
     538             593 :         enabler.enableInterrupts();
     539            2607 : }
     540                 : 
     541                 : static JS_ALWAYS_INLINE bool
     542        59135463 : AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     543                 : {
     544        59135463 :     Value lval = lhs;
     545        59135463 :     Value rval = rhs;
     546                 : 
     547        59135463 :     if (lval.isInt32() && rval.isInt32()) {
     548        47876241 :         int32_t l = lval.toInt32(), r = rval.toInt32();
     549        47876241 :         int32_t sum = l + r;
     550        47876241 :         if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
     551          179634 :             res->setDouble(double(l) + double(r));
     552          179634 :             types::TypeScript::MonitorOverflow(cx);
     553                 :         } else {
     554        47696607 :             res->setInt32(sum);
     555                 :         }
     556                 :     } else
     557                 : #if JS_HAS_XML_SUPPORT
     558        11259222 :     if (IsXML(lval) && IsXML(rval)) {
     559               0 :         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), res))
     560               0 :             return false;
     561               0 :         types::TypeScript::MonitorUnknown(cx);
     562                 :     } else
     563                 : #endif
     564                 :     {
     565                 :         /*
     566                 :          * If either operand is an object, any non-integer result must be
     567                 :          * reported to inference.
     568                 :          */
     569        11259222 :         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
     570                 : 
     571        11259222 :         if (!ToPrimitive(cx, &lval))
     572              11 :             return false;
     573        11259211 :         if (!ToPrimitive(cx, &rval))
     574              16 :             return false;
     575                 :         bool lIsString, rIsString;
     576        11259195 :         if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
     577        18406032 :             js::AutoStringRooter lstr(cx), rstr(cx);
     578         6135344 :             if (lIsString) {
     579         5930345 :                 lstr.setString(lval.toString());
     580                 :             } else {
     581          204999 :                 lstr.setString(ToString(cx, lval));
     582          204999 :                 if (!lstr.string())
     583               0 :                     return false;
     584                 :             }
     585         6135344 :             if (rIsString) {
     586         5304125 :                 rstr.setString(rval.toString());
     587                 :             } else {
     588          831219 :                 rstr.setString(ToString(cx, rval));
     589          831219 :                 if (!rstr.string())
     590               0 :                     return false;
     591                 :             }
     592         6135344 :             JSString *str = js_ConcatStrings(cx, lstr.string(), rstr.string());
     593         6135344 :             if (!str)
     594              13 :                 return false;
     595         6135331 :             if (lIsObject || rIsObject)
     596          149802 :                 types::TypeScript::MonitorString(cx);
     597        12270675 :             res->setString(str);
     598                 :         } else {
     599                 :             double l, r;
     600         5123851 :             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
     601               0 :                 return false;
     602         5123851 :             l += r;
     603        10393197 :             if (!res->setNumber(l) &&
     604         5269346 :                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
     605            3238 :                 types::TypeScript::MonitorOverflow(cx);
     606                 :             }
     607                 :         }
     608                 :     }
     609        59135423 :     return true;
     610                 : }
     611                 : 
     612                 : static JS_ALWAYS_INLINE bool
     613         6633500 : SubOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     614                 : {
     615                 :     double d1, d2;
     616         6633500 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     617               0 :         return false;
     618         6633500 :     double d = d1 - d2;
     619         6633500 :     if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
     620            1114 :         types::TypeScript::MonitorOverflow(cx);
     621         6633500 :     return true;
     622                 : }
     623                 : 
     624                 : static JS_ALWAYS_INLINE bool
     625        24972227 : MulOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     626                 : {
     627                 :     double d1, d2;
     628        24972227 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     629               0 :         return false;
     630        24972227 :     double d = d1 * d2;
     631        24972227 :     if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
     632           81361 :         types::TypeScript::MonitorOverflow(cx);
     633        24972227 :     return true;
     634                 : }
     635                 : 
     636                 : static JS_ALWAYS_INLINE bool
     637         1396383 : DivOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     638                 : {
     639                 :     double d1, d2;
     640         1396383 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     641               0 :         return false;
     642         1396383 :     res->setNumber(NumberDiv(d1, d2));
     643                 : 
     644         1396383 :     if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
     645          726047 :         types::TypeScript::MonitorOverflow(cx);
     646         1396383 :     return true;
     647                 : }
     648                 : 
     649                 : static JS_ALWAYS_INLINE bool
     650          461322 : ModOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
     651                 : {
     652                 :     int32_t l, r;
     653          461322 :     if (lhs.isInt32() && rhs.isInt32() &&
     654                 :         (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
     655          451000 :         int32_t mod = l % r;
     656          451000 :         res->setInt32(mod);
     657          451000 :         return true;
     658                 :     }
     659                 : 
     660                 :     double d1, d2;
     661           10322 :     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
     662               0 :         return false;
     663                 : 
     664           10322 :     if (d2 == 0)
     665             145 :         res->setDouble(js_NaN);
     666                 :     else
     667           10177 :         res->setDouble(js_fmod(d1, d2));
     668           10322 :     types::TypeScript::MonitorOverflow(cx);
     669           10322 :     return true;
     670                 : }
     671                 : 
     672                 : static inline bool
     673         9119686 : FetchElementId(JSContext *cx, JSObject *obj, const Value &idval, jsid &id, Value *vp)
     674                 : {
     675                 :     int32_t i_;
     676         9119686 :     if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
     677         8442122 :         id = INT_TO_JSID(i_);
     678         8442122 :         return true;
     679                 :     }
     680          677564 :     return !!js_InternNonIntElementId(cx, obj, idval, &id, vp);
     681                 : }
     682                 : 
     683                 : static JS_ALWAYS_INLINE bool
     684         6947632 : ToIdOperation(JSContext *cx, const Value &objval, const Value &idval, Value *res)
     685                 : {
     686         6947632 :     if (idval.isInt32()) {
     687         6946748 :         *res = idval;
     688         6946748 :         return true;
     689                 :     }
     690                 : 
     691             884 :     JSObject *obj = ValueToObject(cx, objval);
     692             884 :     if (!obj)
     693               0 :         return false;
     694                 : 
     695                 :     jsid dummy;
     696             884 :     if (!js_InternNonIntElementId(cx, obj, idval, &dummy, res))
     697               0 :         return false;
     698                 : 
     699             884 :     if (!res->isInt32())
     700             884 :         types::TypeScript::MonitorUnknown(cx);
     701             884 :     return true;
     702                 : }
     703                 : 
     704                 : static JS_ALWAYS_INLINE bool
     705        44762406 : GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *obj, const Value &rref, Value *res)
     706                 : {
     707                 : #if JS_HAS_XML_SUPPORT
     708        44762406 :     if (op == JSOP_CALLELEM && JS_UNLIKELY(obj->isXML())) {
     709                 :         jsid id;
     710             540 :         if (!FetchElementId(cx, obj, rref, id, res))
     711               0 :             return false;
     712             540 :         return js_GetXMLMethod(cx, obj, id, res);
     713                 :     }
     714                 : #endif
     715                 : 
     716                 :     uint32_t index;
     717        44761866 :     if (IsDefinitelyIndex(rref, &index)) {
     718                 :         do {
     719        42974892 :             if (obj->isDenseArray()) {
     720        29106374 :                 if (index < obj->getDenseArrayInitializedLength()) {
     721        29005441 :                     *res = obj->getDenseArrayElement(index);
     722        29005441 :                     if (!res->isMagic())
     723        29002860 :                         break;
     724                 :                 }
     725        13868518 :             } else if (obj->isArguments()) {
     726           50376 :                 if (obj->asArguments().getElement(index, res))
     727           45661 :                     break;
     728                 :             }
     729        13926371 :             if (!obj->getElement(cx, index, res))
     730              28 :                 return false;
     731                 :         } while(0);
     732                 :     } else {
     733                 :         JSScript *script;
     734                 :         jsbytecode *pc;
     735         1786974 :         types::TypeScript::GetPcScript(cx, &script, &pc);
     736                 : 
     737         1786974 :         if (script->hasAnalysis())
     738         1786693 :             script->analysis()->getCode(pc).getStringElement = true;
     739                 : 
     740         1786974 :         SpecialId special;
     741         1786974 :         *res = rref;
     742         1786974 :         if (ValueIsSpecial(obj, res, &special, cx)) {
     743               0 :             if (!obj->getSpecial(cx, obj, special, res))
     744               0 :                 return false;
     745                 :         } else {
     746                 :             JSAtom *name;
     747         1786974 :             if (!js_ValueToAtom(cx, *res, &name))
     748               0 :                 return false;
     749                 : 
     750         1786974 :             if (name->isIndex(&index)) {
     751          193379 :                 if (!obj->getElement(cx, index, res))
     752               0 :                     return false;
     753                 :             } else {
     754         1593595 :                 if (!obj->getProperty(cx, name->asPropertyName(), res))
     755              55 :                     return false;
     756                 :             }
     757                 :         }
     758                 :     }
     759                 : 
     760        44761783 :     assertSameCompartment(cx, *res);
     761        44761783 :     return true;
     762                 : }
     763                 : 
     764                 : static JS_ALWAYS_INLINE bool
     765        44834722 : GetElementOperation(JSContext *cx, JSOp op, const Value &lref, const Value &rref, Value *res)
     766                 : {
     767        44834722 :     JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
     768                 : 
     769        44834722 :     if (lref.isString() && rref.isInt32()) {
     770           52930 :         JSString *str = lref.toString();
     771           52930 :         int32_t i = rref.toInt32();
     772           52930 :         if (size_t(i) < str->length()) {
     773           52653 :             str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
     774           52653 :             if (!str)
     775               0 :                 return false;
     776           52653 :             res->setString(str);
     777           52653 :             return true;
     778                 :         }
     779                 :     }
     780                 : 
     781        44782069 :     if (lref.isMagic(JS_LAZY_ARGUMENTS)) {
     782           19345 :         if (rref.isInt32() && size_t(rref.toInt32()) < cx->regs().fp()->numActualArgs()) {
     783           19330 :             *res = cx->regs().fp()->canonicalActualArg(rref.toInt32());
     784           19330 :             return true;
     785                 :         }
     786              15 :         types::MarkArgumentsCreated(cx, cx->fp()->script());
     787              15 :         JS_ASSERT(!lref.isMagic(JS_LAZY_ARGUMENTS));
     788                 :     }
     789                 : 
     790        44762739 :     bool isObject = lref.isObject();
     791        44762739 :     JSObject *obj = ValueToObject(cx, lref);
     792        44762739 :     if (!obj)
     793             333 :         return false;
     794        44762406 :     if (!GetObjectElementOperation(cx, op, obj, rref, res))
     795              83 :         return false;
     796                 : 
     797                 : #if JS_HAS_NO_SUCH_METHOD
     798        44762323 :     if (op == JSOP_CALLELEM && JS_UNLIKELY(res->isPrimitive()) && isObject) {
     799             527 :         if (!OnUnknownMethod(cx, obj, rref, res))
     800               0 :             return false;
     801                 :     }
     802                 : #endif
     803        44762323 :     return true;
     804                 : }
     805                 : 
     806                 : static JS_ALWAYS_INLINE bool
     807        20220091 : SetObjectElementOperation(JSContext *cx, JSObject *obj, jsid id, const Value &value, bool strict)
     808                 : {
     809        20220091 :     types::TypeScript::MonitorAssign(cx, obj, id);
     810                 : 
     811                 :     do {
     812        20220091 :         if (obj->isDenseArray() && JSID_IS_INT(id)) {
     813        12573381 :             uint32_t length = obj->getDenseArrayInitializedLength();
     814        12573381 :             int32_t i = JSID_TO_INT(id);
     815        12573381 :             if ((uint32_t)i < length) {
     816        10390506 :                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
     817           15325 :                     if (js_PrototypeHasIndexedProperties(cx, obj))
     818               0 :                         break;
     819           15325 :                     if ((uint32_t)i >= obj->getArrayLength())
     820               0 :                         obj->setArrayLength(cx, i + 1);
     821                 :                 }
     822        10390506 :                 obj->setDenseArrayElementWithType(cx, i, value);
     823        10390506 :                 return true;
     824                 :             } else {
     825                 :                 JSScript *script;
     826                 :                 jsbytecode *pc;
     827         2182875 :                 types::TypeScript::GetPcScript(cx, &script, &pc);
     828                 : 
     829         2182875 :                 if (script->hasAnalysis())
     830         2182875 :                     script->analysis()->getCode(pc).arrayWriteHole = true;
     831                 :             }
     832                 :         }
     833                 :     } while (0);
     834                 : 
     835         9829585 :     Value tmp = value;
     836         9829585 :     return obj->setGeneric(cx, id, &tmp, strict);
     837                 : }
     838                 : 
     839                 : #define RELATIONAL_OP(OP)                                                     \
     840                 :     JS_BEGIN_MACRO                                                            \
     841                 :         Value lval = lhs;                                                     \
     842                 :         Value rval = rhs;                                                     \
     843                 :         /* Optimize for two int-tagged operands (typical loop control). */    \
     844                 :         if (lval.isInt32() && rval.isInt32()) {                               \
     845                 :             *res = lval.toInt32() OP rval.toInt32();                          \
     846                 :         } else {                                                              \
     847                 :             if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                       \
     848                 :                 return false;                                                 \
     849                 :             if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                       \
     850                 :                 return false;                                                 \
     851                 :             if (lval.isString() && rval.isString()) {                         \
     852                 :                 JSString *l = lval.toString(), *r = rval.toString();          \
     853                 :                 int32_t result;                                               \
     854                 :                 if (!CompareStrings(cx, l, r, &result))                       \
     855                 :                     return false;                                             \
     856                 :                 *res = result OP 0;                                           \
     857                 :             } else {                                                          \
     858                 :                 double l, r;                                                  \
     859                 :                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))       \
     860                 :                     return false;;                                            \
     861                 :                 *res = (l OP r);                                              \
     862                 :             }                                                                 \
     863                 :         }                                                                     \
     864                 :         return true;                                                          \
     865                 :     JS_END_MACRO
     866                 : 
     867                 : static JS_ALWAYS_INLINE bool
     868       157465842 : LessThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     869       157465842 :     RELATIONAL_OP(<);
     870                 : }
     871                 : 
     872                 : static JS_ALWAYS_INLINE bool
     873         1765038 : LessThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     874         1765038 :     RELATIONAL_OP(<=);
     875                 : }
     876                 : 
     877                 : static JS_ALWAYS_INLINE bool
     878         1724099 : GreaterThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     879         1724099 :     RELATIONAL_OP(>);
     880                 : }
     881                 : 
     882                 : static JS_ALWAYS_INLINE bool
     883         6230173 : GreaterThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     884         6230173 :     RELATIONAL_OP(>=);
     885                 : }
     886                 : 
     887                 : #undef RELATIONAL_OP
     888                 : 
     889                 : }  /* namespace js */
     890                 : 
     891                 : #endif /* jsinterpinlines_h__ */

Generated by: LCOV version 1.7