js/src/vm/Interpreter.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * JavaScript bytecode interpreter.
     9  */
    11 #include "vm/Interpreter-inl.h"
    13 #include "mozilla/DebugOnly.h"
    14 #include "mozilla/FloatingPoint.h"
    15 #include "mozilla/PodOperations.h"
    17 #include <string.h>
    19 #include "jsarray.h"
    20 #include "jsatom.h"
    21 #include "jscntxt.h"
    22 #include "jsfun.h"
    23 #include "jsgc.h"
    24 #include "jsiter.h"
    25 #include "jslibmath.h"
    26 #include "jsnum.h"
    27 #include "jsobj.h"
    28 #include "jsopcode.h"
    29 #include "jsprf.h"
    30 #include "jsscript.h"
    31 #include "jsstr.h"
    33 #include "builtin/Eval.h"
    34 #include "jit/BaselineJIT.h"
    35 #include "jit/Ion.h"
    36 #include "jit/IonAnalysis.h"
    37 #include "js/OldDebugAPI.h"
    38 #include "vm/Debugger.h"
    39 #include "vm/Opcodes.h"
    40 #include "vm/Shape.h"
    41 #include "vm/TraceLogging.h"
    43 #include "jsatominlines.h"
    44 #include "jsboolinlines.h"
    45 #include "jsfuninlines.h"
    46 #include "jsinferinlines.h"
    47 #include "jsscriptinlines.h"
    49 #include "jit/IonFrames-inl.h"
    50 #include "vm/Probes-inl.h"
    51 #include "vm/ScopeObject-inl.h"
    52 #include "vm/Stack-inl.h"
    54 using namespace js;
    55 using namespace js::gc;
    56 using namespace js::types;
    58 using mozilla::DebugOnly;
    59 using mozilla::NumberEqualsInt32;
    60 using mozilla::PodCopy;
    61 using JS::ForOfIterator;
    63 /*
    64  * Note: when Clang 3.2 (32-bit) inlines the two functions below in Interpret,
    65  * the conservative stack scanner leaks a ton of memory and this negatively
    66  * influences performance. The MOZ_NEVER_INLINE is a temporary workaround until
    67  * we can remove the conservative scanner. See bug 849526 for more info.
    68  */
    69 #if defined(__clang__) && defined(JS_CPU_X86)
    70 static MOZ_NEVER_INLINE bool
    71 #else
    72 static bool
    73 #endif
    74 ToBooleanOp(const InterpreterRegs &regs)
    75 {
    76     return ToBoolean(regs.stackHandleAt(-1));
    77 }
    79 template <bool Eq>
    80 #if defined(__clang__) && defined(JS_CPU_X86)
    81 static MOZ_NEVER_INLINE bool
    82 #else
    83 static bool
    84 #endif
    85 LooseEqualityOp(JSContext *cx, InterpreterRegs &regs)
    86 {
    87     HandleValue rval = regs.stackHandleAt(-1);
    88     HandleValue lval = regs.stackHandleAt(-2);
    89     bool cond;
    90     if (!LooselyEqual(cx, lval, rval, &cond))
    91         return false;
    92     cond = (cond == Eq);
    93     regs.sp--;
    94     regs.sp[-1].setBoolean(cond);
    95     return true;
    96 }
    98 JSObject *
    99 js::BoxNonStrictThis(JSContext *cx, HandleValue thisv)
   100 {
   101     /*
   102      * Check for SynthesizeFrame poisoning and fast constructors which
   103      * didn't check their callee properly.
   104      */
   105     JS_ASSERT(!thisv.isMagic());
   107     if (thisv.isNullOrUndefined()) {
   108         Rooted<GlobalObject*> global(cx, cx->global());
   109         return JSObject::thisObject(cx, global);
   110     }
   112     if (thisv.isObject())
   113         return &thisv.toObject();
   115     return PrimitiveToObject(cx, thisv);
   116 }
   118 /*
   119  * ECMA requires "the global object", but in embeddings such as the browser,
   120  * which have multiple top-level objects (windows, frames, etc. in the DOM),
   121  * we prefer fun's parent.  An example that causes this code to run:
   122  *
   123  *   // in window w1
   124  *   function f() { return this }
   125  *   function g() { return f }
   126  *
   127  *   // in window w2
   128  *   var h = w1.g()
   129  *   alert(h() == w1)
   130  *
   131  * The alert should display "true".
   132  */
   133 bool
   134 js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
   135 {
   136     /*
   137      * Check for SynthesizeFrame poisoning and fast constructors which
   138      * didn't check their callee properly.
   139      */
   140     JS_ASSERT(!call.thisv().isMagic());
   142 #ifdef DEBUG
   143     JSFunction *fun = call.callee().is<JSFunction>() ? &call.callee().as<JSFunction>() : nullptr;
   144     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->strict());
   145 #endif
   147     JSObject *thisObj = BoxNonStrictThis(cx, call.thisv());
   148     if (!thisObj)
   149         return false;
   151     call.setThis(ObjectValue(*thisObj));
   152     return true;
   153 }
   155 #if JS_HAS_NO_SUCH_METHOD
   157 static const uint32_t JSSLOT_FOUND_FUNCTION = 0;
   158 static const uint32_t JSSLOT_SAVED_ID = 1;
   160 static const Class js_NoSuchMethodClass = {
   161     "NoSuchMethod",
   162     JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
   163     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   164     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
   165 };
   167 /*
   168  * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
   169  * the base object, we search for the __noSuchMethod__ method in the base.
   170  * If it exists, we store the method and the property's id into an object of
   171  * NoSuchMethod class and store this object into the callee's stack slot.
   172  * Later, Invoke will recognise such an object and transfer control to
   173  * NoSuchMethod that invokes the method like:
   174  *
   175  *   this.__noSuchMethod__(id, args)
   176  *
   177  * where id is the name of the method that this invocation attempted to
   178  * call by name, and args is an Array containing this invocation's actual
   179  * parameters.
   180  */
   181 bool
   182 js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval_, MutableHandleValue vp)
   183 {
   184     RootedValue idval(cx, idval_);
   186     RootedValue value(cx);
   187     if (!JSObject::getProperty(cx, obj, obj, cx->names().noSuchMethod, &value))
   188         return false;
   190     if (value.isObject()) {
   191         JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, nullptr, nullptr);
   192         if (!obj)
   193             return false;
   195         obj->setSlot(JSSLOT_FOUND_FUNCTION, value);
   196         obj->setSlot(JSSLOT_SAVED_ID, idval);
   197         vp.setObject(*obj);
   198     }
   199     return true;
   200 }
   202 static bool
   203 NoSuchMethod(JSContext *cx, unsigned argc, Value *vp)
   204 {
   205     InvokeArgs args(cx);
   206     if (!args.init(2))
   207         return false;
   209     JS_ASSERT(vp[0].isObject());
   210     JS_ASSERT(vp[1].isObject());
   211     JSObject *obj = &vp[0].toObject();
   212     JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
   214     args.setCallee(obj->getReservedSlot(JSSLOT_FOUND_FUNCTION));
   215     args.setThis(vp[1]);
   216     args[0].set(obj->getReservedSlot(JSSLOT_SAVED_ID));
   217     JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
   218     if (!argsobj)
   219         return false;
   220     args[1].setObject(*argsobj);
   221     bool ok = Invoke(cx, args);
   222     vp[0] = args.rval();
   223     return ok;
   224 }
   226 #endif /* JS_HAS_NO_SUCH_METHOD */
   228 static inline bool
   229 GetPropertyOperation(JSContext *cx, InterpreterFrame *fp, HandleScript script, jsbytecode *pc,
   230                      MutableHandleValue lval, MutableHandleValue vp)
   231 {
   232     JSOp op = JSOp(*pc);
   234     if (op == JSOP_LENGTH) {
   235         if (IsOptimizedArguments(fp, lval.address())) {
   236             vp.setInt32(fp->numActualArgs());
   237             return true;
   238         }
   240         if (GetLengthProperty(lval, vp))
   241             return true;
   242     }
   244     Rooted<GlobalObject*> global(cx, &fp->global());
   245     RootedId id(cx, NameToId(script->getName(pc)));
   246     RootedObject obj(cx);
   248     /* Optimize (.1).toString(). */
   249     if (lval.isNumber() && id == NameToId(cx->names().toString)) {
   250         JSObject *proto = GlobalObject::getOrCreateNumberPrototype(cx, global);
   251         if (!proto)
   252             return false;
   253         if (ClassMethodIsNative(cx, proto, &NumberObject::class_, id, js_num_toString))
   254             obj = proto;
   255     }
   257     if (!obj) {
   258         obj = ToObjectFromStack(cx, lval);
   259         if (!obj)
   260             return false;
   261     }
   263     bool wasObject = lval.isObject();
   265     if (!JSObject::getGeneric(cx, obj, obj, id, vp))
   266         return false;
   268 #if JS_HAS_NO_SUCH_METHOD
   269     if (op == JSOP_CALLPROP &&
   270         MOZ_UNLIKELY(vp.isUndefined()) &&
   271         wasObject)
   272     {
   273         if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
   274             return false;
   275     }
   276 #endif
   278     return true;
   279 }
   281 static inline bool
   282 NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandleValue vp)
   283 {
   284     JSObject *obj = fp->scopeChain();
   285     PropertyName *name = fp->script()->getName(pc);
   287     /*
   288      * Skip along the scope chain to the enclosing global object. This is
   289      * used for GNAME opcodes where the bytecode emitter has determined a
   290      * name access must be on the global. It also insulates us from bugs
   291      * in the emitter: type inference will assume that GNAME opcodes are
   292      * accessing the global object, and the inferred behavior should match
   293      * the actual behavior even if the id could be found on the scope chain
   294      * before the global object.
   295      */
   296     if (IsGlobalOp(JSOp(*pc)))
   297         obj = &obj->global();
   299     Shape *shape = nullptr;
   300     JSObject *scope = nullptr, *pobj = nullptr;
   301     if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) {
   302         if (FetchNameNoGC(pobj, shape, vp))
   303             return true;
   304     }
   306     RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx);
   307     RootedPropertyName nameRoot(cx, name);
   308     RootedShape shapeRoot(cx);
   310     if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot))
   311         return false;
   313     /* Kludge to allow (typeof foo == "undefined") tests. */
   314     JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
   315     if (op2 == JSOP_TYPEOF)
   316         return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
   317     return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
   318 }
   320 static inline bool
   321 SetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lval,
   322                      HandleValue rval)
   323 {
   324     JS_ASSERT(*pc == JSOP_SETPROP);
   326     RootedObject obj(cx, ToObjectFromStack(cx, lval));
   327     if (!obj)
   328         return false;
   330     RootedValue rref(cx, rval);
   332     RootedId id(cx, NameToId(script->getName(pc)));
   333     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
   334         if (!baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, baseops::Qualified,
   335                                                              &rref, script->strict()))
   336         {
   337             return false;
   338         }
   339     } else {
   340         if (!JSObject::setGeneric(cx, obj, obj, id, &rref, script->strict()))
   341             return false;
   342     }
   344     return true;
   345 }
   347 bool
   348 js::ReportIsNotFunction(JSContext *cx, HandleValue v, int numToSkip, MaybeConstruct construct)
   349 {
   350     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
   351     int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
   353     js_ReportValueError3(cx, error, spIndex, v, NullPtr(), nullptr, nullptr);
   354     return false;
   355 }
   357 JSObject *
   358 js::ValueToCallable(JSContext *cx, HandleValue v, int numToSkip, MaybeConstruct construct)
   359 {
   360     if (v.isObject()) {
   361         JSObject *callable = &v.toObject();
   362         if (callable->isCallable())
   363             return callable;
   364     }
   366     ReportIsNotFunction(cx, v, numToSkip, construct);
   367     return nullptr;
   368 }
   370 static MOZ_NEVER_INLINE bool
   371 Interpret(JSContext *cx, RunState &state);
   373 InterpreterFrame *
   374 InvokeState::pushInterpreterFrame(JSContext *cx)
   375 {
   376     return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, initial_);
   377 }
   379 InterpreterFrame *
   380 ExecuteState::pushInterpreterFrame(JSContext *cx)
   381 {
   382     return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, thisv_, scopeChain_,
   383                                                               type_, evalInFrame_);
   384 }
   386 bool
   387 js::RunScript(JSContext *cx, RunState &state)
   388 {
   389     JS_CHECK_RECURSION(cx, return false);
   391     SPSEntryMarker marker(cx->runtime());
   393     state.script()->ensureNonLazyCanonicalFunction(cx);
   395 #ifdef JS_ION
   396     if (jit::IsIonEnabled(cx)) {
   397         jit::MethodStatus status = jit::CanEnter(cx, state);
   398         if (status == jit::Method_Error)
   399             return false;
   400         if (status == jit::Method_Compiled) {
   401             jit::IonExecStatus status = jit::IonCannon(cx, state);
   402             return !IsErrorStatus(status);
   403         }
   404     }
   406     if (jit::IsBaselineEnabled(cx)) {
   407         jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state);
   408         if (status == jit::Method_Error)
   409             return false;
   410         if (status == jit::Method_Compiled) {
   411             jit::IonExecStatus status = jit::EnterBaselineMethod(cx, state);
   412             return !IsErrorStatus(status);
   413         }
   414     }
   415 #endif
   417     if (state.isInvoke()) {
   418         InvokeState &invoke = *state.asInvoke();
   419         TypeMonitorCall(cx, invoke.args(), invoke.constructing());
   420     }
   422     return Interpret(cx, state);
   423 }
   425 struct AutoGCIfNeeded
   426 {
   427     JSContext *cx_;
   428     AutoGCIfNeeded(JSContext *cx) : cx_(cx) {}
   429     ~AutoGCIfNeeded() { js::gc::GCIfNeeded(cx_); }
   430 };
   432 /*
   433  * Find a function reference and its 'this' value implicit first parameter
   434  * under argc arguments on cx's stack, and call the function.  Push missing
   435  * required arguments, allocate declared local variables, and pop everything
   436  * when done.  Then push the return value.
   437  */
   438 bool
   439 js::Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct)
   440 {
   441     JS_ASSERT(args.length() <= ARGS_LENGTH_MAX);
   442     JS_ASSERT(!cx->compartment()->activeAnalysis);
   444     /* We should never enter a new script while cx->iterValue is live. */
   445     JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE));
   447     /* Perform GC if necessary on exit from the function. */
   448     AutoGCIfNeeded gcIfNeeded(cx);
   450     /* MaybeConstruct is a subset of InitialFrameFlags */
   451     InitialFrameFlags initial = (InitialFrameFlags) construct;
   453     if (args.calleev().isPrimitive())
   454         return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
   456     JSObject &callee = args.callee();
   457     const Class *clasp = callee.getClass();
   459     /* Invoke non-functions. */
   460     if (MOZ_UNLIKELY(clasp != &JSFunction::class_)) {
   461 #if JS_HAS_NO_SUCH_METHOD
   462         if (MOZ_UNLIKELY(clasp == &js_NoSuchMethodClass))
   463             return NoSuchMethod(cx, args.length(), args.base());
   464 #endif
   465         JS_ASSERT_IF(construct, !clasp->construct);
   466         if (!clasp->call)
   467             return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
   468         return CallJSNative(cx, clasp->call, args);
   469     }
   471     /* Invoke native functions. */
   472     JSFunction *fun = &callee.as<JSFunction>();
   473     JS_ASSERT_IF(construct, !fun->isNativeConstructor());
   474     if (fun->isNative())
   475         return CallJSNative(cx, fun->native(), args);
   477     if (!fun->getOrCreateScript(cx))
   478         return false;
   480     /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
   481     InvokeState state(cx, args, initial);
   483     // Check to see if useNewType flag should be set for this frame.
   484     if (construct) {
   485         FrameIter iter(cx);
   486         if (!iter.done() && iter.hasScript()) {
   487             JSScript *script = iter.script();
   488             jsbytecode *pc = iter.pc();
   489             if (UseNewType(cx, script, pc))
   490                 state.setUseNewType();
   491         }
   492     }
   494     bool ok = RunScript(cx, state);
   496     JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
   497     return ok;
   498 }
   500 bool
   501 js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv,
   502            MutableHandleValue rval)
   503 {
   504     InvokeArgs args(cx);
   505     if (!args.init(argc))
   506         return false;
   508     args.setCallee(fval);
   509     args.setThis(thisv);
   510     PodCopy(args.array(), argv, argc);
   512     if (args.thisv().isObject()) {
   513         /*
   514          * We must call the thisObject hook in case we are not called from the
   515          * interpreter, where a prior bytecode has computed an appropriate
   516          * |this| already.  But don't do that if fval is a DOM function.
   517          */
   518         if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
   519             !fval.toObject().as<JSFunction>().isNative() ||
   520             !fval.toObject().as<JSFunction>().jitInfo() ||
   521             fval.toObject().as<JSFunction>().jitInfo()->needsOuterizedThisObject())
   522         {
   523             RootedObject thisObj(cx, &args.thisv().toObject());
   524             JSObject *thisp = JSObject::thisObject(cx, thisObj);
   525             if (!thisp)
   526                 return false;
   527             args.setThis(ObjectValue(*thisp));
   528         }
   529     }
   531     if (!Invoke(cx, args))
   532         return false;
   534     rval.set(args.rval());
   535     return true;
   536 }
   538 bool
   539 js::InvokeConstructor(JSContext *cx, CallArgs args)
   540 {
   541     JS_ASSERT(!JSFunction::class_.construct);
   543     args.setThis(MagicValue(JS_IS_CONSTRUCTING));
   545     if (!args.calleev().isObject())
   546         return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
   548     JSObject &callee = args.callee();
   549     if (callee.is<JSFunction>()) {
   550         RootedFunction fun(cx, &callee.as<JSFunction>());
   552         if (fun->isNativeConstructor()) {
   553             bool ok = CallJSNativeConstructor(cx, fun->native(), args);
   554             return ok;
   555         }
   557         if (!fun->isInterpretedConstructor()) {
   558             RootedValue orig(cx, ObjectValue(*fun->originalFunction()));
   559             return ReportIsNotFunction(cx, orig, args.length() + 1, CONSTRUCT);
   560         }
   561         if (!Invoke(cx, args, CONSTRUCT))
   562             return false;
   564         JS_ASSERT(args.rval().isObject());
   565         return true;
   566     }
   568     const Class *clasp = callee.getClass();
   569     if (!clasp->construct)
   570         return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
   572     return CallJSNativeConstructor(cx, clasp->construct, args);
   573 }
   575 bool
   576 js::InvokeConstructor(JSContext *cx, Value fval, unsigned argc, Value *argv, Value *rval)
   577 {
   578     InvokeArgs args(cx);
   579     if (!args.init(argc))
   580         return false;
   582     args.setCallee(fval);
   583     args.setThis(MagicValue(JS_THIS_POISON));
   584     PodCopy(args.array(), argv, argc);
   586     if (!InvokeConstructor(cx, args))
   587         return false;
   589     *rval = args.rval();
   590     return true;
   591 }
   593 bool
   594 js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc,
   595                          Value *argv, MutableHandleValue rval)
   596 {
   597     /*
   598      * Invoke could result in another try to get or set the same id again, see
   599      * bug 355497.
   600      */
   601     JS_CHECK_RECURSION(cx, return false);
   603     return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
   604 }
   606 bool
   607 js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, const Value &thisv,
   608                   ExecuteType type, AbstractFramePtr evalInFrame, Value *result)
   609 {
   610     JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
   611     JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChainArg.is<ScopeObject>());
   612 #ifdef DEBUG
   613     if (thisv.isObject()) {
   614         RootedObject thisObj(cx, &thisv.toObject());
   615         AutoSuppressGC nogc(cx);
   616         JS_ASSERT(GetOuterObject(cx, thisObj) == thisObj);
   617     }
   618 #endif
   620     if (script->isEmpty()) {
   621         if (result)
   622             result->setUndefined();
   623         return true;
   624     }
   626     TypeScript::SetThis(cx, script, thisv);
   628     probes::StartExecution(script);
   629     ExecuteState state(cx, script, thisv, scopeChainArg, type, evalInFrame, result);
   630     bool ok = RunScript(cx, state);
   631     probes::StopExecution(script);
   633     return ok;
   634 }
   636 bool
   637 js::Execute(JSContext *cx, HandleScript script, JSObject &scopeChainArg, Value *rval)
   638 {
   639     /* The scope chain could be anything, so innerize just in case. */
   640     RootedObject scopeChain(cx, &scopeChainArg);
   641     scopeChain = GetInnerObject(cx, scopeChain);
   642     if (!scopeChain)
   643         return false;
   645     /* Ensure the scope chain is all same-compartment and terminates in a global. */
   646 #ifdef DEBUG
   647     JSObject *s = scopeChain;
   648     do {
   649         assertSameCompartment(cx, s);
   650         JS_ASSERT_IF(!s->enclosingScope(), s->is<GlobalObject>());
   651     } while ((s = s->enclosingScope()));
   652 #endif
   654     /* The VAROBJFIX option makes varObj == globalObj in global code. */
   655     if (!cx->options().varObjFix()) {
   656         if (!scopeChain->setVarObj(cx))
   657             return false;
   658     }
   660     /* Use the scope chain as 'this', modulo outerization. */
   661     JSObject *thisObj = JSObject::thisObject(cx, scopeChain);
   662     if (!thisObj)
   663         return false;
   664     Value thisv = ObjectValue(*thisObj);
   666     return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
   667                          NullFramePtr() /* evalInFrame */, rval);
   668 }
   670 bool
   671 js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp)
   672 {
   673     const Class *clasp = obj->getClass();
   674     RootedValue local(cx, v);
   675     if (clasp->hasInstance)
   676         return clasp->hasInstance(cx, obj, &local, bp);
   678     RootedValue val(cx, ObjectValue(*obj));
   679     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
   680                         JSDVG_SEARCH_STACK, val, NullPtr());
   681     return false;
   682 }
   684 bool
   685 js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
   686 {
   687     if (SameType(lval, rval)) {
   688         if (lval.isString()) {
   689             JSString *l = lval.toString();
   690             JSString *r = rval.toString();
   691             return EqualStrings(cx, l, r, result);
   692         }
   694         if (lval.isDouble()) {
   695             double l = lval.toDouble(), r = rval.toDouble();
   696             *result = (l == r);
   697             return true;
   698         }
   700         if (lval.isObject()) {
   701             JSObject *l = &lval.toObject();
   702             JSObject *r = &rval.toObject();
   703             *result = l == r;
   704             return true;
   705         }
   707         *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
   708         return true;
   709     }
   711     if (lval.isNullOrUndefined()) {
   712         *result = rval.isNullOrUndefined() ||
   713                   (rval.isObject() && EmulatesUndefined(&rval.toObject()));
   714         return true;
   715     }
   717     if (rval.isNullOrUndefined()) {
   718         *result = (lval.isObject() && EmulatesUndefined(&lval.toObject()));
   719         return true;
   720     }
   722     RootedValue lvalue(cx, lval);
   723     RootedValue rvalue(cx, rval);
   725     if (!ToPrimitive(cx, &lvalue))
   726         return false;
   727     if (!ToPrimitive(cx, &rvalue))
   728         return false;
   730     if (lvalue.get().isString() && rvalue.get().isString()) {
   731         JSString *l = lvalue.get().toString();
   732         JSString *r = rvalue.get().toString();
   733         return EqualStrings(cx, l, r, result);
   734     }
   736     double l, r;
   737     if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
   738         return false;
   739     *result = (l == r);
   740     return true;
   741 }
   743 bool
   744 js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal)
   745 {
   746     Value lval = lref, rval = rref;
   747     if (SameType(lval, rval)) {
   748         if (lval.isString())
   749             return EqualStrings(cx, lval.toString(), rval.toString(), equal);
   750         if (lval.isDouble()) {
   751             *equal = (lval.toDouble() == rval.toDouble());
   752             return true;
   753         }
   754         if (lval.isObject()) {
   755             *equal = lval.toObject() == rval.toObject();
   756             return true;
   757         }
   758         if (lval.isUndefined()) {
   759             *equal = true;
   760             return true;
   761         }
   762         *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
   763         return true;
   764     }
   766     if (lval.isDouble() && rval.isInt32()) {
   767         double ld = lval.toDouble();
   768         double rd = rval.toInt32();
   769         *equal = (ld == rd);
   770         return true;
   771     }
   772     if (lval.isInt32() && rval.isDouble()) {
   773         double ld = lval.toInt32();
   774         double rd = rval.toDouble();
   775         *equal = (ld == rd);
   776         return true;
   777     }
   779     *equal = false;
   780     return true;
   781 }
   783 static inline bool
   784 IsNegativeZero(const Value &v)
   785 {
   786     return v.isDouble() && mozilla::IsNegativeZero(v.toDouble());
   787 }
   789 static inline bool
   790 IsNaN(const Value &v)
   791 {
   792     return v.isDouble() && mozilla::IsNaN(v.toDouble());
   793 }
   795 bool
   796 js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same)
   797 {
   798     if (IsNegativeZero(v1)) {
   799         *same = IsNegativeZero(v2);
   800         return true;
   801     }
   802     if (IsNegativeZero(v2)) {
   803         *same = false;
   804         return true;
   805     }
   806     if (IsNaN(v1) && IsNaN(v2)) {
   807         *same = true;
   808         return true;
   809     }
   810     return StrictlyEqual(cx, v1, v2, same);
   811 }
   813 JSType
   814 js::TypeOfObject(JSObject *obj)
   815 {
   816     if (EmulatesUndefined(obj))
   817         return JSTYPE_VOID;
   818     if (obj->isCallable())
   819         return JSTYPE_FUNCTION;
   820     return JSTYPE_OBJECT;
   821 }
   823 JSType
   824 js::TypeOfValue(const Value &v)
   825 {
   826     if (v.isNumber())
   827         return JSTYPE_NUMBER;
   828     if (v.isString())
   829         return JSTYPE_STRING;
   830     if (v.isNull())
   831         return JSTYPE_OBJECT;
   832     if (v.isUndefined())
   833         return JSTYPE_VOID;
   834     if (v.isObject())
   835         return TypeOfObject(&v.toObject());
   836     JS_ASSERT(v.isBoolean());
   837     return JSTYPE_BOOLEAN;
   838 }
   840 /*
   841  * Enter the new with scope using an object at sp[-1] and associate the depth
   842  * of the with block with sp + stackIndex.
   843  */
   844 bool
   845 js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val,
   846                        HandleObject staticWith)
   847 {
   848     JS_ASSERT(staticWith->is<StaticWithObject>());
   849     RootedObject obj(cx);
   850     if (val.isObject()) {
   851         obj = &val.toObject();
   852     } else {
   853         obj = ToObject(cx, val);
   854         if (!obj)
   855             return false;
   856     }
   858     RootedObject scopeChain(cx, frame.scopeChain());
   859     DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, staticWith);
   860     if (!withobj)
   861         return false;
   863     frame.pushOnScopeChain(*withobj);
   864     return true;
   865 }
   867 // Unwind scope chain and iterator to match the static scope corresponding to
   868 // the given bytecode position.
   869 void
   870 js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc)
   871 {
   872     if (si.done())
   873         return;
   875     Rooted<NestedScopeObject *> staticScope(cx, si.frame().script()->getStaticScope(pc));
   877     for (; si.staticScope() != staticScope; ++si) {
   878         switch (si.type()) {
   879           case ScopeIter::Block:
   880             if (cx->compartment()->debugMode())
   881                 DebugScopes::onPopBlock(cx, si);
   882             if (si.staticBlock().needsClone())
   883                 si.frame().popBlock(cx);
   884             break;
   885           case ScopeIter::With:
   886             si.frame().popWith(cx);
   887             break;
   888           case ScopeIter::Call:
   889           case ScopeIter::StrictEvalScope:
   890             break;
   891         }
   892     }
   893 }
   895 static void
   896 ForcedReturn(JSContext *cx, ScopeIter &si, InterpreterRegs &regs)
   897 {
   898     UnwindScope(cx, si, regs.fp()->script()->main());
   899     regs.setToEndOfScript();
   900 }
   902 static void
   903 ForcedReturn(JSContext *cx, InterpreterRegs &regs)
   904 {
   905     ScopeIter si(regs.fp(), regs.pc, cx);
   906     ForcedReturn(cx, si, regs);
   907 }
   909 void
   910 js::UnwindForUncatchableException(JSContext *cx, const InterpreterRegs &regs)
   911 {
   912     /* c.f. the regular (catchable) TryNoteIter loop in HandleError. */
   913     for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
   914         JSTryNote *tn = *tni;
   915         if (tn->kind == JSTRY_ITER) {
   916             Value *sp = regs.spForStackDepth(tn->stackDepth);
   917             UnwindIteratorForUncatchableException(cx, &sp[-1].toObject());
   918         }
   919     }
   920 }
   922 TryNoteIter::TryNoteIter(JSContext *cx, const InterpreterRegs &regs)
   923   : regs(regs),
   924     script(cx, regs.fp()->script()),
   925     pcOffset(regs.pc - script->main())
   926 {
   927     if (script->hasTrynotes()) {
   928         tn = script->trynotes()->vector;
   929         tnEnd = tn + script->trynotes()->length;
   930     } else {
   931         tn = tnEnd = nullptr;
   932     }
   933     settle();
   934 }
   936 void
   937 TryNoteIter::operator++()
   938 {
   939     ++tn;
   940     settle();
   941 }
   943 bool
   944 TryNoteIter::done() const
   945 {
   946     return tn == tnEnd;
   947 }
   949 void
   950 TryNoteIter::settle()
   951 {
   952     for (; tn != tnEnd; ++tn) {
   953         /* If pc is out of range, try the next one. */
   954         if (pcOffset - tn->start >= tn->length)
   955             continue;
   957         /*
   958          * We have a note that covers the exception pc but we must check
   959          * whether the interpreter has already executed the corresponding
   960          * handler. This is possible when the executed bytecode implements
   961          * break or return from inside a for-in loop.
   962          *
   963          * In this case the emitter generates additional [enditer] and [gosub]
   964          * opcodes to close all outstanding iterators and execute the finally
   965          * blocks. If such an [enditer] throws an exception, its pc can still
   966          * be inside several nested for-in loops and try-finally statements
   967          * even if we have already closed the corresponding iterators and
   968          * invoked the finally blocks.
   969          *
   970          * To address this, we make [enditer] always decrease the stack even
   971          * when its implementation throws an exception. Thus already executed
   972          * [enditer] and [gosub] opcodes will have try notes with the stack
   973          * depth exceeding the current one and this condition is what we use to
   974          * filter them out.
   975          */
   976         if (tn->stackDepth <= regs.stackDepth())
   977             break;
   978     }
   979 }
   981 enum HandleErrorContinuation
   982 {
   983     SuccessfulReturnContinuation,
   984     ErrorReturnContinuation,
   985     CatchContinuation,
   986     FinallyContinuation
   987 };
   989 static HandleErrorContinuation
   990 HandleError(JSContext *cx, InterpreterRegs &regs)
   991 {
   992     JS_ASSERT(regs.fp()->script()->containsPC(regs.pc));
   994     ScopeIter si(regs.fp(), regs.pc, cx);
   995     bool ok = false;
   997   again:
   998     if (cx->isExceptionPending()) {
   999         /* Call debugger throw hooks. */
  1000         if (MOZ_UNLIKELY(cx->compartment()->debugMode())) {
  1001             JSTrapStatus status = DebugExceptionUnwind(cx, regs.fp(), regs.pc);
  1002             switch (status) {
  1003               case JSTRAP_ERROR:
  1004                 goto again;
  1006               case JSTRAP_CONTINUE:
  1007               case JSTRAP_THROW:
  1008                 break;
  1010               case JSTRAP_RETURN:
  1011                 ForcedReturn(cx, si, regs);
  1012                 return SuccessfulReturnContinuation;
  1014               default:
  1015                 MOZ_ASSUME_UNREACHABLE("Invalid trap status");
  1019         RootedValue exception(cx);
  1020         for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
  1021             JSTryNote *tn = *tni;
  1023             UnwindScope(cx, si, regs.fp()->script()->main() + tn->start);
  1025             /*
  1026              * Set pc to the first bytecode after the the try note to point
  1027              * to the beginning of catch or finally or to [enditer] closing
  1028              * the for-in loop.
  1029              */
  1030             regs.pc = regs.fp()->script()->main() + tn->start + tn->length;
  1031             regs.sp = regs.spForStackDepth(tn->stackDepth);
  1033             switch (tn->kind) {
  1034               case JSTRY_CATCH:
  1035                 /* Catch cannot intercept the closing of a generator. */
  1036                 if (!cx->getPendingException(&exception))
  1037                     return ErrorReturnContinuation;
  1038                 if (exception.isMagic(JS_GENERATOR_CLOSING))
  1039                     break;
  1040                 return CatchContinuation;
  1042               case JSTRY_FINALLY:
  1043                 return FinallyContinuation;
  1045               case JSTRY_ITER: {
  1046                 /* This is similar to JSOP_ENDITER in the interpreter loop. */
  1047                 JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
  1048                 RootedObject obj(cx, &regs.sp[-1].toObject());
  1049                 bool ok = UnwindIteratorForException(cx, obj);
  1050                 regs.sp -= 1;
  1051                 if (!ok)
  1052                     goto again;
  1053                 break;
  1056               case JSTRY_LOOP:
  1057                 break;
  1061         /*
  1062          * Propagate the exception or error to the caller unless the exception
  1063          * is an asynchronous return from a generator.
  1064          */
  1065         if (cx->isExceptionPending()) {
  1066             RootedValue exception(cx);
  1067             if (!cx->getPendingException(&exception))
  1068                 return ErrorReturnContinuation;
  1070             if (exception.isMagic(JS_GENERATOR_CLOSING)) {
  1071                 cx->clearPendingException();
  1072                 ok = true;
  1073                 regs.fp()->clearReturnValue();
  1076     } else {
  1077         UnwindForUncatchableException(cx, regs);
  1080     ForcedReturn(cx, si, regs);
  1081     return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
  1084 #define REGS                     (activation.regs())
  1085 #define PUSH_COPY(v)             do { *REGS.sp++ = (v); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
  1086 #define PUSH_COPY_SKIP_CHECK(v)  *REGS.sp++ = (v)
  1087 #define PUSH_NULL()              REGS.sp++->setNull()
  1088 #define PUSH_UNDEFINED()         REGS.sp++->setUndefined()
  1089 #define PUSH_BOOLEAN(b)          REGS.sp++->setBoolean(b)
  1090 #define PUSH_DOUBLE(d)           REGS.sp++->setDouble(d)
  1091 #define PUSH_INT32(i)            REGS.sp++->setInt32(i)
  1092 #define PUSH_STRING(s)           do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
  1093 #define PUSH_OBJECT(obj)         do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
  1094 #define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
  1095 #define PUSH_HOLE()              REGS.sp++->setMagic(JS_ELEMENTS_HOLE)
  1096 #define POP_COPY_TO(v)           (v) = *--REGS.sp
  1097 #define POP_RETURN_VALUE()       REGS.fp()->setReturnValue(*--REGS.sp)
  1099 #define FETCH_OBJECT(cx, n, obj)                                              \
  1100     JS_BEGIN_MACRO                                                            \
  1101         HandleValue val = REGS.stackHandleAt(n);                              \
  1102         obj = ToObjectFromStack((cx), (val));                                 \
  1103         if (!obj)                                                             \
  1104             goto error;                                                       \
  1105     JS_END_MACRO
  1107 /*
  1108  * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
  1109  * remain distinct for the decompiler.
  1110  */
  1111 JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
  1113 /* See TRY_BRANCH_AFTER_COND. */
  1114 JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
  1115 JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
  1117 /*
  1118  * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
  1119  * all cases, but we inline the most frequently taken paths here.
  1120  */
  1121 bool
  1122 js::IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval)
  1124     if (iterobj->is<PropertyIteratorObject>()) {
  1125         NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
  1126         if (ni->isKeyIter()) {
  1127             *cond = (ni->props_cursor < ni->props_end);
  1128             return true;
  1131     Rooted<JSObject*> iobj(cx, iterobj);
  1132     if (!js_IteratorMore(cx, iobj, rval))
  1133         return false;
  1134     *cond = rval.isTrue();
  1135     return true;
  1138 bool
  1139 js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
  1141     if (iterobj->is<PropertyIteratorObject>()) {
  1142         NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
  1143         if (ni->isKeyIter()) {
  1144             JS_ASSERT(ni->props_cursor < ni->props_end);
  1145             rval.setString(*ni->current());
  1146             ni->incCursor();
  1147             return true;
  1150     return js_IteratorNext(cx, iterobj, rval);
  1153 /*
  1154  * Compute the implicit |this| parameter for a call expression where the callee
  1155  * funval was resolved from an unqualified name reference to a property on obj
  1156  * (an object on the scope chain).
  1158  * We can avoid computing |this| eagerly and push the implicit callee-coerced
  1159  * |this| value, undefined, if any of these conditions hold:
  1161  * 1. The nominal |this|, obj, is a global object.
  1163  * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
  1164  *    is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
  1165  *    censored with undefined.
  1167  * Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
  1168  * statements and embedding-specific scope objects fall into this category.
  1170  * If the callee is a strict mode function, then code implementing JSOP_THIS
  1171  * in the interpreter and JITs will leave undefined as |this|. If funval is a
  1172  * function not in strict mode, JSOP_THIS code replaces undefined with funval's
  1173  * global.
  1175  * We set *vp to undefined early to reduce code size and bias this code for the
  1176  * common and future-friendly cases.
  1177  */
  1178 static inline bool
  1179 ComputeImplicitThis(JSContext *cx, HandleObject obj, MutableHandleValue vp)
  1181     vp.setUndefined();
  1183     if (obj->is<GlobalObject>())
  1184         return true;
  1186     if (IsCacheableNonGlobalScope(obj))
  1187         return true;
  1189     JSObject *nobj = JSObject::thisObject(cx, obj);
  1190     if (!nobj)
  1191         return false;
  1193     vp.setObject(*nobj);
  1194     return true;
  1197 static MOZ_ALWAYS_INLINE bool
  1198 AddOperation(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  1200     if (lhs.isInt32() && rhs.isInt32()) {
  1201         int32_t l = lhs.toInt32(), r = rhs.toInt32();
  1202         int32_t t;
  1203         if (MOZ_LIKELY(SafeAdd(l, r, &t))) {
  1204             res.setInt32(t);
  1205             return true;
  1209     if (!ToPrimitive(cx, lhs))
  1210         return false;
  1211     if (!ToPrimitive(cx, rhs))
  1212         return false;
  1214     bool lIsString, rIsString;
  1215     if ((lIsString = lhs.isString()) | (rIsString = rhs.isString())) {
  1216         JSString *lstr, *rstr;
  1217         if (lIsString) {
  1218             lstr = lhs.toString();
  1219         } else {
  1220             lstr = ToString<CanGC>(cx, lhs);
  1221             if (!lstr)
  1222                 return false;
  1224         if (rIsString) {
  1225             rstr = rhs.toString();
  1226         } else {
  1227             // Save/restore lstr in case of GC activity under ToString.
  1228             lhs.setString(lstr);
  1229             rstr = ToString<CanGC>(cx, rhs);
  1230             if (!rstr)
  1231                 return false;
  1232             lstr = lhs.toString();
  1234         JSString *str = ConcatStrings<NoGC>(cx, lstr, rstr);
  1235         if (!str) {
  1236             RootedString nlstr(cx, lstr), nrstr(cx, rstr);
  1237             str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
  1238             if (!str)
  1239                 return false;
  1241         res.setString(str);
  1242     } else {
  1243         double l, r;
  1244         if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r))
  1245             return false;
  1246         res.setNumber(l + r);
  1249     return true;
  1252 static MOZ_ALWAYS_INLINE bool
  1253 SubOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  1255     double d1, d2;
  1256     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
  1257         return false;
  1258     res.setNumber(d1 - d2);
  1259     return true;
  1262 static MOZ_ALWAYS_INLINE bool
  1263 MulOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  1265     double d1, d2;
  1266     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
  1267         return false;
  1268     res.setNumber(d1 * d2);
  1269     return true;
  1272 static MOZ_ALWAYS_INLINE bool
  1273 DivOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  1275     double d1, d2;
  1276     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
  1277         return false;
  1278     res.setNumber(NumberDiv(d1, d2));
  1279     return true;
  1282 static MOZ_ALWAYS_INLINE bool
  1283 ModOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  1285     int32_t l, r;
  1286     if (lhs.isInt32() && rhs.isInt32() &&
  1287         (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
  1288         int32_t mod = l % r;
  1289         res.setInt32(mod);
  1290         return true;
  1293     double d1, d2;
  1294     if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
  1295         return false;
  1297     res.setNumber(NumberMod(d1, d2));
  1298     return true;
  1301 static MOZ_ALWAYS_INLINE bool
  1302 SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value,
  1303                           bool strict, JSScript *script = nullptr, jsbytecode *pc = nullptr)
  1305     types::TypeScript::MonitorAssign(cx, obj, id);
  1307 #ifdef JS_ION
  1308     if (obj->isNative() && JSID_IS_INT(id)) {
  1309         uint32_t length = obj->getDenseInitializedLength();
  1310         int32_t i = JSID_TO_INT(id);
  1311         if ((uint32_t)i >= length) {
  1312             // Annotate script if provided with information (e.g. baseline)
  1313             if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
  1314                 script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
  1317 #endif
  1319     if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
  1320         return false;
  1322     RootedValue tmp(cx, value);
  1323     return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
  1326 static MOZ_NEVER_INLINE bool
  1327 Interpret(JSContext *cx, RunState &state)
  1329 /*
  1330  * Define macros for an interpreter loop. Opcode dispatch may be either by a
  1331  * switch statement or by indirect goto (aka a threaded interpreter), depending
  1332  * on compiler support.
  1334  * Threaded interpretation appears to be well-supported by GCC 3 and higher.
  1335  * IBM's C compiler when run with the right options (e.g., -qlanglvl=extended)
  1336  * also supports threading. Ditto the SunPro C compiler.
  1337  */
  1338 #if (__GNUC__ >= 3 ||                                                         \
  1339      (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) ||                      \
  1340      __SUNPRO_C >= 0x570)
  1341 // Non-standard but faster indirect-goto-based dispatch.
  1342 # define INTERPRETER_LOOP()
  1343 # define CASE(OP)                 label_##OP:
  1344 # define DEFAULT()                label_default:
  1345 # define DISPATCH_TO(OP)          goto *addresses[(OP)]
  1347 # define LABEL(X)                 (&&label_##X)
  1349     // Use addresses instead of offsets to optimize for runtime speed over
  1350     // load-time relocation overhead.
  1351     static const void *const addresses[EnableInterruptsPseudoOpcode + 1] = {
  1352 # define OPCODE_LABEL(op, ...)  LABEL(op),
  1353         FOR_EACH_OPCODE(OPCODE_LABEL)
  1354 # undef OPCODE_LABEL
  1355 # define TRAILING_LABEL(v)                                                    \
  1356     ((v) == EnableInterruptsPseudoOpcode                                      \
  1357      ? LABEL(EnableInterruptsPseudoOpcode)                                    \
  1358      : LABEL(default)),
  1359         FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
  1360 # undef TRAILING_LABEL
  1361     };
  1362 #else
  1363 // Portable switch-based dispatch.
  1364 # define INTERPRETER_LOOP()       the_switch: switch (switchOp)
  1365 # define CASE(OP)                 case OP:
  1366 # define DEFAULT()                default:
  1367 # define DISPATCH_TO(OP)                                                      \
  1368     JS_BEGIN_MACRO                                                            \
  1369         switchOp = (OP);                                                      \
  1370         goto the_switch;                                                      \
  1371     JS_END_MACRO
  1373     // This variable is effectively a parameter to the_switch.
  1374     jsbytecode switchOp;
  1375 #endif
  1377     /*
  1378      * Increment REGS.pc by N, load the opcode at that position,
  1379      * and jump to the code to execute it.
  1381      * When Debugger puts a script in single-step mode, all js::Interpret
  1382      * invocations that might be presently running that script must have
  1383      * interrupts enabled. It's not practical to simply check
  1384      * script->stepModeEnabled() at each point some callee could have changed
  1385      * it, because there are so many places js::Interpret could possibly cause
  1386      * JavaScript to run: each place an object might be coerced to a primitive
  1387      * or a number, for example. So instead, we expose a simple mechanism to
  1388      * let Debugger tweak the affected js::Interpret frames when an onStep
  1389      * handler is added: calling activation.enableInterruptsUnconditionally()
  1390      * will enable interrupts, and activation.opMask() is or'd with the opcode
  1391      * to implement a simple alternate dispatch.
  1392      */
  1393 #define ADVANCE_AND_DISPATCH(N)                                               \
  1394     JS_BEGIN_MACRO                                                            \
  1395         REGS.pc += (N);                                                       \
  1396         SANITY_CHECKS();                                                      \
  1397         DISPATCH_TO(*REGS.pc | activation.opMask());                          \
  1398     JS_END_MACRO
  1400    /*
  1401     * Shorthand for the common sequence at the end of a fixed-size opcode.
  1402     */
  1403 #define END_CASE(OP)              ADVANCE_AND_DISPATCH(OP##_LENGTH);
  1405     /*
  1406      * Prepare to call a user-supplied branch handler, and abort the script
  1407      * if it returns false.
  1408      */
  1409 #define CHECK_BRANCH()                                                        \
  1410     JS_BEGIN_MACRO                                                            \
  1411         if (!CheckForInterrupt(cx))                                           \
  1412             goto error;                                                       \
  1413     JS_END_MACRO
  1415     /*
  1416      * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
  1417      * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
  1418      * is the backedge of a loop.
  1419      */
  1420 #define BRANCH(n)                                                             \
  1421     JS_BEGIN_MACRO                                                            \
  1422         int32_t nlen = (n);                                                   \
  1423         if (nlen <= 0)                                                        \
  1424             CHECK_BRANCH();                                                   \
  1425         ADVANCE_AND_DISPATCH(nlen);                                           \
  1426     JS_END_MACRO
  1428 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
  1429     ((dbl) = script->getConst(GET_UINT32_INDEX(REGS.pc + (PCOFF))).toDouble())
  1431 #define SET_SCRIPT(s)                                                         \
  1432     JS_BEGIN_MACRO                                                            \
  1433         script = (s);                                                         \
  1434         if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts()) \
  1435             activation.enableInterruptsUnconditionally();                     \
  1436     JS_END_MACRO
  1438 #define SANITY_CHECKS()                                                       \
  1439     JS_BEGIN_MACRO                                                            \
  1440         js::gc::MaybeVerifyBarriers(cx);                                      \
  1441         JS_ASSERT_IF(script->hasScriptCounts(),                               \
  1442                      activation.opMask() == EnableInterruptsPseudoOpcode);    \
  1443     JS_END_MACRO
  1445     gc::MaybeVerifyBarriers(cx, true);
  1446     JS_ASSERT(!cx->compartment()->activeAnalysis);
  1448     InterpreterFrame *entryFrame = state.pushInterpreterFrame(cx);
  1449     if (!entryFrame)
  1450         return false;
  1452     InterpreterActivation activation(state, cx, entryFrame);
  1454     /* The script is used frequently, so keep a local copy. */
  1455     RootedScript script(cx);
  1456     SET_SCRIPT(REGS.fp()->script());
  1458     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
  1459     uint32_t scriptLogId = TraceLogCreateTextId(logger, script);
  1460     TraceLogStartEvent(logger, scriptLogId);
  1461     TraceLogStartEvent(logger, TraceLogger::Interpreter);
  1463     /*
  1464      * Pool of rooters for use in this interpreter frame. References to these
  1465      * are used for local variables within interpreter cases. This avoids
  1466      * creating new rooters each time an interpreter case is entered, and also
  1467      * correctness pitfalls due to incorrect compilation of destructor calls
  1468      * around computed gotos.
  1469      */
  1470     RootedValue rootValue0(cx), rootValue1(cx);
  1471     RootedString rootString0(cx), rootString1(cx);
  1472     RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
  1473     RootedFunction rootFunction0(cx);
  1474     RootedTypeObject rootType0(cx);
  1475     RootedPropertyName rootName0(cx);
  1476     RootedId rootId0(cx);
  1477     RootedShape rootShape0(cx);
  1478     RootedScript rootScript0(cx);
  1479     DebugOnly<uint32_t> blockDepth;
  1481     if (MOZ_UNLIKELY(REGS.fp()->isGeneratorFrame())) {
  1482         JS_ASSERT(script->containsPC(REGS.pc));
  1483         JS_ASSERT(REGS.stackDepth() <= script->nslots());
  1485         /*
  1486          * To support generator_throw and to catch ignored exceptions,
  1487          * fail if cx->isExceptionPending() is true.
  1488          */
  1489         if (cx->isExceptionPending()) {
  1490             probes::EnterScript(cx, script, script->functionNonDelazifying(), REGS.fp());
  1491             goto error;
  1495     /* State communicated between non-local jumps: */
  1496     bool interpReturnOK;
  1498     if (!activation.entryFrame()->isGeneratorFrame()) {
  1499         if (!activation.entryFrame()->prologue(cx))
  1500             goto error;
  1501     } else {
  1502         if (!probes::EnterScript(cx, script, script->functionNonDelazifying(),
  1503                                  activation.entryFrame()))
  1505             goto error;
  1508     if (MOZ_UNLIKELY(cx->compartment()->debugMode())) {
  1509         JSTrapStatus status = ScriptDebugPrologue(cx, activation.entryFrame(), REGS.pc);
  1510         switch (status) {
  1511           case JSTRAP_CONTINUE:
  1512             break;
  1513           case JSTRAP_RETURN:
  1514             ForcedReturn(cx, REGS);
  1515             goto successful_return_continuation;
  1516           case JSTRAP_THROW:
  1517           case JSTRAP_ERROR:
  1518             goto error;
  1519           default:
  1520             MOZ_ASSUME_UNREACHABLE("bad ScriptDebugPrologue status");
  1524     if (cx->runtime()->profilingScripts || cx->runtime()->debugHooks.interruptHook)
  1525         activation.enableInterruptsUnconditionally();
  1527     // Enter the interpreter loop starting at the current pc.
  1528     ADVANCE_AND_DISPATCH(0);
  1530 INTERPRETER_LOOP() {
  1532 CASE(EnableInterruptsPseudoOpcode)
  1534     bool moreInterrupts = false;
  1535     jsbytecode op = *REGS.pc;
  1537     if (cx->runtime()->profilingScripts) {
  1538         if (!script->hasScriptCounts())
  1539             script->initScriptCounts(cx);
  1540         moreInterrupts = true;
  1543     if (script->hasScriptCounts()) {
  1544         PCCounts counts = script->getPCCounts(REGS.pc);
  1545         counts.get(PCCounts::BASE_INTERP)++;
  1546         moreInterrupts = true;
  1549     if (cx->compartment()->debugMode()) {
  1550         JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook;
  1551         if (hook || script->stepModeEnabled()) {
  1552             RootedValue rval(cx);
  1553             JSTrapStatus status = JSTRAP_CONTINUE;
  1554             if (hook)
  1555                 status = hook(cx, script, REGS.pc, rval.address(),
  1556                               cx->runtime()->debugHooks.interruptHookData);
  1557             if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
  1558                 status = Debugger::onSingleStep(cx, &rval);
  1559             switch (status) {
  1560               case JSTRAP_ERROR:
  1561                 goto error;
  1562               case JSTRAP_CONTINUE:
  1563                 break;
  1564               case JSTRAP_RETURN:
  1565                 REGS.fp()->setReturnValue(rval);
  1566                 ForcedReturn(cx, REGS);
  1567                 goto successful_return_continuation;
  1568               case JSTRAP_THROW:
  1569                 cx->setPendingException(rval);
  1570                 goto error;
  1571               default:;
  1573             moreInterrupts = true;
  1576         if (script->hasAnyBreakpointsOrStepMode())
  1577             moreInterrupts = true;
  1579         if (script->hasBreakpointsAt(REGS.pc)) {
  1580             RootedValue rval(cx);
  1581             JSTrapStatus status = Debugger::onTrap(cx, &rval);
  1582             switch (status) {
  1583               case JSTRAP_ERROR:
  1584                 goto error;
  1585               case JSTRAP_RETURN:
  1586                 REGS.fp()->setReturnValue(rval);
  1587                 ForcedReturn(cx, REGS);
  1588                 goto successful_return_continuation;
  1589               case JSTRAP_THROW:
  1590                 cx->setPendingException(rval);
  1591                 goto error;
  1592               default:
  1593                 break;
  1595             JS_ASSERT(status == JSTRAP_CONTINUE);
  1596             JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
  1600     JS_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
  1601     if (!moreInterrupts)
  1602         activation.clearInterruptsMask();
  1604     /* Commence executing the actual opcode. */
  1605     SANITY_CHECKS();
  1606     DISPATCH_TO(op);
  1609 /* Various 1-byte no-ops. */
  1610 CASE(JSOP_NOP)
  1611 CASE(JSOP_UNUSED2)
  1612 CASE(JSOP_UNUSED45)
  1613 CASE(JSOP_UNUSED46)
  1614 CASE(JSOP_UNUSED47)
  1615 CASE(JSOP_UNUSED48)
  1616 CASE(JSOP_UNUSED49)
  1617 CASE(JSOP_UNUSED50)
  1618 CASE(JSOP_UNUSED51)
  1619 CASE(JSOP_UNUSED52)
  1620 CASE(JSOP_UNUSED57)
  1621 CASE(JSOP_UNUSED101)
  1622 CASE(JSOP_UNUSED102)
  1623 CASE(JSOP_UNUSED103)
  1624 CASE(JSOP_UNUSED104)
  1625 CASE(JSOP_UNUSED105)
  1626 CASE(JSOP_UNUSED107)
  1627 CASE(JSOP_UNUSED124)
  1628 CASE(JSOP_UNUSED125)
  1629 CASE(JSOP_UNUSED126)
  1630 CASE(JSOP_UNUSED138)
  1631 CASE(JSOP_UNUSED139)
  1632 CASE(JSOP_UNUSED140)
  1633 CASE(JSOP_UNUSED141)
  1634 CASE(JSOP_UNUSED142)
  1635 CASE(JSOP_UNUSED146)
  1636 CASE(JSOP_UNUSED147)
  1637 CASE(JSOP_UNUSED148)
  1638 CASE(JSOP_BACKPATCH)
  1639 CASE(JSOP_UNUSED150)
  1640 CASE(JSOP_UNUSED156)
  1641 CASE(JSOP_UNUSED157)
  1642 CASE(JSOP_UNUSED158)
  1643 CASE(JSOP_UNUSED159)
  1644 CASE(JSOP_UNUSED161)
  1645 CASE(JSOP_UNUSED162)
  1646 CASE(JSOP_UNUSED163)
  1647 CASE(JSOP_UNUSED164)
  1648 CASE(JSOP_UNUSED165)
  1649 CASE(JSOP_UNUSED166)
  1650 CASE(JSOP_UNUSED167)
  1651 CASE(JSOP_UNUSED168)
  1652 CASE(JSOP_UNUSED169)
  1653 CASE(JSOP_UNUSED170)
  1654 CASE(JSOP_UNUSED171)
  1655 CASE(JSOP_UNUSED172)
  1656 CASE(JSOP_UNUSED173)
  1657 CASE(JSOP_UNUSED174)
  1658 CASE(JSOP_UNUSED175)
  1659 CASE(JSOP_UNUSED176)
  1660 CASE(JSOP_UNUSED177)
  1661 CASE(JSOP_UNUSED178)
  1662 CASE(JSOP_UNUSED179)
  1663 CASE(JSOP_UNUSED180)
  1664 CASE(JSOP_UNUSED181)
  1665 CASE(JSOP_UNUSED182)
  1666 CASE(JSOP_UNUSED183)
  1667 CASE(JSOP_UNUSED185)
  1668 CASE(JSOP_UNUSED186)
  1669 CASE(JSOP_UNUSED187)
  1670 CASE(JSOP_UNUSED189)
  1671 CASE(JSOP_UNUSED190)
  1672 CASE(JSOP_UNUSED191)
  1673 CASE(JSOP_UNUSED192)
  1674 CASE(JSOP_UNUSED196)
  1675 CASE(JSOP_UNUSED201)
  1676 CASE(JSOP_UNUSED205)
  1677 CASE(JSOP_UNUSED206)
  1678 CASE(JSOP_UNUSED207)
  1679 CASE(JSOP_UNUSED208)
  1680 CASE(JSOP_UNUSED209)
  1681 CASE(JSOP_UNUSED210)
  1682 CASE(JSOP_UNUSED211)
  1683 CASE(JSOP_UNUSED212)
  1684 CASE(JSOP_UNUSED213)
  1685 CASE(JSOP_UNUSED219)
  1686 CASE(JSOP_UNUSED220)
  1687 CASE(JSOP_UNUSED221)
  1688 CASE(JSOP_UNUSED222)
  1689 CASE(JSOP_UNUSED223)
  1690 CASE(JSOP_CONDSWITCH)
  1691 CASE(JSOP_TRY)
  1693     JS_ASSERT(js_CodeSpec[*REGS.pc].length == 1);
  1694     ADVANCE_AND_DISPATCH(1);
  1697 CASE(JSOP_LOOPHEAD)
  1698 END_CASE(JSOP_LOOPHEAD)
  1700 CASE(JSOP_LABEL)
  1701 END_CASE(JSOP_LABEL)
  1703 CASE(JSOP_LOOPENTRY)
  1705 #ifdef JS_ION
  1706     // Attempt on-stack replacement with Baseline code.
  1707     if (jit::IsBaselineEnabled(cx)) {
  1708         jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp(), false);
  1709         if (status == jit::Method_Error)
  1710             goto error;
  1711         if (status == jit::Method_Compiled) {
  1712             bool wasSPS = REGS.fp()->hasPushedSPSFrame();
  1713             jit::IonExecStatus maybeOsr = jit::EnterBaselineAtBranch(cx, REGS.fp(), REGS.pc);
  1715             // We failed to call into baseline at all, so treat as an error.
  1716             if (maybeOsr == jit::IonExec_Aborted)
  1717                 goto error;
  1719             interpReturnOK = (maybeOsr == jit::IonExec_Ok);
  1721             // Pop the SPS frame pushed by the interpreter.  (The compiled version of the
  1722             // function popped a copy of the frame pushed by the OSR trampoline.)
  1723             if (wasSPS)
  1724                 cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
  1726             if (activation.entryFrame() != REGS.fp())
  1727                 goto jit_return_pop_frame;
  1728             goto leave_on_safe_point;
  1731 #endif /* JS_ION */
  1733 END_CASE(JSOP_LOOPENTRY)
  1735 CASE(JSOP_LINENO)
  1736 END_CASE(JSOP_LINENO)
  1738 CASE(JSOP_UNDEFINED)
  1739     PUSH_UNDEFINED();
  1740 END_CASE(JSOP_UNDEFINED)
  1742 CASE(JSOP_POP)
  1743     REGS.sp--;
  1744 END_CASE(JSOP_POP)
  1746 CASE(JSOP_POPN)
  1747     JS_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
  1748     REGS.sp -= GET_UINT16(REGS.pc);
  1749 END_CASE(JSOP_POPN)
  1751 CASE(JSOP_DUPAT)
  1753     JS_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
  1754     unsigned i = GET_UINT24(REGS.pc);
  1755     const Value &rref = REGS.sp[-int(i + 1)];
  1756     PUSH_COPY(rref);
  1758 END_CASE(JSOP_DUPAT)
  1760 CASE(JSOP_SETRVAL)
  1761     POP_RETURN_VALUE();
  1762 END_CASE(JSOP_SETRVAL)
  1764 CASE(JSOP_ENTERWITH)
  1766     RootedValue &val = rootValue0;
  1767     RootedObject &staticWith = rootObject0;
  1768     val = REGS.sp[-1];
  1769     REGS.sp--;
  1770     staticWith = script->getObject(REGS.pc);
  1772     if (!EnterWithOperation(cx, REGS.fp(), val, staticWith))
  1773         goto error;
  1775 END_CASE(JSOP_ENTERWITH)
  1777 CASE(JSOP_LEAVEWITH)
  1778     REGS.fp()->popWith(cx);
  1779 END_CASE(JSOP_LEAVEWITH)
  1781 CASE(JSOP_RETURN)
  1782     POP_RETURN_VALUE();
  1783     /* FALL THROUGH */
  1785 CASE(JSOP_RETRVAL)
  1787     /*
  1788      * When the inlined frame exits with an exception or an error, ok will be
  1789      * false after the inline_return label.
  1790      */
  1791     CHECK_BRANCH();
  1793   successful_return_continuation:
  1794     interpReturnOK = true;
  1795   return_continuation:
  1796     if (activation.entryFrame() != REGS.fp())
  1797   inline_return:
  1799         // Stop the engine. (No details about which engine exactly, could be
  1800         // interpreter, Baseline or IonMonkey.)
  1801         TraceLogStopEvent(logger);
  1802         // Stop the script. (Again no details about which script exactly.)
  1803         TraceLogStopEvent(logger);
  1805         if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
  1806             interpReturnOK = ScriptDebugEpilogue(cx, REGS.fp(), REGS.pc, interpReturnOK);
  1808         if (!REGS.fp()->isYielding())
  1809             REGS.fp()->epilogue(cx);
  1810         else
  1811             probes::ExitScript(cx, script, script->functionNonDelazifying(),
  1812                                REGS.fp()->hasPushedSPSFrame());
  1814 #if defined(JS_ION)
  1815   jit_return_pop_frame:
  1816 #endif
  1818         activation.popInlineFrame(REGS.fp());
  1819         SET_SCRIPT(REGS.fp()->script());
  1821 #if defined(JS_ION)
  1822   jit_return:
  1823 #endif
  1825         JS_ASSERT(js_CodeSpec[*REGS.pc].format & JOF_INVOKE);
  1827         /* Resume execution in the calling frame. */
  1828         if (MOZ_LIKELY(interpReturnOK)) {
  1829             TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
  1831             ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
  1834         /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */
  1835         REGS.pc += JSOP_CALL_LENGTH;
  1836         goto error;
  1837     } else {
  1838         JS_ASSERT(REGS.stackDepth() == 0);
  1840     goto exit;
  1843 CASE(JSOP_DEFAULT)
  1844     REGS.sp--;
  1845     /* FALL THROUGH */
  1846 CASE(JSOP_GOTO)
  1848     BRANCH(GET_JUMP_OFFSET(REGS.pc));
  1851 CASE(JSOP_IFEQ)
  1853     bool cond = ToBooleanOp(REGS);
  1854     REGS.sp--;
  1855     if (!cond)
  1856         BRANCH(GET_JUMP_OFFSET(REGS.pc));
  1858 END_CASE(JSOP_IFEQ)
  1860 CASE(JSOP_IFNE)
  1862     bool cond = ToBooleanOp(REGS);
  1863     REGS.sp--;
  1864     if (cond)
  1865         BRANCH(GET_JUMP_OFFSET(REGS.pc));
  1867 END_CASE(JSOP_IFNE)
  1869 CASE(JSOP_OR)
  1871     bool cond = ToBooleanOp(REGS);
  1872     if (cond)
  1873         ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
  1875 END_CASE(JSOP_OR)
  1877 CASE(JSOP_AND)
  1879     bool cond = ToBooleanOp(REGS);
  1880     if (!cond)
  1881         ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
  1883 END_CASE(JSOP_AND)
  1885 #define FETCH_ELEMENT_ID(n, id)                                               \
  1886     JS_BEGIN_MACRO                                                            \
  1887         if (!ValueToId<CanGC>(cx, REGS.stackHandleAt(n), &(id))) \
  1888             goto error;                                                       \
  1889     JS_END_MACRO
  1891 #define TRY_BRANCH_AFTER_COND(cond,spdec)                                     \
  1892     JS_BEGIN_MACRO                                                            \
  1893         JS_ASSERT(js_CodeSpec[*REGS.pc].length == 1);                         \
  1894         unsigned diff_ = (unsigned) GET_UINT8(REGS.pc) - (unsigned) JSOP_IFEQ; \
  1895         if (diff_ <= 1) {                                                     \
  1896             REGS.sp -= (spdec);                                               \
  1897             if ((cond) == (diff_ != 0)) {                                     \
  1898                 ++REGS.pc;                                                    \
  1899                 BRANCH(GET_JUMP_OFFSET(REGS.pc));                             \
  1900             }                                                                 \
  1901             ADVANCE_AND_DISPATCH(1 + JSOP_IFEQ_LENGTH);                       \
  1902         }                                                                     \
  1903     JS_END_MACRO
  1905 CASE(JSOP_IN)
  1907     HandleValue rref = REGS.stackHandleAt(-1);
  1908     if (!rref.isObject()) {
  1909         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, js::NullPtr());
  1910         goto error;
  1912     RootedObject &obj = rootObject0;
  1913     obj = &rref.toObject();
  1914     RootedId &id = rootId0;
  1915     FETCH_ELEMENT_ID(-2, id);
  1916     RootedObject &obj2 = rootObject1;
  1917     RootedShape &prop = rootShape0;
  1918     if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
  1919         goto error;
  1920     bool cond = prop != nullptr;
  1921     prop = nullptr;
  1922     TRY_BRANCH_AFTER_COND(cond, 2);
  1923     REGS.sp--;
  1924     REGS.sp[-1].setBoolean(cond);
  1926 END_CASE(JSOP_IN)
  1928 CASE(JSOP_ITER)
  1930     JS_ASSERT(REGS.stackDepth() >= 1);
  1931     uint8_t flags = GET_UINT8(REGS.pc);
  1932     MutableHandleValue res = REGS.stackHandleAt(-1);
  1933     if (!ValueToIterator(cx, flags, res))
  1934         goto error;
  1935     JS_ASSERT(!res.isPrimitive());
  1937 END_CASE(JSOP_ITER)
  1939 CASE(JSOP_MOREITER)
  1941     JS_ASSERT(REGS.stackDepth() >= 1);
  1942     JS_ASSERT(REGS.sp[-1].isObject());
  1943     PUSH_NULL();
  1944     bool cond;
  1945     MutableHandleValue res = REGS.stackHandleAt(-1);
  1946     if (!IteratorMore(cx, &REGS.sp[-2].toObject(), &cond, res))
  1947         goto error;
  1948     REGS.sp[-1].setBoolean(cond);
  1950 END_CASE(JSOP_MOREITER)
  1952 CASE(JSOP_ITERNEXT)
  1954     JS_ASSERT(REGS.sp[-1].isObject());
  1955     PUSH_NULL();
  1956     MutableHandleValue res = REGS.stackHandleAt(-1);
  1957     RootedObject &obj = rootObject0;
  1958     obj = &REGS.sp[-2].toObject();
  1959     if (!IteratorNext(cx, obj, res))
  1960         goto error;
  1962 END_CASE(JSOP_ITERNEXT)
  1964 CASE(JSOP_ENDITER)
  1966     JS_ASSERT(REGS.stackDepth() >= 1);
  1967     RootedObject &obj = rootObject0;
  1968     obj = &REGS.sp[-1].toObject();
  1969     bool ok = CloseIterator(cx, obj);
  1970     REGS.sp--;
  1971     if (!ok)
  1972         goto error;
  1974 END_CASE(JSOP_ENDITER)
  1976 CASE(JSOP_DUP)
  1978     JS_ASSERT(REGS.stackDepth() >= 1);
  1979     const Value &rref = REGS.sp[-1];
  1980     PUSH_COPY(rref);
  1982 END_CASE(JSOP_DUP)
  1984 CASE(JSOP_DUP2)
  1986     JS_ASSERT(REGS.stackDepth() >= 2);
  1987     const Value &lref = REGS.sp[-2];
  1988     const Value &rref = REGS.sp[-1];
  1989     PUSH_COPY(lref);
  1990     PUSH_COPY(rref);
  1992 END_CASE(JSOP_DUP2)
  1994 CASE(JSOP_SWAP)
  1996     JS_ASSERT(REGS.stackDepth() >= 2);
  1997     Value &lref = REGS.sp[-2];
  1998     Value &rref = REGS.sp[-1];
  1999     lref.swap(rref);
  2001 END_CASE(JSOP_SWAP)
  2003 CASE(JSOP_PICK)
  2005     unsigned i = GET_UINT8(REGS.pc);
  2006     JS_ASSERT(REGS.stackDepth() >= i + 1);
  2007     Value lval = REGS.sp[-int(i + 1)];
  2008     memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
  2009     REGS.sp[-1] = lval;
  2011 END_CASE(JSOP_PICK)
  2013 CASE(JSOP_SETCONST)
  2015     RootedPropertyName &name = rootName0;
  2016     name = script->getName(REGS.pc);
  2018     RootedValue &rval = rootValue0;
  2019     rval = REGS.sp[-1];
  2021     RootedObject &obj = rootObject0;
  2022     obj = &REGS.fp()->varObj();
  2024     if (!SetConstOperation(cx, obj, name, rval))
  2025         goto error;
  2027 END_CASE(JSOP_SETCONST);
  2029 CASE(JSOP_BINDGNAME)
  2030     PUSH_OBJECT(REGS.fp()->global());
  2031 END_CASE(JSOP_BINDGNAME)
  2033 CASE(JSOP_BINDINTRINSIC)
  2034     PUSH_OBJECT(*cx->global()->intrinsicsHolder());
  2035 END_CASE(JSOP_BINDINTRINSIC)
  2037 CASE(JSOP_BINDNAME)
  2039     RootedObject &scopeChain = rootObject0;
  2040     scopeChain = REGS.fp()->scopeChain();
  2042     RootedPropertyName &name = rootName0;
  2043     name = script->getName(REGS.pc);
  2045     /* Assigning to an undeclared name adds a property to the global object. */
  2046     RootedObject &scope = rootObject1;
  2047     if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &scope))
  2048         goto error;
  2050     PUSH_OBJECT(*scope);
  2052 END_CASE(JSOP_BINDNAME)
  2054 #define BITWISE_OP(OP)                                                        \
  2055     JS_BEGIN_MACRO                                                            \
  2056         int32_t i, j;                                                         \
  2057         if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))                         \
  2058             goto error;                                                       \
  2059         if (!ToInt32(cx, REGS.stackHandleAt(-1), &j))                         \
  2060             goto error;                                                       \
  2061         i = i OP j;                                                           \
  2062         REGS.sp--;                                                            \
  2063         REGS.sp[-1].setInt32(i);                                              \
  2064     JS_END_MACRO
  2066 CASE(JSOP_BITOR)
  2067     BITWISE_OP(|);
  2068 END_CASE(JSOP_BITOR)
  2070 CASE(JSOP_BITXOR)
  2071     BITWISE_OP(^);
  2072 END_CASE(JSOP_BITXOR)
  2074 CASE(JSOP_BITAND)
  2075     BITWISE_OP(&);
  2076 END_CASE(JSOP_BITAND)
  2078 #undef BITWISE_OP
  2080 CASE(JSOP_EQ)
  2081     if (!LooseEqualityOp<true>(cx, REGS))
  2082         goto error;
  2083 END_CASE(JSOP_EQ)
  2085 CASE(JSOP_NE)
  2086     if (!LooseEqualityOp<false>(cx, REGS))
  2087         goto error;
  2088 END_CASE(JSOP_NE)
  2090 #define STRICT_EQUALITY_OP(OP, COND)                                          \
  2091     JS_BEGIN_MACRO                                                            \
  2092         const Value &rref = REGS.sp[-1];                                      \
  2093         const Value &lref = REGS.sp[-2];                                      \
  2094         bool equal;                                                           \
  2095         if (!StrictlyEqual(cx, lref, rref, &equal))                           \
  2096             goto error;                                                       \
  2097         (COND) = equal OP true;                                               \
  2098         REGS.sp--;                                                            \
  2099     JS_END_MACRO
  2101 CASE(JSOP_STRICTEQ)
  2103     bool cond;
  2104     STRICT_EQUALITY_OP(==, cond);
  2105     REGS.sp[-1].setBoolean(cond);
  2107 END_CASE(JSOP_STRICTEQ)
  2109 CASE(JSOP_STRICTNE)
  2111     bool cond;
  2112     STRICT_EQUALITY_OP(!=, cond);
  2113     REGS.sp[-1].setBoolean(cond);
  2115 END_CASE(JSOP_STRICTNE)
  2117 CASE(JSOP_CASE)
  2119     bool cond;
  2120     STRICT_EQUALITY_OP(==, cond);
  2121     if (cond) {
  2122         REGS.sp--;
  2123         BRANCH(GET_JUMP_OFFSET(REGS.pc));
  2126 END_CASE(JSOP_CASE)
  2128 #undef STRICT_EQUALITY_OP
  2130 CASE(JSOP_LT)
  2132     bool cond;
  2133     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2134     MutableHandleValue rval = REGS.stackHandleAt(-1);
  2135     if (!LessThanOperation(cx, lval, rval, &cond))
  2136         goto error;
  2137     TRY_BRANCH_AFTER_COND(cond, 2);
  2138     REGS.sp[-2].setBoolean(cond);
  2139     REGS.sp--;
  2141 END_CASE(JSOP_LT)
  2143 CASE(JSOP_LE)
  2145     bool cond;
  2146     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2147     MutableHandleValue rval = REGS.stackHandleAt(-1);
  2148     if (!LessThanOrEqualOperation(cx, lval, rval, &cond))
  2149         goto error;
  2150     TRY_BRANCH_AFTER_COND(cond, 2);
  2151     REGS.sp[-2].setBoolean(cond);
  2152     REGS.sp--;
  2154 END_CASE(JSOP_LE)
  2156 CASE(JSOP_GT)
  2158     bool cond;
  2159     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2160     MutableHandleValue rval = REGS.stackHandleAt(-1);
  2161     if (!GreaterThanOperation(cx, lval, rval, &cond))
  2162         goto error;
  2163     TRY_BRANCH_AFTER_COND(cond, 2);
  2164     REGS.sp[-2].setBoolean(cond);
  2165     REGS.sp--;
  2167 END_CASE(JSOP_GT)
  2169 CASE(JSOP_GE)
  2171     bool cond;
  2172     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2173     MutableHandleValue rval = REGS.stackHandleAt(-1);
  2174     if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond))
  2175         goto error;
  2176     TRY_BRANCH_AFTER_COND(cond, 2);
  2177     REGS.sp[-2].setBoolean(cond);
  2178     REGS.sp--;
  2180 END_CASE(JSOP_GE)
  2182 #define SIGNED_SHIFT_OP(OP)                                                   \
  2183     JS_BEGIN_MACRO                                                            \
  2184         int32_t i, j;                                                         \
  2185         if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))                         \
  2186             goto error;                                                       \
  2187         if (!ToInt32(cx, REGS.stackHandleAt(-1), &j))                         \
  2188             goto error;                                                       \
  2189         i = i OP (j & 31);                                                    \
  2190         REGS.sp--;                                                            \
  2191         REGS.sp[-1].setInt32(i);                                              \
  2192     JS_END_MACRO
  2194 CASE(JSOP_LSH)
  2195     SIGNED_SHIFT_OP(<<);
  2196 END_CASE(JSOP_LSH)
  2198 CASE(JSOP_RSH)
  2199     SIGNED_SHIFT_OP(>>);
  2200 END_CASE(JSOP_RSH)
  2202 #undef SIGNED_SHIFT_OP
  2204 CASE(JSOP_URSH)
  2206     HandleValue lval = REGS.stackHandleAt(-2);
  2207     HandleValue rval = REGS.stackHandleAt(-1);
  2208     MutableHandleValue res = REGS.stackHandleAt(-2);
  2209     if (!UrshOperation(cx, lval, rval, res))
  2210         goto error;
  2211     REGS.sp--;
  2213 END_CASE(JSOP_URSH)
  2215 CASE(JSOP_ADD)
  2217     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2218     MutableHandleValue rval = REGS.stackHandleAt(-1);
  2219     MutableHandleValue res = REGS.stackHandleAt(-2);
  2220     if (!AddOperation(cx, lval, rval, res))
  2221         goto error;
  2222     REGS.sp--;
  2224 END_CASE(JSOP_ADD)
  2226 CASE(JSOP_SUB)
  2228     RootedValue &lval = rootValue0, &rval = rootValue1;
  2229     lval = REGS.sp[-2];
  2230     rval = REGS.sp[-1];
  2231     MutableHandleValue res = REGS.stackHandleAt(-2);
  2232     if (!SubOperation(cx, lval, rval, res))
  2233         goto error;
  2234     REGS.sp--;
  2236 END_CASE(JSOP_SUB)
  2238 CASE(JSOP_MUL)
  2240     RootedValue &lval = rootValue0, &rval = rootValue1;
  2241     lval = REGS.sp[-2];
  2242     rval = REGS.sp[-1];
  2243     MutableHandleValue res = REGS.stackHandleAt(-2);
  2244     if (!MulOperation(cx, lval, rval, res))
  2245         goto error;
  2246     REGS.sp--;
  2248 END_CASE(JSOP_MUL)
  2250 CASE(JSOP_DIV)
  2252     RootedValue &lval = rootValue0, &rval = rootValue1;
  2253     lval = REGS.sp[-2];
  2254     rval = REGS.sp[-1];
  2255     MutableHandleValue res = REGS.stackHandleAt(-2);
  2256     if (!DivOperation(cx, lval, rval, res))
  2257         goto error;
  2258     REGS.sp--;
  2260 END_CASE(JSOP_DIV)
  2262 CASE(JSOP_MOD)
  2264     RootedValue &lval = rootValue0, &rval = rootValue1;
  2265     lval = REGS.sp[-2];
  2266     rval = REGS.sp[-1];
  2267     MutableHandleValue res = REGS.stackHandleAt(-2);
  2268     if (!ModOperation(cx, lval, rval, res))
  2269         goto error;
  2270     REGS.sp--;
  2272 END_CASE(JSOP_MOD)
  2274 CASE(JSOP_NOT)
  2276     bool cond = ToBooleanOp(REGS);
  2277     REGS.sp--;
  2278     PUSH_BOOLEAN(!cond);
  2280 END_CASE(JSOP_NOT)
  2282 CASE(JSOP_BITNOT)
  2284     int32_t i;
  2285     HandleValue value = REGS.stackHandleAt(-1);
  2286     if (!BitNot(cx, value, &i))
  2287         goto error;
  2288     REGS.sp[-1].setInt32(i);
  2290 END_CASE(JSOP_BITNOT)
  2292 CASE(JSOP_NEG)
  2294     RootedValue &val = rootValue0;
  2295     val = REGS.sp[-1];
  2296     MutableHandleValue res = REGS.stackHandleAt(-1);
  2297     if (!NegOperation(cx, script, REGS.pc, val, res))
  2298         goto error;
  2300 END_CASE(JSOP_NEG)
  2302 CASE(JSOP_POS)
  2303     if (!ToNumber(cx, REGS.stackHandleAt(-1)))
  2304         goto error;
  2305 END_CASE(JSOP_POS)
  2307 CASE(JSOP_DELNAME)
  2309     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
  2310     JS_ASSERT(!script->strict());
  2312     RootedPropertyName &name = rootName0;
  2313     name = script->getName(REGS.pc);
  2315     RootedObject &scopeObj = rootObject0;
  2316     scopeObj = REGS.fp()->scopeChain();
  2318     PUSH_BOOLEAN(true);
  2319     MutableHandleValue res = REGS.stackHandleAt(-1);
  2320     if (!DeleteNameOperation(cx, name, scopeObj, res))
  2321         goto error;
  2323 END_CASE(JSOP_DELNAME)
  2325 CASE(JSOP_DELPROP)
  2327     RootedPropertyName &name = rootName0;
  2328     name = script->getName(REGS.pc);
  2330     RootedObject &obj = rootObject0;
  2331     FETCH_OBJECT(cx, -1, obj);
  2333     bool succeeded;
  2334     if (!JSObject::deleteProperty(cx, obj, name, &succeeded))
  2335         goto error;
  2336     if (!succeeded && script->strict()) {
  2337         obj->reportNotConfigurable(cx, NameToId(name));
  2338         goto error;
  2340     MutableHandleValue res = REGS.stackHandleAt(-1);
  2341     res.setBoolean(succeeded);
  2343 END_CASE(JSOP_DELPROP)
  2345 CASE(JSOP_DELELEM)
  2347     /* Fetch the left part and resolve it to a non-null object. */
  2348     RootedObject &obj = rootObject0;
  2349     FETCH_OBJECT(cx, -2, obj);
  2351     RootedValue &propval = rootValue0;
  2352     propval = REGS.sp[-1];
  2354     bool succeeded;
  2355     if (!JSObject::deleteByValue(cx, obj, propval, &succeeded))
  2356         goto error;
  2357     if (!succeeded && script->strict()) {
  2358         // XXX This observably calls ToString(propval).  We should convert to
  2359         //     PropertyKey and use that to delete, and to report an error if
  2360         //     necessary!
  2361         RootedId id(cx);
  2362         if (!ValueToId<CanGC>(cx, propval, &id))
  2363             goto error;
  2364         obj->reportNotConfigurable(cx, id);
  2365         goto error;
  2368     MutableHandleValue res = REGS.stackHandleAt(-2);
  2369     res.setBoolean(succeeded);
  2370     REGS.sp--;
  2372 END_CASE(JSOP_DELELEM)
  2374 CASE(JSOP_TOID)
  2376     /*
  2377      * Increment or decrement requires use to lookup the same property twice,
  2378      * but we need to avoid the observable stringification the second time.
  2379      * There must be an object value below the id, which will not be popped.
  2380      */
  2381     RootedValue &objval = rootValue0, &idval = rootValue1;
  2382     objval = REGS.sp[-2];
  2383     idval = REGS.sp[-1];
  2385     MutableHandleValue res = REGS.stackHandleAt(-1);
  2386     if (!ToIdOperation(cx, script, REGS.pc, objval, idval, res))
  2387         goto error;
  2389 END_CASE(JSOP_TOID)
  2391 CASE(JSOP_TYPEOFEXPR)
  2392 CASE(JSOP_TYPEOF)
  2394     REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
  2396 END_CASE(JSOP_TYPEOF)
  2398 CASE(JSOP_VOID)
  2399     REGS.sp[-1].setUndefined();
  2400 END_CASE(JSOP_VOID)
  2402 CASE(JSOP_THIS)
  2403     if (!ComputeThis(cx, REGS.fp()))
  2404         goto error;
  2405     PUSH_COPY(REGS.fp()->thisValue());
  2406 END_CASE(JSOP_THIS)
  2408 CASE(JSOP_GETPROP)
  2409 CASE(JSOP_GETXPROP)
  2410 CASE(JSOP_LENGTH)
  2411 CASE(JSOP_CALLPROP)
  2414     MutableHandleValue lval = REGS.stackHandleAt(-1);
  2415     if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval))
  2416         goto error;
  2418     TypeScript::Monitor(cx, script, REGS.pc, lval);
  2419     assertSameCompartmentDebugOnly(cx, lval);
  2421 END_CASE(JSOP_GETPROP)
  2423 CASE(JSOP_SETINTRINSIC)
  2425     HandleValue value = REGS.stackHandleAt(-1);
  2427     if (!SetIntrinsicOperation(cx, script, REGS.pc, value))
  2428         goto error;
  2430     REGS.sp[-2] = REGS.sp[-1];
  2431     REGS.sp--;
  2433 END_CASE(JSOP_SETINTRINSIC)
  2435 CASE(JSOP_SETGNAME)
  2436 CASE(JSOP_SETNAME)
  2438     RootedObject &scope = rootObject0;
  2439     scope = &REGS.sp[-2].toObject();
  2441     HandleValue value = REGS.stackHandleAt(-1);
  2443     if (!SetNameOperation(cx, script, REGS.pc, scope, value))
  2444         goto error;
  2446     REGS.sp[-2] = REGS.sp[-1];
  2447     REGS.sp--;
  2449 END_CASE(JSOP_SETNAME)
  2451 CASE(JSOP_SETPROP)
  2453     HandleValue lval = REGS.stackHandleAt(-2);
  2454     HandleValue rval = REGS.stackHandleAt(-1);
  2456     if (!SetPropertyOperation(cx, script, REGS.pc, lval, rval))
  2457         goto error;
  2459     REGS.sp[-2] = REGS.sp[-1];
  2460     REGS.sp--;
  2462 END_CASE(JSOP_SETPROP)
  2464 CASE(JSOP_GETELEM)
  2465 CASE(JSOP_CALLELEM)
  2467     MutableHandleValue lval = REGS.stackHandleAt(-2);
  2468     HandleValue rval = REGS.stackHandleAt(-1);
  2469     MutableHandleValue res = REGS.stackHandleAt(-2);
  2471     bool done = false;
  2472     if (!GetElemOptimizedArguments(cx, REGS.fp(), lval, rval, res, &done))
  2473         goto error;
  2475     if (!done) {
  2476         if (!GetElementOperation(cx, JSOp(*REGS.pc), lval, rval, res))
  2477             goto error;
  2480     TypeScript::Monitor(cx, script, REGS.pc, res);
  2481     REGS.sp--;
  2483 END_CASE(JSOP_GETELEM)
  2485 CASE(JSOP_SETELEM)
  2487     RootedObject &obj = rootObject0;
  2488     FETCH_OBJECT(cx, -3, obj);
  2489     RootedId &id = rootId0;
  2490     FETCH_ELEMENT_ID(-2, id);
  2491     Value &value = REGS.sp[-1];
  2492     if (!SetObjectElementOperation(cx, obj, id, value, script->strict()))
  2493         goto error;
  2494     REGS.sp[-3] = value;
  2495     REGS.sp -= 2;
  2497 END_CASE(JSOP_SETELEM)
  2499 CASE(JSOP_EVAL)
  2501     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
  2502     if (REGS.fp()->scopeChain()->global().valueIsEval(args.calleev())) {
  2503         if (!DirectEval(cx, args))
  2504             goto error;
  2505     } else {
  2506         if (!Invoke(cx, args))
  2507             goto error;
  2509     REGS.sp = args.spAfterCall();
  2510     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
  2512 END_CASE(JSOP_EVAL)
  2514 CASE(JSOP_SPREADNEW)
  2515 CASE(JSOP_SPREADCALL)
  2516     if (REGS.fp()->hasPushedSPSFrame())
  2517         cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
  2518     /* FALL THROUGH */
  2520 CASE(JSOP_SPREADEVAL)
  2522     JS_ASSERT(REGS.stackDepth() >= 3);
  2523     RootedObject &aobj = rootObject0;
  2524     aobj = &REGS.sp[-1].toObject();
  2526     uint32_t length = aobj->as<ArrayObject>().length();
  2528     if (length > ARGS_LENGTH_MAX) {
  2529         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
  2530                              *REGS.pc == JSOP_SPREADNEW ? JSMSG_TOO_MANY_CON_SPREADARGS
  2531                                                         : JSMSG_TOO_MANY_FUN_SPREADARGS);
  2532         goto error;
  2535     InvokeArgs args(cx);
  2537     if (!args.init(length))
  2538         return false;
  2540     args.setCallee(REGS.sp[-3]);
  2541     args.setThis(REGS.sp[-2]);
  2543     if (!GetElements(cx, aobj, length, args.array()))
  2544         goto error;
  2546     switch (*REGS.pc) {
  2547       case JSOP_SPREADNEW:
  2548         if (!InvokeConstructor(cx, args))
  2549             goto error;
  2550         break;
  2551       case JSOP_SPREADCALL:
  2552         if (!Invoke(cx, args))
  2553             goto error;
  2554         break;
  2555       case JSOP_SPREADEVAL:
  2556         if (REGS.fp()->scopeChain()->global().valueIsEval(args.calleev())) {
  2557             if (!DirectEval(cx, args))
  2558                 goto error;
  2559         } else {
  2560             if (!Invoke(cx, args))
  2561                 goto error;
  2563         break;
  2564       default:
  2565         MOZ_ASSUME_UNREACHABLE("bad spread opcode");
  2568     REGS.sp -= 2;
  2569     REGS.sp[-1] = args.rval();
  2570     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
  2572 END_CASE(JSOP_SPREADCALL)
  2574 CASE(JSOP_FUNAPPLY)
  2576     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
  2577     if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args.calleev(), args.array(),
  2578                                             args.length()))
  2579         goto error;
  2580     /* FALL THROUGH */
  2583 CASE(JSOP_NEW)
  2584 CASE(JSOP_CALL)
  2585 CASE(JSOP_FUNCALL)
  2587     if (REGS.fp()->hasPushedSPSFrame())
  2588         cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
  2589     JS_ASSERT(REGS.stackDepth() >= 2 + GET_ARGC(REGS.pc));
  2590     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
  2592     bool construct = (*REGS.pc == JSOP_NEW);
  2594     RootedFunction &fun = rootFunction0;
  2595     RootedScript &funScript = rootScript0;
  2596     bool isFunction = IsFunctionObject(args.calleev(), fun.address());
  2598     /*
  2599      * Some builtins are marked as clone-at-callsite to increase precision of
  2600      * TI and JITs.
  2601      */
  2602     if (isFunction && fun->isInterpreted()) {
  2603         funScript = fun->getOrCreateScript(cx);
  2604         if (!funScript)
  2605             goto error;
  2606         if (funScript->shouldCloneAtCallsite()) {
  2607             fun = CloneFunctionAtCallsite(cx, fun, script, REGS.pc);
  2608             if (!fun)
  2609                 goto error;
  2610             args.setCallee(ObjectValue(*fun));
  2614     /* Don't bother trying to fast-path calls to scripted non-constructors. */
  2615     if (!isFunction || !fun->isInterpretedConstructor()) {
  2616         if (construct) {
  2617             if (!InvokeConstructor(cx, args))
  2618                 goto error;
  2619         } else {
  2620             if (!Invoke(cx, args))
  2621                 goto error;
  2623         Value *newsp = args.spAfterCall();
  2624         TypeScript::Monitor(cx, script, REGS.pc, newsp[-1]);
  2625         REGS.sp = newsp;
  2626         ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
  2629     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
  2630     bool newType = UseNewType(cx, script, REGS.pc);
  2632     TypeMonitorCall(cx, args, construct);
  2634 #ifdef JS_ION
  2636         InvokeState state(cx, args, initial);
  2637         if (newType)
  2638             state.setUseNewType();
  2640         if (!newType && jit::IsIonEnabled(cx)) {
  2641             jit::MethodStatus status = jit::CanEnter(cx, state);
  2642             if (status == jit::Method_Error)
  2643                 goto error;
  2644             if (status == jit::Method_Compiled) {
  2645                 jit::IonExecStatus exec = jit::IonCannon(cx, state);
  2646                 CHECK_BRANCH();
  2647                 REGS.sp = args.spAfterCall();
  2648                 interpReturnOK = !IsErrorStatus(exec);
  2649                 goto jit_return;
  2653         if (jit::IsBaselineEnabled(cx)) {
  2654             jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state);
  2655             if (status == jit::Method_Error)
  2656                 goto error;
  2657             if (status == jit::Method_Compiled) {
  2658                 jit::IonExecStatus exec = jit::EnterBaselineMethod(cx, state);
  2659                 CHECK_BRANCH();
  2660                 REGS.sp = args.spAfterCall();
  2661                 interpReturnOK = !IsErrorStatus(exec);
  2662                 goto jit_return;
  2666 #endif
  2668     funScript = fun->nonLazyScript();
  2669     if (!activation.pushInlineFrame(args, funScript, initial))
  2670         goto error;
  2672     if (newType)
  2673         REGS.fp()->setUseNewType();
  2675     SET_SCRIPT(REGS.fp()->script());
  2677     uint32_t scriptLogId = TraceLogCreateTextId(logger, script);
  2678     TraceLogStartEvent(logger, scriptLogId);
  2679     TraceLogStartEvent(logger, TraceLogger::Interpreter);
  2681     if (!REGS.fp()->prologue(cx))
  2682         goto error;
  2683     if (MOZ_UNLIKELY(cx->compartment()->debugMode())) {
  2684         switch (ScriptDebugPrologue(cx, REGS.fp(), REGS.pc)) {
  2685           case JSTRAP_CONTINUE:
  2686             break;
  2687           case JSTRAP_RETURN:
  2688             ForcedReturn(cx, REGS);
  2689             goto successful_return_continuation;
  2690           case JSTRAP_THROW:
  2691           case JSTRAP_ERROR:
  2692             goto error;
  2693           default:
  2694             MOZ_ASSUME_UNREACHABLE("bad ScriptDebugPrologue status");
  2698     /* Load first op and dispatch it (safe since JSOP_RETRVAL). */
  2699     ADVANCE_AND_DISPATCH(0);
  2702 CASE(JSOP_SETCALL)
  2704     JS_ALWAYS_FALSE(SetCallOperation(cx));
  2705     goto error;
  2707 END_CASE(JSOP_SETCALL)
  2709 CASE(JSOP_IMPLICITTHIS)
  2711     RootedPropertyName &name = rootName0;
  2712     name = script->getName(REGS.pc);
  2714     RootedObject &scopeObj = rootObject0;
  2715     scopeObj = REGS.fp()->scopeChain();
  2717     RootedObject &scope = rootObject1;
  2718     if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope))
  2719         goto error;
  2721     RootedValue &v = rootValue0;
  2722     if (!ComputeImplicitThis(cx, scope, &v))
  2723         goto error;
  2724     PUSH_COPY(v);
  2726 END_CASE(JSOP_IMPLICITTHIS)
  2728 CASE(JSOP_GETGNAME)
  2729 CASE(JSOP_NAME)
  2731     RootedValue &rval = rootValue0;
  2733     if (!NameOperation(cx, REGS.fp(), REGS.pc, &rval))
  2734         goto error;
  2736     PUSH_COPY(rval);
  2737     TypeScript::Monitor(cx, script, REGS.pc, rval);
  2739 END_CASE(JSOP_NAME)
  2741 CASE(JSOP_GETINTRINSIC)
  2743     RootedValue &rval = rootValue0;
  2745     if (!GetIntrinsicOperation(cx, REGS.pc, &rval))
  2746         goto error;
  2748     PUSH_COPY(rval);
  2749     TypeScript::Monitor(cx, script, REGS.pc, rval);
  2751 END_CASE(JSOP_GETINTRINSIC)
  2753 CASE(JSOP_UINT16)
  2754     PUSH_INT32((int32_t) GET_UINT16(REGS.pc));
  2755 END_CASE(JSOP_UINT16)
  2757 CASE(JSOP_UINT24)
  2758     PUSH_INT32((int32_t) GET_UINT24(REGS.pc));
  2759 END_CASE(JSOP_UINT24)
  2761 CASE(JSOP_INT8)
  2762     PUSH_INT32(GET_INT8(REGS.pc));
  2763 END_CASE(JSOP_INT8)
  2765 CASE(JSOP_INT32)
  2766     PUSH_INT32(GET_INT32(REGS.pc));
  2767 END_CASE(JSOP_INT32)
  2769 CASE(JSOP_DOUBLE)
  2771     double dbl;
  2772     LOAD_DOUBLE(0, dbl);
  2773     PUSH_DOUBLE(dbl);
  2775 END_CASE(JSOP_DOUBLE)
  2777 CASE(JSOP_STRING)
  2778     PUSH_STRING(script->getAtom(REGS.pc));
  2779 END_CASE(JSOP_STRING)
  2781 CASE(JSOP_OBJECT)
  2783     RootedObject &ref = rootObject0;
  2784     ref = script->getObject(REGS.pc);
  2785     if (JS::CompartmentOptionsRef(cx).cloneSingletons(cx)) {
  2786         JSObject *obj = js::DeepCloneObjectLiteral(cx, ref, js::MaybeSingletonObject);
  2787         if (!obj)
  2788             goto error;
  2789         PUSH_OBJECT(*obj);
  2790     } else {
  2791         JS::CompartmentOptionsRef(cx).setSingletonsAsValues();
  2792         PUSH_OBJECT(*ref);
  2795 END_CASE(JSOP_OBJECT)
  2797 CASE(JSOP_REGEXP)
  2799     /*
  2800      * Push a regexp object cloned from the regexp literal object mapped by the
  2801      * bytecode at pc.
  2802      */
  2803     JSObject *obj = CloneRegExpObject(cx, script->getRegExp(REGS.pc));
  2804     if (!obj)
  2805         goto error;
  2806     PUSH_OBJECT(*obj);
  2808 END_CASE(JSOP_REGEXP)
  2810 CASE(JSOP_ZERO)
  2811     PUSH_INT32(0);
  2812 END_CASE(JSOP_ZERO)
  2814 CASE(JSOP_ONE)
  2815     PUSH_INT32(1);
  2816 END_CASE(JSOP_ONE)
  2818 CASE(JSOP_NULL)
  2819     PUSH_NULL();
  2820 END_CASE(JSOP_NULL)
  2822 CASE(JSOP_FALSE)
  2823     PUSH_BOOLEAN(false);
  2824 END_CASE(JSOP_FALSE)
  2826 CASE(JSOP_TRUE)
  2827     PUSH_BOOLEAN(true);
  2828 END_CASE(JSOP_TRUE)
  2830 CASE(JSOP_TABLESWITCH)
  2832     jsbytecode *pc2 = REGS.pc;
  2833     int32_t len = GET_JUMP_OFFSET(pc2);
  2835     /*
  2836      * ECMAv2+ forbids conversion of discriminant, so we will skip to the
  2837      * default case if the discriminant isn't already an int jsval.  (This
  2838      * opcode is emitted only for dense int-domain switches.)
  2839      */
  2840     const Value &rref = *--REGS.sp;
  2841     int32_t i;
  2842     if (rref.isInt32()) {
  2843         i = rref.toInt32();
  2844     } else {
  2845         /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
  2846         if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i))
  2847             ADVANCE_AND_DISPATCH(len);
  2850     pc2 += JUMP_OFFSET_LEN;
  2851     int32_t low = GET_JUMP_OFFSET(pc2);
  2852     pc2 += JUMP_OFFSET_LEN;
  2853     int32_t high = GET_JUMP_OFFSET(pc2);
  2855     i -= low;
  2856     if ((uint32_t)i < (uint32_t)(high - low + 1)) {
  2857         pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
  2858         int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
  2859         if (off)
  2860             len = off;
  2862     ADVANCE_AND_DISPATCH(len);
  2865 CASE(JSOP_ARGUMENTS)
  2866     JS_ASSERT(!REGS.fp()->fun()->hasRest());
  2867     if (!script->ensureHasAnalyzedArgsUsage(cx))
  2868         goto error;
  2869     if (script->needsArgsObj()) {
  2870         ArgumentsObject *obj = ArgumentsObject::createExpected(cx, REGS.fp());
  2871         if (!obj)
  2872             goto error;
  2873         PUSH_COPY(ObjectValue(*obj));
  2874     } else {
  2875         PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
  2877 END_CASE(JSOP_ARGUMENTS)
  2879 CASE(JSOP_RUNONCE)
  2881     if (!RunOnceScriptPrologue(cx, script))
  2882         goto error;
  2884 END_CASE(JSOP_RUNONCE)
  2886 CASE(JSOP_REST)
  2888     RootedObject &rest = rootObject0;
  2889     rest = REGS.fp()->createRestParameter(cx);
  2890     if (!rest)
  2891         goto error;
  2892     PUSH_COPY(ObjectValue(*rest));
  2894 END_CASE(JSOP_REST)
  2896 CASE(JSOP_GETALIASEDVAR)
  2898     ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
  2899     PUSH_COPY(REGS.fp()->aliasedVarScope(sc).aliasedVar(sc));
  2900     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
  2902 END_CASE(JSOP_GETALIASEDVAR)
  2904 CASE(JSOP_SETALIASEDVAR)
  2906     ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
  2907     ScopeObject &obj = REGS.fp()->aliasedVarScope(sc);
  2909     // Avoid computing the name if no type updates are needed, as this may be
  2910     // expensive on scopes with large numbers of variables.
  2911     PropertyName *name = (obj.hasSingletonType() && !obj.hasLazyType())
  2912                          ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, REGS.pc)
  2913                          : nullptr;
  2915     obj.setAliasedVar(cx, sc, name, REGS.sp[-1]);
  2917 END_CASE(JSOP_SETALIASEDVAR)
  2919 CASE(JSOP_GETARG)
  2921     unsigned i = GET_ARGNO(REGS.pc);
  2922     if (script->argsObjAliasesFormals())
  2923         PUSH_COPY(REGS.fp()->argsObj().arg(i));
  2924     else
  2925         PUSH_COPY(REGS.fp()->unaliasedFormal(i));
  2927 END_CASE(JSOP_GETARG)
  2929 CASE(JSOP_SETARG)
  2931     unsigned i = GET_ARGNO(REGS.pc);
  2932     if (script->argsObjAliasesFormals())
  2933         REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
  2934     else
  2935         REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
  2937 END_CASE(JSOP_SETARG)
  2939 CASE(JSOP_GETLOCAL)
  2941     uint32_t i = GET_LOCALNO(REGS.pc);
  2942     PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
  2944     /*
  2945      * Skip the same-compartment assertion if the local will be immediately
  2946      * popped. We do not guarantee sync for dead locals when coming in from the
  2947      * method JIT, and a GETLOCAL followed by POP is not considered to be
  2948      * a use of the variable.
  2949      */
  2950     if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
  2951         assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
  2953 END_CASE(JSOP_GETLOCAL)
  2955 CASE(JSOP_SETLOCAL)
  2957     uint32_t i = GET_LOCALNO(REGS.pc);
  2958     REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
  2960 END_CASE(JSOP_SETLOCAL)
  2962 CASE(JSOP_DEFCONST)
  2963 CASE(JSOP_DEFVAR)
  2965     /* ES5 10.5 step 8 (with subsequent errata). */
  2966     unsigned attrs = JSPROP_ENUMERATE;
  2967     if (!REGS.fp()->isEvalFrame())
  2968         attrs |= JSPROP_PERMANENT;
  2969     if (*REGS.pc == JSOP_DEFCONST)
  2970         attrs |= JSPROP_READONLY;
  2972     /* Step 8b. */
  2973     RootedObject &obj = rootObject0;
  2974     obj = &REGS.fp()->varObj();
  2976     RootedPropertyName &name = rootName0;
  2977     name = script->getName(REGS.pc);
  2979     if (!DefVarOrConstOperation(cx, obj, name, attrs))
  2980         goto error;
  2982 END_CASE(JSOP_DEFVAR)
  2984 CASE(JSOP_DEFFUN)
  2986     /*
  2987      * A top-level function defined in Global or Eval code (see ECMA-262
  2988      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
  2989      * a compound statement (not at the top statement level of global code, or
  2990      * at the top level of a function body).
  2991      */
  2992     RootedFunction &fun = rootFunction0;
  2993     fun = script->getFunction(GET_UINT32_INDEX(REGS.pc));
  2995     if (!DefFunOperation(cx, script, REGS.fp()->scopeChain(), fun))
  2996         goto error;
  2998 END_CASE(JSOP_DEFFUN)
  3000 CASE(JSOP_LAMBDA)
  3002     /* Load the specified function object literal. */
  3003     RootedFunction &fun = rootFunction0;
  3004     fun = script->getFunction(GET_UINT32_INDEX(REGS.pc));
  3006     JSObject *obj = Lambda(cx, fun, REGS.fp()->scopeChain());
  3007     if (!obj)
  3008         goto error;
  3009     JS_ASSERT(obj->getProto());
  3010     PUSH_OBJECT(*obj);
  3012 END_CASE(JSOP_LAMBDA)
  3014 CASE(JSOP_LAMBDA_ARROW)
  3016     /* Load the specified function object literal. */
  3017     RootedFunction &fun = rootFunction0;
  3018     fun = script->getFunction(GET_UINT32_INDEX(REGS.pc));
  3019     RootedValue &thisv = rootValue0;
  3020     thisv = REGS.sp[-1];
  3021     JSObject *obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv);
  3022     if (!obj)
  3023         goto error;
  3024     JS_ASSERT(obj->getProto());
  3025     REGS.sp[-1].setObject(*obj);
  3027 END_CASE(JSOP_LAMBDA_ARROW)
  3029 CASE(JSOP_CALLEE)
  3030     JS_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
  3031     PUSH_COPY(REGS.fp()->calleev());
  3032 END_CASE(JSOP_CALLEE)
  3034 CASE(JSOP_INITPROP_GETTER)
  3035 CASE(JSOP_INITPROP_SETTER)
  3037     RootedObject &obj = rootObject0;
  3038     RootedPropertyName &name = rootName0;
  3039     RootedObject &val = rootObject1;
  3041     JS_ASSERT(REGS.stackDepth() >= 2);
  3042     obj = &REGS.sp[-2].toObject();
  3043     name = script->getName(REGS.pc);
  3044     val = &REGS.sp[-1].toObject();
  3046     if (!InitGetterSetterOperation(cx, REGS.pc, obj, name, val))
  3047         goto error;
  3049     REGS.sp--;
  3051 END_CASE(JSOP_INITPROP_GETTER)
  3053 CASE(JSOP_INITELEM_GETTER)
  3054 CASE(JSOP_INITELEM_SETTER)
  3056     RootedObject &obj = rootObject0;
  3057     RootedValue &idval = rootValue0;
  3058     RootedObject &val = rootObject1;
  3060     JS_ASSERT(REGS.stackDepth() >= 3);
  3061     obj = &REGS.sp[-3].toObject();
  3062     idval = REGS.sp[-2];
  3063     val = &REGS.sp[-1].toObject();
  3065     if (!InitGetterSetterOperation(cx, REGS.pc, obj, idval, val))
  3066         goto error;
  3068     REGS.sp -= 2;
  3070 END_CASE(JSOP_INITELEM_GETTER)
  3072 CASE(JSOP_HOLE)
  3073     PUSH_HOLE();
  3074 END_CASE(JSOP_HOLE)
  3076 CASE(JSOP_NEWINIT)
  3078     uint8_t i = GET_UINT8(REGS.pc);
  3079     JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
  3081     RootedObject &obj = rootObject0;
  3082     NewObjectKind newKind;
  3083     if (i == JSProto_Array) {
  3084         newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_);
  3085         obj = NewDenseEmptyArray(cx, nullptr, newKind);
  3086     } else {
  3087         gc::AllocKind allocKind = GuessObjectGCKind(0);
  3088         newKind = UseNewTypeForInitializer(script, REGS.pc, &JSObject::class_);
  3089         obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind);
  3091     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
  3092         goto error;
  3094     PUSH_OBJECT(*obj);
  3096 END_CASE(JSOP_NEWINIT)
  3098 CASE(JSOP_NEWARRAY)
  3100     unsigned count = GET_UINT24(REGS.pc);
  3101     RootedObject &obj = rootObject0;
  3102     NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_);
  3103     obj = NewDenseAllocatedArray(cx, count, nullptr, newKind);
  3104     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
  3105         goto error;
  3107     PUSH_OBJECT(*obj);
  3109 END_CASE(JSOP_NEWARRAY)
  3111 CASE(JSOP_NEWOBJECT)
  3113     RootedObject &baseobj = rootObject0;
  3114     baseobj = script->getObject(REGS.pc);
  3116     RootedObject &obj = rootObject1;
  3117     NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, baseobj->getClass());
  3118     obj = CopyInitializerObject(cx, baseobj, newKind);
  3119     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
  3120         goto error;
  3122     PUSH_OBJECT(*obj);
  3124 END_CASE(JSOP_NEWOBJECT)
  3126 CASE(JSOP_ENDINIT)
  3128     /* FIXME remove JSOP_ENDINIT bug 588522 */
  3129     JS_ASSERT(REGS.stackDepth() >= 1);
  3130     JS_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
  3132 END_CASE(JSOP_ENDINIT)
  3134 CASE(JSOP_MUTATEPROTO)
  3136     MOZ_ASSERT(REGS.stackDepth() >= 2);
  3138     if (REGS.sp[-1].isObjectOrNull()) {
  3139         RootedObject &newProto = rootObject1;
  3140         rootObject1 = REGS.sp[-1].toObjectOrNull();
  3142         RootedObject &obj = rootObject0;
  3143         obj = &REGS.sp[-2].toObject();
  3144         MOZ_ASSERT(obj->is<JSObject>());
  3146         bool succeeded;
  3147         if (!JSObject::setProto(cx, obj, newProto, &succeeded))
  3148             goto error;
  3149         MOZ_ASSERT(succeeded);
  3152     REGS.sp--;
  3154 END_CASE(JSOP_MUTATEPROTO);
  3156 CASE(JSOP_INITPROP)
  3158     /* Load the property's initial value into rval. */
  3159     JS_ASSERT(REGS.stackDepth() >= 2);
  3160     RootedValue &rval = rootValue0;
  3161     rval = REGS.sp[-1];
  3163     /* Load the object being initialized into lval/obj. */
  3164     RootedObject &obj = rootObject0;
  3165     obj = &REGS.sp[-2].toObject();
  3166     JS_ASSERT(obj->is<JSObject>());
  3168     PropertyName *name = script->getName(REGS.pc);
  3170     RootedId &id = rootId0;
  3171     id = NameToId(name);
  3173     if (!DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE))
  3174         goto error;
  3176     REGS.sp--;
  3178 END_CASE(JSOP_INITPROP);
  3180 CASE(JSOP_INITELEM)
  3182     JS_ASSERT(REGS.stackDepth() >= 3);
  3183     HandleValue val = REGS.stackHandleAt(-1);
  3184     HandleValue id = REGS.stackHandleAt(-2);
  3186     RootedObject &obj = rootObject0;
  3187     obj = &REGS.sp[-3].toObject();
  3189     if (!InitElemOperation(cx, obj, id, val))
  3190         goto error;
  3192     REGS.sp -= 2;
  3194 END_CASE(JSOP_INITELEM)
  3196 CASE(JSOP_INITELEM_ARRAY)
  3198     JS_ASSERT(REGS.stackDepth() >= 2);
  3199     HandleValue val = REGS.stackHandleAt(-1);
  3201     RootedObject &obj = rootObject0;
  3202     obj = &REGS.sp[-2].toObject();
  3204     JS_ASSERT(obj->is<ArrayObject>());
  3206     uint32_t index = GET_UINT24(REGS.pc);
  3207     if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
  3208         goto error;
  3210     REGS.sp--;
  3212 END_CASE(JSOP_INITELEM_ARRAY)
  3214 CASE(JSOP_INITELEM_INC)
  3216     JS_ASSERT(REGS.stackDepth() >= 3);
  3217     HandleValue val = REGS.stackHandleAt(-1);
  3219     RootedObject &obj = rootObject0;
  3220     obj = &REGS.sp[-3].toObject();
  3222     uint32_t index = REGS.sp[-2].toInt32();
  3223     if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
  3224         goto error;
  3226     REGS.sp[-2].setInt32(index + 1);
  3227     REGS.sp--;
  3229 END_CASE(JSOP_INITELEM_INC)
  3231 CASE(JSOP_SPREAD)
  3233     int32_t count = REGS.sp[-2].toInt32();
  3234     RootedObject &arr = rootObject0;
  3235     arr = &REGS.sp[-3].toObject();
  3236     const Value iterable = REGS.sp[-1];
  3237     ForOfIterator iter(cx);
  3238     RootedValue &iterVal = rootValue0;
  3239     iterVal.set(iterable);
  3240     if (!iter.init(iterVal))
  3241         goto error;
  3242     while (true) {
  3243         bool done;
  3244         if (!iter.next(&iterVal, &done))
  3245             goto error;
  3246         if (done)
  3247             break;
  3248         if (count == INT32_MAX) {
  3249             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
  3250                                  JSMSG_SPREAD_TOO_LARGE);
  3251             goto error;
  3253         if (!JSObject::defineElement(cx, arr, count++, iterVal, nullptr, nullptr,
  3254                                      JSPROP_ENUMERATE))
  3255             goto error;
  3257     REGS.sp[-2].setInt32(count);
  3258     REGS.sp--;
  3260 END_CASE(JSOP_SPREAD)
  3262 CASE(JSOP_GOSUB)
  3264     PUSH_BOOLEAN(false);
  3265     int32_t i = script->pcToOffset(REGS.pc) + JSOP_GOSUB_LENGTH;
  3266     int32_t len = GET_JUMP_OFFSET(REGS.pc);
  3267     PUSH_INT32(i);
  3268     ADVANCE_AND_DISPATCH(len);
  3271 CASE(JSOP_RETSUB)
  3273     /* Pop [exception or hole, retsub pc-index]. */
  3274     Value rval, lval;
  3275     POP_COPY_TO(rval);
  3276     POP_COPY_TO(lval);
  3277     JS_ASSERT(lval.isBoolean());
  3278     if (lval.toBoolean()) {
  3279         /*
  3280          * Exception was pending during finally, throw it *before* we adjust
  3281          * pc, because pc indexes into script->trynotes.  This turns out not to
  3282          * be necessary, but it seems clearer.  And it points out a FIXME:
  3283          * 350509, due to Igor Bukanov.
  3284          */
  3285         cx->setPendingException(rval);
  3286         goto error;
  3288     JS_ASSERT(rval.isInt32());
  3290     /* Increment the PC by this much. */
  3291     int32_t len = rval.toInt32() - int32_t(script->pcToOffset(REGS.pc));
  3292     ADVANCE_AND_DISPATCH(len);
  3295 CASE(JSOP_EXCEPTION)
  3297     PUSH_NULL();
  3298     MutableHandleValue res = REGS.stackHandleAt(-1);
  3299     if (!GetAndClearException(cx, res))
  3300         goto error;
  3302 END_CASE(JSOP_EXCEPTION)
  3304 CASE(JSOP_FINALLY)
  3305     CHECK_BRANCH();
  3306 END_CASE(JSOP_FINALLY)
  3308 CASE(JSOP_THROWING)
  3310     JS_ASSERT(!cx->isExceptionPending());
  3311     Value v;
  3312     POP_COPY_TO(v);
  3313     cx->setPendingException(v);
  3315 END_CASE(JSOP_THROWING)
  3317 CASE(JSOP_THROW)
  3319     CHECK_BRANCH();
  3320     RootedValue &v = rootValue0;
  3321     POP_COPY_TO(v);
  3322     JS_ALWAYS_FALSE(Throw(cx, v));
  3323     /* let the code at error try to catch the exception. */
  3324     goto error;
  3327 CASE(JSOP_INSTANCEOF)
  3329     RootedValue &rref = rootValue0;
  3330     rref = REGS.sp[-1];
  3331     if (rref.isPrimitive()) {
  3332         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, js::NullPtr());
  3333         goto error;
  3335     RootedObject &obj = rootObject0;
  3336     obj = &rref.toObject();
  3337     bool cond = false;
  3338     if (!HasInstance(cx, obj, REGS.stackHandleAt(-2), &cond))
  3339         goto error;
  3340     REGS.sp--;
  3341     REGS.sp[-1].setBoolean(cond);
  3343 END_CASE(JSOP_INSTANCEOF)
  3345 CASE(JSOP_DEBUGGER)
  3347     JSTrapStatus st = JSTRAP_CONTINUE;
  3348     RootedValue rval(cx);
  3349     if (JSDebuggerHandler handler = cx->runtime()->debugHooks.debuggerHandler)
  3350         st = handler(cx, script, REGS.pc, rval.address(), cx->runtime()->debugHooks.debuggerHandlerData);
  3351     if (st == JSTRAP_CONTINUE)
  3352         st = Debugger::onDebuggerStatement(cx, &rval);
  3353     switch (st) {
  3354       case JSTRAP_ERROR:
  3355         goto error;
  3356       case JSTRAP_CONTINUE:
  3357         break;
  3358       case JSTRAP_RETURN:
  3359         REGS.fp()->setReturnValue(rval);
  3360         ForcedReturn(cx, REGS);
  3361         goto successful_return_continuation;
  3362       case JSTRAP_THROW:
  3363         cx->setPendingException(rval);
  3364         goto error;
  3365       default:;
  3368 END_CASE(JSOP_DEBUGGER)
  3370 CASE(JSOP_PUSHBLOCKSCOPE)
  3372     StaticBlockObject &blockObj = script->getObject(REGS.pc)->as<StaticBlockObject>();
  3374     JS_ASSERT(blockObj.needsClone());
  3375     // Clone block and push on scope chain.
  3376     if (!REGS.fp()->pushBlock(cx, blockObj))
  3377         goto error;
  3379 END_CASE(JSOP_PUSHBLOCKSCOPE)
  3381 CASE(JSOP_POPBLOCKSCOPE)
  3383 #ifdef DEBUG
  3384     // Pop block from scope chain.
  3385     JS_ASSERT(*(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH) == JSOP_DEBUGLEAVEBLOCK);
  3386     NestedScopeObject *scope = script->getStaticScope(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH);
  3387     JS_ASSERT(scope && scope->is<StaticBlockObject>());
  3388     StaticBlockObject &blockObj = scope->as<StaticBlockObject>();
  3389     JS_ASSERT(blockObj.needsClone());
  3390 #endif
  3392     // Pop block from scope chain.
  3393     REGS.fp()->popBlock(cx);
  3395 END_CASE(JSOP_POPBLOCKSCOPE)
  3397 CASE(JSOP_DEBUGLEAVEBLOCK)
  3399     JS_ASSERT(script->getStaticScope(REGS.pc));
  3400     JS_ASSERT(script->getStaticScope(REGS.pc)->is<StaticBlockObject>());
  3402     // FIXME: This opcode should not be necessary.  The debugger shouldn't need
  3403     // help from bytecode to do its job.  See bug 927782.
  3405     if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
  3406         DebugScopes::onPopBlock(cx, REGS.fp(), REGS.pc);
  3408 END_CASE(JSOP_DEBUGLEAVEBLOCK)
  3410 CASE(JSOP_GENERATOR)
  3412     JS_ASSERT(!cx->isExceptionPending());
  3413     REGS.fp()->initGeneratorFrame();
  3414     REGS.pc += JSOP_GENERATOR_LENGTH;
  3415     JSObject *obj = js_NewGenerator(cx, REGS);
  3416     if (!obj)
  3417         goto error;
  3418     REGS.fp()->setReturnValue(ObjectValue(*obj));
  3419     REGS.fp()->setYielding();
  3420     interpReturnOK = true;
  3421     if (activation.entryFrame() != REGS.fp())
  3422         goto inline_return;
  3423     goto exit;
  3426 CASE(JSOP_YIELD)
  3427     JS_ASSERT(!cx->isExceptionPending());
  3428     JS_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
  3429     if (cx->innermostGenerator()->state == JSGEN_CLOSING) {
  3430         RootedValue &val = rootValue0;
  3431         val.setObject(REGS.fp()->callee());
  3432         js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr());
  3433         goto error;
  3435     REGS.fp()->setReturnValue(REGS.sp[-1]);
  3436     REGS.fp()->setYielding();
  3437     REGS.pc += JSOP_YIELD_LENGTH;
  3438     interpReturnOK = true;
  3439     goto exit;
  3441 CASE(JSOP_ARRAYPUSH)
  3443     RootedObject &obj = rootObject0;
  3444     obj = &REGS.sp[-1].toObject();
  3445     if (!NewbornArrayPush(cx, obj, REGS.sp[-2]))
  3446         goto error;
  3447     REGS.sp -= 2;
  3449 END_CASE(JSOP_ARRAYPUSH)
  3451 DEFAULT()
  3453     char numBuf[12];
  3454     JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc);
  3455     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
  3456                          JSMSG_BAD_BYTECODE, numBuf);
  3457     goto error;
  3460 } /* interpreter loop */
  3462     MOZ_ASSUME_UNREACHABLE("Interpreter loop exited via fallthrough");
  3464   error:
  3465     switch (HandleError(cx, REGS)) {
  3466       case SuccessfulReturnContinuation:
  3467         goto successful_return_continuation;
  3469       case ErrorReturnContinuation:
  3470         interpReturnOK = false;
  3471         goto return_continuation;
  3473       case CatchContinuation:
  3474         ADVANCE_AND_DISPATCH(0);
  3476       case FinallyContinuation:
  3477         /*
  3478          * Push (true, exception) pair for finally to indicate that [retsub]
  3479          * should rethrow the exception.
  3480          */
  3481         RootedValue &exception = rootValue0;
  3482         if (!cx->getPendingException(&exception)) {
  3483             interpReturnOK = false;
  3484             goto return_continuation;
  3486         PUSH_BOOLEAN(true);
  3487         PUSH_COPY(exception);
  3488         cx->clearPendingException();
  3489         ADVANCE_AND_DISPATCH(0);
  3491     MOZ_ASSUME_UNREACHABLE("Invalid HandleError continuation");
  3493   exit:
  3494     if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
  3495         interpReturnOK = ScriptDebugEpilogue(cx, REGS.fp(), REGS.pc, interpReturnOK);
  3496     if (!REGS.fp()->isYielding())
  3497         REGS.fp()->epilogue(cx);
  3498     else
  3499         probes::ExitScript(cx, script, script->functionNonDelazifying(),
  3500                            REGS.fp()->hasPushedSPSFrame());
  3502     gc::MaybeVerifyBarriers(cx, true);
  3504     TraceLogStopEvent(logger);
  3505     TraceLogStopEvent(logger, scriptLogId);
  3507 #ifdef JS_ION
  3508     /*
  3509      * This path is used when it's guaranteed the method can be finished
  3510      * inside the JIT.
  3511      */
  3512   leave_on_safe_point:
  3513 #endif
  3515     if (interpReturnOK)
  3516         state.setReturnValue(activation.entryFrame()->returnValue());
  3518     return interpReturnOK;
  3521 bool
  3522 js::Throw(JSContext *cx, HandleValue v)
  3524     JS_ASSERT(!cx->isExceptionPending());
  3525     cx->setPendingException(v);
  3526     return false;
  3529 bool
  3530 js::GetProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
  3532     if (name == cx->names().length) {
  3533         // Fast path for strings, arrays and arguments.
  3534         if (GetLengthProperty(v, vp))
  3535             return true;
  3538     RootedObject obj(cx, ToObjectFromStack(cx, v));
  3539     if (!obj)
  3540         return false;
  3541     return JSObject::getProperty(cx, obj, obj, name, vp);
  3544 bool
  3545 js::CallProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
  3547     if (!GetProperty(cx, v, name, vp))
  3548         return false;
  3550 #if JS_HAS_NO_SUCH_METHOD
  3551     if (MOZ_UNLIKELY(vp.isUndefined()) && v.isObject())
  3553         RootedObject obj(cx, &v.toObject());
  3554         if (!OnUnknownMethod(cx, obj, StringValue(name), vp))
  3555             return false;
  3557 #endif
  3559     return true;
  3562 bool
  3563 js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name, MutableHandleValue vp)
  3565     RootedShape shape(cx);
  3566     RootedObject obj(cx), pobj(cx);
  3567     if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape))
  3568         return false;
  3570     if (!shape) {
  3571         JSAutoByteString printable;
  3572         if (AtomToPrintableString(cx, name, &printable))
  3573             js_ReportIsNotDefined(cx, printable.ptr());
  3574         return false;
  3577     return JSObject::getProperty(cx, obj, obj, name, vp);
  3580 /*
  3581  * Alternate form for NAME opcodes followed immediately by a TYPEOF,
  3582  * which do not report an exception on (typeof foo == "undefined") tests.
  3583  */
  3584 bool
  3585 js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandlePropertyName name,
  3586                           MutableHandleValue vp)
  3588     RootedShape shape(cx);
  3589     RootedObject obj(cx), pobj(cx);
  3590     if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape))
  3591         return false;
  3593     if (!shape) {
  3594         vp.set(UndefinedValue());
  3595         return true;
  3598     return JSObject::getProperty(cx, obj, obj, name, vp);
  3601 JSObject *
  3602 js::Lambda(JSContext *cx, HandleFunction fun, HandleObject parent)
  3604     MOZ_ASSERT(!fun->isArrow());
  3606     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, TenuredObject));
  3607     if (!clone)
  3608         return nullptr;
  3610     MOZ_ASSERT(clone->global() == clone->global());
  3611     return clone;
  3614 JSObject *
  3615 js::LambdaArrow(JSContext *cx, HandleFunction fun, HandleObject parent, HandleValue thisv)
  3617     MOZ_ASSERT(fun->isArrow());
  3619     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, TenuredObject));
  3620     if (!clone)
  3621         return nullptr;
  3623     MOZ_ASSERT(clone->as<JSFunction>().isArrow());
  3624     clone->as<JSFunction>().setExtendedSlot(0, thisv);
  3626     MOZ_ASSERT(clone->global() == clone->global());
  3627     return clone;
  3630 bool
  3631 js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain,
  3632                     HandleFunction funArg)
  3634     /*
  3635      * If static link is not current scope, clone fun's object to link to the
  3636      * current scope via parent. We do this to enable sharing of compiled
  3637      * functions among multiple equivalent scopes, amortizing the cost of
  3638      * compilation over a number of executions.  Examples include XUL scripts
  3639      * and event handlers shared among Firefox or other Mozilla app chrome
  3640      * windows, and user-defined JS functions precompiled and then shared among
  3641      * requests in server-side JS.
  3642      */
  3643     RootedFunction fun(cx, funArg);
  3644     if (fun->isNative() || fun->environment() != scopeChain) {
  3645         fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, TenuredObject);
  3646         if (!fun)
  3647             return false;
  3648     } else {
  3649         JS_ASSERT(script->compileAndGo());
  3650         JS_ASSERT(!script->functionNonDelazifying());
  3653     /*
  3654      * We define the function as a property of the variable object and not the
  3655      * current scope chain even for the case of function expression statements
  3656      * and functions defined by eval inside let or with blocks.
  3657      */
  3658     RootedObject parent(cx, scopeChain);
  3659     while (!parent->isVarObj())
  3660         parent = parent->enclosingScope();
  3662     /* ES5 10.5 (NB: with subsequent errata). */
  3663     RootedPropertyName name(cx, fun->atom()->asPropertyName());
  3665     RootedShape shape(cx);
  3666     RootedObject pobj(cx);
  3667     if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
  3668         return false;
  3670     RootedValue rval(cx, ObjectValue(*fun));
  3672     /*
  3673      * ECMA requires functions defined when entering Eval code to be
  3674      * impermanent.
  3675      */
  3676     unsigned attrs = script->isActiveEval()
  3677                      ? JSPROP_ENUMERATE
  3678                      : JSPROP_ENUMERATE | JSPROP_PERMANENT;
  3680     /* Steps 5d, 5f. */
  3681     if (!shape || pobj != parent) {
  3682         return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub,
  3683                                         JS_StrictPropertyStub, attrs);
  3686     /* Step 5e. */
  3687     JS_ASSERT(parent->isNative());
  3688     if (parent->is<GlobalObject>()) {
  3689         if (shape->configurable()) {
  3690             return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub,
  3691                                             JS_StrictPropertyStub, attrs);
  3694         if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
  3695             JSAutoByteString bytes;
  3696             if (AtomToPrintableString(cx, name, &bytes)) {
  3697                 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_REDEFINE_PROP,
  3698                                      bytes.ptr());
  3701             return false;
  3705     /*
  3706      * Non-global properties, and global properties which we aren't simply
  3707      * redefining, must be set.  First, this preserves their attributes.
  3708      * Second, this will produce warnings and/or errors as necessary if the
  3709      * specified Call object property is not writable (const).
  3710      */
  3712     /* Step 5f. */
  3713     return JSObject::setProperty(cx, parent, parent, name, &rval, script->strict());
  3716 bool
  3717 js::SetCallOperation(JSContext *cx)
  3719     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_LEFTSIDE_OF_ASS);
  3720     return false;
  3723 bool
  3724 js::GetAndClearException(JSContext *cx, MutableHandleValue res)
  3726     bool status = cx->getPendingException(res);
  3727     cx->clearPendingException();
  3728     if (!status)
  3729         return false;
  3731     // Allow interrupting deeply nested exception handling.
  3732     return CheckForInterrupt(cx);
  3735 template <bool strict>
  3736 bool
  3737 js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value)
  3739     RootedValue v(cx, value);
  3740     return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
  3743 template bool js::SetProperty<true> (JSContext *cx, HandleObject obj, HandleId id, const Value &value);
  3744 template bool js::SetProperty<false>(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
  3746 template <bool strict>
  3747 bool
  3748 js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp)
  3750     RootedObject obj(cx, ToObjectFromStack(cx, v));
  3751     if (!obj)
  3752         return false;
  3754     if (!JSObject::deleteProperty(cx, obj, name, bp))
  3755         return false;
  3757     if (strict && !*bp) {
  3758         obj->reportNotConfigurable(cx, NameToId(name));
  3759         return false;
  3761     return true;
  3764 template bool js::DeleteProperty<true> (JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp);
  3765 template bool js::DeleteProperty<false>(JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp);
  3767 template <bool strict>
  3768 bool
  3769 js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bp)
  3771     RootedObject obj(cx, ToObjectFromStack(cx, val));
  3772     if (!obj)
  3773         return false;
  3775     if (!JSObject::deleteByValue(cx, obj, index, bp))
  3776         return false;
  3778     if (strict && !*bp) {
  3779         // XXX This observably calls ToString(propval).  We should convert to
  3780         //     PropertyKey and use that to delete, and to report an error if
  3781         //     necessary!
  3782         RootedId id(cx);
  3783         if (!ValueToId<CanGC>(cx, index, &id))
  3784             return false;
  3785         obj->reportNotConfigurable(cx, id);
  3786         return false;
  3788     return true;
  3791 template bool js::DeleteElement<true> (JSContext *, HandleValue, HandleValue, bool *succeeded);
  3792 template bool js::DeleteElement<false>(JSContext *, HandleValue, HandleValue, bool *succeeded);
  3794 bool
  3795 js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp)
  3797     return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp);
  3800 bool
  3801 js::CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res)
  3803     return GetElementOperation(cx, JSOP_CALLELEM, lref, rref, res);
  3806 bool
  3807 js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
  3808                      bool strict)
  3810     RootedId id(cx);
  3811     if (!ValueToId<CanGC>(cx, index, &id))
  3812         return false;
  3813     return SetObjectElementOperation(cx, obj, id, value, strict);
  3816 bool
  3817 js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
  3818                      bool strict, HandleScript script, jsbytecode *pc)
  3820     JS_ASSERT(pc);
  3821     RootedId id(cx);
  3822     if (!ValueToId<CanGC>(cx, index, &id))
  3823         return false;
  3824     return SetObjectElementOperation(cx, obj, id, value, strict, script, pc);
  3827 bool
  3828 js::InitElementArray(JSContext *cx, jsbytecode *pc, HandleObject obj, uint32_t index, HandleValue value)
  3830     return InitArrayElemOperation(cx, pc, obj, index, value);
  3833 bool
  3834 js::AddValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3836     return AddOperation(cx, lhs, rhs, res);
  3839 bool
  3840 js::SubValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3842     return SubOperation(cx, lhs, rhs, res);
  3845 bool
  3846 js::MulValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3848     return MulOperation(cx, lhs, rhs, res);
  3851 bool
  3852 js::DivValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3854     return DivOperation(cx, lhs, rhs, res);
  3857 bool
  3858 js::ModValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3860     return ModOperation(cx, lhs, rhs, res);
  3863 bool
  3864 js::UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
  3866     return UrshOperation(cx, lhs, rhs, res);
  3869 bool
  3870 js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject scopeObj,
  3871                         MutableHandleValue res)
  3873     RootedObject scope(cx), pobj(cx);
  3874     RootedShape shape(cx);
  3875     if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape))
  3876         return false;
  3878     if (!scope) {
  3879         // Return true for non-existent names.
  3880         res.setBoolean(true);
  3881         return true;
  3884     bool succeeded;
  3885     if (!JSObject::deleteProperty(cx, scope, name, &succeeded))
  3886         return false;
  3887     res.setBoolean(succeeded);
  3888     return true;
  3891 bool
  3892 js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name,
  3893                           MutableHandleValue res)
  3895     RootedObject obj(cx);
  3896     if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj))
  3897         return false;
  3899     return ComputeImplicitThis(cx, obj, res);
  3902 bool
  3903 js::RunOnceScriptPrologue(JSContext *cx, HandleScript script)
  3905     JS_ASSERT(script->treatAsRunOnce());
  3907     if (!script->hasRunOnce()) {
  3908         script->setHasRunOnce();
  3909         return true;
  3912     // Force instantiation of the script's function's type to ensure the flag
  3913     // is preserved in type information.
  3914     if (!script->functionNonDelazifying()->getType(cx))
  3915         return false;
  3917     types::MarkTypeObjectFlags(cx, script->functionNonDelazifying(),
  3918                                types::OBJECT_FLAG_RUNONCE_INVALIDATED);
  3919     return true;
  3922 bool
  3923 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id,
  3924                               HandleObject val)
  3926     JS_ASSERT(val->isCallable());
  3927     PropertyOp getter;
  3928     StrictPropertyOp setter;
  3929     unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
  3931     JSOp op = JSOp(*pc);
  3933     if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER) {
  3934         getter = CastAsPropertyOp(val);
  3935         setter = JS_StrictPropertyStub;
  3936         attrs |= JSPROP_GETTER;
  3937     } else {
  3938         JS_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER);
  3939         getter = JS_PropertyStub;
  3940         setter = CastAsStrictPropertyOp(val);
  3941         attrs |= JSPROP_SETTER;
  3944     RootedValue scratch(cx);
  3945     return JSObject::defineGeneric(cx, obj, id, scratch, getter, setter, attrs);
  3948 bool
  3949 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj,
  3950                               HandlePropertyName name, HandleObject val)
  3952     RootedId id(cx, NameToId(name));
  3953     return InitGetterSetterOperation(cx, pc, obj, id, val);
  3956 bool
  3957 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
  3958                               HandleObject val)
  3960     RootedId id(cx);
  3961     if (!ValueToId<CanGC>(cx, idval, &id))
  3962         return false;
  3964     return InitGetterSetterOperation(cx, pc, obj, id, val);

mercurial