tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Interpreter.cpp (168698B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/. */
      6 
      7 /*
      8 * JavaScript bytecode interpreter.
      9 */
     10 
     11 #include "vm/Interpreter-inl.h"
     12 
     13 #include "mozilla/DebugOnly.h"
     14 #include "mozilla/FloatingPoint.h"
     15 #include "mozilla/Maybe.h"
     16 #include "mozilla/ScopeExit.h"
     17 #include "mozilla/Sprintf.h"
     18 #include "mozilla/TimeStamp.h"
     19 
     20 #include <string.h>
     21 
     22 #include "jsapi.h"
     23 #include "jsnum.h"
     24 
     25 #include "builtin/Array.h"
     26 #include "builtin/Eval.h"
     27 #include "builtin/ModuleObject.h"
     28 #include "builtin/Object.h"
     29 #include "builtin/Promise.h"
     30 #include "gc/GC.h"
     31 #include "jit/BaselineJIT.h"
     32 #include "jit/Jit.h"
     33 #include "jit/JitRuntime.h"
     34 #include "js/EnvironmentChain.h"      // JS::SupportUnscopables
     35 #include "js/experimental/JitInfo.h"  // JSJitInfo
     36 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
     37 #include "js/friend/StackLimits.h"    // js::AutoCheckRecursionLimit
     38 #include "js/friend/WindowProxy.h"    // js::IsWindowProxy
     39 #include "js/Printer.h"
     40 #include "proxy/DeadObjectProxy.h"
     41 #include "util/StringBuilder.h"
     42 #include "vm/AsyncFunction.h"
     43 #include "vm/AsyncIteration.h"
     44 #include "vm/BigIntType.h"
     45 #include "vm/BytecodeUtil.h"  // JSDVG_SEARCH_STACK
     46 #include "vm/ConstantCompareOperand.h"
     47 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     48 #  include "vm/ErrorObject.h"
     49 #endif
     50 #include "vm/EqualityOperations.h"  // js::StrictlyEqual
     51 #include "vm/GeneratorObject.h"
     52 #include "vm/Iteration.h"
     53 #include "vm/JSContext.h"
     54 #include "vm/JSFunction.h"
     55 #include "vm/JSObject.h"
     56 #include "vm/JSScript.h"
     57 #include "vm/Opcodes.h"
     58 #include "vm/PlainObject.h"  // js::PlainObject
     59 #include "vm/Scope.h"
     60 #include "vm/Shape.h"
     61 #include "vm/SharedStencil.h"  // GCThingIndex
     62 #include "vm/StringType.h"
     63 #include "vm/ThrowMsgKind.h"     // ThrowMsgKind
     64 #include "vm/TypeofEqOperand.h"  // TypeofEqOperand
     65 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     66 #  include "vm/UsingHint.h"
     67 #endif
     68 #include "builtin/Boolean-inl.h"
     69 #include "debugger/DebugAPI-inl.h"
     70 #include "vm/ArgumentsObject-inl.h"
     71 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     72 #  include "vm/DisposableRecord-inl.h"
     73 #endif
     74 #include "vm/EnvironmentObject-inl.h"
     75 #include "vm/GeckoProfiler-inl.h"
     76 #include "vm/JSScript-inl.h"
     77 #include "vm/NativeObject-inl.h"
     78 #include "vm/ObjectOperations-inl.h"
     79 #include "vm/PlainObject-inl.h"  // js::CopyInitializerObject, js::CreateThis
     80 #include "vm/Probes-inl.h"
     81 #include "vm/Stack-inl.h"
     82 
     83 using namespace js;
     84 
     85 using mozilla::DebugOnly;
     86 using mozilla::NumberEqualsInt32;
     87 
     88 template <bool Eq>
     89 static MOZ_ALWAYS_INLINE bool LooseEqualityOp(JSContext* cx,
     90                                              InterpreterRegs& regs) {
     91  HandleValue rval = regs.stackHandleAt(-1);
     92  HandleValue lval = regs.stackHandleAt(-2);
     93  bool cond;
     94  if (!LooselyEqual(cx, lval, rval, &cond)) {
     95    return false;
     96  }
     97  cond = (cond == Eq);
     98  regs.sp--;
     99  regs.sp[-1].setBoolean(cond);
    100  return true;
    101 }
    102 
    103 JSObject* js::BoxNonStrictThis(JSContext* cx, HandleValue thisv) {
    104  MOZ_ASSERT(!thisv.isMagic());
    105 
    106  if (thisv.isNullOrUndefined()) {
    107    return cx->global()->lexicalEnvironment().thisObject();
    108  }
    109 
    110  if (thisv.isObject()) {
    111    return &thisv.toObject();
    112  }
    113 
    114  return PrimitiveToObject(cx, thisv);
    115 }
    116 
    117 static bool IsNSVOLexicalEnvironment(JSObject* env) {
    118  return env->is<LexicalEnvironmentObject>() &&
    119         env->as<LexicalEnvironmentObject>()
    120             .enclosingEnvironment()
    121             .is<NonSyntacticVariablesObject>();
    122 }
    123 
    124 bool js::GetFunctionThis(JSContext* cx, AbstractFramePtr frame,
    125                         MutableHandleValue res) {
    126  MOZ_ASSERT(frame.isFunctionFrame());
    127  MOZ_ASSERT(!frame.callee()->isArrow());
    128 
    129  if (frame.thisArgument().isObject() || frame.callee()->strict()) {
    130    res.set(frame.thisArgument());
    131    return true;
    132  }
    133 
    134  MOZ_ASSERT(!frame.callee()->isSelfHostedBuiltin(),
    135             "Self-hosted builtins must be strict");
    136 
    137  RootedValue thisv(cx, frame.thisArgument());
    138 
    139  // If there is a NSVO on environment chain, use it as basis for fallback
    140  // global |this|. This gives a consistent definition of global lexical
    141  // |this| between function and global contexts.
    142  //
    143  // NOTE: If only non-syntactic WithEnvironments are on the chain, we use the
    144  // global lexical |this| value. This is for compatibility with the Subscript
    145  // Loader.
    146  if (frame.script()->hasNonSyntacticScope() && thisv.isNullOrUndefined()) {
    147    JSObject* env = frame.environmentChain();
    148    while (true) {
    149      if (IsNSVOLexicalEnvironment(env) ||
    150          env->is<GlobalLexicalEnvironmentObject>()) {
    151        auto* obj = env->as<ExtensibleLexicalEnvironmentObject>().thisObject();
    152        res.setObject(*obj);
    153        return true;
    154      }
    155      if (!env->enclosingEnvironment()) {
    156        // This can only happen in Debugger eval frames: in that case we
    157        // don't always have a global lexical env, see EvaluateInEnv.
    158        MOZ_ASSERT(env->is<GlobalObject>());
    159        res.setObject(*GetThisObject(env));
    160        return true;
    161      }
    162      env = env->enclosingEnvironment();
    163    }
    164  }
    165 
    166  JSObject* obj = BoxNonStrictThis(cx, thisv);
    167  if (!obj) {
    168    return false;
    169  }
    170 
    171  res.setObject(*obj);
    172  return true;
    173 }
    174 
    175 void js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
    176                                   MutableHandleValue res) {
    177  JSObject* env = envChain;
    178  while (true) {
    179    if (env->is<ExtensibleLexicalEnvironmentObject>()) {
    180      auto* obj = env->as<ExtensibleLexicalEnvironmentObject>().thisObject();
    181      res.setObject(*obj);
    182      return;
    183    }
    184    if (!env->enclosingEnvironment()) {
    185      // This can only happen in Debugger eval frames: in that case we
    186      // don't always have a global lexical env, see EvaluateInEnv.
    187      MOZ_ASSERT(env->is<GlobalObject>());
    188      res.setObject(*GetThisObject(env));
    189      return;
    190    }
    191    env = env->enclosingEnvironment();
    192  }
    193 }
    194 
    195 #ifdef DEBUG
    196 static bool IsSelfHostedOrKnownBuiltinCtor(JSFunction* fun, JSContext* cx) {
    197  if (fun->isSelfHostedOrIntrinsic()) {
    198    return true;
    199  }
    200 
    201  // GetBuiltinConstructor in MapGroupBy
    202  if (fun == cx->global()->maybeGetConstructor(JSProto_Map)) {
    203    return true;
    204  }
    205 
    206  // GetBuiltinConstructor in intlFallbackSymbol
    207  if (fun == cx->global()->maybeGetConstructor(JSProto_Symbol)) {
    208    return true;
    209  }
    210 
    211  // ConstructorForTypedArray in MergeSortTypedArray
    212  if (fun == cx->global()->maybeGetConstructor(JSProto_Int8Array) ||
    213      fun == cx->global()->maybeGetConstructor(JSProto_Uint8Array) ||
    214      fun == cx->global()->maybeGetConstructor(JSProto_Int16Array) ||
    215      fun == cx->global()->maybeGetConstructor(JSProto_Uint16Array) ||
    216      fun == cx->global()->maybeGetConstructor(JSProto_Int32Array) ||
    217      fun == cx->global()->maybeGetConstructor(JSProto_Uint32Array) ||
    218      fun == cx->global()->maybeGetConstructor(JSProto_Float32Array) ||
    219      fun == cx->global()->maybeGetConstructor(JSProto_Float64Array) ||
    220      fun == cx->global()->maybeGetConstructor(JSProto_Uint8ClampedArray) ||
    221      fun == cx->global()->maybeGetConstructor(JSProto_BigInt64Array) ||
    222      fun == cx->global()->maybeGetConstructor(JSProto_BigUint64Array)) {
    223    return true;
    224  }
    225 
    226  return false;
    227 }
    228 #endif  // DEBUG
    229 
    230 bool js::Debug_CheckSelfHosted(JSContext* cx, HandleValue funVal) {
    231 #ifdef DEBUG
    232  JSFunction* fun = &UncheckedUnwrap(&funVal.toObject())->as<JSFunction>();
    233  MOZ_ASSERT(IsSelfHostedOrKnownBuiltinCtor(fun, cx),
    234             "functions directly called inside self-hosted JS must be one of "
    235             "selfhosted function, self-hosted intrinsic, or known built-in "
    236             "constructor");
    237 #else
    238  MOZ_CRASH("self-hosted checks should only be done in Debug builds");
    239 #endif
    240 
    241  // This is purely to police self-hosted code. There is no actual operation.
    242  return true;
    243 }
    244 
    245 static inline bool GetLengthProperty(const Value& lval, MutableHandleValue vp) {
    246  /* Optimize length accesses on strings, arrays, and arguments. */
    247  if (lval.isString()) {
    248    vp.setInt32(lval.toString()->length());
    249    return true;
    250  }
    251  if (lval.isObject()) {
    252    JSObject* obj = &lval.toObject();
    253    if (obj->is<ArrayObject>()) {
    254      vp.setNumber(obj->as<ArrayObject>().length());
    255      return true;
    256    }
    257 
    258    if (obj->is<ArgumentsObject>()) {
    259      ArgumentsObject* argsobj = &obj->as<ArgumentsObject>();
    260      if (!argsobj->hasOverriddenLength()) {
    261        uint32_t length = argsobj->initialLength();
    262        MOZ_ASSERT(length < INT32_MAX);
    263        vp.setInt32(int32_t(length));
    264        return true;
    265      }
    266    }
    267  }
    268 
    269  return false;
    270 }
    271 
    272 static inline bool GetNameOperation(JSContext* cx, HandleObject envChain,
    273                                    Handle<PropertyName*> name, JSOp nextOp,
    274                                    MutableHandleValue vp) {
    275  /* Kludge to allow (typeof foo == "undefined") tests. */
    276  if (IsTypeOfNameOp(nextOp)) {
    277    return GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, vp);
    278  }
    279  return GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, vp);
    280 }
    281 
    282 bool js::GetImportOperation(JSContext* cx, HandleObject envChain,
    283                            HandleScript script, jsbytecode* pc,
    284                            MutableHandleValue vp) {
    285  RootedObject env(cx), pobj(cx);
    286  Rooted<PropertyName*> name(cx, script->getName(pc));
    287  PropertyResult prop;
    288 
    289  MOZ_ALWAYS_TRUE(LookupName(cx, name, envChain, &env, &pobj, &prop));
    290  MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
    291  MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
    292  return FetchName<GetNameMode::Normal>(cx, env, pobj, name, prop, vp);
    293 }
    294 
    295 bool js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
    296                             MaybeConstruct construct) {
    297  unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
    298  int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
    299 
    300  ReportValueError(cx, error, spIndex, v, nullptr);
    301  return false;
    302 }
    303 
    304 JSObject* js::ValueToCallable(JSContext* cx, HandleValue v, int numToSkip,
    305                              MaybeConstruct construct) {
    306  if (v.isObject() && v.toObject().isCallable()) {
    307    return &v.toObject();
    308  }
    309 
    310  ReportIsNotFunction(cx, v, numToSkip, construct);
    311  return nullptr;
    312 }
    313 
    314 static bool MaybeCreateThisForConstructor(JSContext* cx, const CallArgs& args) {
    315  if (args.thisv().isObject()) {
    316    return true;
    317  }
    318 
    319  RootedFunction callee(cx, &args.callee().as<JSFunction>());
    320  RootedObject newTarget(cx, &args.newTarget().toObject());
    321 
    322  MOZ_ASSERT(callee->hasBytecode());
    323 
    324  if (!CreateThis(cx, callee, newTarget, GenericObject, args.mutableThisv())) {
    325    return false;
    326  }
    327 
    328  // Ensure the callee still has a non-lazy script. We normally don't relazify
    329  // in active compartments, but the .prototype lookup might have called the
    330  // relazifyFunctions testing function that doesn't have this restriction.
    331  return JSFunction::getOrCreateScript(cx, callee);
    332 }
    333 
    334 InterpreterFrame* InvokeState::pushInterpreterFrame(JSContext* cx) {
    335  return cx->interpreterStack().pushInvokeFrame(cx, args_, construct_);
    336 }
    337 
    338 InterpreterFrame* ExecuteState::pushInterpreterFrame(JSContext* cx) {
    339  return cx->interpreterStack().pushExecuteFrame(cx, script_, envChain_,
    340                                                 evalInFrame_);
    341 }
    342 
    343 InterpreterFrame* RunState::pushInterpreterFrame(JSContext* cx) {
    344  if (isInvoke()) {
    345    return asInvoke()->pushInterpreterFrame(cx);
    346  }
    347  return asExecute()->pushInterpreterFrame(cx);
    348 }
    349 
    350 static MOZ_ALWAYS_INLINE bool MaybeEnterInterpreterTrampoline(JSContext* cx,
    351                                                              RunState& state) {
    352 #ifdef NIGHTLY_BUILD
    353  if (jit::JitOptions.emitInterpreterEntryTrampoline &&
    354      cx->runtime()->hasJitRuntime()) {
    355    js::jit::JitRuntime* jitRuntime = cx->runtime()->jitRuntime();
    356    JSScript* script = state.script();
    357 
    358    uint8_t* codeRaw = nullptr;
    359    auto p = jitRuntime->getInterpreterEntryMap()->lookup(script);
    360    if (p) {
    361      codeRaw = p->value().raw();
    362    } else {
    363      js::jit::JitCode* code =
    364          jitRuntime->generateEntryTrampolineForScript(cx, script);
    365      if (!code) {
    366        ReportOutOfMemory(cx);
    367        return false;
    368      }
    369 
    370      js::jit::EntryTrampoline entry(cx, code);
    371      if (!jitRuntime->getInterpreterEntryMap()->put(script, entry)) {
    372        ReportOutOfMemory(cx);
    373        return false;
    374      }
    375      codeRaw = code->raw();
    376    }
    377 
    378    MOZ_ASSERT(codeRaw, "Should have a valid trampoline here.");
    379    // The C++ entry thunk is located at the vmInterpreterEntryOffset offset.
    380    codeRaw += jitRuntime->vmInterpreterEntryOffset();
    381    return js::jit::EnterInterpreterEntryTrampoline(codeRaw, cx, &state);
    382  }
    383 #endif
    384  return Interpret(cx, state);
    385 }
    386 
    387 static void AssertExceptionResult(JSContext* cx) {
    388  // If this assertion fails, a JSNative or code in the VM returned false
    389  // without throwing an exception or calling JS::ReportUncatchableException.
    390  MOZ_ASSERT(cx->isExceptionPending() || cx->isPropagatingForcedReturn() ||
    391             cx->hadUncatchableException());
    392 }
    393 
    394 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
    395 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
    396 // avoid this.
    397 #ifdef _MSC_VER
    398 #  pragma optimize("g", off)
    399 #endif
    400 bool js::RunScript(JSContext* cx, RunState& state) {
    401  AutoCheckRecursionLimit recursion(cx);
    402  if (!recursion.check(cx)) {
    403    return false;
    404  }
    405 
    406  MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(),
    407                !cx->runtime()->jitRuntime()->disallowArbitraryCode());
    408 
    409  // Since any script can conceivably GC, make sure it's safe to do so.
    410  cx->verifyIsSafeToGC();
    411 
    412  // Don't run script while suppressing GC to not confuse JIT code that assumes
    413  // some new objects will be allocated in the nursery.
    414  MOZ_ASSERT(!cx->suppressGC);
    415 
    416  MOZ_ASSERT(cx->realm() == state.script()->realm());
    417 
    418  MOZ_DIAGNOSTIC_ASSERT(cx->realm()->isSystem() ||
    419                        cx->runtime()->allowContentJS());
    420 
    421  if (!DebugAPI::checkNoExecute(cx, state.script())) {
    422    return false;
    423  }
    424 
    425  GeckoProfilerEntryMarker marker(cx, state.script());
    426 
    427  // If the isExecuting flag was not set, then enable it.
    428  //  This flag is only set on the initial, outermost RunScript call.
    429  //  Also start a timer if measureExecutionTimeEnabled() is true.
    430  bool isExecuting = cx->isExecutingRef();
    431  bool timerEnabled = cx->measuringExecutionTimeEnabled();
    432 
    433  mozilla::TimeStamp startTime;
    434  if (!isExecuting) {
    435    cx->setIsExecuting(true);
    436    if (timerEnabled) {
    437      startTime = mozilla::TimeStamp::Now();
    438    }
    439  }
    440  auto onScopeExit = mozilla::MakeScopeExit([&]() {
    441    if (!isExecuting) {
    442      cx->setIsExecuting(false);
    443      if (timerEnabled) {
    444        mozilla::TimeDuration delta = mozilla::TimeStamp::Now() - startTime;
    445        cx->realm()->timers.executionTime += delta;
    446      }
    447    }
    448  });
    449 
    450  jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
    451  switch (status) {
    452    case jit::EnterJitStatus::Error:
    453      return false;
    454    case jit::EnterJitStatus::Ok:
    455      return true;
    456    case jit::EnterJitStatus::NotEntered:
    457      break;
    458  }
    459 
    460  bool ok = MaybeEnterInterpreterTrampoline(cx, state);
    461  if (!ok) {
    462    AssertExceptionResult(cx);
    463  }
    464  return ok;
    465 }
    466 #ifdef _MSC_VER
    467 #  pragma optimize("", on)
    468 #endif
    469 
    470 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
    471 MOZ_ALWAYS_INLINE bool CallJSNative(JSContext* cx, Native native,
    472                                    CallReason reason, const CallArgs& args) {
    473  AutoCheckRecursionLimit recursion(cx);
    474  if (!recursion.check(cx)) {
    475    return false;
    476  }
    477 
    478  NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
    479  if (resumeMode != NativeResumeMode::Continue) {
    480    return resumeMode == NativeResumeMode::Override;
    481  }
    482 
    483 #ifdef DEBUG
    484  bool alreadyThrowing = cx->isExceptionPending();
    485 #endif
    486  cx->check(args);
    487  MOZ_ASSERT(!args.callee().is<ProxyObject>());
    488 
    489  AutoRealm ar(cx, &args.callee());
    490  bool ok = native(cx, args.length(), args.base());
    491  if (ok) {
    492    cx->check(args.rval());
    493    MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
    494  } else {
    495    AssertExceptionResult(cx);
    496  }
    497  return ok;
    498 }
    499 
    500 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
    501 MOZ_ALWAYS_INLINE bool CallJSNativeConstructor(JSContext* cx, Native native,
    502                                               const CallArgs& args) {
    503 #ifdef DEBUG
    504  RootedObject callee(cx, &args.callee());
    505 #endif
    506 
    507  MOZ_ASSERT(args.thisv().isMagic());
    508  if (!CallJSNative(cx, native, CallReason::Call, args)) {
    509    return false;
    510  }
    511 
    512  /*
    513   * Native constructors must return non-primitive values on success.
    514   * Although it is legal, if a constructor returns the callee, there is a
    515   * 99.9999% chance it is a bug. If any valid code actually wants the
    516   * constructor to return the callee, the assertion can be removed or
    517   * (another) conjunct can be added to the antecedent.
    518   *
    519   * Exceptions:
    520   * - (new Object(Object)) returns the callee.
    521   * - The bound function construct hook can return an arbitrary object,
    522   *   including the callee.
    523   *
    524   * Also allow if this may be due to a debugger hook since fuzzing may let this
    525   * happen.
    526   */
    527  MOZ_ASSERT(args.rval().isObject());
    528  MOZ_ASSERT_IF(!JS_IsNativeFunction(callee, obj_construct) &&
    529                    !callee->is<BoundFunctionObject>() &&
    530                    !cx->realm()->debuggerObservesNativeCall(),
    531                args.rval() != ObjectValue(*callee));
    532 
    533  return true;
    534 }
    535 
    536 /*
    537 * Find a function reference and its 'this' value implicit first parameter
    538 * under argc arguments on cx's stack, and call the function.  Push missing
    539 * required arguments, allocate declared local variables, and pop everything
    540 * when done.  Then push the return value.
    541 *
    542 * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
    543 *       necessary.  The caller (usually the interpreter) must have performed
    544 *       this step already!
    545 */
    546 bool js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
    547                                 MaybeConstruct construct,
    548                                 CallReason reason /* = CallReason::Call */) {
    549  MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
    550 
    551  unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
    552  if (args.calleev().isPrimitive()) {
    553    return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
    554  }
    555 
    556  /* Invoke non-functions. */
    557  if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) {
    558    MOZ_ASSERT_IF(construct, !args.callee().isConstructor());
    559 
    560    if (!args.callee().isCallable()) {
    561      return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
    562    }
    563 
    564    if (args.callee().is<ProxyObject>()) {
    565      RootedObject proxy(cx, &args.callee());
    566      return Proxy::call(cx, proxy, args);
    567    }
    568 
    569    JSNative call = args.callee().callHook();
    570    MOZ_ASSERT(call, "isCallable without a callHook?");
    571 
    572    return CallJSNative(cx, call, reason, args);
    573  }
    574 
    575  /* Invoke native functions. */
    576  RootedFunction fun(cx, &args.callee().as<JSFunction>());
    577  if (fun->isNativeFun()) {
    578    MOZ_ASSERT_IF(construct, !fun->isConstructor());
    579    JSNative native = fun->native();
    580    if (!construct && args.ignoresReturnValue() && fun->hasJitInfo()) {
    581      const JSJitInfo* jitInfo = fun->jitInfo();
    582      if (jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) {
    583        native = jitInfo->ignoresReturnValueMethod;
    584      }
    585    }
    586    return CallJSNative(cx, native, reason, args);
    587  }
    588 
    589  // Self-hosted builtins are considered native by the onNativeCall hook.
    590  if (fun->isSelfHostedBuiltin()) {
    591    NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
    592    if (resumeMode != NativeResumeMode::Continue) {
    593      return resumeMode == NativeResumeMode::Override;
    594    }
    595  }
    596 
    597  if (!JSFunction::getOrCreateScript(cx, fun)) {
    598    return false;
    599  }
    600 
    601  /* Run function until JSOp::RetRval, JSOp::Return or error. */
    602  InvokeState state(cx, args, construct);
    603 
    604  // Create |this| if we're constructing. Switch to the callee's realm to
    605  // ensure this object has the correct realm.
    606  AutoRealm ar(cx, state.script());
    607  if (construct && !MaybeCreateThisForConstructor(cx, args)) {
    608    return false;
    609  }
    610 
    611  // Calling class constructors throws an error from the callee's realm.
    612  if (construct != CONSTRUCT && fun->isClassConstructor()) {
    613    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    614                              JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
    615    return false;
    616  }
    617 
    618  bool ok = RunScript(cx, state);
    619 
    620  MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
    621  return ok;
    622 }
    623 
    624 // Returns true if the callee needs an outerized |this| object. Outerization
    625 // means passing the WindowProxy instead of the Window (a GlobalObject) because
    626 // we must never expose the Window to script. This returns false only for DOM
    627 // getters or setters.
    628 static bool CalleeNeedsOuterizedThisObject(Value callee) {
    629  if (!callee.isObject() || !callee.toObject().is<JSFunction>()) {
    630    return true;
    631  }
    632  JSFunction& fun = callee.toObject().as<JSFunction>();
    633  if (!fun.isNativeFun() || !fun.hasJitInfo()) {
    634    return true;
    635  }
    636  return fun.jitInfo()->needsOuterizedThisObject();
    637 }
    638 
    639 static bool InternalCall(JSContext* cx, const AnyInvokeArgs& args,
    640                         CallReason reason) {
    641  MOZ_ASSERT(args.array() + args.length() == args.end(),
    642             "must pass calling arguments to a calling attempt");
    643 
    644 #ifdef DEBUG
    645  // The caller is responsible for calling GetThisObject if needed.
    646  if (args.thisv().isObject()) {
    647    JSObject* thisObj = &args.thisv().toObject();
    648    MOZ_ASSERT_IF(CalleeNeedsOuterizedThisObject(args.calleev()),
    649                  GetThisObject(thisObj) == thisObj);
    650  }
    651 #endif
    652 
    653  return InternalCallOrConstruct(cx, args, NO_CONSTRUCT, reason);
    654 }
    655 
    656 bool js::CallFromStack(JSContext* cx, const CallArgs& args,
    657                       CallReason reason /* = CallReason::Call */) {
    658  return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args), reason);
    659 }
    660 
    661 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
    662 // 7.3.12 Call.
    663 bool js::Call(JSContext* cx, HandleValue fval, HandleValue thisv,
    664              const AnyInvokeArgs& args, MutableHandleValue rval,
    665              CallReason reason) {
    666  // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
    667  // shadowing.
    668  args.CallArgs::setCallee(fval);
    669  args.CallArgs::setThis(thisv);
    670 
    671  if (thisv.isObject()) {
    672    // If |this| is a global object, it might be a Window and in that case we
    673    // usually have to pass the WindowProxy instead.
    674    JSObject* thisObj = &thisv.toObject();
    675    if (thisObj->is<GlobalObject>()) {
    676      if (CalleeNeedsOuterizedThisObject(fval)) {
    677        args.mutableThisv().setObject(*GetThisObject(thisObj));
    678      }
    679    } else {
    680      // Fast path: we don't have to do anything if the object isn't a global.
    681      MOZ_ASSERT(GetThisObject(thisObj) == thisObj);
    682    }
    683  }
    684 
    685  if (!InternalCall(cx, args, reason)) {
    686    return false;
    687  }
    688 
    689  rval.set(args.rval());
    690  return true;
    691 }
    692 
    693 static bool InternalConstruct(JSContext* cx, const AnyConstructArgs& args,
    694                              CallReason reason = CallReason::Call) {
    695  MOZ_ASSERT(args.array() + args.length() + 1 == args.end(),
    696             "must pass constructing arguments to a construction attempt");
    697  MOZ_ASSERT(!FunctionClass.getConstruct());
    698  MOZ_ASSERT(!ExtendedFunctionClass.getConstruct());
    699 
    700  // Callers are responsible for enforcing these preconditions.
    701  MOZ_ASSERT(IsConstructor(args.calleev()),
    702             "trying to construct a value that isn't a constructor");
    703  MOZ_ASSERT(IsConstructor(args.CallArgs::newTarget()),
    704             "provided new.target value must be a constructor");
    705 
    706  MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING) ||
    707             args.thisv().isObject());
    708 
    709  JSObject& callee = args.callee();
    710  if (callee.is<JSFunction>()) {
    711    RootedFunction fun(cx, &callee.as<JSFunction>());
    712 
    713    if (fun->isNativeFun()) {
    714      return CallJSNativeConstructor(cx, fun->native(), args);
    715    }
    716 
    717    if (!InternalCallOrConstruct(cx, args, CONSTRUCT, reason)) {
    718      return false;
    719    }
    720 
    721    MOZ_ASSERT(args.CallArgs::rval().isObject());
    722    return true;
    723  }
    724 
    725  if (callee.is<ProxyObject>()) {
    726    RootedObject proxy(cx, &callee);
    727    return Proxy::construct(cx, proxy, args);
    728  }
    729 
    730  JSNative construct = callee.constructHook();
    731  MOZ_ASSERT(construct != nullptr, "IsConstructor without a construct hook?");
    732 
    733  return CallJSNativeConstructor(cx, construct, args);
    734 }
    735 
    736 // Check that |callee|, the callee in a |new| expression, is a constructor.
    737 static bool StackCheckIsConstructorCalleeNewTarget(JSContext* cx,
    738                                                   HandleValue callee,
    739                                                   HandleValue newTarget) {
    740  // Calls from the stack could have any old non-constructor callee.
    741  if (!IsConstructor(callee)) {
    742    ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, callee,
    743                     nullptr);
    744    return false;
    745  }
    746 
    747  // The new.target has already been vetted by previous calls, or is the callee.
    748  // We can just assert that it's a constructor.
    749  MOZ_ASSERT(IsConstructor(newTarget));
    750 
    751  return true;
    752 }
    753 
    754 bool js::ConstructFromStack(JSContext* cx, const CallArgs& args,
    755                            CallReason reason /* CallReason::Call */) {
    756  if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(),
    757                                              args.newTarget())) {
    758    return false;
    759  }
    760 
    761  return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args),
    762                           reason);
    763 }
    764 
    765 bool js::Construct(JSContext* cx, HandleValue fval,
    766                   const AnyConstructArgs& args, HandleValue newTarget,
    767                   MutableHandleObject objp) {
    768  MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING));
    769 
    770  // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
    771  args.CallArgs::setCallee(fval);
    772  args.CallArgs::newTarget().set(newTarget);
    773 
    774  if (!InternalConstruct(cx, args)) {
    775    return false;
    776  }
    777 
    778  MOZ_ASSERT(args.CallArgs::rval().isObject());
    779  objp.set(&args.CallArgs::rval().toObject());
    780  return true;
    781 }
    782 
    783 bool js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
    784                                           HandleValue thisv,
    785                                           const AnyConstructArgs& args,
    786                                           HandleValue newTarget,
    787                                           MutableHandleValue rval) {
    788  args.CallArgs::setCallee(fval);
    789 
    790  MOZ_ASSERT(thisv.isObject());
    791  args.CallArgs::setThis(thisv);
    792 
    793  args.CallArgs::newTarget().set(newTarget);
    794 
    795  if (!InternalConstruct(cx, args)) {
    796    return false;
    797  }
    798 
    799  rval.set(args.CallArgs::rval());
    800  return true;
    801 }
    802 
    803 bool js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
    804                    MutableHandleValue rval) {
    805  FixedInvokeArgs<0> args(cx);
    806 
    807  return Call(cx, getter, thisv, args, rval, CallReason::Getter);
    808 }
    809 
    810 bool js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
    811                    HandleValue v) {
    812  FixedInvokeArgs<1> args(cx);
    813  args[0].set(v);
    814 
    815  RootedValue ignored(cx);
    816  return Call(cx, setter, thisv, args, &ignored, CallReason::Setter);
    817 }
    818 
    819 bool js::ExecuteKernel(JSContext* cx, HandleScript script,
    820                       HandleObject envChainArg, AbstractFramePtr evalInFrame,
    821                       MutableHandleValue result) {
    822  MOZ_ASSERT_IF(script->isGlobalCode(),
    823                envChainArg->is<GlobalLexicalEnvironmentObject>() ||
    824                    !IsSyntacticEnvironment(envChainArg));
    825 #ifdef DEBUG
    826  RootedObject terminatingEnv(cx, envChainArg);
    827  while (IsSyntacticEnvironment(terminatingEnv)) {
    828    terminatingEnv = terminatingEnv->enclosingEnvironment();
    829  }
    830  MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
    831             script->hasNonSyntacticScope());
    832 #endif
    833 
    834  if (script->treatAsRunOnce()) {
    835    if (script->hasRunOnce()) {
    836      JS_ReportErrorASCII(cx,
    837                          "Trying to execute a run-once script multiple times");
    838      return false;
    839    }
    840 
    841    script->setHasRunOnce();
    842  }
    843 
    844  if (script->isEmpty()) {
    845    result.setUndefined();
    846    return true;
    847  }
    848 
    849  ExecuteState state(cx, script, envChainArg, evalInFrame, result);
    850  return RunScript(cx, state);
    851 }
    852 
    853 bool js::Execute(JSContext* cx, HandleScript script, HandleObject envChain,
    854                 MutableHandleValue rval) {
    855  /* The env chain is something we control, so we know it can't
    856     have any outer objects on it. */
    857  MOZ_ASSERT(!IsWindowProxy(envChain));
    858 
    859  if (script->isModule()) {
    860    MOZ_RELEASE_ASSERT(
    861        envChain == script->module()->environment(),
    862        "Module scripts can only be executed in the module's environment");
    863  } else {
    864    MOZ_RELEASE_ASSERT(
    865        envChain->is<GlobalLexicalEnvironmentObject>() ||
    866            script->hasNonSyntacticScope(),
    867        "Only global scripts with non-syntactic envs can be executed with "
    868        "interesting envchains");
    869  }
    870 
    871  /* Ensure the env chain is all same-compartment and terminates in a global. */
    872 #ifdef DEBUG
    873  JSObject* s = envChain;
    874  do {
    875    cx->check(s);
    876    MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
    877  } while ((s = s->enclosingEnvironment()));
    878 #endif
    879 
    880  return ExecuteKernel(cx, script, envChain, NullFramePtr() /* evalInFrame */,
    881                       rval);
    882 }
    883 
    884 /*
    885 * ES6 (4-25-16) 12.10.4 InstanceofOperator
    886 */
    887 bool js::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v,
    888                            bool* bp) {
    889  /* Step 1. is handled by caller. */
    890 
    891  /* Step 2. */
    892  RootedValue hasInstance(cx);
    893  RootedId id(cx, PropertyKey::Symbol(cx->wellKnownSymbols().hasInstance));
    894  if (!GetProperty(cx, obj, obj, id, &hasInstance)) {
    895    return false;
    896  }
    897 
    898  if (!hasInstance.isNullOrUndefined()) {
    899    if (!IsCallable(hasInstance)) {
    900      return ReportIsNotFunction(cx, hasInstance);
    901    }
    902 
    903    /* Step 3. */
    904    RootedValue rval(cx);
    905    if (!Call(cx, hasInstance, obj, v, &rval)) {
    906      return false;
    907    }
    908    *bp = ToBoolean(rval);
    909    return true;
    910  }
    911 
    912  /* Step 4. */
    913  if (!obj->isCallable()) {
    914    RootedValue val(cx, ObjectValue(*obj));
    915    return ReportIsNotFunction(cx, val);
    916  }
    917 
    918  /* Step 5. */
    919  return OrdinaryHasInstance(cx, obj, v, bp);
    920 }
    921 
    922 JSType js::TypeOfObject(JSObject* obj) {
    923  AutoUnsafeCallWithABI unsafe;
    924  if (EmulatesUndefined(obj)) {
    925    return JSTYPE_UNDEFINED;
    926  }
    927  if (obj->isCallable()) {
    928    return JSTYPE_FUNCTION;
    929  }
    930  return JSTYPE_OBJECT;
    931 }
    932 
    933 JSType js::TypeOfValue(const Value& v) {
    934  switch (v.type()) {
    935    case ValueType::Double:
    936    case ValueType::Int32:
    937      return JSTYPE_NUMBER;
    938    case ValueType::String:
    939      return JSTYPE_STRING;
    940    case ValueType::Null:
    941      return JSTYPE_OBJECT;
    942    case ValueType::Undefined:
    943      return JSTYPE_UNDEFINED;
    944    case ValueType::Object:
    945      return TypeOfObject(&v.toObject());
    946    case ValueType::Boolean:
    947      return JSTYPE_BOOLEAN;
    948    case ValueType::BigInt:
    949      return JSTYPE_BIGINT;
    950    case ValueType::Symbol:
    951      return JSTYPE_SYMBOL;
    952    case ValueType::Magic:
    953    case ValueType::PrivateGCThing:
    954      break;
    955  }
    956 
    957  ReportBadValueTypeAndCrash(v);
    958 }
    959 
    960 bool js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) {
    961  if (IsConstructor(heritage)) {
    962    return true;
    963  }
    964 
    965  if (heritage.isNull()) {
    966    return true;
    967  }
    968 
    969  if (heritage.isObject()) {
    970    ReportIsNotFunction(cx, heritage, 0, CONSTRUCT);
    971    return false;
    972  }
    973 
    974  ReportValueError(cx, JSMSG_BAD_HERITAGE, -1, heritage, nullptr,
    975                   "not an object or null");
    976  return false;
    977 }
    978 
    979 PlainObject* js::ObjectWithProtoOperation(JSContext* cx, HandleValue val) {
    980  if (!val.isObjectOrNull()) {
    981    ReportValueError(cx, JSMSG_NOT_OBJORNULL, -1, val, nullptr);
    982    return nullptr;
    983  }
    984 
    985  RootedObject proto(cx, val.toObjectOrNull());
    986  return NewPlainObjectWithProto(cx, proto);
    987 }
    988 
    989 JSObject* js::FunWithProtoOperation(JSContext* cx, HandleFunction fun,
    990                                    HandleObject parent, HandleObject proto) {
    991  return CloneFunctionReuseScript(cx, fun, parent, proto);
    992 }
    993 
    994 /*
    995 * Enter the new with environment using an object at sp[-1] and associate the
    996 * depth of the with block with sp + stackIndex.
    997 */
    998 bool js::EnterWithOperation(JSContext* cx, AbstractFramePtr frame,
    999                            HandleValue val, Handle<WithScope*> scope) {
   1000  RootedObject obj(cx);
   1001  if (val.isObject()) {
   1002    obj = &val.toObject();
   1003  } else {
   1004    obj = ToObject(cx, val);
   1005    if (!obj) {
   1006      return false;
   1007    }
   1008  }
   1009 
   1010  RootedObject envChain(cx, frame.environmentChain());
   1011  WithEnvironmentObject* withobj = WithEnvironmentObject::create(
   1012      cx, obj, envChain, scope, JS::SupportUnscopables::Yes);
   1013  if (!withobj) {
   1014    return false;
   1015  }
   1016 
   1017  frame.pushOnEnvironmentChain(*withobj);
   1018  return true;
   1019 }
   1020 
   1021 static void PopEnvironment(JSContext* cx, EnvironmentIter& ei) {
   1022  switch (ei.scope().kind()) {
   1023    case ScopeKind::Lexical:
   1024    case ScopeKind::SimpleCatch:
   1025    case ScopeKind::Catch:
   1026    case ScopeKind::NamedLambda:
   1027    case ScopeKind::StrictNamedLambda:
   1028    case ScopeKind::FunctionLexical:
   1029    case ScopeKind::ClassBody:
   1030      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   1031        DebugEnvironments::onPopLexical(cx, ei);
   1032      }
   1033      if (ei.scope().hasEnvironment()) {
   1034        ei.initialFrame()
   1035            .popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
   1036      }
   1037      break;
   1038    case ScopeKind::With:
   1039      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   1040        DebugEnvironments::onPopWith(ei.initialFrame());
   1041      }
   1042      ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
   1043      break;
   1044    case ScopeKind::Function:
   1045      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   1046        DebugEnvironments::onPopCall(cx, ei.initialFrame());
   1047      }
   1048      if (ei.scope().hasEnvironment()) {
   1049        ei.initialFrame().popOffEnvironmentChain<CallObject>();
   1050      }
   1051      break;
   1052    case ScopeKind::FunctionBodyVar:
   1053    case ScopeKind::StrictEval:
   1054      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   1055        DebugEnvironments::onPopVar(cx, ei);
   1056      }
   1057      if (ei.scope().hasEnvironment()) {
   1058        ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
   1059      }
   1060      break;
   1061    case ScopeKind::Module:
   1062      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   1063        DebugEnvironments::onPopModule(cx, ei);
   1064      }
   1065      break;
   1066    case ScopeKind::Eval:
   1067    case ScopeKind::Global:
   1068    case ScopeKind::NonSyntactic:
   1069      break;
   1070    case ScopeKind::WasmInstance:
   1071    case ScopeKind::WasmFunction:
   1072      MOZ_CRASH("wasm is not interpreted");
   1073      break;
   1074  }
   1075 }
   1076 
   1077 // Unwind environment chain and iterator to match the env corresponding to
   1078 // the given bytecode position.
   1079 void js::UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc) {
   1080  if (!ei.withinInitialFrame()) {
   1081    return;
   1082  }
   1083 
   1084  Rooted<Scope*> scope(cx, ei.initialFrame().script()->innermostScope(pc));
   1085 
   1086 #ifdef DEBUG
   1087  // A frame's environment chain cannot be unwound to anything enclosing the
   1088  // body scope of a script.  This includes the parameter defaults
   1089  // environment and the decl env object. These environments, once pushed
   1090  // onto the environment chain, are expected to be there for the duration
   1091  // of the frame.
   1092  //
   1093  // Attempting to unwind to the parameter defaults code in a script is a
   1094  // bug; that section of code has no try-catch blocks.
   1095  JSScript* script = ei.initialFrame().script();
   1096  for (uint32_t i = 0; i < script->bodyScopeIndex(); i++) {
   1097    MOZ_ASSERT(scope != script->getScope(GCThingIndex(i)));
   1098  }
   1099 #endif
   1100 
   1101  for (; ei.maybeScope() != scope; ei++) {
   1102    PopEnvironment(cx, ei);
   1103  }
   1104 }
   1105 
   1106 // Unwind all environments. This is needed because block scopes may cover the
   1107 // first bytecode at a script's main(). e.g.,
   1108 //
   1109 //     function f() { { let i = 0; } }
   1110 //
   1111 // will have no pc location distinguishing the first block scope from the
   1112 // outermost function scope.
   1113 void js::UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei) {
   1114  for (; ei.withinInitialFrame(); ei++) {
   1115    PopEnvironment(cx, ei);
   1116  }
   1117 }
   1118 
   1119 // Compute the pc needed to unwind the environment to the beginning of a try
   1120 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
   1121 // first opcode of an inner scope, with the same problem as above. e.g.,
   1122 //
   1123 // try { { let x; } }
   1124 //
   1125 // will have no pc location distinguishing the try block scope from the inner
   1126 // let block scope.
   1127 jsbytecode* js::UnwindEnvironmentToTryPc(JSScript* script, const TryNote* tn) {
   1128  jsbytecode* pc = script->offsetToPC(tn->start);
   1129  if (tn->kind() == TryNoteKind::Catch || tn->kind() == TryNoteKind::Finally) {
   1130    pc -= JSOpLength_Try;
   1131    MOZ_ASSERT(JSOp(*pc) == JSOp::Try);
   1132  } else if (tn->kind() == TryNoteKind::Destructuring) {
   1133    pc -= JSOpLength_TryDestructuring;
   1134    MOZ_ASSERT(JSOp(*pc) == JSOp::TryDestructuring);
   1135  }
   1136  return pc;
   1137 }
   1138 
   1139 static void SettleOnTryNote(JSContext* cx, const TryNote* tn,
   1140                            EnvironmentIter& ei, InterpreterRegs& regs) {
   1141  // Unwind the environment to the beginning of the JSOp::Try.
   1142  UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
   1143 
   1144  // Set pc to the first bytecode after the the try note to point
   1145  // to the beginning of catch or finally.
   1146  regs.pc = regs.fp()->script()->offsetToPC(tn->start + tn->length);
   1147  regs.sp = regs.spForStackDepth(tn->stackDepth);
   1148 }
   1149 
   1150 class InterpreterTryNoteFilter {
   1151  const InterpreterRegs& regs_;
   1152 
   1153 public:
   1154  explicit InterpreterTryNoteFilter(const InterpreterRegs& regs)
   1155      : regs_(regs) {}
   1156  bool operator()(const TryNote* note) {
   1157    return note->stackDepth <= regs_.stackDepth();
   1158  }
   1159 };
   1160 
   1161 class TryNoteIterInterpreter : public TryNoteIter<InterpreterTryNoteFilter> {
   1162 public:
   1163  TryNoteIterInterpreter(JSContext* cx, const InterpreterRegs& regs)
   1164      : TryNoteIter(cx, regs.fp()->script(), regs.pc,
   1165                    InterpreterTryNoteFilter(regs)) {}
   1166 };
   1167 
   1168 static void UnwindIteratorsForUncatchableException(
   1169    JSContext* cx, const InterpreterRegs& regs) {
   1170  // c.f. the regular (catchable) TryNoteIterInterpreter loop in
   1171  // ProcessTryNotes.
   1172  for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
   1173    const TryNote* tn = *tni;
   1174    switch (tn->kind()) {
   1175      case TryNoteKind::ForIn: {
   1176        Value* sp = regs.spForStackDepth(tn->stackDepth);
   1177        UnwindIteratorForUncatchableException(&sp[-1].toObject());
   1178        break;
   1179      }
   1180      default:
   1181        break;
   1182    }
   1183  }
   1184 }
   1185 
   1186 enum HandleErrorContinuation {
   1187  SuccessfulReturnContinuation,
   1188  ErrorReturnContinuation,
   1189  CatchContinuation,
   1190  FinallyContinuation
   1191 };
   1192 
   1193 static HandleErrorContinuation ProcessTryNotes(JSContext* cx,
   1194                                               EnvironmentIter& ei,
   1195                                               InterpreterRegs& regs) {
   1196  for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
   1197    const TryNote* tn = *tni;
   1198 
   1199    switch (tn->kind()) {
   1200      case TryNoteKind::Catch:
   1201        /* Catch cannot intercept the closing of a generator. */
   1202        if (cx->isClosingGenerator()) {
   1203          break;
   1204        }
   1205 
   1206        SettleOnTryNote(cx, tn, ei, regs);
   1207        return CatchContinuation;
   1208 
   1209      case TryNoteKind::Finally:
   1210        SettleOnTryNote(cx, tn, ei, regs);
   1211        return FinallyContinuation;
   1212 
   1213      case TryNoteKind::ForIn: {
   1214        /* This is similar to JSOp::EndIter in the interpreter loop. */
   1215        MOZ_ASSERT(tn->stackDepth <= regs.stackDepth());
   1216        Value* sp = regs.spForStackDepth(tn->stackDepth);
   1217        JSObject* obj = &sp[-1].toObject();
   1218        CloseIterator(obj);
   1219        break;
   1220      }
   1221 
   1222      case TryNoteKind::Destructuring: {
   1223        // Whether the destructuring iterator is done is at the top of the
   1224        // stack. The iterator object is second from the top.
   1225        MOZ_ASSERT(tn->stackDepth > 1);
   1226        Value* sp = regs.spForStackDepth(tn->stackDepth);
   1227        RootedValue doneValue(cx, sp[-1]);
   1228        MOZ_RELEASE_ASSERT(!doneValue.isMagic());
   1229        bool done = ToBoolean(doneValue);
   1230        if (!done) {
   1231          RootedObject iterObject(cx, &sp[-2].toObject());
   1232          if (!IteratorCloseForException(cx, iterObject)) {
   1233            SettleOnTryNote(cx, tn, ei, regs);
   1234            return ErrorReturnContinuation;
   1235          }
   1236        }
   1237        break;
   1238      }
   1239 
   1240      case TryNoteKind::ForOf:
   1241      case TryNoteKind::Loop:
   1242        break;
   1243 
   1244      // TryNoteKind::ForOfIterClose is handled internally by the try note
   1245      // iterator.
   1246      default:
   1247        MOZ_CRASH("Invalid try note");
   1248    }
   1249  }
   1250 
   1251  return SuccessfulReturnContinuation;
   1252 }
   1253 
   1254 bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
   1255                                      bool ok) {
   1256  /*
   1257   * Propagate the exception or error to the caller unless the exception
   1258   * is an asynchronous return from a generator.
   1259   */
   1260  if (cx->isClosingGenerator()) {
   1261    cx->clearPendingException();
   1262    ok = true;
   1263    auto* genObj = GetGeneratorObjectForFrame(cx, frame);
   1264    genObj->setClosed(cx);
   1265  }
   1266  return ok;
   1267 }
   1268 
   1269 static HandleErrorContinuation HandleError(JSContext* cx,
   1270                                           InterpreterRegs& regs) {
   1271  MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
   1272  MOZ_ASSERT(cx->realm() == regs.fp()->script()->realm());
   1273 
   1274  if (regs.fp()->script()->hasScriptCounts()) {
   1275    PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
   1276    // If we failed to allocate, then skip the increment and continue to
   1277    // handle the exception.
   1278    if (counts) {
   1279      counts->numExec()++;
   1280    }
   1281  }
   1282 
   1283  EnvironmentIter ei(cx, regs.fp(), regs.pc);
   1284  bool ok = false;
   1285 
   1286 again:
   1287  if (cx->isExceptionPending()) {
   1288    /* Call debugger throw hooks. */
   1289    if (!cx->isClosingGenerator()) {
   1290      if (!DebugAPI::onExceptionUnwind(cx, regs.fp())) {
   1291        if (!cx->isExceptionPending()) {
   1292          goto again;
   1293        }
   1294      }
   1295      // Ensure that the debugger hasn't returned 'true' while clearing the
   1296      // exception state.
   1297      MOZ_ASSERT(cx->isExceptionPending());
   1298    }
   1299 
   1300    HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
   1301    switch (res) {
   1302      case SuccessfulReturnContinuation:
   1303        break;
   1304      case ErrorReturnContinuation:
   1305        goto again;
   1306      case CatchContinuation:
   1307      case FinallyContinuation:
   1308        // No need to increment the PCCounts number of execution here, as
   1309        // the interpreter increments any PCCounts if present.
   1310        MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
   1311                      regs.fp()->script()->maybeGetPCCounts(regs.pc));
   1312        return res;
   1313    }
   1314 
   1315    ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
   1316  } else {
   1317    UnwindIteratorsForUncatchableException(cx, regs);
   1318 
   1319    // We may be propagating a forced return from a debugger hook function.
   1320    if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
   1321      cx->clearPropagatingForcedReturn();
   1322      ok = true;
   1323    }
   1324  }
   1325 
   1326  ok = DebugAPI::onLeaveFrame(cx, regs.fp(), regs.pc, ok);
   1327 
   1328  // After this point, we will pop the frame regardless. Settle the frame on
   1329  // the end of the script.
   1330  regs.setToEndOfScript();
   1331 
   1332  return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
   1333 }
   1334 
   1335 #define REGS (activation.regs())
   1336 #define PUSH_COPY(v)                 \
   1337  do {                               \
   1338    *REGS.sp++ = (v);                \
   1339    cx->debugOnlyCheck(REGS.sp[-1]); \
   1340  } while (0)
   1341 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
   1342 #define PUSH_NULL() REGS.sp++->setNull()
   1343 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
   1344 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
   1345 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
   1346 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
   1347 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
   1348 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
   1349 #define PUSH_STRING(s)               \
   1350  do {                               \
   1351    REGS.sp++->setString(s);         \
   1352    cx->debugOnlyCheck(REGS.sp[-1]); \
   1353  } while (0)
   1354 #define PUSH_OBJECT(obj)             \
   1355  do {                               \
   1356    REGS.sp++->setObject(obj);       \
   1357    cx->debugOnlyCheck(REGS.sp[-1]); \
   1358  } while (0)
   1359 #define PUSH_OBJECT_OR_NULL(obj)     \
   1360  do {                               \
   1361    REGS.sp++->setObjectOrNull(obj); \
   1362    cx->debugOnlyCheck(REGS.sp[-1]); \
   1363  } while (0)
   1364 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
   1365 #define POP_COPY_TO(v) (v) = *--REGS.sp
   1366 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
   1367 
   1368 /*
   1369 * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
   1370 * remain distinct for the decompiler.
   1371 */
   1372 static_assert(JSOpLength_SetName == JSOpLength_SetProp);
   1373 
   1374 /* See TRY_BRANCH_AFTER_COND. */
   1375 static_assert(JSOpLength_JumpIfTrue == JSOpLength_JumpIfFalse);
   1376 static_assert(uint8_t(JSOp::JumpIfTrue) == uint8_t(JSOp::JumpIfFalse) + 1);
   1377 
   1378 /*
   1379 * Compute the implicit |this| value used by a call expression with an
   1380 * unqualified name reference. The environment the binding was found on is
   1381 * passed as argument, env.
   1382 *
   1383 * The implicit |this| is |undefined| for all environment types except
   1384 * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
   1385 * if the embedding uses a non-syntactic WithEnvironmentObject.
   1386 *
   1387 * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
   1388 * extensible LexicalEnviornmentObject, but it will not be considered as an
   1389 * implicit |this|. This is for compatibility with the Gecko subscript loader.
   1390 */
   1391 static inline Value ComputeImplicitThis(JSObject* env) {
   1392  // Fast-path for GlobalObject
   1393  if (env->is<GlobalObject>()) {
   1394    return UndefinedValue();
   1395  }
   1396 
   1397  // WithEnvironmentObjects have an actual implicit |this|
   1398  if (env->is<WithEnvironmentObject>()) {
   1399    auto* thisObject = env->as<WithEnvironmentObject>().withThis();
   1400    return ObjectValue(*thisObject);
   1401  }
   1402 
   1403  // Debugger environments need special casing, as despite being
   1404  // non-syntactic, they wrap syntactic environments and should not be
   1405  // treated like other embedding-specific non-syntactic environments.
   1406  if (env->is<DebugEnvironmentProxy>()) {
   1407    return ComputeImplicitThis(&env->as<DebugEnvironmentProxy>().environment());
   1408  }
   1409 
   1410  MOZ_ASSERT(env->is<EnvironmentObject>());
   1411  return UndefinedValue();
   1412 }
   1413 
   1414 // BigInt proposal 3.2.4 Abstract Relational Comparison
   1415 // Returns Nothing when at least one operand is a NaN, or when
   1416 // ToNumeric or StringToBigInt can't interpret a string as a numeric
   1417 // value. (These cases correspond to a NaN result in the spec.)
   1418 // Otherwise, return a boolean to indicate whether lhs is less than
   1419 // rhs. The operands must be primitives; the caller is responsible for
   1420 // evaluating them in the correct order.
   1421 static MOZ_ALWAYS_INLINE bool LessThanImpl(JSContext* cx,
   1422                                           MutableHandleValue lhs,
   1423                                           MutableHandleValue rhs,
   1424                                           mozilla::Maybe<bool>& res) {
   1425  // Steps 1 and 2 are performed by the caller.
   1426 
   1427  // Step 3.
   1428  if (lhs.isString() && rhs.isString()) {
   1429    JSString* l = lhs.toString();
   1430    JSString* r = rhs.toString();
   1431    int32_t result;
   1432    if (!CompareStrings(cx, l, r, &result)) {
   1433      return false;
   1434    }
   1435    res = mozilla::Some(result < 0);
   1436    return true;
   1437  }
   1438 
   1439  // Step 4a.
   1440  if (lhs.isBigInt() && rhs.isString()) {
   1441    return BigInt::lessThan(cx, lhs, rhs, res);
   1442  }
   1443 
   1444  // Step 4b.
   1445  if (lhs.isString() && rhs.isBigInt()) {
   1446    return BigInt::lessThan(cx, lhs, rhs, res);
   1447  }
   1448 
   1449  // Steps 4c and 4d.
   1450  if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
   1451    return false;
   1452  }
   1453 
   1454  // Steps 4e-j.
   1455  if (lhs.isBigInt() || rhs.isBigInt()) {
   1456    return BigInt::lessThan(cx, lhs, rhs, res);
   1457  }
   1458 
   1459  // Step 4e for Number operands.
   1460  MOZ_ASSERT(lhs.isNumber() && rhs.isNumber());
   1461  double lhsNum = lhs.toNumber();
   1462  double rhsNum = rhs.toNumber();
   1463 
   1464  if (std::isnan(lhsNum) || std::isnan(rhsNum)) {
   1465    res = mozilla::Maybe<bool>(mozilla::Nothing());
   1466    return true;
   1467  }
   1468 
   1469  res = mozilla::Some(lhsNum < rhsNum);
   1470  return true;
   1471 }
   1472 
   1473 static MOZ_ALWAYS_INLINE bool LessThanOperation(JSContext* cx,
   1474                                                MutableHandleValue lhs,
   1475                                                MutableHandleValue rhs,
   1476                                                bool* res) {
   1477  if (lhs.isInt32() && rhs.isInt32()) {
   1478    *res = lhs.toInt32() < rhs.toInt32();
   1479    return true;
   1480  }
   1481 
   1482  if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
   1483    return false;
   1484  }
   1485 
   1486  if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
   1487    return false;
   1488  }
   1489 
   1490  mozilla::Maybe<bool> tmpResult;
   1491  if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
   1492    return false;
   1493  }
   1494  *res = tmpResult.valueOr(false);
   1495  return true;
   1496 }
   1497 
   1498 static MOZ_ALWAYS_INLINE bool LessThanOrEqualOperation(JSContext* cx,
   1499                                                       MutableHandleValue lhs,
   1500                                                       MutableHandleValue rhs,
   1501                                                       bool* res) {
   1502  if (lhs.isInt32() && rhs.isInt32()) {
   1503    *res = lhs.toInt32() <= rhs.toInt32();
   1504    return true;
   1505  }
   1506 
   1507  if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
   1508    return false;
   1509  }
   1510 
   1511  if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
   1512    return false;
   1513  }
   1514 
   1515  mozilla::Maybe<bool> tmpResult;
   1516  if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
   1517    return false;
   1518  }
   1519  *res = !tmpResult.valueOr(true);
   1520  return true;
   1521 }
   1522 
   1523 static MOZ_ALWAYS_INLINE bool GreaterThanOperation(JSContext* cx,
   1524                                                   MutableHandleValue lhs,
   1525                                                   MutableHandleValue rhs,
   1526                                                   bool* res) {
   1527  if (lhs.isInt32() && rhs.isInt32()) {
   1528    *res = lhs.toInt32() > rhs.toInt32();
   1529    return true;
   1530  }
   1531 
   1532  if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
   1533    return false;
   1534  }
   1535 
   1536  if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
   1537    return false;
   1538  }
   1539 
   1540  mozilla::Maybe<bool> tmpResult;
   1541  if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
   1542    return false;
   1543  }
   1544  *res = tmpResult.valueOr(false);
   1545  return true;
   1546 }
   1547 
   1548 static MOZ_ALWAYS_INLINE bool GreaterThanOrEqualOperation(
   1549    JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
   1550  if (lhs.isInt32() && rhs.isInt32()) {
   1551    *res = lhs.toInt32() >= rhs.toInt32();
   1552    return true;
   1553  }
   1554 
   1555  if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
   1556    return false;
   1557  }
   1558 
   1559  if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
   1560    return false;
   1561  }
   1562 
   1563  mozilla::Maybe<bool> tmpResult;
   1564  if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
   1565    return false;
   1566  }
   1567  *res = !tmpResult.valueOr(true);
   1568  return true;
   1569 }
   1570 
   1571 static MOZ_ALWAYS_INLINE bool SetObjectElementOperation(
   1572    JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
   1573    HandleValue receiver, bool strict) {
   1574  ObjectOpResult result;
   1575  return SetProperty(cx, obj, id, value, receiver, result) &&
   1576         result.checkStrictModeError(cx, obj, id, strict);
   1577 }
   1578 
   1579 void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
   1580                                HandleValue rref) {
   1581  auto uniqueCharsFromString = [](JSContext* cx,
   1582                                  HandleValue ref) -> UniqueChars {
   1583    static const size_t MaxStringLength = 16;
   1584    RootedString str(cx, ref.toString());
   1585    if (str->length() > MaxStringLength) {
   1586      JSStringBuilder buf(cx);
   1587      if (!buf.appendSubstring(str, 0, MaxStringLength)) {
   1588        return nullptr;
   1589      }
   1590      if (!buf.append("...")) {
   1591        return nullptr;
   1592      }
   1593      str = buf.finishString();
   1594      if (!str) {
   1595        return nullptr;
   1596      }
   1597    }
   1598    return QuoteString(cx, str, '"');
   1599  };
   1600 
   1601  if (lref.isString() && rref.isString()) {
   1602    UniqueChars lbytes = uniqueCharsFromString(cx, lref);
   1603    if (!lbytes) {
   1604      return;
   1605    }
   1606    UniqueChars rbytes = uniqueCharsFromString(cx, rref);
   1607    if (!rbytes) {
   1608      return;
   1609    }
   1610    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_IN_STRING,
   1611                             lbytes.get(), rbytes.get());
   1612    return;
   1613  }
   1614 
   1615  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_IN_NOT_OBJECT,
   1616                            InformalValueTypeName(rref));
   1617 }
   1618 
   1619 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   1620 // Explicit Resource Management Proposal
   1621 // 7.5.6 GetDisposeMethod ( V, hint )
   1622 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-getdisposemethod
   1623 // Steps 1.b.ii.1.a-f
   1624 bool js::SyncDisposalClosure(JSContext* cx, unsigned argc, JS::Value* vp) {
   1625  JS::CallArgs args = CallArgsFromVp(argc, vp);
   1626 
   1627  JS::Rooted<JSFunction*> callee(cx, &args.callee().as<JSFunction>());
   1628 
   1629  JS::Rooted<JS::Value> method(
   1630      cx, callee->getExtendedSlot(uint8_t(SyncDisposalClosureSlots::Method)));
   1631 
   1632  // Step 1.b.ii.1.a. Let O be the this value.
   1633  JS::Handle<JS::Value> O = args.thisv();
   1634 
   1635  // Step 1.b.ii.1.b. Let promiseCapability be !
   1636  // NewPromiseCapability(%Promise%).
   1637  JSObject* createPromise = JS::NewPromiseObject(cx, nullptr);
   1638  if (!createPromise) {
   1639    return false;
   1640  }
   1641  JS::Rooted<PromiseObject*> promiseCapability(
   1642      cx, &createPromise->as<PromiseObject>());
   1643 
   1644  // Step 1.b.ii.1.c. Let result be Completion(Call(method, O)).
   1645  JS::Rooted<JS::Value> rval(cx);
   1646  bool result = Call(cx, method, O, &rval);
   1647 
   1648  // Step 1.b.ii.1.d. IfAbruptRejectPromise(result, promiseCapability).
   1649  if (!result) {
   1650    return AbruptRejectPromise(cx, args, promiseCapability, nullptr);
   1651  }
   1652 
   1653  // Step 1.b.ii.1.e. Perform ? Call(promiseCapability.[[Resolve]], undefined, «
   1654  // undefined »).
   1655  if (!JS::ResolvePromise(cx, promiseCapability, JS::UndefinedHandleValue)) {
   1656    return false;
   1657  }
   1658 
   1659  // Step 1.b.ii.1.f. Return promiseCapability.[[Promise]].
   1660  args.rval().set(JS::ObjectValue(*promiseCapability));
   1661  return true;
   1662 }
   1663 
   1664 // Explicit Resource Management Proposal
   1665 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposeresources
   1666 // Steps 3.e.iii.1.c-e.
   1667 ErrorObject* js::CreateSuppressedError(JSContext* cx,
   1668                                       JS::Handle<JS::Value> error,
   1669                                       JS::Handle<JS::Value> suppressed) {
   1670  // Step 3.e.iii.1.c. Let error be a newly created SuppressedError object.
   1671  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
   1672                           JSMSG_ERROR_WAS_SUPPRESSED);
   1673 
   1674  if (cx->isThrowingOutOfMemory()) {
   1675    return nullptr;
   1676  }
   1677 
   1678  JS::Rooted<JS::Value> thrownSuppressed(cx);
   1679 
   1680  if (!cx->getPendingException(&thrownSuppressed)) {
   1681    return nullptr;
   1682  }
   1683 
   1684  if (!thrownSuppressed.isObject() ||
   1685      !thrownSuppressed.toObject().is<ErrorObject>()) {
   1686    return nullptr;
   1687  }
   1688 
   1689  cx->clearPendingException();
   1690 
   1691  JS::Rooted<ErrorObject*> errorObj(
   1692      cx, &thrownSuppressed.toObject().as<ErrorObject>());
   1693 
   1694  // Step 3.e.iii.1.d. Perform
   1695  // CreateNonEnumerableDataPropertyOrThrow(error, "error", result).
   1696  if (!NativeDefineDataProperty(cx, errorObj, cx->names().error, error, 0)) {
   1697    return nullptr;
   1698  }
   1699 
   1700  // Step 3.e.iii.1.e. Perform
   1701  // CreateNonEnumerableDataPropertyOrThrow(error, "suppressed",
   1702  // suppressed).
   1703  if (!NativeDefineDataProperty(cx, errorObj, cx->names().suppressed,
   1704                                suppressed, 0)) {
   1705    return nullptr;
   1706  }
   1707 
   1708  // TODO: Improve the capturing of stack and error messages (Bug 1906150)
   1709 
   1710  return errorObj;
   1711 }
   1712 
   1713 // Explicit Resource Management Proposal
   1714 // 7.5.4 AddDisposableResource ( disposeCapability, V, hint [ , method ] )
   1715 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-adddisposableresource
   1716 // Step 3
   1717 bool js::AddDisposableResourceToCapability(JSContext* cx,
   1718                                           JS::Handle<JSObject*> env,
   1719                                           JS::Handle<JS::Value> val,
   1720                                           JS::Handle<JS::Value> method,
   1721                                           bool needsClosure, UsingHint hint) {
   1722  JS::Rooted<ArrayObject*> disposeCapability(
   1723      cx,
   1724      env->as<DisposableEnvironmentObject>().getOrCreateDisposeCapability(cx));
   1725  if (!disposeCapability) {
   1726    return false;
   1727  }
   1728 
   1729  JS::Rooted<JS::Value> disposeMethod(cx);
   1730 
   1731  if (needsClosure) {
   1732    JS::Handle<PropertyName*> funName = cx->names().empty_;
   1733    JSFunction* asyncWrapper =
   1734        NewNativeFunction(cx, SyncDisposalClosure, 0, funName,
   1735                          gc::AllocKind::FUNCTION_EXTENDED, GenericObject);
   1736 
   1737    if (!asyncWrapper) {
   1738      return false;
   1739    }
   1740    asyncWrapper->initExtendedSlot(uint8_t(SyncDisposalClosureSlots::Method),
   1741                                   method);
   1742    disposeMethod.set(JS::ObjectValue(*asyncWrapper));
   1743  } else {
   1744    disposeMethod.set(method);
   1745  }
   1746 
   1747  DisposableRecordObject* disposableRecord =
   1748      DisposableRecordObject::create(cx, val, disposeMethod, hint);
   1749  if (!disposableRecord) {
   1750    return false;
   1751  }
   1752 
   1753  return NewbornArrayPush(cx, disposeCapability,
   1754                          JS::ObjectValue(*disposableRecord));
   1755 }
   1756 #endif
   1757 
   1758 bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx,
   1759                                                           RunState& state) {
   1760 /*
   1761 * Define macros for an interpreter loop. Opcode dispatch is done by
   1762 * indirect goto (aka a threaded interpreter), which is technically
   1763 * non-standard but is supported by all of our supported compilers.
   1764 */
   1765 #define INTERPRETER_LOOP()
   1766 #define CASE(OP) label_##OP:
   1767 #define DEFAULT() \
   1768  label_default:
   1769 #define DISPATCH_TO(OP) goto* addresses[(OP)]
   1770 
   1771 #define LABEL(X) (&&label_##X)
   1772 
   1773  // Use addresses instead of offsets to optimize for runtime speed over
   1774  // load-time relocation overhead.
   1775  static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
   1776 #define OPCODE_LABEL(op, ...) LABEL(op),
   1777      FOR_EACH_OPCODE(OPCODE_LABEL)
   1778 #undef OPCODE_LABEL
   1779 #define TRAILING_LABEL(v)                                                    \
   1780  ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
   1781                                       : LABEL(default)),
   1782          FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
   1783 #undef TRAILING_LABEL
   1784  };
   1785 
   1786  /*
   1787   * Increment REGS.pc by N, load the opcode at that position,
   1788   * and jump to the code to execute it.
   1789   *
   1790   * When Debugger puts a script in single-step mode, all js::Interpret
   1791   * invocations that might be presently running that script must have
   1792   * interrupts enabled. It's not practical to simply check
   1793   * script->stepModeEnabled() at each point some callee could have changed
   1794   * it, because there are so many places js::Interpret could possibly cause
   1795   * JavaScript to run: each place an object might be coerced to a primitive
   1796   * or a number, for example. So instead, we expose a simple mechanism to
   1797   * let Debugger tweak the affected js::Interpret frames when an onStep
   1798   * handler is added: calling activation.enableInterruptsUnconditionally()
   1799   * will enable interrupts, and activation.opMask() is or'd with the opcode
   1800   * to implement a simple alternate dispatch.
   1801   */
   1802 #define ADVANCE_AND_DISPATCH(N)                  \
   1803  JS_BEGIN_MACRO                                 \
   1804    REGS.pc += (N);                              \
   1805    SANITY_CHECKS();                             \
   1806    DISPATCH_TO(*REGS.pc | activation.opMask()); \
   1807  JS_END_MACRO
   1808 
   1809  /*
   1810   * Shorthand for the common sequence at the end of a fixed-size opcode.
   1811   */
   1812 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
   1813 
   1814  /*
   1815   * Prepare to call a user-supplied branch handler, and abort the script
   1816   * if it returns false.
   1817   */
   1818 #define CHECK_BRANCH()                      \
   1819  JS_BEGIN_MACRO                            \
   1820    if (!CheckForInterrupt(cx)) goto error; \
   1821  JS_END_MACRO
   1822 
   1823  /*
   1824   * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
   1825   * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
   1826   * is the backedge of a loop.
   1827   */
   1828 #define BRANCH(n)                  \
   1829  JS_BEGIN_MACRO                   \
   1830    int32_t nlen = (n);            \
   1831    if (nlen <= 0) CHECK_BRANCH(); \
   1832    ADVANCE_AND_DISPATCH(nlen);    \
   1833  JS_END_MACRO
   1834 
   1835  /*
   1836   * Initialize code coverage vectors.
   1837   */
   1838 #define INIT_COVERAGE()                                \
   1839  JS_BEGIN_MACRO                                       \
   1840    if (!script->hasScriptCounts()) {                  \
   1841      if (cx->realm()->collectCoverageForDebug()) {    \
   1842        if (!script->initScriptCounts(cx)) goto error; \
   1843      }                                                \
   1844    }                                                  \
   1845  JS_END_MACRO
   1846 
   1847  /*
   1848   * Increment the code coverage counter associated with the given pc.
   1849   */
   1850 #define COUNT_COVERAGE_PC(PC)                          \
   1851  JS_BEGIN_MACRO                                       \
   1852    if (script->hasScriptCounts()) {                   \
   1853      PCCounts* counts = script->maybeGetPCCounts(PC); \
   1854      MOZ_ASSERT(counts);                              \
   1855      counts->numExec()++;                             \
   1856    }                                                  \
   1857  JS_END_MACRO
   1858 
   1859 #define COUNT_COVERAGE_MAIN()                                        \
   1860  JS_BEGIN_MACRO                                                     \
   1861    jsbytecode* main = script->main();                               \
   1862    if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
   1863  JS_END_MACRO
   1864 
   1865 #define COUNT_COVERAGE()                              \
   1866  JS_BEGIN_MACRO                                      \
   1867    MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
   1868    COUNT_COVERAGE_PC(REGS.pc);                       \
   1869  JS_END_MACRO
   1870 
   1871 #define SET_SCRIPT(s)                                    \
   1872  JS_BEGIN_MACRO                                         \
   1873    script = (s);                                        \
   1874    MOZ_ASSERT(cx->realm() == script->realm());          \
   1875    if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
   1876        script->hasScriptCounts())                       \
   1877      activation.enableInterruptsUnconditionally();      \
   1878  JS_END_MACRO
   1879 
   1880 #define SANITY_CHECKS()              \
   1881  JS_BEGIN_MACRO                     \
   1882    js::gc::MaybeVerifyBarriers(cx); \
   1883  JS_END_MACRO
   1884 
   1885 // Verify that an uninitialized lexical is followed by a correct check op.
   1886 #ifdef DEBUG
   1887 #  define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val)                        \
   1888    JS_BEGIN_MACRO                                                         \
   1889      if (IsUninitializedLexical(val)) {                                   \
   1890        JSOp next = JSOp(*GetNextPc(REGS.pc));                             \
   1891        MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
   1892                   next == JSOp::CheckThisReinit ||                        \
   1893                   next == JSOp::CheckAliasedLexical);                     \
   1894      }                                                                    \
   1895    JS_END_MACRO
   1896 #else
   1897 #  define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
   1898    JS_BEGIN_MACRO                                  \
   1899    /* nothing */                                   \
   1900    JS_END_MACRO
   1901 #endif
   1902 
   1903  gc::MaybeVerifyBarriers(cx, true);
   1904 
   1905  InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
   1906  if (!entryFrame) {
   1907    return false;
   1908  }
   1909 
   1910  InterpreterActivation activation(state, cx, entryFrame);
   1911 
   1912  /* The script is used frequently, so keep a local copy. */
   1913  RootedScript script(cx);
   1914  SET_SCRIPT(REGS.fp()->script());
   1915 
   1916  /*
   1917   * Pool of rooters for use in this interpreter frame. References to these
   1918   * are used for local variables within interpreter cases. This avoids
   1919   * creating new rooters each time an interpreter case is entered, and also
   1920   * correctness pitfalls due to incorrect compilation of destructor calls
   1921   * around computed gotos.
   1922   */
   1923  RootedTuple<Value, Value, JSObject*, JSObject*, JSFunction*, JSAtom*,
   1924              PropertyName*, PropertyKey, JSScript*, Scope*>
   1925      roots(cx);
   1926  RootedField<Value, 0> rootValue0(roots);
   1927  RootedField<Value, 1> rootValue1(roots);
   1928  RootedField<JSObject*, 2> rootObject0(roots);
   1929  RootedField<JSObject*, 3> rootObject1(roots);
   1930  RootedField<JSFunction*> rootFunction0(roots);
   1931  RootedField<JSAtom*> rootAtom0(roots);
   1932  RootedField<PropertyName*> rootName0(roots);
   1933  RootedField<PropertyKey> rootId0(roots);
   1934  RootedField<JSScript*> rootScript0(roots);
   1935  RootedField<Scope*> rootScope0(roots);
   1936 
   1937  DebugOnly<uint32_t> blockDepth;
   1938 
   1939  /* State communicated between non-local jumps: */
   1940  bool interpReturnOK;
   1941  bool frameHalfInitialized;
   1942 
   1943  if (!activation.entryFrame()->prologue(cx)) {
   1944    goto prologue_error;
   1945  }
   1946 
   1947  if (!DebugAPI::onEnterFrame(cx, activation.entryFrame())) {
   1948    goto error;
   1949  }
   1950 
   1951  // Increment the coverage for the main entry point.
   1952  INIT_COVERAGE();
   1953  COUNT_COVERAGE_MAIN();
   1954 
   1955  // Enter the interpreter loop starting at the current pc.
   1956  ADVANCE_AND_DISPATCH(0);
   1957 
   1958  INTERPRETER_LOOP() {
   1959    CASE(EnableInterruptsPseudoOpcode) {
   1960      bool moreInterrupts = false;
   1961      jsbytecode op = *REGS.pc;
   1962 
   1963      if (!script->hasScriptCounts() &&
   1964          cx->realm()->collectCoverageForDebug()) {
   1965        if (!script->initScriptCounts(cx)) {
   1966          goto error;
   1967        }
   1968      }
   1969 
   1970      if (script->isDebuggee()) {
   1971        if (DebugAPI::stepModeEnabled(script)) {
   1972          if (!DebugAPI::onSingleStep(cx)) {
   1973            goto error;
   1974          }
   1975          moreInterrupts = true;
   1976        }
   1977 
   1978        if (DebugAPI::hasAnyBreakpointsOrStepMode(script)) {
   1979          moreInterrupts = true;
   1980        }
   1981 
   1982        if (DebugAPI::hasBreakpointsAt(script, REGS.pc)) {
   1983          if (!DebugAPI::onTrap(cx)) {
   1984            goto error;
   1985          }
   1986        }
   1987      }
   1988 
   1989      MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
   1990      if (!moreInterrupts) {
   1991        activation.clearInterruptsMask();
   1992      }
   1993 
   1994      /* Commence executing the actual opcode. */
   1995      SANITY_CHECKS();
   1996      DISPATCH_TO(op);
   1997    }
   1998 
   1999    /* Various 1-byte no-ops. */
   2000    CASE(Nop)
   2001    CASE(Try)
   2002    CASE(NopDestructuring)
   2003    CASE(NopIsAssignOp)
   2004    CASE(TryDestructuring) {
   2005      MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);
   2006      ADVANCE_AND_DISPATCH(1);
   2007    }
   2008 
   2009    CASE(JumpTarget)
   2010    COUNT_COVERAGE();
   2011    END_CASE(JumpTarget)
   2012 
   2013    CASE(LoopHead) {
   2014      COUNT_COVERAGE();
   2015 
   2016      // Attempt on-stack replacement into the Baseline Interpreter.
   2017      if (jit::IsBaselineInterpreterEnabled()) {
   2018        script->incWarmUpCounter();
   2019 
   2020        jit::MethodStatus status =
   2021            jit::CanEnterBaselineInterpreterAtBranch(cx, REGS.fp());
   2022        if (status == jit::Method_Error) {
   2023          goto error;
   2024        }
   2025        if (status == jit::Method_Compiled) {
   2026          bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
   2027 
   2028          jit::JitExecStatus maybeOsr;
   2029          {
   2030            GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
   2031            maybeOsr =
   2032                jit::EnterBaselineInterpreterAtBranch(cx, REGS.fp(), REGS.pc);
   2033          }
   2034 
   2035          // We failed to call into baseline at all, so treat as an error.
   2036          if (maybeOsr == jit::JitExec_Aborted) {
   2037            goto error;
   2038          }
   2039 
   2040          interpReturnOK = (maybeOsr == jit::JitExec_Ok);
   2041 
   2042          // Pop the profiler frame pushed by the interpreter.  (The compiled
   2043          // version of the function popped a copy of the frame pushed by the
   2044          // OSR trampoline.)
   2045          if (wasProfiler) {
   2046            cx->geckoProfiler().exit(cx, script);
   2047          }
   2048 
   2049          if (activation.entryFrame() != REGS.fp()) {
   2050            goto jit_return_pop_frame;
   2051          }
   2052          goto leave_on_safe_point;
   2053        }
   2054      }
   2055    }
   2056    END_CASE(LoopHead)
   2057 
   2058    CASE(Lineno)
   2059    END_CASE(Lineno)
   2060 
   2061    CASE(ForceInterpreter) {
   2062      // Ensure pattern matching still works.
   2063      MOZ_ASSERT(script->hasForceInterpreterOp());
   2064    }
   2065    END_CASE(ForceInterpreter)
   2066 
   2067    CASE(Undefined) { PUSH_UNDEFINED(); }
   2068    END_CASE(Undefined)
   2069 
   2070    CASE(Pop) { REGS.sp--; }
   2071    END_CASE(Pop)
   2072 
   2073    CASE(PopN) {
   2074      MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
   2075      REGS.sp -= GET_UINT16(REGS.pc);
   2076    }
   2077    END_CASE(PopN)
   2078 
   2079    CASE(DupAt) {
   2080      MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
   2081      unsigned i = GET_UINT24(REGS.pc);
   2082      const Value& rref = REGS.sp[-int(i + 1)];
   2083      PUSH_COPY(rref);
   2084    }
   2085    END_CASE(DupAt)
   2086 
   2087    CASE(SetRval) { POP_RETURN_VALUE(); }
   2088    END_CASE(SetRval)
   2089 
   2090    CASE(GetRval) { PUSH_COPY(REGS.fp()->returnValue()); }
   2091    END_CASE(GetRval)
   2092 
   2093    CASE(EnterWith) {
   2094      ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
   2095      REGS.sp--;
   2096      ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
   2097 
   2098      if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
   2099        goto error;
   2100      }
   2101    }
   2102    END_CASE(EnterWith)
   2103 
   2104    CASE(LeaveWith) {
   2105      REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
   2106    }
   2107    END_CASE(LeaveWith)
   2108 
   2109 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   2110    CASE(AddDisposable) {
   2111      ReservedRooted<JSObject*> env(&rootObject0,
   2112                                    REGS.fp()->environmentChain());
   2113 
   2114      ReservedRooted<JS::Value> needsClosure(&rootValue0);
   2115      POP_COPY_TO(needsClosure);
   2116 
   2117      ReservedRooted<JS::Value> method(&rootValue1);
   2118      POP_COPY_TO(method);
   2119 
   2120      JS::Rooted<JS::Value> val(cx);
   2121      POP_COPY_TO(val);
   2122 
   2123      UsingHint hint = UsingHint(GET_UINT8(REGS.pc));
   2124 
   2125      if (!AddDisposableResourceToCapability(cx, env, val, method,
   2126                                             needsClosure.toBoolean(), hint)) {
   2127        goto error;
   2128      }
   2129    }
   2130    END_CASE(AddDisposable)
   2131 
   2132    CASE(TakeDisposeCapability) {
   2133      ReservedRooted<JSObject*> env(&rootObject0,
   2134                                    REGS.fp()->environmentChain());
   2135      JS::Value maybeDisposables =
   2136          env->as<DisposableEnvironmentObject>().getDisposables();
   2137 
   2138      MOZ_ASSERT(maybeDisposables.isObject() || maybeDisposables.isUndefined());
   2139 
   2140      if (maybeDisposables.isUndefined()) {
   2141        PUSH_UNDEFINED();
   2142      } else {
   2143        PUSH_OBJECT(maybeDisposables.toObject());
   2144        env->as<DisposableEnvironmentObject>().clearDisposables();
   2145      }
   2146    }
   2147    END_CASE(TakeDisposeCapability)
   2148 
   2149    CASE(CreateSuppressedError) {
   2150      ReservedRooted<JS::Value> error(&rootValue0);
   2151      ReservedRooted<JS::Value> suppressed(&rootValue1);
   2152      POP_COPY_TO(suppressed);
   2153      POP_COPY_TO(error);
   2154      ErrorObject* errorObj = CreateSuppressedError(cx, error, suppressed);
   2155      if (!errorObj) {
   2156        goto error;
   2157      }
   2158      PUSH_OBJECT(*errorObj);
   2159    }
   2160    END_CASE(CreateSuppressedError)
   2161 #endif
   2162 
   2163    CASE(Return) {
   2164      POP_RETURN_VALUE();
   2165      /* FALL THROUGH */
   2166    }
   2167    CASE(RetRval) {
   2168      /*
   2169       * When the inlined frame exits with an exception or an error, ok will be
   2170       * false after the inline_return label.
   2171       */
   2172      CHECK_BRANCH();
   2173 
   2174    successful_return_continuation:
   2175      interpReturnOK = true;
   2176 
   2177    return_continuation:
   2178      frameHalfInitialized = false;
   2179 
   2180    prologue_return_continuation:
   2181 
   2182      if (activation.entryFrame() != REGS.fp()) {
   2183        // Stop the engine. (No details about which engine exactly, could be
   2184        // interpreter, Baseline or IonMonkey.)
   2185        if (MOZ_LIKELY(!frameHalfInitialized)) {
   2186          interpReturnOK =
   2187              DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
   2188 
   2189          REGS.fp()->epilogue(cx, REGS.pc);
   2190        }
   2191 
   2192      jit_return_pop_frame:
   2193 
   2194        activation.popInlineFrame(REGS.fp());
   2195        {
   2196          JSScript* callerScript = REGS.fp()->script();
   2197          if (cx->realm() != callerScript->realm()) {
   2198            cx->leaveRealm(callerScript->realm());
   2199          }
   2200          SET_SCRIPT(callerScript);
   2201        }
   2202 
   2203      jit_return:
   2204 
   2205        MOZ_ASSERT(IsInvokePC(REGS.pc));
   2206        MOZ_ASSERT(cx->realm() == script->realm());
   2207 
   2208        /* Resume execution in the calling frame. */
   2209        if (MOZ_LIKELY(interpReturnOK)) {
   2210          if (JSOp(*REGS.pc) == JSOp::Resume) {
   2211            ADVANCE_AND_DISPATCH(JSOpLength_Resume);
   2212          }
   2213 
   2214          MOZ_ASSERT(GetBytecodeLength(REGS.pc) == JSOpLength_Call);
   2215          ADVANCE_AND_DISPATCH(JSOpLength_Call);
   2216        }
   2217 
   2218        goto error;
   2219      } else {
   2220        // Stack should be empty for the outer frame, unless we executed the
   2221        // first |await| expression in an async function.
   2222        MOZ_ASSERT(REGS.stackDepth() == 0 ||
   2223                   (JSOp(*REGS.pc) == JSOp::Await &&
   2224                    !REGS.fp()->isResumedGenerator()));
   2225      }
   2226      goto exit;
   2227    }
   2228 
   2229    CASE(Default) {
   2230      REGS.sp--;
   2231      /* FALL THROUGH */
   2232    }
   2233    CASE(Goto) { BRANCH(GET_JUMP_OFFSET(REGS.pc)); }
   2234 
   2235    CASE(JumpIfFalse) {
   2236      bool cond = ToBoolean(REGS.stackHandleAt(-1));
   2237      REGS.sp--;
   2238      if (!cond) {
   2239        BRANCH(GET_JUMP_OFFSET(REGS.pc));
   2240      }
   2241    }
   2242    END_CASE(JumpIfFalse)
   2243 
   2244    CASE(JumpIfTrue) {
   2245      bool cond = ToBoolean(REGS.stackHandleAt(-1));
   2246      REGS.sp--;
   2247      if (cond) {
   2248        BRANCH(GET_JUMP_OFFSET(REGS.pc));
   2249      }
   2250    }
   2251    END_CASE(JumpIfTrue)
   2252 
   2253    CASE(Or) {
   2254      bool cond = ToBoolean(REGS.stackHandleAt(-1));
   2255      if (cond) {
   2256        ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
   2257      }
   2258    }
   2259    END_CASE(Or)
   2260 
   2261    CASE(Coalesce) {
   2262      MutableHandleValue res = REGS.stackHandleAt(-1);
   2263      bool cond = !res.isNullOrUndefined();
   2264      if (cond) {
   2265        ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
   2266      }
   2267    }
   2268    END_CASE(Coalesce)
   2269 
   2270    CASE(And) {
   2271      bool cond = ToBoolean(REGS.stackHandleAt(-1));
   2272      if (!cond) {
   2273        ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
   2274      }
   2275    }
   2276    END_CASE(And)
   2277 
   2278 #define FETCH_ELEMENT_ID(n, id)                                       \
   2279  JS_BEGIN_MACRO                                                      \
   2280    if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
   2281  JS_END_MACRO
   2282 
   2283 #define TRY_BRANCH_AFTER_COND(cond, spdec)                          \
   2284  JS_BEGIN_MACRO                                                    \
   2285    MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);                    \
   2286    unsigned diff_ =                                                \
   2287        (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
   2288    if (diff_ <= 1) {                                               \
   2289      REGS.sp -= (spdec);                                           \
   2290      if ((cond) == (diff_ != 0)) {                                 \
   2291        ++REGS.pc;                                                  \
   2292        BRANCH(GET_JUMP_OFFSET(REGS.pc));                           \
   2293      }                                                             \
   2294      ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse);             \
   2295    }                                                               \
   2296  JS_END_MACRO
   2297 
   2298    CASE(In) {
   2299      HandleValue rref = REGS.stackHandleAt(-1);
   2300      if (!rref.isObject()) {
   2301        HandleValue lref = REGS.stackHandleAt(-2);
   2302        ReportInNotObjectError(cx, lref, rref);
   2303        goto error;
   2304      }
   2305      bool found;
   2306      {
   2307        ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
   2308        ReservedRooted<jsid> id(&rootId0);
   2309        FETCH_ELEMENT_ID(-2, id);
   2310        if (!HasProperty(cx, obj, id, &found)) {
   2311          goto error;
   2312        }
   2313      }
   2314      TRY_BRANCH_AFTER_COND(found, 2);
   2315      REGS.sp--;
   2316      REGS.sp[-1].setBoolean(found);
   2317    }
   2318    END_CASE(In)
   2319 
   2320    CASE(HasOwn) {
   2321      HandleValue val = REGS.stackHandleAt(-1);
   2322      HandleValue idval = REGS.stackHandleAt(-2);
   2323 
   2324      bool found;
   2325      if (!HasOwnProperty(cx, val, idval, &found)) {
   2326        goto error;
   2327      }
   2328 
   2329      REGS.sp--;
   2330      REGS.sp[-1].setBoolean(found);
   2331    }
   2332    END_CASE(HasOwn)
   2333 
   2334    CASE(CheckPrivateField) {
   2335      /* Load the object being initialized into lval/val. */
   2336      HandleValue val = REGS.stackHandleAt(-2);
   2337      HandleValue idval = REGS.stackHandleAt(-1);
   2338 
   2339      bool result = false;
   2340      if (!CheckPrivateFieldOperation(cx, REGS.pc, val, idval, &result)) {
   2341        goto error;
   2342      }
   2343 
   2344      PUSH_BOOLEAN(result);
   2345    }
   2346    END_CASE(CheckPrivateField)
   2347 
   2348    CASE(NewPrivateName) {
   2349      ReservedRooted<JSAtom*> name(&rootAtom0, script->getAtom(REGS.pc));
   2350 
   2351      auto* symbol = NewPrivateName(cx, name);
   2352      if (!symbol) {
   2353        goto error;
   2354      }
   2355 
   2356      PUSH_SYMBOL(symbol);
   2357    }
   2358    END_CASE(NewPrivateName)
   2359 
   2360    CASE(IsNullOrUndefined) {
   2361      bool b = REGS.sp[-1].isNullOrUndefined();
   2362      PUSH_BOOLEAN(b);
   2363    }
   2364    END_CASE(IsNullOrUndefined)
   2365 
   2366    CASE(Iter) {
   2367      MOZ_ASSERT(REGS.stackDepth() >= 1);
   2368      HandleValue val = REGS.stackHandleAt(-1);
   2369      JSObject* iter = ValueToIterator(cx, val);
   2370      if (!iter) {
   2371        goto error;
   2372      }
   2373      REGS.sp[-1].setObject(*iter);
   2374    }
   2375    END_CASE(Iter)
   2376 
   2377    CASE(MoreIter) {
   2378      MOZ_ASSERT(REGS.stackDepth() >= 1);
   2379      MOZ_ASSERT(REGS.sp[-1].isObject());
   2380      Value v = IteratorMore(&REGS.sp[-1].toObject());
   2381      PUSH_COPY(v);
   2382    }
   2383    END_CASE(MoreIter)
   2384 
   2385    CASE(IsNoIter) {
   2386      bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
   2387      PUSH_BOOLEAN(b);
   2388    }
   2389    END_CASE(IsNoIter)
   2390 
   2391    CASE(EndIter) {
   2392      MOZ_ASSERT(REGS.stackDepth() >= 2);
   2393      CloseIterator(&REGS.sp[-2].toObject());
   2394      REGS.sp -= 2;
   2395    }
   2396    END_CASE(EndIter)
   2397 
   2398    CASE(CloseIter) {
   2399      ReservedRooted<JSObject*> iter(&rootObject0, &REGS.sp[-1].toObject());
   2400      CompletionKind kind = CompletionKind(GET_UINT8(REGS.pc));
   2401      if (!CloseIterOperation(cx, iter, kind)) {
   2402        goto error;
   2403      }
   2404      REGS.sp--;
   2405    }
   2406    END_CASE(CloseIter)
   2407 
   2408    CASE(OptimizeGetIterator) {
   2409      bool result = OptimizeGetIterator(REGS.sp[-1], cx);
   2410      REGS.sp[-1].setBoolean(result);
   2411    }
   2412    END_CASE(OptimizeGetIterator)
   2413 
   2414    CASE(IsGenClosing) {
   2415      bool b = REGS.sp[-1].isMagic(JS_GENERATOR_CLOSING);
   2416      PUSH_BOOLEAN(b);
   2417    }
   2418    END_CASE(IsGenClosing)
   2419 
   2420    CASE(Dup) {
   2421      MOZ_ASSERT(REGS.stackDepth() >= 1);
   2422      const Value& rref = REGS.sp[-1];
   2423      PUSH_COPY(rref);
   2424    }
   2425    END_CASE(Dup)
   2426 
   2427    CASE(Dup2) {
   2428      MOZ_ASSERT(REGS.stackDepth() >= 2);
   2429      const Value& lref = REGS.sp[-2];
   2430      const Value& rref = REGS.sp[-1];
   2431      PUSH_COPY(lref);
   2432      PUSH_COPY(rref);
   2433    }
   2434    END_CASE(Dup2)
   2435 
   2436    CASE(Swap) {
   2437      MOZ_ASSERT(REGS.stackDepth() >= 2);
   2438      Value& lref = REGS.sp[-2];
   2439      Value& rref = REGS.sp[-1];
   2440      lref.swap(rref);
   2441    }
   2442    END_CASE(Swap)
   2443 
   2444    CASE(Pick) {
   2445      unsigned i = GET_UINT8(REGS.pc);
   2446      MOZ_ASSERT(REGS.stackDepth() >= i + 1);
   2447      Value lval = REGS.sp[-int(i + 1)];
   2448      memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
   2449      REGS.sp[-1] = lval;
   2450    }
   2451    END_CASE(Pick)
   2452 
   2453    CASE(Unpick) {
   2454      int i = GET_UINT8(REGS.pc);
   2455      MOZ_ASSERT(REGS.stackDepth() >= unsigned(i) + 1);
   2456      Value lval = REGS.sp[-1];
   2457      memmove(REGS.sp - i, REGS.sp - (i + 1), sizeof(Value) * i);
   2458      REGS.sp[-(i + 1)] = lval;
   2459    }
   2460    END_CASE(Unpick)
   2461 
   2462    CASE(BindUnqualifiedGName)
   2463    CASE(BindUnqualifiedName) {
   2464      JSOp op = JSOp(*REGS.pc);
   2465      ReservedRooted<JSObject*> envChain(&rootObject0);
   2466      if (op == JSOp::BindUnqualifiedName) {
   2467        envChain.set(REGS.fp()->environmentChain());
   2468      } else {
   2469        MOZ_ASSERT(!script->hasNonSyntacticScope());
   2470        envChain.set(&REGS.fp()->global().lexicalEnvironment());
   2471      }
   2472      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2473 
   2474      // Assigning to an undeclared name adds a property to the global object.
   2475      JSObject* env = LookupNameUnqualified(cx, name, envChain);
   2476      if (!env) {
   2477        goto error;
   2478      }
   2479 
   2480      PUSH_OBJECT(*env);
   2481 
   2482      static_assert(
   2483          JSOpLength_BindUnqualifiedName == JSOpLength_BindUnqualifiedGName,
   2484          "We're sharing the END_CASE so the lengths better match");
   2485    }
   2486    END_CASE(BindUnqualifiedName)
   2487 
   2488    CASE(BindName) {
   2489      auto envChain = REGS.fp()->environmentChain();
   2490      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2491 
   2492      JSObject* env = LookupNameWithGlobalDefault(cx, name, envChain);
   2493      if (!env) {
   2494        goto error;
   2495      }
   2496 
   2497      PUSH_OBJECT(*env);
   2498    }
   2499    END_CASE(BindName)
   2500 
   2501    CASE(BindVar) {
   2502      JSObject* varObj = BindVarOperation(cx, REGS.fp()->environmentChain());
   2503      PUSH_OBJECT(*varObj);
   2504    }
   2505    END_CASE(BindVar)
   2506 
   2507    CASE(BitOr) {
   2508      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2509      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2510      MutableHandleValue res = REGS.stackHandleAt(-2);
   2511      if (!BitOrOperation(cx, lhs, rhs, res)) {
   2512        goto error;
   2513      }
   2514      REGS.sp--;
   2515    }
   2516    END_CASE(BitOr)
   2517 
   2518    CASE(BitXor) {
   2519      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2520      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2521      MutableHandleValue res = REGS.stackHandleAt(-2);
   2522      if (!BitXorOperation(cx, lhs, rhs, res)) {
   2523        goto error;
   2524      }
   2525      REGS.sp--;
   2526    }
   2527    END_CASE(BitXor)
   2528 
   2529    CASE(BitAnd) {
   2530      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2531      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2532      MutableHandleValue res = REGS.stackHandleAt(-2);
   2533      if (!BitAndOperation(cx, lhs, rhs, res)) {
   2534        goto error;
   2535      }
   2536      REGS.sp--;
   2537    }
   2538    END_CASE(BitAnd)
   2539 
   2540    CASE(Eq) {
   2541      if (!LooseEqualityOp<true>(cx, REGS)) {
   2542        goto error;
   2543      }
   2544    }
   2545    END_CASE(Eq)
   2546 
   2547    CASE(Ne) {
   2548      if (!LooseEqualityOp<false>(cx, REGS)) {
   2549        goto error;
   2550      }
   2551    }
   2552    END_CASE(Ne)
   2553 
   2554 #define STRICT_EQUALITY_OP(OP, COND)                  \
   2555  JS_BEGIN_MACRO                                      \
   2556    const Value& lval = REGS.sp[-2];                  \
   2557    const Value& rval = REGS.sp[-1];                  \
   2558    bool equal;                                       \
   2559    if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
   2560      goto error;                                     \
   2561    }                                                 \
   2562    (COND) = equal OP true;                           \
   2563    REGS.sp--;                                        \
   2564  JS_END_MACRO
   2565 
   2566    CASE(StrictEq) {
   2567      bool cond;
   2568      STRICT_EQUALITY_OP(==, cond);
   2569      REGS.sp[-1].setBoolean(cond);
   2570    }
   2571    END_CASE(StrictEq)
   2572 
   2573    CASE(StrictNe) {
   2574      bool cond;
   2575      STRICT_EQUALITY_OP(!=, cond);
   2576      REGS.sp[-1].setBoolean(cond);
   2577    }
   2578    END_CASE(StrictNe)
   2579 
   2580 #undef STRICT_EQUALITY_OP
   2581 
   2582    CASE(StrictConstantEq) {
   2583      const Value& value = REGS.sp[-1];
   2584      bool equal = js::ConstantStrictEqual(value, GET_UINT16(REGS.pc));
   2585      REGS.sp[-1].setBoolean(equal);
   2586    }
   2587    END_CASE(StrictConstantEq)
   2588 
   2589    CASE(StrictConstantNe) {
   2590      const Value& value = REGS.sp[-1];
   2591      bool equal = js::ConstantStrictEqual(value, GET_UINT16(REGS.pc));
   2592      REGS.sp[-1].setBoolean(!equal);
   2593    }
   2594    END_CASE(StrictConstantNe)
   2595 
   2596    CASE(Case) {
   2597      bool cond = REGS.sp[-1].toBoolean();
   2598      REGS.sp--;
   2599      if (cond) {
   2600        REGS.sp--;
   2601        BRANCH(GET_JUMP_OFFSET(REGS.pc));
   2602      }
   2603    }
   2604    END_CASE(Case)
   2605 
   2606    CASE(Lt) {
   2607      bool cond;
   2608      MutableHandleValue lval = REGS.stackHandleAt(-2);
   2609      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2610      if (!LessThanOperation(cx, lval, rval, &cond)) {
   2611        goto error;
   2612      }
   2613      TRY_BRANCH_AFTER_COND(cond, 2);
   2614      REGS.sp[-2].setBoolean(cond);
   2615      REGS.sp--;
   2616    }
   2617    END_CASE(Lt)
   2618 
   2619    CASE(Le) {
   2620      bool cond;
   2621      MutableHandleValue lval = REGS.stackHandleAt(-2);
   2622      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2623      if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) {
   2624        goto error;
   2625      }
   2626      TRY_BRANCH_AFTER_COND(cond, 2);
   2627      REGS.sp[-2].setBoolean(cond);
   2628      REGS.sp--;
   2629    }
   2630    END_CASE(Le)
   2631 
   2632    CASE(Gt) {
   2633      bool cond;
   2634      MutableHandleValue lval = REGS.stackHandleAt(-2);
   2635      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2636      if (!GreaterThanOperation(cx, lval, rval, &cond)) {
   2637        goto error;
   2638      }
   2639      TRY_BRANCH_AFTER_COND(cond, 2);
   2640      REGS.sp[-2].setBoolean(cond);
   2641      REGS.sp--;
   2642    }
   2643    END_CASE(Gt)
   2644 
   2645    CASE(Ge) {
   2646      bool cond;
   2647      MutableHandleValue lval = REGS.stackHandleAt(-2);
   2648      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2649      if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) {
   2650        goto error;
   2651      }
   2652      TRY_BRANCH_AFTER_COND(cond, 2);
   2653      REGS.sp[-2].setBoolean(cond);
   2654      REGS.sp--;
   2655    }
   2656    END_CASE(Ge)
   2657 
   2658    CASE(Lsh) {
   2659      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2660      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2661      MutableHandleValue res = REGS.stackHandleAt(-2);
   2662      if (!BitLshOperation(cx, lhs, rhs, res)) {
   2663        goto error;
   2664      }
   2665      REGS.sp--;
   2666    }
   2667    END_CASE(Lsh)
   2668 
   2669    CASE(Rsh) {
   2670      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2671      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2672      MutableHandleValue res = REGS.stackHandleAt(-2);
   2673      if (!BitRshOperation(cx, lhs, rhs, res)) {
   2674        goto error;
   2675      }
   2676      REGS.sp--;
   2677    }
   2678    END_CASE(Rsh)
   2679 
   2680    CASE(Ursh) {
   2681      MutableHandleValue lhs = REGS.stackHandleAt(-2);
   2682      MutableHandleValue rhs = REGS.stackHandleAt(-1);
   2683      MutableHandleValue res = REGS.stackHandleAt(-2);
   2684      if (!UrshOperation(cx, lhs, rhs, res)) {
   2685        goto error;
   2686      }
   2687      REGS.sp--;
   2688    }
   2689    END_CASE(Ursh)
   2690 
   2691    CASE(Add) {
   2692      MutableHandleValue lval = REGS.stackHandleAt(-2);
   2693      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2694      MutableHandleValue res = REGS.stackHandleAt(-2);
   2695      if (!AddOperation(cx, lval, rval, res)) {
   2696        goto error;
   2697      }
   2698      REGS.sp--;
   2699    }
   2700    END_CASE(Add)
   2701 
   2702    CASE(Sub) {
   2703      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
   2704      ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
   2705      MutableHandleValue res = REGS.stackHandleAt(-2);
   2706      if (!SubOperation(cx, &lval, &rval, res)) {
   2707        goto error;
   2708      }
   2709      REGS.sp--;
   2710    }
   2711    END_CASE(Sub)
   2712 
   2713    CASE(Mul) {
   2714      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
   2715      ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
   2716      MutableHandleValue res = REGS.stackHandleAt(-2);
   2717      if (!MulOperation(cx, &lval, &rval, res)) {
   2718        goto error;
   2719      }
   2720      REGS.sp--;
   2721    }
   2722    END_CASE(Mul)
   2723 
   2724    CASE(Div) {
   2725      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
   2726      ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
   2727      MutableHandleValue res = REGS.stackHandleAt(-2);
   2728      if (!DivOperation(cx, &lval, &rval, res)) {
   2729        goto error;
   2730      }
   2731      REGS.sp--;
   2732    }
   2733    END_CASE(Div)
   2734 
   2735    CASE(Mod) {
   2736      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
   2737      ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
   2738      MutableHandleValue res = REGS.stackHandleAt(-2);
   2739      if (!ModOperation(cx, &lval, &rval, res)) {
   2740        goto error;
   2741      }
   2742      REGS.sp--;
   2743    }
   2744    END_CASE(Mod)
   2745 
   2746    CASE(Pow) {
   2747      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
   2748      ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
   2749      MutableHandleValue res = REGS.stackHandleAt(-2);
   2750      if (!PowOperation(cx, &lval, &rval, res)) {
   2751        goto error;
   2752      }
   2753      REGS.sp--;
   2754    }
   2755    END_CASE(Pow)
   2756 
   2757    CASE(Not) {
   2758      bool cond = ToBoolean(REGS.stackHandleAt(-1));
   2759      REGS.sp--;
   2760      PUSH_BOOLEAN(!cond);
   2761    }
   2762    END_CASE(Not)
   2763 
   2764    CASE(BitNot) {
   2765      MutableHandleValue val = REGS.stackHandleAt(-1);
   2766      if (!BitNotOperation(cx, val, val)) {
   2767        goto error;
   2768      }
   2769    }
   2770    END_CASE(BitNot)
   2771 
   2772    CASE(Neg) {
   2773      MutableHandleValue val = REGS.stackHandleAt(-1);
   2774      if (!NegOperation(cx, val, val)) {
   2775        goto error;
   2776      }
   2777    }
   2778    END_CASE(Neg)
   2779 
   2780    CASE(Pos) {
   2781      if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
   2782        goto error;
   2783      }
   2784    }
   2785    END_CASE(Pos)
   2786 
   2787    CASE(DelName) {
   2788      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2789      HandleObject envChain = REGS.fp()->environmentChain();
   2790 
   2791      PUSH_BOOLEAN(true);
   2792      MutableHandleValue res = REGS.stackHandleAt(-1);
   2793      if (!DeleteNameOperation(cx, name, envChain, res)) {
   2794        goto error;
   2795      }
   2796    }
   2797    END_CASE(DelName)
   2798 
   2799    CASE(DelProp)
   2800    CASE(StrictDelProp) {
   2801      static_assert(JSOpLength_DelProp == JSOpLength_StrictDelProp,
   2802                    "delprop and strictdelprop must be the same size");
   2803      HandleValue val = REGS.stackHandleAt(-1);
   2804      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2805      bool res = false;
   2806      if (JSOp(*REGS.pc) == JSOp::StrictDelProp) {
   2807        if (!DelPropOperation<true>(cx, val, name, &res)) {
   2808          goto error;
   2809        }
   2810      } else {
   2811        if (!DelPropOperation<false>(cx, val, name, &res)) {
   2812          goto error;
   2813        }
   2814      }
   2815      REGS.sp[-1].setBoolean(res);
   2816    }
   2817    END_CASE(DelProp)
   2818 
   2819    CASE(DelElem)
   2820    CASE(StrictDelElem) {
   2821      static_assert(JSOpLength_DelElem == JSOpLength_StrictDelElem,
   2822                    "delelem and strictdelelem must be the same size");
   2823      HandleValue val = REGS.stackHandleAt(-2);
   2824      HandleValue propval = REGS.stackHandleAt(-1);
   2825      bool res = false;
   2826      if (JSOp(*REGS.pc) == JSOp::StrictDelElem) {
   2827        if (!DelElemOperation<true>(cx, val, propval, &res)) {
   2828          goto error;
   2829        }
   2830      } else {
   2831        if (!DelElemOperation<false>(cx, val, propval, &res)) {
   2832          goto error;
   2833        }
   2834      }
   2835      REGS.sp[-2].setBoolean(res);
   2836      REGS.sp--;
   2837    }
   2838    END_CASE(DelElem)
   2839 
   2840    CASE(ToPropertyKey) {
   2841      ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
   2842      MutableHandleValue res = REGS.stackHandleAt(-1);
   2843      if (!ToPropertyKeyOperation(cx, idval, res)) {
   2844        goto error;
   2845      }
   2846    }
   2847    END_CASE(ToPropertyKey)
   2848 
   2849    CASE(TypeofExpr)
   2850    CASE(Typeof) {
   2851      REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
   2852    }
   2853    END_CASE(Typeof)
   2854 
   2855    CASE(TypeofEq) {
   2856      auto operand = TypeofEqOperand::fromRawValue(GET_UINT8(REGS.pc));
   2857      bool result = js::TypeOfValue(REGS.sp[-1]) == operand.type();
   2858      if (operand.compareOp() == JSOp::Ne) {
   2859        result = !result;
   2860      }
   2861      REGS.sp[-1].setBoolean(result);
   2862    }
   2863    END_CASE(TypeofEq)
   2864 
   2865    CASE(Void) { REGS.sp[-1].setUndefined(); }
   2866    END_CASE(Void)
   2867 
   2868    CASE(FunctionThis) {
   2869      PUSH_NULL();
   2870      if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
   2871        goto error;
   2872      }
   2873    }
   2874    END_CASE(FunctionThis)
   2875 
   2876    CASE(GlobalThis) {
   2877      MOZ_ASSERT(!script->hasNonSyntacticScope());
   2878      PUSH_OBJECT(*cx->global()->lexicalEnvironment().thisObject());
   2879    }
   2880    END_CASE(GlobalThis)
   2881 
   2882    CASE(NonSyntacticGlobalThis) {
   2883      PUSH_NULL();
   2884      GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(),
   2885                                REGS.stackHandleAt(-1));
   2886    }
   2887    END_CASE(NonSyntacticGlobalThis)
   2888 
   2889    CASE(CheckIsObj) {
   2890      if (!REGS.sp[-1].isObject()) {
   2891        MOZ_ALWAYS_FALSE(
   2892            ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
   2893        goto error;
   2894      }
   2895    }
   2896    END_CASE(CheckIsObj)
   2897 
   2898    CASE(CheckThis) {
   2899      if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
   2900        MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
   2901        goto error;
   2902      }
   2903    }
   2904    END_CASE(CheckThis)
   2905 
   2906    CASE(CheckThisReinit) {
   2907      if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
   2908        MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
   2909        goto error;
   2910      }
   2911    }
   2912    END_CASE(CheckThisReinit)
   2913 
   2914    CASE(CheckReturn) {
   2915      ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-1]);
   2916      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2917      if (!REGS.fp()->checkReturn(cx, thisv, rval)) {
   2918        goto error;
   2919      }
   2920    }
   2921    END_CASE(CheckReturn)
   2922 
   2923    CASE(GetProp) {
   2924      ReservedRooted<Value> lval(&rootValue0, REGS.sp[-1]);
   2925      MutableHandleValue res = REGS.stackHandleAt(-1);
   2926      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2927      if (!GetProperty(cx, lval, name, res)) {
   2928        goto error;
   2929      }
   2930      cx->debugOnlyCheck(res);
   2931    }
   2932    END_CASE(GetProp)
   2933 
   2934    CASE(GetPropSuper) {
   2935      ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-2]);
   2936      HandleValue lval = REGS.stackHandleAt(-1);
   2937      MOZ_ASSERT(lval.isObjectOrNull());
   2938      MutableHandleValue rref = REGS.stackHandleAt(-2);
   2939      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   2940 
   2941      ReservedRooted<JSObject*> obj(&rootObject0);
   2942      obj = ToObjectFromStackForPropertyAccess(cx, lval, -1, name);
   2943      if (!obj) {
   2944        goto error;
   2945      }
   2946 
   2947      if (!GetProperty(cx, obj, receiver, name, rref)) {
   2948        goto error;
   2949      }
   2950 
   2951      cx->debugOnlyCheck(rref);
   2952 
   2953      REGS.sp--;
   2954    }
   2955    END_CASE(GetPropSuper)
   2956 
   2957    CASE(GetBoundName) {
   2958      ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-1].toObject());
   2959      ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
   2960      MutableHandleValue rval = REGS.stackHandleAt(-1);
   2961      if (!GetNameBoundInEnvironment(cx, env, id, rval)) {
   2962        goto error;
   2963      }
   2964      cx->debugOnlyCheck(rval);
   2965    }
   2966    END_CASE(GetBoundName)
   2967 
   2968    CASE(SetIntrinsic) {
   2969      HandleValue value = REGS.stackHandleAt(-1);
   2970 
   2971      if (!SetIntrinsicOperation(cx, script, REGS.pc, value)) {
   2972        goto error;
   2973      }
   2974    }
   2975    END_CASE(SetIntrinsic)
   2976 
   2977    CASE(SetGName)
   2978    CASE(StrictSetGName)
   2979    CASE(SetName)
   2980    CASE(StrictSetName) {
   2981      static_assert(JSOpLength_SetName == JSOpLength_StrictSetName,
   2982                    "setname and strictsetname must be the same size");
   2983      static_assert(JSOpLength_SetGName == JSOpLength_StrictSetGName,
   2984                    "setgname and strictsetgname must be the same size");
   2985      static_assert(JSOpLength_SetName == JSOpLength_SetGName,
   2986                    "We're sharing the END_CASE so the lengths better match");
   2987 
   2988      ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-2].toObject());
   2989      HandleValue value = REGS.stackHandleAt(-1);
   2990 
   2991      if (!SetNameOperation(cx, script, REGS.pc, env, value)) {
   2992        goto error;
   2993      }
   2994 
   2995      REGS.sp[-2] = REGS.sp[-1];
   2996      REGS.sp--;
   2997    }
   2998    END_CASE(SetName)
   2999 
   3000    CASE(SetProp)
   3001    CASE(StrictSetProp) {
   3002      static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp,
   3003                    "setprop and strictsetprop must be the same size");
   3004      int lvalIndex = -2;
   3005      HandleValue lval = REGS.stackHandleAt(lvalIndex);
   3006      HandleValue rval = REGS.stackHandleAt(-1);
   3007 
   3008      ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
   3009 
   3010      bool strict = JSOp(*REGS.pc) == JSOp::StrictSetProp;
   3011 
   3012      ReservedRooted<JSObject*> obj(&rootObject0);
   3013      obj = ToObjectFromStackForPropertyAccess(cx, lval, lvalIndex, id);
   3014      if (!obj) {
   3015        goto error;
   3016      }
   3017 
   3018      if (!SetObjectElementOperation(cx, obj, id, rval, lval, strict)) {
   3019        goto error;
   3020      }
   3021 
   3022      REGS.sp[-2] = REGS.sp[-1];
   3023      REGS.sp--;
   3024    }
   3025    END_CASE(SetProp)
   3026 
   3027    CASE(SetPropSuper)
   3028    CASE(StrictSetPropSuper) {
   3029      static_assert(
   3030          JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper,
   3031          "setprop-super and strictsetprop-super must be the same size");
   3032 
   3033      HandleValue receiver = REGS.stackHandleAt(-3);
   3034      HandleValue lval = REGS.stackHandleAt(-2);
   3035      MOZ_ASSERT(lval.isObjectOrNull());
   3036      HandleValue rval = REGS.stackHandleAt(-1);
   3037      ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
   3038 
   3039      bool strict = JSOp(*REGS.pc) == JSOp::StrictSetPropSuper;
   3040 
   3041      ReservedRooted<JSObject*> obj(&rootObject0);
   3042      obj = ToObjectFromStackForPropertyAccess(cx, lval, -2, id);
   3043      if (!obj) {
   3044        goto error;
   3045      }
   3046 
   3047      if (!SetObjectElementOperation(cx, obj, id, rval, receiver, strict)) {
   3048        goto error;
   3049      }
   3050 
   3051      REGS.sp[-3] = REGS.sp[-1];
   3052      REGS.sp -= 2;
   3053    }
   3054    END_CASE(SetPropSuper)
   3055 
   3056    CASE(GetElem) {
   3057      int lvalIndex = -2;
   3058      ReservedRooted<Value> lval(&rootValue0, REGS.sp[lvalIndex]);
   3059      HandleValue rval = REGS.stackHandleAt(-1);
   3060      MutableHandleValue res = REGS.stackHandleAt(-2);
   3061 
   3062      if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval, res)) {
   3063        goto error;
   3064      }
   3065 
   3066      REGS.sp--;
   3067    }
   3068    END_CASE(GetElem)
   3069 
   3070    CASE(GetElemSuper) {
   3071      ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
   3072      HandleValue index = REGS.stackHandleAt(-2);
   3073      HandleValue lval = REGS.stackHandleAt(-1);
   3074      MOZ_ASSERT(lval.isObjectOrNull());
   3075 
   3076      MutableHandleValue res = REGS.stackHandleAt(-3);
   3077 
   3078      ReservedRooted<JSObject*> obj(&rootObject0);
   3079      obj = ToObjectFromStackForPropertyAccess(cx, lval, -1, index);
   3080      if (!obj) {
   3081        goto error;
   3082      }
   3083 
   3084      if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, index,
   3085                                     res)) {
   3086        goto error;
   3087      }
   3088 
   3089      REGS.sp -= 2;
   3090    }
   3091    END_CASE(GetElemSuper)
   3092 
   3093    CASE(SetElem)
   3094    CASE(StrictSetElem) {
   3095      static_assert(JSOpLength_SetElem == JSOpLength_StrictSetElem,
   3096                    "setelem and strictsetelem must be the same size");
   3097      int receiverIndex = -3;
   3098      HandleValue receiver = REGS.stackHandleAt(receiverIndex);
   3099      HandleValue value = REGS.stackHandleAt(-1);
   3100 
   3101      ReservedRooted<JSObject*> obj(&rootObject0);
   3102      obj = ToObjectFromStackForPropertyAccess(cx, receiver, receiverIndex,
   3103                                               REGS.stackHandleAt(-2));
   3104      if (!obj) {
   3105        goto error;
   3106      }
   3107 
   3108      ReservedRooted<jsid> id(&rootId0);
   3109      FETCH_ELEMENT_ID(-2, id);
   3110 
   3111      if (!SetObjectElementOperation(cx, obj, id, value, receiver,
   3112                                     JSOp(*REGS.pc) == JSOp::StrictSetElem)) {
   3113        goto error;
   3114      }
   3115      REGS.sp[-3] = value;
   3116      REGS.sp -= 2;
   3117    }
   3118    END_CASE(SetElem)
   3119 
   3120    CASE(SetElemSuper)
   3121    CASE(StrictSetElemSuper) {
   3122      static_assert(
   3123          JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper,
   3124          "setelem-super and strictsetelem-super must be the same size");
   3125 
   3126      HandleValue receiver = REGS.stackHandleAt(-4);
   3127      HandleValue lval = REGS.stackHandleAt(-2);
   3128      MOZ_ASSERT(lval.isObjectOrNull());
   3129      HandleValue value = REGS.stackHandleAt(-1);
   3130 
   3131      ReservedRooted<JSObject*> obj(&rootObject0);
   3132      obj = ToObjectFromStackForPropertyAccess(cx, lval, -2,
   3133                                               REGS.stackHandleAt(-3));
   3134      if (!obj) {
   3135        goto error;
   3136      }
   3137 
   3138      ReservedRooted<jsid> id(&rootId0);
   3139      FETCH_ELEMENT_ID(-3, id);
   3140 
   3141      bool strict = JSOp(*REGS.pc) == JSOp::StrictSetElemSuper;
   3142      if (!SetObjectElementOperation(cx, obj, id, value, receiver, strict)) {
   3143        goto error;
   3144      }
   3145      REGS.sp[-4] = value;
   3146      REGS.sp -= 3;
   3147    }
   3148    END_CASE(SetElemSuper)
   3149 
   3150    CASE(Eval)
   3151    CASE(StrictEval) {
   3152      static_assert(JSOpLength_Eval == JSOpLength_StrictEval,
   3153                    "eval and stricteval must be the same size");
   3154 
   3155      CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
   3156      if (cx->global()->valueIsEval(args.calleev())) {
   3157        if (!DirectEval(cx, args.get(0), args.rval())) {
   3158          goto error;
   3159        }
   3160      } else {
   3161        if (!CallFromStack(cx, args, CallReason::Call)) {
   3162          goto error;
   3163        }
   3164      }
   3165 
   3166      REGS.sp = args.spAfterCall();
   3167    }
   3168    END_CASE(Eval)
   3169 
   3170    CASE(SpreadNew)
   3171    CASE(SpreadCall)
   3172    CASE(SpreadSuperCall) {
   3173      if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
   3174        cx->geckoProfiler().updatePC(cx, script, REGS.pc);
   3175      }
   3176      /* FALL THROUGH */
   3177    }
   3178 
   3179    CASE(SpreadEval)
   3180    CASE(StrictSpreadEval) {
   3181      static_assert(JSOpLength_SpreadEval == JSOpLength_StrictSpreadEval,
   3182                    "spreadeval and strictspreadeval must be the same size");
   3183      bool construct = JSOp(*REGS.pc) == JSOp::SpreadNew ||
   3184                       JSOp(*REGS.pc) == JSOp::SpreadSuperCall;
   3185 
   3186      MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
   3187 
   3188      HandleValue callee = REGS.stackHandleAt(-3 - construct);
   3189      HandleValue thisv = REGS.stackHandleAt(-2 - construct);
   3190      HandleValue arr = REGS.stackHandleAt(-1 - construct);
   3191      MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
   3192 
   3193      ReservedRooted<Value> newTarget(&rootValue0);
   3194      if (construct) {
   3195        newTarget = REGS.sp[-1];
   3196      } else {
   3197        newTarget = NullValue();
   3198      }
   3199 
   3200      if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr,
   3201                               newTarget, ret)) {
   3202        goto error;
   3203      }
   3204 
   3205      REGS.sp -= 2 + construct;
   3206    }
   3207    END_CASE(SpreadCall)
   3208 
   3209    CASE(New)
   3210    CASE(NewContent)
   3211    CASE(Call)
   3212    CASE(CallContent)
   3213    CASE(CallIgnoresRv)
   3214    CASE(CallIter)
   3215    CASE(CallContentIter)
   3216    CASE(SuperCall) {
   3217      static_assert(JSOpLength_Call == JSOpLength_New,
   3218                    "call and new must be the same size");
   3219      static_assert(JSOpLength_Call == JSOpLength_CallContent,
   3220                    "call and call-content must be the same size");
   3221      static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,
   3222                    "call and call-ignores-rv must be the same size");
   3223      static_assert(JSOpLength_Call == JSOpLength_CallIter,
   3224                    "call and calliter must be the same size");
   3225      static_assert(JSOpLength_Call == JSOpLength_CallContentIter,
   3226                    "call and call-content-iter must be the same size");
   3227      static_assert(JSOpLength_Call == JSOpLength_SuperCall,
   3228                    "call and supercall must be the same size");
   3229 
   3230      if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
   3231        cx->geckoProfiler().updatePC(cx, script, REGS.pc);
   3232      }
   3233 
   3234      JSOp op = JSOp(*REGS.pc);
   3235      MaybeConstruct construct = MaybeConstruct(
   3236          op == JSOp::New || op == JSOp::NewContent || op == JSOp::SuperCall);
   3237      bool ignoresReturnValue = op == JSOp::CallIgnoresRv;
   3238      unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
   3239 
   3240      MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
   3241      CallArgs args =
   3242          CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
   3243 
   3244      JSFunction* maybeFun;
   3245      bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
   3246 
   3247      // Use the slow path if the callee is not an interpreted function, if we
   3248      // have to throw an exception, or if we might have to invoke the
   3249      // OnNativeCall hook for a self-hosted builtin.
   3250      if (!isFunction || !maybeFun->isInterpreted() ||
   3251          (construct && !maybeFun->isConstructor()) ||
   3252          (!construct && maybeFun->isClassConstructor()) ||
   3253          cx->realm()->debuggerObservesNativeCall()) {
   3254        if (construct) {
   3255          CallReason reason = op == JSOp::NewContent ? CallReason::CallContent
   3256                                                     : CallReason::Call;
   3257          if (!ConstructFromStack(cx, args, reason)) {
   3258            goto error;
   3259          }
   3260        } else {
   3261          if ((op == JSOp::CallIter || op == JSOp::CallContentIter) &&
   3262              args.calleev().isPrimitive()) {
   3263            MOZ_ASSERT(args.length() == 0, "thisv must be on top of the stack");
   3264            ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
   3265            goto error;
   3266          }
   3267 
   3268          CallReason reason =
   3269              (op == JSOp::CallContent || op == JSOp::CallContentIter)
   3270                  ? CallReason::CallContent
   3271                  : CallReason::Call;
   3272          if (!CallFromStack(cx, args, reason)) {
   3273            goto error;
   3274          }
   3275        }
   3276        Value* newsp = args.spAfterCall();
   3277        REGS.sp = newsp;
   3278        ADVANCE_AND_DISPATCH(JSOpLength_Call);
   3279      }
   3280 
   3281      {
   3282        MOZ_ASSERT(maybeFun);
   3283        ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
   3284        ReservedRooted<JSScript*> funScript(
   3285            &rootScript0, JSFunction::getOrCreateScript(cx, fun));
   3286        if (!funScript) {
   3287          goto error;
   3288        }
   3289 
   3290        // Enter the callee's realm if this is a cross-realm call. Use
   3291        // MakeScopeExit to leave this realm on all error/JIT-return paths
   3292        // below.
   3293        const bool isCrossRealm = cx->realm() != funScript->realm();
   3294        if (isCrossRealm) {
   3295          cx->enterRealmOf(funScript);
   3296        }
   3297        auto leaveRealmGuard =
   3298            mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
   3299              if (isCrossRealm) {
   3300                cx->leaveRealm(script->realm());
   3301              }
   3302            });
   3303 
   3304        if (construct && !MaybeCreateThisForConstructor(cx, args)) {
   3305          goto error;
   3306        }
   3307 
   3308        {
   3309          InvokeState state(cx, args, construct);
   3310 
   3311          jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
   3312          switch (status) {
   3313            case jit::EnterJitStatus::Error:
   3314              goto error;
   3315            case jit::EnterJitStatus::Ok:
   3316              interpReturnOK = true;
   3317              CHECK_BRANCH();
   3318              REGS.sp = args.spAfterCall();
   3319              goto jit_return;
   3320            case jit::EnterJitStatus::NotEntered:
   3321              break;
   3322          }
   3323 
   3324 #ifdef NIGHTLY_BUILD
   3325          // If entry trampolines are enabled, call back into
   3326          // MaybeEnterInterpreterTrampoline so we can generate an
   3327          // entry trampoline for the new frame.
   3328          if (jit::JitOptions.emitInterpreterEntryTrampoline) {
   3329            if (MaybeEnterInterpreterTrampoline(cx, state)) {
   3330              interpReturnOK = true;
   3331              CHECK_BRANCH();
   3332              REGS.sp = args.spAfterCall();
   3333              goto jit_return;
   3334            }
   3335            goto error;
   3336          }
   3337 #endif
   3338        }
   3339 
   3340        funScript = fun->nonLazyScript();
   3341 
   3342        if (!activation.pushInlineFrame(args, funScript, construct)) {
   3343          goto error;
   3344        }
   3345        leaveRealmGuard.release();  // We leave the callee's realm when we
   3346                                    // call popInlineFrame.
   3347      }
   3348 
   3349      SET_SCRIPT(REGS.fp()->script());
   3350 
   3351      if (!REGS.fp()->prologue(cx)) {
   3352        goto prologue_error;
   3353      }
   3354 
   3355      if (!DebugAPI::onEnterFrame(cx, REGS.fp())) {
   3356        goto error;
   3357      }
   3358 
   3359      // Increment the coverage for the main entry point.
   3360      INIT_COVERAGE();
   3361      COUNT_COVERAGE_MAIN();
   3362 
   3363      /* Load first op and dispatch it (safe since JSOp::RetRval). */
   3364      ADVANCE_AND_DISPATCH(0);
   3365    }
   3366 
   3367    CASE(OptimizeSpreadCall) {
   3368      ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
   3369      MutableHandleValue rval = REGS.stackHandleAt(-1);
   3370 
   3371      if (!OptimizeSpreadCall(cx, val, rval)) {
   3372        goto error;
   3373      }
   3374    }
   3375    END_CASE(OptimizeSpreadCall)
   3376 
   3377    CASE(ThrowMsg) {
   3378      MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(REGS.pc)));
   3379      goto error;
   3380    }
   3381    END_CASE(ThrowMsg)
   3382 
   3383    CASE(ImplicitThis) {
   3384      Value thisv = ComputeImplicitThis(&REGS.sp[-1].toObject());
   3385      REGS.sp[-1] = thisv;
   3386    }
   3387    END_CASE(ImplicitThis)
   3388 
   3389    CASE(GetGName) {
   3390      ReservedRooted<Value> rval(&rootValue0);
   3391      ReservedRooted<JSObject*> env(&rootObject0,
   3392                                    &cx->global()->lexicalEnvironment());
   3393      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   3394      MOZ_ASSERT(!script->hasNonSyntacticScope());
   3395      if (!GetNameOperation(cx, env, name, JSOp(REGS.pc[JSOpLength_GetGName]),
   3396                            &rval)) {
   3397        goto error;
   3398      }
   3399 
   3400      PUSH_COPY(rval);
   3401    }
   3402    END_CASE(GetGName)
   3403 
   3404    CASE(GetName) {
   3405      ReservedRooted<Value> rval(&rootValue0);
   3406      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   3407      if (!GetNameOperation(cx, REGS.fp()->environmentChain(), name,
   3408                            JSOp(REGS.pc[JSOpLength_GetName]), &rval)) {
   3409        goto error;
   3410      }
   3411 
   3412      PUSH_COPY(rval);
   3413    }
   3414    END_CASE(GetName)
   3415 
   3416    CASE(GetImport) {
   3417      PUSH_NULL();
   3418      MutableHandleValue rval = REGS.stackHandleAt(-1);
   3419      HandleObject envChain = REGS.fp()->environmentChain();
   3420      if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) {
   3421        goto error;
   3422      }
   3423    }
   3424    END_CASE(GetImport)
   3425 
   3426    CASE(GetIntrinsic) {
   3427      ReservedRooted<Value> rval(&rootValue0);
   3428      if (!GetIntrinsicOperation(cx, script, REGS.pc, &rval)) {
   3429        goto error;
   3430      }
   3431 
   3432      PUSH_COPY(rval);
   3433    }
   3434    END_CASE(GetIntrinsic)
   3435 
   3436    CASE(Uint16) { PUSH_INT32((int32_t)GET_UINT16(REGS.pc)); }
   3437    END_CASE(Uint16)
   3438 
   3439    CASE(Uint24) { PUSH_INT32((int32_t)GET_UINT24(REGS.pc)); }
   3440    END_CASE(Uint24)
   3441 
   3442    CASE(Int8) { PUSH_INT32(GET_INT8(REGS.pc)); }
   3443    END_CASE(Int8)
   3444 
   3445    CASE(Int32) { PUSH_INT32(GET_INT32(REGS.pc)); }
   3446    END_CASE(Int32)
   3447 
   3448    CASE(Double) { PUSH_COPY(GET_INLINE_VALUE(REGS.pc)); }
   3449    END_CASE(Double)
   3450 
   3451    CASE(String) { PUSH_STRING(script->getString(REGS.pc)); }
   3452    END_CASE(String)
   3453 
   3454    CASE(ToString) {
   3455      MutableHandleValue oper = REGS.stackHandleAt(-1);
   3456 
   3457      if (!oper.isString()) {
   3458        JSString* operString = ToString<CanGC>(cx, oper);
   3459        if (!operString) {
   3460          goto error;
   3461        }
   3462        oper.setString(operString);
   3463      }
   3464    }
   3465    END_CASE(ToString)
   3466 
   3467    CASE(Symbol) {
   3468      PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
   3469    }
   3470    END_CASE(Symbol)
   3471 
   3472    CASE(Object) {
   3473      MOZ_ASSERT(script->treatAsRunOnce());
   3474      PUSH_OBJECT(*script->getObject(REGS.pc));
   3475    }
   3476    END_CASE(Object)
   3477 
   3478    CASE(CallSiteObj) {
   3479      JSObject* cso = script->getObject(REGS.pc);
   3480      MOZ_ASSERT(!cso->as<ArrayObject>().isExtensible());
   3481      MOZ_ASSERT(cso->as<ArrayObject>().containsPure(cx->names().raw));
   3482      PUSH_OBJECT(*cso);
   3483    }
   3484    END_CASE(CallSiteObj)
   3485 
   3486    CASE(RegExp) {
   3487      /*
   3488       * Push a regexp object cloned from the regexp literal object mapped by
   3489       * the bytecode at pc.
   3490       */
   3491      ReservedRooted<JSObject*> re(&rootObject0, script->getRegExp(REGS.pc));
   3492      JSObject* obj = CloneRegExpObject(cx, re.as<RegExpObject>());
   3493      if (!obj) {
   3494        goto error;
   3495      }
   3496      PUSH_OBJECT(*obj);
   3497    }
   3498    END_CASE(RegExp)
   3499 
   3500    CASE(Zero) { PUSH_INT32(0); }
   3501    END_CASE(Zero)
   3502 
   3503    CASE(One) { PUSH_INT32(1); }
   3504    END_CASE(One)
   3505 
   3506    CASE(Null) { PUSH_NULL(); }
   3507    END_CASE(Null)
   3508 
   3509    CASE(False) { PUSH_BOOLEAN(false); }
   3510    END_CASE(False)
   3511 
   3512    CASE(True) { PUSH_BOOLEAN(true); }
   3513    END_CASE(True)
   3514 
   3515    CASE(TableSwitch) {
   3516      jsbytecode* pc2 = REGS.pc;
   3517      int32_t len = GET_JUMP_OFFSET(pc2);
   3518 
   3519      /*
   3520       * ECMAv2+ forbids conversion of discriminant, so we will skip to the
   3521       * default case if the discriminant isn't already an int jsval.  (This
   3522       * opcode is emitted only for dense int-domain switches.)
   3523       */
   3524      const Value& rref = *--REGS.sp;
   3525      int32_t i;
   3526      if (rref.isInt32()) {
   3527        i = rref.toInt32();
   3528      } else {
   3529        /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
   3530        if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i)) {
   3531          ADVANCE_AND_DISPATCH(len);
   3532        }
   3533      }
   3534 
   3535      pc2 += JUMP_OFFSET_LEN;
   3536      int32_t low = GET_JUMP_OFFSET(pc2);
   3537      pc2 += JUMP_OFFSET_LEN;
   3538      int32_t high = GET_JUMP_OFFSET(pc2);
   3539 
   3540      i = uint32_t(i) - uint32_t(low);
   3541      if (uint32_t(i) < uint32_t(high - low + 1)) {
   3542        len = script->tableSwitchCaseOffset(REGS.pc, uint32_t(i)) -
   3543              script->pcToOffset(REGS.pc);
   3544      }
   3545      ADVANCE_AND_DISPATCH(len);
   3546    }
   3547 
   3548    CASE(Arguments) {
   3549      MOZ_ASSERT(script->needsArgsObj());
   3550      ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
   3551      if (!obj) {
   3552        goto error;
   3553      }
   3554      PUSH_COPY(ObjectValue(*obj));
   3555    }
   3556    END_CASE(Arguments)
   3557 
   3558    CASE(Rest) {
   3559      ReservedRooted<JSObject*> rest(&rootObject0,
   3560                                     REGS.fp()->createRestParameter(cx));
   3561      if (!rest) {
   3562        goto error;
   3563      }
   3564      PUSH_COPY(ObjectValue(*rest));
   3565    }
   3566    END_CASE(Rest)
   3567 
   3568    CASE(GetAliasedVar) {
   3569      EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
   3570      ReservedRooted<Value> val(
   3571          &rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
   3572 
   3573      ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
   3574 
   3575      PUSH_COPY(val);
   3576    }
   3577    END_CASE(GetAliasedVar)
   3578 
   3579    CASE(GetAliasedDebugVar) {
   3580      EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
   3581      ReservedRooted<Value> val(
   3582          &rootValue0,
   3583          REGS.fp()->aliasedEnvironmentMaybeDebug(ec).aliasedBinding(ec));
   3584 
   3585      ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
   3586 
   3587      PUSH_COPY(val);
   3588    }
   3589    END_CASE(GetAliasedVar)
   3590 
   3591    CASE(SetAliasedVar) {
   3592      EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
   3593      EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
   3594      MOZ_ASSERT(!IsUninitializedLexical(obj.aliasedBinding(ec)));
   3595      obj.setAliasedBinding(ec, REGS.sp[-1]);
   3596    }
   3597    END_CASE(SetAliasedVar)
   3598 
   3599    CASE(ThrowSetConst) {
   3600      ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, REGS.pc);
   3601      goto error;
   3602    }
   3603    END_CASE(ThrowSetConst)
   3604 
   3605    CASE(CheckLexical) {
   3606      if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
   3607        ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
   3608                                  REGS.pc);
   3609        goto error;
   3610      }
   3611    }
   3612    END_CASE(CheckLexical)
   3613 
   3614    CASE(CheckAliasedLexical) {
   3615      if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
   3616        ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
   3617                                  REGS.pc);
   3618        goto error;
   3619      }
   3620    }
   3621    END_CASE(CheckAliasedLexical)
   3622 
   3623    CASE(InitLexical) {
   3624      uint32_t i = GET_LOCALNO(REGS.pc);
   3625      REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
   3626    }
   3627    END_CASE(InitLexical)
   3628 
   3629    CASE(InitAliasedLexical) {
   3630      EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
   3631      EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
   3632      obj.setAliasedBinding(ec, REGS.sp[-1]);
   3633    }
   3634    END_CASE(InitAliasedLexical)
   3635 
   3636    CASE(InitGLexical) {
   3637      ExtensibleLexicalEnvironmentObject* lexicalEnv;
   3638      if (script->hasNonSyntacticScope()) {
   3639        lexicalEnv = &REGS.fp()->extensibleLexicalEnvironment();
   3640      } else {
   3641        lexicalEnv = &cx->global()->lexicalEnvironment();
   3642      }
   3643      HandleValue value = REGS.stackHandleAt(-1);
   3644      InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
   3645    }
   3646    END_CASE(InitGLexical)
   3647 
   3648    CASE(Uninitialized) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL); }
   3649    END_CASE(Uninitialized)
   3650 
   3651    CASE(GetArg) {
   3652      unsigned i = GET_ARGNO(REGS.pc);
   3653      if (script->argsObjAliasesFormals()) {
   3654        PUSH_COPY(REGS.fp()->argsObj().arg(i));
   3655      } else {
   3656        PUSH_COPY(REGS.fp()->unaliasedFormal(i));
   3657      }
   3658    }
   3659    END_CASE(GetArg)
   3660 
   3661    CASE(GetFrameArg) {
   3662      uint32_t i = GET_ARGNO(REGS.pc);
   3663      PUSH_COPY(REGS.fp()->unaliasedFormal(i, DONT_CHECK_ALIASING));
   3664    }
   3665    END_CASE(GetFrameArg)
   3666 
   3667    CASE(SetArg) {
   3668      unsigned i = GET_ARGNO(REGS.pc);
   3669      if (script->argsObjAliasesFormals()) {
   3670        REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
   3671      } else {
   3672        REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
   3673      }
   3674    }
   3675    END_CASE(SetArg)
   3676 
   3677    CASE(GetLocal) {
   3678      uint32_t i = GET_LOCALNO(REGS.pc);
   3679      PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
   3680 
   3681 #ifdef DEBUG
   3682      if (IsUninitializedLexical(REGS.sp[-1])) {
   3683        JSOp next = JSOp(*GetNextPc(REGS.pc));
   3684        MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn ||
   3685                   next == JSOp::CheckThisReinit || next == JSOp::CheckLexical);
   3686      }
   3687 
   3688      /*
   3689       * Skip the same-compartment assertion if the local will be immediately
   3690       * popped. We do not guarantee sync for dead locals when coming in from
   3691       * the method JIT, and a GetLocal followed by Pop is not considered to
   3692       * be a use of the variable.
   3693       */
   3694      if (JSOp(REGS.pc[JSOpLength_GetLocal]) != JSOp::Pop) {
   3695        cx->debugOnlyCheck(REGS.sp[-1]);
   3696      }
   3697 #endif
   3698    }
   3699    END_CASE(GetLocal)
   3700 
   3701    CASE(SetLocal) {
   3702      uint32_t i = GET_LOCALNO(REGS.pc);
   3703 
   3704      MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
   3705 
   3706      REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
   3707    }
   3708    END_CASE(SetLocal)
   3709 
   3710    CASE(ArgumentsLength) {
   3711      MOZ_ASSERT(!script->needsArgsObj());
   3712      PUSH_INT32(REGS.fp()->numActualArgs());
   3713    }
   3714    END_CASE(ArgumentsLength)
   3715 
   3716    CASE(GetActualArg) {
   3717      MOZ_ASSERT(!script->needsArgsObj());
   3718      uint32_t index = REGS.sp[-1].toInt32();
   3719      REGS.sp[-1] = REGS.fp()->unaliasedActual(index);
   3720    }
   3721    END_CASE(GetActualArg)
   3722 
   3723    CASE(GlobalOrEvalDeclInstantiation) {
   3724      GCThingIndex lastFun = GET_GCTHING_INDEX(REGS.pc);
   3725      HandleObject env = REGS.fp()->environmentChain();
   3726      if (!GlobalOrEvalDeclInstantiation(cx, env, script, lastFun)) {
   3727        goto error;
   3728      }
   3729    }
   3730    END_CASE(GlobalOrEvalDeclInstantiation)
   3731 
   3732    CASE(Lambda) {
   3733      /* Load the specified function object literal. */
   3734      ReservedRooted<JSFunction*> fun(&rootFunction0,
   3735                                      script->getFunction(REGS.pc));
   3736      JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
   3737      if (!obj) {
   3738        goto error;
   3739      }
   3740 
   3741      MOZ_ASSERT(obj->staticPrototype());
   3742      PUSH_OBJECT(*obj);
   3743    }
   3744    END_CASE(Lambda)
   3745 
   3746    CASE(ToAsyncIter) {
   3747      ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
   3748      ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-2].toObject());
   3749      JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
   3750      if (!asyncIter) {
   3751        goto error;
   3752      }
   3753 
   3754      REGS.sp--;
   3755      REGS.sp[-1].setObject(*asyncIter);
   3756    }
   3757    END_CASE(ToAsyncIter)
   3758 
   3759    CASE(CanSkipAwait) {
   3760      ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
   3761      bool canSkip;
   3762      if (!CanSkipAwait(cx, val, &canSkip)) {
   3763        goto error;
   3764      }
   3765 
   3766      PUSH_BOOLEAN(canSkip);
   3767    }
   3768    END_CASE(CanSkipAwait)
   3769 
   3770    CASE(MaybeExtractAwaitValue) {
   3771      MutableHandleValue val = REGS.stackHandleAt(-2);
   3772      ReservedRooted<Value> canSkip(&rootValue0, REGS.sp[-1]);
   3773 
   3774      if (canSkip.toBoolean()) {
   3775        if (!ExtractAwaitValue(cx, val, val)) {
   3776          goto error;
   3777        }
   3778      }
   3779    }
   3780    END_CASE(MaybeExtractAwaitValue)
   3781 
   3782    CASE(AsyncAwait) {
   3783      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3784      ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
   3785      ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
   3786      JSObject* promise =
   3787          AsyncFunctionAwait(cx, gen.as<AsyncFunctionGeneratorObject>(), value);
   3788      if (!promise) {
   3789        goto error;
   3790      }
   3791 
   3792      REGS.sp--;
   3793      REGS.sp[-1].setObject(*promise);
   3794    }
   3795    END_CASE(AsyncAwait)
   3796 
   3797    CASE(AsyncResolve) {
   3798      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3799      ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
   3800      ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
   3801      JSObject* promise = AsyncFunctionResolve(
   3802          cx, gen.as<AsyncFunctionGeneratorObject>(), value);
   3803      if (!promise) {
   3804        goto error;
   3805      }
   3806 
   3807      REGS.sp--;
   3808      REGS.sp[-1].setObject(*promise);
   3809    }
   3810    END_CASE(AsyncResolve)
   3811 
   3812    CASE(AsyncReject) {
   3813      MOZ_ASSERT(REGS.stackDepth() >= 3);
   3814      ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
   3815      ReservedRooted<Value> stack(&rootValue0, REGS.sp[-2]);
   3816      ReservedRooted<Value> reason(&rootValue1, REGS.sp[-3]);
   3817      JSObject* promise = AsyncFunctionReject(
   3818          cx, gen.as<AsyncFunctionGeneratorObject>(), reason, stack);
   3819      if (!promise) {
   3820        goto error;
   3821      }
   3822 
   3823      REGS.sp -= 2;
   3824      REGS.sp[-1].setObject(*promise);
   3825    }
   3826    END_CASE(AsyncReject)
   3827 
   3828    CASE(SetFunName) {
   3829      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3830      FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(REGS.pc));
   3831      ReservedRooted<Value> name(&rootValue0, REGS.sp[-1]);
   3832      ReservedRooted<JSFunction*> fun(&rootFunction0,
   3833                                      &REGS.sp[-2].toObject().as<JSFunction>());
   3834      if (!SetFunctionName(cx, fun, name, prefixKind)) {
   3835        goto error;
   3836      }
   3837 
   3838      REGS.sp--;
   3839    }
   3840    END_CASE(SetFunName)
   3841 
   3842    CASE(Callee) {
   3843      MOZ_ASSERT(REGS.fp()->isFunctionFrame());
   3844      PUSH_COPY(REGS.fp()->calleev());
   3845    }
   3846    END_CASE(Callee)
   3847 
   3848    CASE(InitPropGetter)
   3849    CASE(InitHiddenPropGetter)
   3850    CASE(InitPropSetter)
   3851    CASE(InitHiddenPropSetter) {
   3852      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3853 
   3854      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
   3855      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   3856      ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
   3857 
   3858      if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
   3859        goto error;
   3860      }
   3861 
   3862      REGS.sp--;
   3863    }
   3864    END_CASE(InitPropGetter)
   3865 
   3866    CASE(InitElemGetter)
   3867    CASE(InitHiddenElemGetter)
   3868    CASE(InitElemSetter)
   3869    CASE(InitHiddenElemSetter) {
   3870      MOZ_ASSERT(REGS.stackDepth() >= 3);
   3871 
   3872      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
   3873      ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
   3874      ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
   3875 
   3876      if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
   3877        goto error;
   3878      }
   3879 
   3880      REGS.sp -= 2;
   3881    }
   3882    END_CASE(InitElemGetter)
   3883 
   3884    CASE(Hole) { PUSH_MAGIC(JS_ELEMENTS_HOLE); }
   3885    END_CASE(Hole)
   3886 
   3887    CASE(NewInit) {
   3888      JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
   3889 
   3890      if (!obj) {
   3891        goto error;
   3892      }
   3893      PUSH_OBJECT(*obj);
   3894    }
   3895    END_CASE(NewInit)
   3896 
   3897    CASE(NewArray) {
   3898      uint32_t length = GET_UINT32(REGS.pc);
   3899      ArrayObject* obj = NewArrayOperation(cx, length);
   3900      if (!obj) {
   3901        goto error;
   3902      }
   3903      PUSH_OBJECT(*obj);
   3904    }
   3905    END_CASE(NewArray)
   3906 
   3907    CASE(NewObject) {
   3908      JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
   3909      if (!obj) {
   3910        goto error;
   3911      }
   3912      PUSH_OBJECT(*obj);
   3913    }
   3914    END_CASE(NewObject)
   3915 
   3916    CASE(MutateProto) {
   3917      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3918 
   3919      if (REGS.sp[-1].isObjectOrNull()) {
   3920        ReservedRooted<JSObject*> newProto(&rootObject1,
   3921                                           REGS.sp[-1].toObjectOrNull());
   3922        ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
   3923        MOZ_ASSERT(obj->is<PlainObject>());
   3924 
   3925        if (!SetPrototype(cx, obj, newProto)) {
   3926          goto error;
   3927        }
   3928      }
   3929 
   3930      REGS.sp--;
   3931    }
   3932    END_CASE(MutateProto)
   3933 
   3934    CASE(InitProp)
   3935    CASE(InitLockedProp)
   3936    CASE(InitHiddenProp) {
   3937      static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp,
   3938                    "initprop and initlockedprop must be the same size");
   3939      static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp,
   3940                    "initprop and inithiddenprop must be the same size");
   3941      /* Load the property's initial value into rval. */
   3942      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3943      ReservedRooted<Value> rval(&rootValue0, REGS.sp[-1]);
   3944 
   3945      /* Load the object being initialized into lval/obj. */
   3946      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
   3947 
   3948      ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
   3949 
   3950      if (!InitPropertyOperation(cx, REGS.pc, obj, name, rval)) {
   3951        goto error;
   3952      }
   3953 
   3954      REGS.sp--;
   3955    }
   3956    END_CASE(InitProp)
   3957 
   3958    CASE(InitElem)
   3959    CASE(InitHiddenElem)
   3960    CASE(InitLockedElem) {
   3961      MOZ_ASSERT(REGS.stackDepth() >= 3);
   3962      HandleValue val = REGS.stackHandleAt(-1);
   3963      HandleValue id = REGS.stackHandleAt(-2);
   3964 
   3965      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
   3966 
   3967      if (!InitElemOperation(cx, REGS.pc, obj, id, val)) {
   3968        goto error;
   3969      }
   3970 
   3971      REGS.sp -= 2;
   3972    }
   3973    END_CASE(InitElem)
   3974 
   3975    CASE(InitElemArray) {
   3976      MOZ_ASSERT(REGS.stackDepth() >= 2);
   3977      HandleValue val = REGS.stackHandleAt(-1);
   3978      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
   3979 
   3980      InitElemArrayOperation(cx, REGS.pc, obj.as<ArrayObject>(), val);
   3981      REGS.sp--;
   3982    }
   3983    END_CASE(InitElemArray)
   3984 
   3985    CASE(InitElemInc) {
   3986      MOZ_ASSERT(REGS.stackDepth() >= 3);
   3987      HandleValue val = REGS.stackHandleAt(-1);
   3988 
   3989      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
   3990 
   3991      uint32_t index = REGS.sp[-2].toInt32();
   3992      if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index, val)) {
   3993        goto error;
   3994      }
   3995 
   3996      REGS.sp[-2].setInt32(index + 1);
   3997      REGS.sp--;
   3998    }
   3999    END_CASE(InitElemInc)
   4000 
   4001    CASE(Exception) {
   4002      PUSH_NULL();
   4003      MutableHandleValue res = REGS.stackHandleAt(-1);
   4004      if (!GetAndClearException(cx, res)) {
   4005        goto error;
   4006      }
   4007    }
   4008    END_CASE(Exception)
   4009 
   4010    CASE(ExceptionAndStack) {
   4011      ReservedRooted<Value> stack(&rootValue0);
   4012      if (!cx->getPendingExceptionStack(&stack)) {
   4013        goto error;
   4014      }
   4015      PUSH_NULL();
   4016      MutableHandleValue res = REGS.stackHandleAt(-1);
   4017      if (!GetAndClearException(cx, res)) {
   4018        goto error;
   4019      }
   4020      PUSH_COPY(stack);
   4021    }
   4022    END_CASE(ExceptionAndStack)
   4023 
   4024    CASE(Finally) { CHECK_BRANCH(); }
   4025    END_CASE(Finally)
   4026 
   4027    CASE(Throw) {
   4028      CHECK_BRANCH();
   4029      ReservedRooted<Value> v(&rootValue0);
   4030      POP_COPY_TO(v);
   4031      MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
   4032      /* let the code at error try to catch the exception. */
   4033      goto error;
   4034    }
   4035 
   4036    CASE(ThrowWithStack) {
   4037      CHECK_BRANCH();
   4038      ReservedRooted<Value> v(&rootValue0);
   4039      ReservedRooted<Value> stack(&rootValue1);
   4040      POP_COPY_TO(stack);
   4041      POP_COPY_TO(v);
   4042      MOZ_ALWAYS_FALSE(ThrowWithStackOperation(cx, v, stack));
   4043      /* let the code at error try to catch the exception. */
   4044      goto error;
   4045    }
   4046 
   4047    CASE(Instanceof) {
   4048      ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
   4049      if (HandleValue(rref).isPrimitive()) {
   4050        ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
   4051        goto error;
   4052      }
   4053      ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
   4054      bool cond = false;
   4055      if (!InstanceofOperator(cx, obj, REGS.stackHandleAt(-2), &cond)) {
   4056        goto error;
   4057      }
   4058      REGS.sp--;
   4059      REGS.sp[-1].setBoolean(cond);
   4060    }
   4061    END_CASE(Instanceof)
   4062 
   4063    CASE(Debugger) {
   4064      if (!DebugAPI::onDebuggerStatement(cx, REGS.fp())) {
   4065        goto error;
   4066      }
   4067    }
   4068    END_CASE(Debugger)
   4069 
   4070    CASE(PushLexicalEnv) {
   4071      ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
   4072 
   4073      // Create block environment and push on scope chain.
   4074      if (!REGS.fp()->pushLexicalEnvironment(cx, scope.as<LexicalScope>())) {
   4075        goto error;
   4076      }
   4077    }
   4078    END_CASE(PushLexicalEnv)
   4079 
   4080    CASE(PopLexicalEnv) {
   4081 #ifdef DEBUG
   4082      Scope* scope = script->lookupScope(REGS.pc);
   4083      MOZ_ASSERT(scope);
   4084      MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
   4085      MOZ_ASSERT_IF(scope->is<LexicalScope>(),
   4086                    scope->as<LexicalScope>().hasEnvironment());
   4087      MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
   4088                    scope->as<ClassBodyScope>().hasEnvironment());
   4089 #endif
   4090 
   4091      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   4092        DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
   4093      }
   4094 
   4095      // Pop block from scope chain.
   4096      REGS.fp()->popOffEnvironmentChain<LexicalEnvironmentObject>();
   4097    }
   4098    END_CASE(PopLexicalEnv)
   4099 
   4100    CASE(DebugLeaveLexicalEnv) {
   4101 #ifdef DEBUG
   4102      Scope* scope = script->lookupScope(REGS.pc);
   4103      MOZ_ASSERT(scope);
   4104      MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
   4105      MOZ_ASSERT_IF(scope->is<LexicalScope>(),
   4106                    !scope->as<LexicalScope>().hasEnvironment());
   4107      MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
   4108                    !scope->as<ClassBodyScope>().hasEnvironment());
   4109 #endif
   4110      // FIXME: This opcode should not be necessary.  The debugger shouldn't
   4111      // need help from bytecode to do its job.  See bug 927782.
   4112 
   4113      if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
   4114        DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
   4115      }
   4116    }
   4117    END_CASE(DebugLeaveLexicalEnv)
   4118 
   4119    CASE(FreshenLexicalEnv) {
   4120 #ifdef DEBUG
   4121      Scope* scope = script->getScope(REGS.pc);
   4122      auto envChain = REGS.fp()->environmentChain();
   4123      auto* envScope = &envChain->as<BlockLexicalEnvironmentObject>().scope();
   4124      MOZ_ASSERT(scope == envScope);
   4125 #endif
   4126 
   4127      if (!REGS.fp()->freshenLexicalEnvironment(cx, REGS.pc)) {
   4128        goto error;
   4129      }
   4130    }
   4131    END_CASE(FreshenLexicalEnv)
   4132 
   4133    CASE(RecreateLexicalEnv) {
   4134 #ifdef DEBUG
   4135      Scope* scope = script->getScope(REGS.pc);
   4136      auto envChain = REGS.fp()->environmentChain();
   4137      auto* envScope = &envChain->as<BlockLexicalEnvironmentObject>().scope();
   4138      MOZ_ASSERT(scope == envScope);
   4139 #endif
   4140 
   4141      if (!REGS.fp()->recreateLexicalEnvironment(cx, REGS.pc)) {
   4142        goto error;
   4143      }
   4144    }
   4145    END_CASE(RecreateLexicalEnv)
   4146 
   4147    CASE(PushClassBodyEnv) {
   4148      ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
   4149 
   4150      if (!REGS.fp()->pushClassBodyEnvironment(cx,
   4151                                               scope.as<ClassBodyScope>())) {
   4152        goto error;
   4153      }
   4154    }
   4155    END_CASE(PushClassBodyEnv)
   4156 
   4157    CASE(PushVarEnv) {
   4158      ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
   4159 
   4160      if (!REGS.fp()->pushVarEnvironment(cx, scope)) {
   4161        goto error;
   4162      }
   4163    }
   4164    END_CASE(PushVarEnv)
   4165 
   4166    CASE(Generator) {
   4167      MOZ_ASSERT(!cx->isExceptionPending());
   4168      MOZ_ASSERT(REGS.stackDepth() == 0);
   4169      JSObject* obj = AbstractGeneratorObject::createFromFrame(cx, REGS.fp());
   4170      if (!obj) {
   4171        goto error;
   4172      }
   4173      PUSH_OBJECT(*obj);
   4174    }
   4175    END_CASE(Generator)
   4176 
   4177    CASE(InitialYield) {
   4178      MOZ_ASSERT(!cx->isExceptionPending());
   4179      MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
   4180                    REGS.fp()->isModuleFrame());
   4181      MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
   4182                    REGS.fp()->isFunctionFrame());
   4183      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
   4184      POP_RETURN_VALUE();
   4185      MOZ_ASSERT(REGS.stackDepth() == 0);
   4186      if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
   4187                                            script->nfixed())) {
   4188        goto error;
   4189      }
   4190      goto successful_return_continuation;
   4191    }
   4192 
   4193    CASE(Yield)
   4194    CASE(Await) {
   4195      MOZ_ASSERT(!cx->isExceptionPending());
   4196      MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
   4197                    REGS.fp()->isModuleFrame());
   4198      MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
   4199                    REGS.fp()->isFunctionFrame());
   4200      ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
   4201      if (!AbstractGeneratorObject::suspend(
   4202              cx, obj, REGS.fp(), REGS.pc,
   4203              script->nfixed() + REGS.stackDepth() - 2)) {
   4204        goto error;
   4205      }
   4206 
   4207      REGS.sp--;
   4208      POP_RETURN_VALUE();
   4209 
   4210      goto successful_return_continuation;
   4211    }
   4212 
   4213    CASE(ResumeKind) {
   4214      GeneratorResumeKind resumeKind = ResumeKindFromPC(REGS.pc);
   4215      PUSH_INT32(int32_t(resumeKind));
   4216    }
   4217    END_CASE(ResumeKind)
   4218 
   4219    CASE(CheckResumeKind) {
   4220      int32_t kindInt = REGS.sp[-1].toInt32();
   4221      GeneratorResumeKind resumeKind = IntToResumeKind(kindInt);
   4222      if (MOZ_UNLIKELY(resumeKind != GeneratorResumeKind::Next)) {
   4223        ReservedRooted<Value> val(&rootValue0, REGS.sp[-3]);
   4224        Rooted<AbstractGeneratorObject*> gen(
   4225            cx, &REGS.sp[-2].toObject().as<AbstractGeneratorObject>());
   4226        MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen,
   4227                                                val, resumeKind));
   4228        goto error;
   4229      }
   4230      REGS.sp -= 2;
   4231    }
   4232    END_CASE(CheckResumeKind)
   4233 
   4234    CASE(Resume) {
   4235      {
   4236        Rooted<AbstractGeneratorObject*> gen(
   4237            cx, &REGS.sp[-3].toObject().as<AbstractGeneratorObject>());
   4238        ReservedRooted<Value> val(&rootValue0, REGS.sp[-2]);
   4239        ReservedRooted<Value> resumeKindVal(&rootValue1, REGS.sp[-1]);
   4240 
   4241        // popInlineFrame expects there to be an additional value on the stack
   4242        // to pop off, so leave "gen" on the stack.
   4243        REGS.sp -= 1;
   4244 
   4245        if (!AbstractGeneratorObject::resume(cx, activation, gen, val,
   4246                                             resumeKindVal)) {
   4247          goto error;
   4248        }
   4249 
   4250        JSScript* generatorScript = REGS.fp()->script();
   4251        if (cx->realm() != generatorScript->realm()) {
   4252          cx->enterRealmOf(generatorScript);
   4253        }
   4254        SET_SCRIPT(generatorScript);
   4255 
   4256        if (!probes::EnterScript(cx, generatorScript,
   4257                                 generatorScript->function(), REGS.fp())) {
   4258          goto error;
   4259        }
   4260 
   4261        if (!DebugAPI::onResumeFrame(cx, REGS.fp())) {
   4262          MOZ_ASSERT_IF(cx->isPropagatingForcedReturn(), gen->isClosed());
   4263          goto error;
   4264        }
   4265      }
   4266      ADVANCE_AND_DISPATCH(0);
   4267    }
   4268 
   4269    CASE(AfterYield) {
   4270      // AbstractGeneratorObject::resume takes care of setting the frame's
   4271      // debuggee flag.
   4272      MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
   4273      COUNT_COVERAGE();
   4274    }
   4275    END_CASE(AfterYield)
   4276 
   4277    CASE(FinalYieldRval) {
   4278      ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-1].toObject());
   4279      REGS.sp--;
   4280      AbstractGeneratorObject::finalSuspend(cx, gen);
   4281      goto successful_return_continuation;
   4282    }
   4283 
   4284    CASE(CheckClassHeritage) {
   4285      HandleValue heritage = REGS.stackHandleAt(-1);
   4286 
   4287      if (!CheckClassHeritageOperation(cx, heritage)) {
   4288        goto error;
   4289      }
   4290    }
   4291    END_CASE(CheckClassHeritage)
   4292 
   4293    CASE(BuiltinObject) {
   4294      auto kind = BuiltinObjectKind(GET_UINT8(REGS.pc));
   4295      JSObject* builtin = BuiltinObjectOperation(cx, kind);
   4296      if (!builtin) {
   4297        goto error;
   4298      }
   4299      PUSH_OBJECT(*builtin);
   4300    }
   4301    END_CASE(BuiltinObject)
   4302 
   4303    CASE(FunWithProto) {
   4304      ReservedRooted<JSObject*> proto(&rootObject1, &REGS.sp[-1].toObject());
   4305 
   4306      /* Load the specified function object literal. */
   4307      ReservedRooted<JSFunction*> fun(&rootFunction0,
   4308                                      script->getFunction(REGS.pc));
   4309 
   4310      JSObject* obj =
   4311          FunWithProtoOperation(cx, fun, REGS.fp()->environmentChain(), proto);
   4312      if (!obj) {
   4313        goto error;
   4314      }
   4315 
   4316      REGS.sp[-1].setObject(*obj);
   4317    }
   4318    END_CASE(FunWithProto)
   4319 
   4320    CASE(ObjWithProto) {
   4321      JSObject* obj = ObjectWithProtoOperation(cx, REGS.stackHandleAt(-1));
   4322      if (!obj) {
   4323        goto error;
   4324      }
   4325 
   4326      REGS.sp[-1].setObject(*obj);
   4327    }
   4328    END_CASE(ObjWithProto)
   4329 
   4330    CASE(InitHomeObject) {
   4331      MOZ_ASSERT(REGS.stackDepth() >= 2);
   4332 
   4333      /* Load the function to be initialized */
   4334      JSFunction* func = &REGS.sp[-2].toObject().as<JSFunction>();
   4335      MOZ_ASSERT(func->allowSuperProperty());
   4336 
   4337      /* Load the home object */
   4338      JSObject* obj = &REGS.sp[-1].toObject();
   4339      MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
   4340 
   4341      func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
   4342                            ObjectValue(*obj));
   4343      REGS.sp--;
   4344    }
   4345    END_CASE(InitHomeObject)
   4346 
   4347    CASE(SuperBase) {
   4348      JSFunction& superEnvFunc = REGS.sp[-1].toObject().as<JSFunction>();
   4349      MOZ_ASSERT(superEnvFunc.allowSuperProperty());
   4350      MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject());
   4351      const Value& homeObjVal = superEnvFunc.getExtendedSlot(
   4352          FunctionExtended::METHOD_HOMEOBJECT_SLOT);
   4353 
   4354      JSObject* homeObj = &homeObjVal.toObject();
   4355      JSObject* superBase = HomeObjectSuperBase(homeObj);
   4356 
   4357      REGS.sp[-1].setObjectOrNull(superBase);
   4358    }
   4359    END_CASE(SuperBase)
   4360 
   4361    CASE(NewTarget) {
   4362      PUSH_COPY(REGS.fp()->newTarget());
   4363      MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
   4364    }
   4365    END_CASE(NewTarget)
   4366 
   4367    CASE(ImportMeta) {
   4368      JSObject* metaObject = ImportMetaOperation(cx, script);
   4369      if (!metaObject) {
   4370        goto error;
   4371      }
   4372 
   4373      PUSH_OBJECT(*metaObject);
   4374    }
   4375    END_CASE(ImportMeta)
   4376 
   4377    CASE(DynamicImport) {
   4378      ReservedRooted<Value> options(&rootValue0, REGS.sp[-1]);
   4379      REGS.sp--;
   4380 
   4381      ReservedRooted<Value> specifier(&rootValue1);
   4382      POP_COPY_TO(specifier);
   4383 
   4384      JSObject* promise =
   4385          StartDynamicModuleImport(cx, script, specifier, options);
   4386      if (!promise) goto error;
   4387 
   4388      PUSH_OBJECT(*promise);
   4389    }
   4390    END_CASE(DynamicImport)
   4391 
   4392    CASE(EnvCallee) {
   4393      uint16_t numHops = GET_ENVCOORD_HOPS(REGS.pc);
   4394      JSObject* env = &REGS.fp()->environmentChain()->as<EnvironmentObject>();
   4395      for (unsigned i = 0; i < numHops; i++) {
   4396        env = &env->as<EnvironmentObject>().enclosingEnvironment();
   4397      }
   4398      PUSH_OBJECT(env->as<CallObject>().callee());
   4399    }
   4400    END_CASE(EnvCallee)
   4401 
   4402    CASE(SuperFun) {
   4403      JSObject* superEnvFunc = &REGS.sp[-1].toObject();
   4404      JSObject* superFun = SuperFunOperation(superEnvFunc);
   4405      REGS.sp[-1].setObjectOrNull(superFun);
   4406    }
   4407    END_CASE(SuperFun)
   4408 
   4409    CASE(CheckObjCoercible) {
   4410      ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
   4411      if (checkVal.isNullOrUndefined()) {
   4412        MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, checkVal));
   4413        goto error;
   4414      }
   4415    }
   4416    END_CASE(CheckObjCoercible)
   4417 
   4418    CASE(DebugCheckSelfHosted) {
   4419 #ifdef DEBUG
   4420      ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
   4421      if (!Debug_CheckSelfHosted(cx, checkVal)) {
   4422        goto error;
   4423      }
   4424 #endif
   4425    }
   4426    END_CASE(DebugCheckSelfHosted)
   4427 
   4428    CASE(IsConstructing) { PUSH_MAGIC(JS_IS_CONSTRUCTING); }
   4429    END_CASE(IsConstructing)
   4430 
   4431    CASE(Inc) {
   4432      MutableHandleValue val = REGS.stackHandleAt(-1);
   4433      if (!IncOperation(cx, val, val)) {
   4434        goto error;
   4435      }
   4436    }
   4437    END_CASE(Inc)
   4438 
   4439    CASE(Dec) {
   4440      MutableHandleValue val = REGS.stackHandleAt(-1);
   4441      if (!DecOperation(cx, val, val)) {
   4442        goto error;
   4443      }
   4444    }
   4445    END_CASE(Dec)
   4446 
   4447    CASE(ToNumeric) {
   4448      if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
   4449        goto error;
   4450      }
   4451    }
   4452    END_CASE(ToNumeric)
   4453 
   4454    CASE(BigInt) { PUSH_BIGINT(script->getBigInt(REGS.pc)); }
   4455    END_CASE(BigInt)
   4456 
   4457    DEFAULT() {
   4458      char numBuf[12];
   4459      SprintfLiteral(numBuf, "%d", *REGS.pc);
   4460      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   4461                                JSMSG_BAD_BYTECODE, numBuf);
   4462      goto error;
   4463    }
   4464 
   4465  } /* interpreter loop */
   4466 
   4467  MOZ_CRASH("Interpreter loop exited via fallthrough");
   4468 
   4469 error:
   4470  switch (HandleError(cx, REGS)) {
   4471    case SuccessfulReturnContinuation:
   4472      goto successful_return_continuation;
   4473 
   4474    case ErrorReturnContinuation:
   4475      CheckForOOMStackTraceInterrupt(cx);
   4476      interpReturnOK = false;
   4477      goto return_continuation;
   4478 
   4479    case CatchContinuation:
   4480      ADVANCE_AND_DISPATCH(0);
   4481 
   4482    case FinallyContinuation: {
   4483      /*
   4484       * Push (exception, stack, true) triple for finally to indicate that we
   4485       * should rethrow the exception.
   4486       */
   4487      ReservedRooted<Value> exception(&rootValue0);
   4488      ReservedRooted<Value> exceptionStack(&rootValue1);
   4489      if (!cx->getPendingException(&exception) ||
   4490          !cx->getPendingExceptionStack(&exceptionStack)) {
   4491        interpReturnOK = false;
   4492        goto return_continuation;
   4493      }
   4494      PUSH_COPY(exception);
   4495      PUSH_COPY(exceptionStack);
   4496      PUSH_BOOLEAN(true);
   4497      cx->clearPendingException();
   4498    }
   4499      ADVANCE_AND_DISPATCH(0);
   4500  }
   4501 
   4502  MOZ_CRASH("Invalid HandleError continuation");
   4503 
   4504 exit:
   4505  if (MOZ_LIKELY(!frameHalfInitialized)) {
   4506    interpReturnOK =
   4507        DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
   4508 
   4509    REGS.fp()->epilogue(cx, REGS.pc);
   4510  }
   4511 
   4512  gc::MaybeVerifyBarriers(cx, true);
   4513 
   4514  /*
   4515   * This path is used when it's guaranteed the method can be finished
   4516   * inside the JIT.
   4517   */
   4518 leave_on_safe_point:
   4519 
   4520  if (interpReturnOK) {
   4521    state.setReturnValue(activation.entryFrame()->returnValue());
   4522  }
   4523 
   4524  return interpReturnOK;
   4525 
   4526 prologue_error:
   4527  interpReturnOK = false;
   4528  frameHalfInitialized = true;
   4529  goto prologue_return_continuation;
   4530 }
   4531 
   4532 bool js::ThrowOperation(JSContext* cx, HandleValue v) {
   4533  MOZ_ASSERT(!cx->isExceptionPending());
   4534  cx->setPendingException(v, ShouldCaptureStack::Maybe);
   4535  return false;
   4536 }
   4537 
   4538 bool js::ThrowWithStackOperation(JSContext* cx, HandleValue v,
   4539                                 HandleValue stack) {
   4540  MOZ_ASSERT(!cx->isExceptionPending());
   4541  MOZ_ASSERT(stack.isObjectOrNull());
   4542 
   4543  // Use a normal throw when no stack was recorded.
   4544  if (!stack.isObject()) {
   4545    return ThrowOperation(cx, v);
   4546  }
   4547 
   4548  MOZ_ASSERT(UncheckedUnwrap(&stack.toObject())->is<SavedFrame>() ||
   4549             IsDeadProxyObject(&stack.toObject()));
   4550 
   4551  Rooted<SavedFrame*> stackObj(cx,
   4552                               stack.toObject().maybeUnwrapIf<SavedFrame>());
   4553  cx->setPendingException(v, stackObj);
   4554  return false;
   4555 }
   4556 
   4557 bool js::GetPendingExceptionStack(JSContext* cx, MutableHandleValue vp) {
   4558  MOZ_ASSERT(cx->isExceptionPending());
   4559  return cx->getPendingExceptionStack(vp);
   4560 }
   4561 
   4562 bool js::GetProperty(JSContext* cx, HandleValue v, Handle<PropertyName*> name,
   4563                     MutableHandleValue vp) {
   4564  if (name == cx->names().length) {
   4565    // Fast path for strings, arrays and arguments.
   4566    if (::GetLengthProperty(v, vp)) {
   4567      return true;
   4568    }
   4569  }
   4570 
   4571  // Optimize common cases like (2).toString() or "foo".valueOf() to not
   4572  // create a wrapper object.
   4573  if (v.isPrimitive() && !v.isNullOrUndefined()) {
   4574    JSObject* proto;
   4575 
   4576    switch (v.type()) {
   4577      case ValueType::Double:
   4578      case ValueType::Int32:
   4579        proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
   4580        break;
   4581      case ValueType::Boolean:
   4582        proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
   4583        break;
   4584      case ValueType::String:
   4585        proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
   4586        break;
   4587      case ValueType::Symbol:
   4588        proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
   4589        break;
   4590      case ValueType::BigInt:
   4591        proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
   4592        break;
   4593      case ValueType::Undefined:
   4594      case ValueType::Null:
   4595      case ValueType::Magic:
   4596      case ValueType::PrivateGCThing:
   4597      case ValueType::Object:
   4598        MOZ_CRASH("unexpected type");
   4599    }
   4600 
   4601    if (!proto) {
   4602      return false;
   4603    }
   4604 
   4605    if (GetPropertyPure(cx, proto, NameToId(name), vp.address())) {
   4606      return true;
   4607    }
   4608  }
   4609 
   4610  RootedValue receiver(cx, v);
   4611  RootedObject obj(
   4612      cx, ToObjectFromStackForPropertyAccess(cx, v, JSDVG_SEARCH_STACK, name));
   4613  if (!obj) {
   4614    return false;
   4615  }
   4616 
   4617  return GetProperty(cx, obj, receiver, name, vp);
   4618 }
   4619 
   4620 JSObject* js::LambdaBaselineFallback(JSContext* cx, HandleFunction fun,
   4621                                     HandleObject parent, gc::AllocSite* site) {
   4622  MOZ_ASSERT(site);
   4623  gc::Heap heap = site->initialHeap();
   4624  JSObject* obj = Lambda(cx, fun, parent, heap, site);
   4625  MOZ_ASSERT_IF(obj && heap == gc::Heap::Tenured, obj->isTenured());
   4626  return obj;
   4627 }
   4628 
   4629 JSObject* js::LambdaOptimizedFallback(JSContext* cx, HandleFunction fun,
   4630                                      HandleObject parent, gc::Heap heap) {
   4631  // It's important to use the correct heap here so that tenured allocation
   4632  // fallback will refill the appropriate free list allowing subsequent JIT
   4633  // allocation in tenured heap to succeed.
   4634  gc::AllocSite* site = cx->zone()->optimizedAllocSite();
   4635  JSObject* obj = Lambda(cx, fun, parent, heap, site);
   4636  MOZ_ASSERT_IF(obj && heap == gc::Heap::Tenured, obj->isTenured());
   4637  return obj;
   4638 }
   4639 
   4640 JSObject* js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent,
   4641                     gc::Heap heap, gc::AllocSite* site) {
   4642  JSFunction* clone;
   4643  if (fun->isNativeFun()) {
   4644    MOZ_ASSERT(IsAsmJSModule(fun));
   4645    MOZ_ASSERT(heap == gc::Heap::Default);  // Not supported.
   4646    clone = CloneAsmJSModuleFunction(cx, fun);
   4647  } else {
   4648    RootedObject proto(cx, fun->staticPrototype());
   4649    clone = CloneFunctionReuseScript(cx, fun, parent, proto, heap, site);
   4650  }
   4651  if (!clone) {
   4652    return nullptr;
   4653  }
   4654 
   4655  MOZ_ASSERT(fun->global() == clone->global());
   4656  return clone;
   4657 }
   4658 
   4659 JSObject* js::BindVarOperation(JSContext* cx, JSObject* envChain) {
   4660  // Note: BindVarOperation has an unused cx argument because the JIT callVM
   4661  // machinery requires this.
   4662  return &GetVariablesObject(envChain);
   4663 }
   4664 
   4665 JSObject* js::ImportMetaOperation(JSContext* cx, HandleScript script) {
   4666  RootedObject module(cx, GetModuleObjectForScript(script));
   4667  return GetOrCreateModuleMetaObject(cx, module);
   4668 }
   4669 
   4670 JSObject* js::BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind) {
   4671  return GetOrCreateBuiltinObject(cx, kind);
   4672 }
   4673 
   4674 bool js::ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind) {
   4675  auto errorNum = ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind));
   4676  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNum);
   4677  return false;
   4678 }
   4679 
   4680 bool js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
   4681                                      MutableHandle<SavedFrame*> stack) {
   4682  if (!cx->getPendingException(res)) {
   4683    return false;
   4684  }
   4685  stack.set(cx->getPendingExceptionStack());
   4686  cx->clearPendingException();
   4687 
   4688  // Allow interrupting deeply nested exception handling.
   4689  return CheckForInterrupt(cx);
   4690 }
   4691 
   4692 bool js::GetAndClearException(JSContext* cx, MutableHandleValue res) {
   4693  Rooted<SavedFrame*> stack(cx);
   4694  return GetAndClearExceptionAndStack(cx, res, &stack);
   4695 }
   4696 
   4697 template <bool strict>
   4698 bool js::DelPropOperation(JSContext* cx, HandleValue val,
   4699                          Handle<PropertyName*> name, bool* res) {
   4700  const int valIndex = -1;
   4701  RootedObject obj(cx,
   4702                   ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
   4703  if (!obj) {
   4704    return false;
   4705  }
   4706 
   4707  RootedId id(cx, NameToId(name));
   4708  ObjectOpResult result;
   4709  if (!DeleteProperty(cx, obj, id, result)) {
   4710    return false;
   4711  }
   4712 
   4713  if (strict) {
   4714    if (!result) {
   4715      return result.reportError(cx, obj, id);
   4716    }
   4717    *res = true;
   4718  } else {
   4719    *res = result.ok();
   4720  }
   4721  return true;
   4722 }
   4723 
   4724 template bool js::DelPropOperation<true>(JSContext* cx, HandleValue val,
   4725                                         Handle<PropertyName*> name, bool* res);
   4726 template bool js::DelPropOperation<false>(JSContext* cx, HandleValue val,
   4727                                          Handle<PropertyName*> name,
   4728                                          bool* res);
   4729 
   4730 template <bool strict>
   4731 bool js::DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
   4732                          bool* res) {
   4733  const int valIndex = -2;
   4734  RootedObject obj(
   4735      cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, index));
   4736  if (!obj) {
   4737    return false;
   4738  }
   4739 
   4740  RootedId id(cx);
   4741  if (!ToPropertyKey(cx, index, &id)) {
   4742    return false;
   4743  }
   4744  ObjectOpResult result;
   4745  if (!DeleteProperty(cx, obj, id, result)) {
   4746    return false;
   4747  }
   4748 
   4749  if (strict) {
   4750    if (!result) {
   4751      return result.reportError(cx, obj, id);
   4752    }
   4753    *res = true;
   4754  } else {
   4755    *res = result.ok();
   4756  }
   4757  return true;
   4758 }
   4759 
   4760 template bool js::DelElemOperation<true>(JSContext*, HandleValue, HandleValue,
   4761                                         bool*);
   4762 template bool js::DelElemOperation<false>(JSContext*, HandleValue, HandleValue,
   4763                                          bool*);
   4764 
   4765 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
   4766                          HandleValue value, bool strict) {
   4767  RootedId id(cx);
   4768  if (!ToPropertyKey(cx, index, &id)) {
   4769    return false;
   4770  }
   4771  RootedValue receiver(cx, ObjectValue(*obj));
   4772  return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
   4773 }
   4774 
   4775 bool js::SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
   4776                                      HandleValue index, HandleValue value,
   4777                                      HandleValue receiver, bool strict) {
   4778  RootedId id(cx);
   4779  if (!ToPropertyKey(cx, index, &id)) {
   4780    return false;
   4781  }
   4782  return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
   4783 }
   4784 
   4785 bool js::AddValues(JSContext* cx, MutableHandleValue lhs,
   4786                   MutableHandleValue rhs, MutableHandleValue res) {
   4787  return AddOperation(cx, lhs, rhs, res);
   4788 }
   4789 
   4790 bool js::SubValues(JSContext* cx, MutableHandleValue lhs,
   4791                   MutableHandleValue rhs, MutableHandleValue res) {
   4792  return SubOperation(cx, lhs, rhs, res);
   4793 }
   4794 
   4795 bool js::MulValues(JSContext* cx, MutableHandleValue lhs,
   4796                   MutableHandleValue rhs, MutableHandleValue res) {
   4797  return MulOperation(cx, lhs, rhs, res);
   4798 }
   4799 
   4800 bool js::DivValues(JSContext* cx, MutableHandleValue lhs,
   4801                   MutableHandleValue rhs, MutableHandleValue res) {
   4802  return DivOperation(cx, lhs, rhs, res);
   4803 }
   4804 
   4805 bool js::ModValues(JSContext* cx, MutableHandleValue lhs,
   4806                   MutableHandleValue rhs, MutableHandleValue res) {
   4807  return ModOperation(cx, lhs, rhs, res);
   4808 }
   4809 
   4810 bool js::PowValues(JSContext* cx, MutableHandleValue lhs,
   4811                   MutableHandleValue rhs, MutableHandleValue res) {
   4812  return PowOperation(cx, lhs, rhs, res);
   4813 }
   4814 
   4815 bool js::BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res) {
   4816  return BitNotOperation(cx, in, res);
   4817 }
   4818 
   4819 bool js::BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4820                MutableHandleValue res) {
   4821  return BitXorOperation(cx, lhs, rhs, res);
   4822 }
   4823 
   4824 bool js::BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4825               MutableHandleValue res) {
   4826  return BitOrOperation(cx, lhs, rhs, res);
   4827 }
   4828 
   4829 bool js::BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4830                MutableHandleValue res) {
   4831  return BitAndOperation(cx, lhs, rhs, res);
   4832 }
   4833 
   4834 bool js::BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4835                MutableHandleValue res) {
   4836  return BitLshOperation(cx, lhs, rhs, res);
   4837 }
   4838 
   4839 bool js::BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4840                MutableHandleValue res) {
   4841  return BitRshOperation(cx, lhs, rhs, res);
   4842 }
   4843 
   4844 bool js::UrshValues(JSContext* cx, MutableHandleValue lhs,
   4845                    MutableHandleValue rhs, MutableHandleValue res) {
   4846  return UrshOperation(cx, lhs, rhs, res);
   4847 }
   4848 
   4849 bool js::LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
   4850                  bool* res) {
   4851  return LessThanOperation(cx, lhs, rhs, res);
   4852 }
   4853 
   4854 bool js::LessThanOrEqual(JSContext* cx, MutableHandleValue lhs,
   4855                         MutableHandleValue rhs, bool* res) {
   4856  return LessThanOrEqualOperation(cx, lhs, rhs, res);
   4857 }
   4858 
   4859 bool js::GreaterThan(JSContext* cx, MutableHandleValue lhs,
   4860                     MutableHandleValue rhs, bool* res) {
   4861  return GreaterThanOperation(cx, lhs, rhs, res);
   4862 }
   4863 
   4864 bool js::GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs,
   4865                            MutableHandleValue rhs, bool* res) {
   4866  return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
   4867 }
   4868 
   4869 bool js::DeleteNameOperation(JSContext* cx, Handle<PropertyName*> name,
   4870                             HandleObject envChain, MutableHandleValue res) {
   4871  RootedObject env(cx), pobj(cx);
   4872  PropertyResult prop;
   4873  if (!LookupName(cx, name, envChain, &env, &pobj, &prop)) {
   4874    return false;
   4875  }
   4876 
   4877  if (!env) {
   4878    // Return true for non-existent names.
   4879    res.setBoolean(true);
   4880    return true;
   4881  }
   4882 
   4883  ObjectOpResult result;
   4884  RootedId id(cx, NameToId(name));
   4885  if (!DeleteProperty(cx, env, id, result)) {
   4886    return false;
   4887  }
   4888 
   4889  bool status = result.ok();
   4890  res.setBoolean(status);
   4891 
   4892  return true;
   4893 }
   4894 
   4895 void js::ImplicitThisOperation(JSContext* cx, HandleObject env,
   4896                               MutableHandleValue res) {
   4897  // Note: ImplicitThisOperation has an unused cx argument because the JIT
   4898  // callVM machinery requires this.
   4899  res.set(ComputeImplicitThis(env));
   4900 }
   4901 
   4902 unsigned js::GetInitDataPropAttrs(JSOp op) {
   4903  switch (op) {
   4904    case JSOp::InitProp:
   4905    case JSOp::InitElem:
   4906      return JSPROP_ENUMERATE;
   4907    case JSOp::InitLockedProp:
   4908    case JSOp::InitLockedElem:
   4909      return JSPROP_PERMANENT | JSPROP_READONLY;
   4910    case JSOp::InitHiddenProp:
   4911    case JSOp::InitHiddenElem:
   4912      // Non-enumerable, but writable and configurable
   4913      return 0;
   4914    default:;
   4915  }
   4916  MOZ_CRASH("Unknown data initprop");
   4917 }
   4918 
   4919 static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
   4920                                      HandleObject obj, HandleId id,
   4921                                      HandleObject val) {
   4922  MOZ_ASSERT(val->isCallable());
   4923 
   4924  JSOp op = JSOp(*pc);
   4925 
   4926  unsigned attrs = 0;
   4927  if (!IsHiddenInitOp(op)) {
   4928    attrs |= JSPROP_ENUMERATE;
   4929  }
   4930 
   4931  if (op == JSOp::InitPropGetter || op == JSOp::InitElemGetter ||
   4932      op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter) {
   4933    return DefineAccessorProperty(cx, obj, id, val, nullptr, attrs);
   4934  }
   4935 
   4936  MOZ_ASSERT(op == JSOp::InitPropSetter || op == JSOp::InitElemSetter ||
   4937             op == JSOp::InitHiddenPropSetter ||
   4938             op == JSOp::InitHiddenElemSetter);
   4939  return DefineAccessorProperty(cx, obj, id, nullptr, val, attrs);
   4940 }
   4941 
   4942 bool js::InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
   4943                                       HandleObject obj,
   4944                                       Handle<PropertyName*> name,
   4945                                       HandleObject val) {
   4946  RootedId id(cx, NameToId(name));
   4947  return InitGetterSetterOperation(cx, pc, obj, id, val);
   4948 }
   4949 
   4950 bool js::InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
   4951                                       HandleObject obj, HandleValue idval,
   4952                                       HandleObject val) {
   4953  RootedId id(cx);
   4954  if (!ToPropertyKey(cx, idval, &id)) {
   4955    return false;
   4956  }
   4957 
   4958  return InitGetterSetterOperation(cx, pc, obj, id, val);
   4959 }
   4960 
   4961 bool js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
   4962                             HandleValue thisv, HandleValue callee,
   4963                             HandleValue arr, HandleValue newTarget,
   4964                             MutableHandleValue res) {
   4965  Rooted<ArrayObject*> aobj(cx, &arr.toObject().as<ArrayObject>());
   4966  uint32_t length = aobj->length();
   4967  JSOp op = JSOp(*pc);
   4968  bool constructing = op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall;
   4969 
   4970  // {Construct,Invoke}Args::init does this too, but this gives us a better
   4971  // error message.
   4972  if (length > ARGS_LENGTH_MAX) {
   4973    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   4974                              constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
   4975                                           : JSMSG_TOO_MANY_FUN_SPREADARGS);
   4976    return false;
   4977  }
   4978 
   4979  // Do our own checks for the callee being a function, as Invoke uses the
   4980  // expression decompiler to decompile the callee stack operand based on
   4981  // the number of arguments. Spread operations have the callee at sp - 3
   4982  // when not constructing, and sp - 4 when constructing.
   4983  if (callee.isPrimitive()) {
   4984    return ReportIsNotFunction(cx, callee, 2 + constructing,
   4985                               constructing ? CONSTRUCT : NO_CONSTRUCT);
   4986  }
   4987 
   4988  if (!callee.toObject().isCallable()) {
   4989    return ReportIsNotFunction(cx, callee, 2 + constructing,
   4990                               constructing ? CONSTRUCT : NO_CONSTRUCT);
   4991  }
   4992 
   4993  // The object must be an array with dense elements and no holes. Baseline's
   4994  // optimized spread call stubs rely on this.
   4995  MOZ_ASSERT(IsPackedArray(aobj));
   4996 
   4997  if (constructing) {
   4998    if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget)) {
   4999      return false;
   5000    }
   5001 
   5002    ConstructArgs cargs(cx);
   5003    if (!cargs.init(cx, length)) {
   5004      return false;
   5005    }
   5006 
   5007    if (!GetElements(cx, aobj, length, cargs.array())) {
   5008      return false;
   5009    }
   5010 
   5011    RootedObject obj(cx);
   5012    if (!Construct(cx, callee, cargs, newTarget, &obj)) {
   5013      return false;
   5014    }
   5015    res.setObject(*obj);
   5016  } else {
   5017    InvokeArgs args(cx);
   5018    if (!args.init(cx, length)) {
   5019      return false;
   5020    }
   5021 
   5022    if (!GetElements(cx, aobj, length, args.array())) {
   5023      return false;
   5024    }
   5025 
   5026    if ((op == JSOp::SpreadEval || op == JSOp::StrictSpreadEval) &&
   5027        cx->global()->valueIsEval(callee)) {
   5028      if (!DirectEval(cx, args.get(0), res)) {
   5029        return false;
   5030      }
   5031    } else {
   5032      MOZ_ASSERT(op == JSOp::SpreadCall || op == JSOp::SpreadEval ||
   5033                     op == JSOp::StrictSpreadEval,
   5034                 "bad spread opcode");
   5035 
   5036      if (!Call(cx, callee, thisv, args, res)) {
   5037        return false;
   5038      }
   5039    }
   5040  }
   5041 
   5042  return true;
   5043 }
   5044 
   5045 static bool OptimizeArrayIteration(JSObject* obj, JSContext* cx) {
   5046  // Optimize spread call by skipping spread operation when following
   5047  // conditions are met:
   5048  //   * the argument is an array
   5049  //   * the array has no hole
   5050  //   * array[@@iterator] is not modified
   5051  //   * the array's prototype is Array.prototype
   5052  //   * Array.prototype[@@iterator] is not modified
   5053  //   * %ArrayIteratorPrototype%.next is not modified
   5054  //   * %ArrayIteratorPrototype%.return is not defined
   5055  //   * return is nowhere on the proto chain
   5056  return IsArrayWithDefaultIterator<MustBePacked::Yes>(obj, cx);
   5057 }
   5058 
   5059 static bool OptimizeArgumentsSpreadCall(JSContext* cx, HandleObject obj,
   5060                                        MutableHandleValue result) {
   5061  MOZ_ASSERT(result.isUndefined());
   5062 
   5063  // Optimize spread call by skipping the spread operation when the following
   5064  // conditions are met:
   5065  //   * the argument is an arguments object
   5066  //   * the arguments object has no deleted elements
   5067  //   * arguments.length is not overridden
   5068  //   * arguments[@@iterator] is not overridden
   5069  //   * the arguments object belongs to the current realm (affects which
   5070  //     %ArrayIteratorPrototype% is used)
   5071  //   * %ArrayIteratorPrototype%.next is not modified
   5072 
   5073  if (!obj->is<ArgumentsObject>()) {
   5074    return true;
   5075  }
   5076 
   5077  Handle<ArgumentsObject*> args = obj.as<ArgumentsObject>();
   5078  if (args->hasOverriddenElement() || args->hasOverriddenLength() ||
   5079      args->hasOverriddenIterator()) {
   5080    return true;
   5081  }
   5082  if (cx->realm() != args->realm()) {
   5083    return true;
   5084  }
   5085 
   5086  if (!HasOptimizableArrayIteratorPrototype(cx)) {
   5087    return true;
   5088  }
   5089 
   5090  auto* array = ArrayFromArgumentsObject(cx, args);
   5091  if (!array) {
   5092    return false;
   5093  }
   5094 
   5095  result.setObject(*array);
   5096  return true;
   5097 }
   5098 
   5099 bool js::OptimizeSpreadCall(JSContext* cx, HandleValue arg,
   5100                            MutableHandleValue result) {
   5101  // This function returns |undefined| if the spread operation can't be
   5102  // optimized.
   5103  result.setUndefined();
   5104 
   5105  if (!arg.isObject()) {
   5106    return true;
   5107  }
   5108 
   5109  RootedObject obj(cx, &arg.toObject());
   5110  if (OptimizeArrayIteration(obj, cx)) {
   5111    result.setObject(*obj);
   5112    return true;
   5113  }
   5114 
   5115  if (!OptimizeArgumentsSpreadCall(cx, obj, result)) {
   5116    return false;
   5117  }
   5118  if (result.isObject()) {
   5119    return true;
   5120  }
   5121 
   5122  MOZ_ASSERT(result.isUndefined());
   5123  return true;
   5124 }
   5125 
   5126 bool js::OptimizeGetIterator(Value arg, JSContext* cx) {
   5127  if (!arg.isObject()) {
   5128    return false;
   5129  }
   5130  return OptimizeArrayIteration(&arg.toObject(), cx);
   5131 }
   5132 
   5133 ArrayObject* js::ArrayFromArgumentsObject(JSContext* cx,
   5134                                          Handle<ArgumentsObject*> args) {
   5135  MOZ_ASSERT(!args->hasOverriddenLength());
   5136  MOZ_ASSERT(!args->hasOverriddenElement());
   5137 
   5138  uint32_t length = args->initialLength();
   5139  auto* array = NewDenseFullyAllocatedArray(cx, length);
   5140  if (!array) {
   5141    return nullptr;
   5142  }
   5143  array->setDenseInitializedLength(length);
   5144 
   5145  for (uint32_t index = 0; index < length; index++) {
   5146    const Value& v = args->element(index);
   5147    array->initDenseElement(index, v);
   5148  }
   5149 
   5150  return array;
   5151 }
   5152 
   5153 JSObject* js::NewObjectOperation(JSContext* cx, HandleScript script,
   5154                                 const jsbytecode* pc) {
   5155  if (JSOp(*pc) == JSOp::NewObject) {
   5156    Rooted<SharedShape*> shape(cx, script->getShape(pc));
   5157    return PlainObject::createWithShape(cx, shape);
   5158  }
   5159 
   5160  MOZ_ASSERT(JSOp(*pc) == JSOp::NewInit);
   5161  uint8_t propCount = GET_UINT8(pc);
   5162  if (propCount > 0) {
   5163    gc::AllocKind allocKind = gc::GetGCObjectKind(propCount);
   5164    return NewPlainObjectWithAllocKind(cx, allocKind);
   5165  }
   5166  return NewPlainObject(cx);
   5167 }
   5168 
   5169 JSObject* js::NewPlainObjectBaselineFallback(JSContext* cx,
   5170                                             Handle<SharedShape*> shape,
   5171                                             gc::AllocKind allocKind,
   5172                                             gc::AllocSite* site) {
   5173  MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
   5174 
   5175  mozilla::Maybe<AutoRealm> ar;
   5176  if (cx->realm() != shape->realm()) {
   5177    MOZ_ASSERT(cx->compartment() == shape->compartment());
   5178    ar.emplace(cx, shape);
   5179  }
   5180 
   5181  gc::Heap initialHeap = site->initialHeap();
   5182  return NativeObject::create<PlainObject>(cx, allocKind, initialHeap, shape,
   5183                                           site);
   5184 }
   5185 
   5186 JSObject* js::NewPlainObjectOptimizedFallback(JSContext* cx,
   5187                                              Handle<SharedShape*> shape,
   5188                                              gc::AllocKind allocKind,
   5189                                              gc::Heap initialHeap) {
   5190  MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
   5191 
   5192  mozilla::Maybe<AutoRealm> ar;
   5193  if (cx->realm() != shape->realm()) {
   5194    MOZ_ASSERT(cx->compartment() == shape->compartment());
   5195    ar.emplace(cx, shape);
   5196  }
   5197 
   5198  gc::AllocSite* site = cx->zone()->optimizedAllocSite();
   5199  return NativeObject::create<PlainObject>(cx, allocKind, initialHeap, shape,
   5200                                           site);
   5201 }
   5202 
   5203 ArrayObject* js::NewArrayOperation(
   5204    JSContext* cx, uint32_t length,
   5205    NewObjectKind newKind /* = GenericObject */) {
   5206  return NewDenseFullyAllocatedArray(cx, length, newKind);
   5207 }
   5208 
   5209 ArrayObject* js::NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length,
   5210                                                gc::AllocKind allocKind,
   5211                                                gc::AllocSite* site) {
   5212  NewObjectKind newKind =
   5213      site->initialHeap() == gc::Heap::Tenured ? TenuredObject : GenericObject;
   5214  ArrayObject* array = NewDenseFullyAllocatedArray(cx, length, newKind, site);
   5215  // It's important that we allocate an object with the alloc kind we were
   5216  // expecting so that a new arena gets allocated if the current arena for that
   5217  // kind is full.
   5218  MOZ_ASSERT_IF(array && array->isTenured(),
   5219                array->asTenured().getAllocKind() == allocKind);
   5220  return array;
   5221 }
   5222 
   5223 ArrayObject* js::NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length,
   5224                                                 gc::AllocKind allocKind,
   5225                                                 NewObjectKind newKind) {
   5226  gc::AllocSite* site = cx->zone()->optimizedAllocSite();
   5227  ArrayObject* array = NewDenseFullyAllocatedArray(cx, length, newKind, site);
   5228  // It's important that we allocate an object with the alloc kind we were
   5229  // expecting so that a new arena gets allocated if the current arena for that
   5230  // kind is full.
   5231  MOZ_ASSERT_IF(array && array->isTenured(),
   5232                array->asTenured().getAllocKind() == allocKind);
   5233  return array;
   5234 }
   5235 
   5236 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
   5237                                   HandleId id) {
   5238  MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
   5239             errorNumber == JSMSG_BAD_CONST_ASSIGN);
   5240  if (UniqueChars printable =
   5241          IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
   5242    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
   5243                             printable.get());
   5244  }
   5245 }
   5246 
   5247 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
   5248                                   Handle<PropertyName*> name) {
   5249  RootedId id(cx, NameToId(name));
   5250  ReportRuntimeLexicalError(cx, errorNumber, id);
   5251 }
   5252 
   5253 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
   5254                                   HandleScript script, jsbytecode* pc) {
   5255  JSOp op = JSOp(*pc);
   5256  MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical ||
   5257             op == JSOp::ThrowSetConst || op == JSOp::GetImport);
   5258 
   5259  Rooted<PropertyName*> name(cx);
   5260  if (IsLocalOp(op)) {
   5261    name = FrameSlotName(script, pc)->asPropertyName();
   5262  } else if (IsAliasedVarOp(op)) {
   5263    name = EnvironmentCoordinateNameSlow(script, pc);
   5264  } else {
   5265    MOZ_ASSERT(IsAtomOp(op));
   5266    name = script->getName(pc);
   5267  }
   5268 
   5269  ReportRuntimeLexicalError(cx, errorNumber, name);
   5270 }
   5271 
   5272 bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) {
   5273  switch (kind) {
   5274    case CheckIsObjectKind::IteratorNext:
   5275      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5276                                JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
   5277      break;
   5278    case CheckIsObjectKind::IteratorReturn:
   5279      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5280                                JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "return");
   5281      break;
   5282    case CheckIsObjectKind::IteratorThrow:
   5283      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5284                                JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "throw");
   5285      break;
   5286    case CheckIsObjectKind::GetIterator:
   5287      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5288                                JSMSG_GET_ITER_RETURNED_PRIMITIVE);
   5289      break;
   5290    case CheckIsObjectKind::GetAsyncIterator:
   5291      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5292                                JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
   5293      break;
   5294 #ifdef ENABLE_DECORATORS
   5295    case CheckIsObjectKind::DecoratorReturn:
   5296      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5297                                JSMSG_DECORATOR_INVALID_RETURN_TYPE);
   5298      break;
   5299 #endif
   5300 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   5301    case CheckIsObjectKind::Disposable:
   5302      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5303                                JSMSG_DISPOSABLE_NOT_OBJ);
   5304      break;
   5305 #endif
   5306    default:
   5307      MOZ_CRASH("Unknown kind");
   5308  }
   5309  return false;
   5310 }
   5311 
   5312 bool js::ThrowUninitializedThis(JSContext* cx) {
   5313  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5314                            JSMSG_UNINITIALIZED_THIS);
   5315  return false;
   5316 }
   5317 
   5318 bool js::ThrowInitializedThis(JSContext* cx) {
   5319  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
   5320  return false;
   5321 }
   5322 
   5323 bool js::ThrowObjectCoercible(JSContext* cx, HandleValue value) {
   5324  MOZ_ASSERT(value.isNullOrUndefined());
   5325  ReportIsNullOrUndefinedForPropertyAccess(cx, value, JSDVG_SEARCH_STACK);
   5326  return false;
   5327 }
   5328 
   5329 bool js::SetPropertySuper(JSContext* cx, HandleValue lval, HandleValue receiver,
   5330                          Handle<PropertyName*> name, HandleValue rval,
   5331                          bool strict) {
   5332  MOZ_ASSERT(lval.isObjectOrNull());
   5333 
   5334  RootedObject obj(cx, ToObjectFromStackForPropertyAccess(
   5335                           cx, lval, JSDVG_SEARCH_STACK, name));
   5336  if (!obj) {
   5337    return false;
   5338  }
   5339 
   5340  RootedId id(cx, NameToId(name));
   5341  return SetObjectElementOperation(cx, obj, id, rval, receiver, strict);
   5342 }
   5343 
   5344 bool js::SetElementSuper(JSContext* cx, HandleValue lval, HandleValue receiver,
   5345                         HandleValue index, HandleValue rval, bool strict) {
   5346  MOZ_ASSERT(lval.isObjectOrNull());
   5347 
   5348  RootedObject obj(cx, ToObjectFromStackForPropertyAccess(
   5349                           cx, lval, JSDVG_SEARCH_STACK, index));
   5350  if (!obj) {
   5351    return false;
   5352  }
   5353 
   5354  return SetObjectElementWithReceiver(cx, obj, index, rval, receiver, strict);
   5355 }
   5356 
   5357 bool js::LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc,
   5358                             MutableHandleValue result) {
   5359  EnvironmentCoordinate ec(pc);
   5360 
   5361  for (unsigned i = ec.hops(); i; i--) {
   5362    if (env->is<EnvironmentObject>()) {
   5363      env = &env->as<EnvironmentObject>().enclosingEnvironment();
   5364    } else {
   5365      MOZ_ASSERT(env->is<DebugEnvironmentProxy>());
   5366      env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment();
   5367    }
   5368  }
   5369 
   5370  EnvironmentObject& finalEnv =
   5371      env->is<EnvironmentObject>()
   5372          ? env->as<EnvironmentObject>()
   5373          : env->as<DebugEnvironmentProxy>().environment();
   5374 
   5375  result.set(finalEnv.aliasedBinding(ec));
   5376  return true;
   5377 }
   5378 
   5379 // https://tc39.es/ecma262/#sec-iteratorclose
   5380 bool js::CloseIterOperation(JSContext* cx, HandleObject iter,
   5381                            CompletionKind kind) {
   5382  // Steps 1-2 are implicit.
   5383 
   5384  // Step 3
   5385  RootedValue returnMethod(cx);
   5386  bool innerResult =
   5387      GetProperty(cx, iter, iter, cx->names().return_, &returnMethod);
   5388 
   5389  // Step 4
   5390  RootedValue result(cx);
   5391  if (innerResult) {
   5392    // Step 4b
   5393    if (returnMethod.isNullOrUndefined()) {
   5394      return true;
   5395    }
   5396    // Step 4c
   5397    if (IsCallable(returnMethod)) {
   5398      RootedValue thisVal(cx, ObjectValue(*iter));
   5399      innerResult = Call(cx, returnMethod, thisVal, &result);
   5400    } else {
   5401      innerResult = ReportIsNotFunction(cx, returnMethod);
   5402    }
   5403  }
   5404 
   5405  // Step 5
   5406  if (kind == CompletionKind::Throw) {
   5407    // If we close an iterator while unwinding for an exception,
   5408    // the initial exception takes priority over any exception thrown
   5409    // while closing the iterator.
   5410    if (cx->isExceptionPending()) {
   5411      cx->clearPendingException();
   5412    }
   5413    return true;
   5414  }
   5415 
   5416  // Step 6
   5417  if (!innerResult) {
   5418    return false;
   5419  }
   5420 
   5421  // Step 7
   5422  if (!result.isObject()) {
   5423    return ThrowCheckIsObject(cx, CheckIsObjectKind::IteratorReturn);
   5424  }
   5425 
   5426  // Step 8
   5427  return true;
   5428 }