LCOV - app.info - js/src/jsinterpinlines.h

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