tor-browser

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

Frame.cpp (66485B)


      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 #include "debugger/Frame-inl.h"
      8 
      9 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, MOZ_ASSERT_IF, MOZ_CRASH
     10 #include "mozilla/HashTable.h"   // for HashMapEntry
     11 #include "mozilla/Maybe.h"       // for Maybe
     12 #include "mozilla/Range.h"       // for Range
     13 #include "mozilla/RangedPtr.h"   // for RangedPtr
     14 #include "mozilla/Result.h"      // for Result
     15 #include "mozilla/ScopeExit.h"   // for ScopeExit
     16 #include "mozilla/Vector.h"      // for Vector
     17 
     18 #include <stddef.h>  // for size_t
     19 #include <stdint.h>  // for int32_t
     20 #include <string.h>  // for strlen
     21 #include <utility>   // for std::move
     22 
     23 #include "jsnum.h"  // for Int32ToString
     24 
     25 #include "builtin/Array.h"      // for NewDenseCopiedArray
     26 #include "debugger/Debugger.h"  // for Completion, Debugger
     27 #include "debugger/DebugScript.h"
     28 #include "debugger/Environment.h"       // for DebuggerEnvironment
     29 #include "debugger/NoExecute.h"         // for LeaveDebuggeeNoExecute
     30 #include "debugger/Object.h"            // for DebuggerObject
     31 #include "debugger/Script.h"            // for DebuggerScript
     32 #include "frontend/BytecodeCompiler.h"  // for CompileGlobalScript, CompileGlobalScriptWithExtraBindings, CompileEvalScript
     33 #include "frontend/FrontendContext.h"   // for AutoReportFrontendContext
     34 #include "gc/Barrier.h"                 // for HeapPtr
     35 #include "gc/GC.h"                      // for MemoryUse
     36 #include "gc/GCContext.h"               // for JS::GCContext
     37 #include "gc/Marking.h"                 // for IsAboutToBeFinalized
     38 #include "gc/Tracer.h"                  // for TraceCrossCompartmentEdge
     39 #include "gc/ZoneAllocator.h"           // for AddCellMemory
     40 #include "jit/JSJitFrameIter.h"         // for InlineFrameIterator
     41 #include "jit/RematerializedFrame.h"    // for RematerializedFrame
     42 #include "js/CallArgs.h"                // for CallArgs
     43 #include "js/EnvironmentChain.h"        // JS::EnvironmentChain
     44 #include "js/friend/ErrorMessages.h"    // for GetErrorMessage, JSMSG_*
     45 #include "js/GCVector.h"                // for JS::StackGCVector
     46 #include "js/Object.h"                  // for SetReservedSlot
     47 #include "js/Proxy.h"                   // for PrivateValue
     48 #include "js/RootingAPI.h"  // for JS::Rooted, JS::Handle, JS::MutableHandle
     49 #include "js/SourceText.h"  // for SourceText, SourceOwnership
     50 #include "js/StableStringChars.h"  // for AutoStableStringChars
     51 #include "vm/ArgumentsObject.h"    // for ArgumentsObject
     52 #include "vm/ArrayObject.h"        // for ArrayObject
     53 #include "vm/AsyncFunction.h"      // for AsyncFunctionGeneratorObject
     54 #include "vm/AsyncIteration.h"     // for AsyncGeneratorObject
     55 #include "vm/BytecodeUtil.h"       // for JSDVG_SEARCH_STACK
     56 #include "vm/Compartment.h"        // for Compartment
     57 #include "vm/EnvironmentObject.h"  // for GlobalLexicalEnvironmentObject
     58 #include "vm/GeneratorObject.h"    // for AbstractGeneratorObject
     59 #include "vm/GlobalObject.h"       // for GlobalObject
     60 #include "vm/Interpreter.h"        // for Call, ExecuteKernel
     61 #include "vm/JSAtomUtils.h"        // for Atomize, AtomizeUTF8Chars
     62 #include "vm/JSContext.h"          // for JSContext, ReportValueError
     63 #include "vm/JSFunction.h"         // for JSFunction, NewNativeFunction
     64 #include "vm/JSObject.h"           // for JSObject, RequireObject
     65 #include "vm/JSScript.h"           // for JSScript
     66 #include "vm/NativeObject.h"       // for NativeDefineDataProperty
     67 #include "vm/Realm.h"              // for AutoRealm
     68 #include "vm/Runtime.h"            // for JSAtomState
     69 #include "vm/Scope.h"              // for PositionalFormalParameterIter
     70 #include "vm/Stack.h"              // for AbstractFramePtr, FrameIter
     71 #include "vm/StringType.h"         // for PropertyName, JSString
     72 #include "wasm/WasmDebug.h"        // for DebugState
     73 #include "wasm/WasmDebugFrame.h"   // for DebugFrame
     74 #include "wasm/WasmInstance.h"     // for Instance
     75 #include "wasm/WasmJS.h"           // for WasmInstanceObject
     76 
     77 #include "debugger/Debugger-inl.h"    // for Debugger::fromJSObject
     78 #include "gc/WeakMap-inl.h"           // for WeakMap::remove
     79 #include "vm/Compartment-inl.h"       // for Compartment::wrap
     80 #include "vm/JSContext-inl.h"         // for JSContext::check
     81 #include "vm/JSObject-inl.h"          // for NewObjectWithGivenProto
     82 #include "vm/NativeObject-inl.h"      // for NativeObject::global
     83 #include "vm/ObjectOperations-inl.h"  // for GetProperty
     84 #include "vm/Realm-inl.h"             // for AutoRealm::AutoRealm
     85 #include "vm/Stack-inl.h"             // for AbstractFramePtr::script
     86 
     87 namespace js {
     88 namespace jit {
     89 class JitFrameLayout;
     90 } /* namespace jit */
     91 } /* namespace js */
     92 
     93 using namespace js;
     94 
     95 using JS::AutoStableStringChars;
     96 using JS::CompileOptions;
     97 using JS::SourceOwnership;
     98 using JS::SourceText;
     99 using mozilla::Maybe;
    100 
    101 ScriptedOnStepHandler::ScriptedOnStepHandler(JSObject* object)
    102    : object_(object) {
    103  MOZ_ASSERT(object_->isCallable());
    104 }
    105 
    106 JSObject* ScriptedOnStepHandler::object() const { return object_; }
    107 
    108 void ScriptedOnStepHandler::hold(JSObject* owner) {
    109  AddCellMemory(owner, allocSize(), MemoryUse::DebuggerOnStepHandler);
    110 }
    111 
    112 void ScriptedOnStepHandler::drop(JS::GCContext* gcx, JSObject* owner) {
    113  gcx->delete_(owner, this, allocSize(), MemoryUse::DebuggerOnStepHandler);
    114 }
    115 
    116 void ScriptedOnStepHandler::trace(JSTracer* tracer) {
    117  TraceEdge(tracer, &object_, "OnStepHandlerFunction.object");
    118 }
    119 
    120 bool ScriptedOnStepHandler::onStep(JSContext* cx, Handle<DebuggerFrame*> frame,
    121                                   ResumeMode& resumeMode,
    122                                   MutableHandleValue vp) {
    123  RootedValue fval(cx, ObjectValue(*object_));
    124  RootedValue rval(cx);
    125  if (!js::Call(cx, fval, frame, &rval)) {
    126    return false;
    127  }
    128 
    129  return ParseResumptionValue(cx, rval, resumeMode, vp);
    130 };
    131 
    132 size_t ScriptedOnStepHandler::allocSize() const { return sizeof(*this); }
    133 
    134 ScriptedOnPopHandler::ScriptedOnPopHandler(JSObject* object) : object_(object) {
    135  MOZ_ASSERT(object->isCallable());
    136 }
    137 
    138 JSObject* ScriptedOnPopHandler::object() const { return object_; }
    139 
    140 void ScriptedOnPopHandler::hold(JSObject* owner) {
    141  AddCellMemory(owner, allocSize(), MemoryUse::DebuggerOnPopHandler);
    142 }
    143 
    144 void ScriptedOnPopHandler::drop(JS::GCContext* gcx, JSObject* owner) {
    145  gcx->delete_(owner, this, allocSize(), MemoryUse::DebuggerOnPopHandler);
    146 }
    147 
    148 void ScriptedOnPopHandler::trace(JSTracer* tracer) {
    149  TraceEdge(tracer, &object_, "OnStepHandlerFunction.object");
    150 }
    151 
    152 bool ScriptedOnPopHandler::onPop(JSContext* cx, Handle<DebuggerFrame*> frame,
    153                                 const Completion& completion,
    154                                 ResumeMode& resumeMode,
    155                                 MutableHandleValue vp) {
    156  Debugger* dbg = frame->owner();
    157 
    158  RootedValue completionValue(cx);
    159  if (!completion.buildCompletionValue(cx, dbg, &completionValue)) {
    160    return false;
    161  }
    162 
    163  RootedValue fval(cx, ObjectValue(*object_));
    164  RootedValue rval(cx);
    165  if (!js::Call(cx, fval, frame, completionValue, &rval)) {
    166    return false;
    167  }
    168 
    169  return ParseResumptionValue(cx, rval, resumeMode, vp);
    170 };
    171 
    172 size_t ScriptedOnPopHandler::allocSize() const { return sizeof(*this); }
    173 
    174 js::Debugger* js::DebuggerFrame::owner() const {
    175  JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
    176  return Debugger::fromJSObject(dbgobj);
    177 }
    178 
    179 const JSClassOps DebuggerFrame::classOps_ = {
    180    nullptr,                         // addProperty
    181    nullptr,                         // delProperty
    182    nullptr,                         // enumerate
    183    nullptr,                         // newEnumerate
    184    nullptr,                         // resolve
    185    nullptr,                         // mayResolve
    186    finalize,                        // finalize
    187    nullptr,                         // call
    188    nullptr,                         // construct
    189    CallTraceMethod<DebuggerFrame>,  // trace
    190 };
    191 
    192 const JSClass DebuggerFrame::class_ = {
    193    "Frame",
    194    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
    195        // We require foreground finalization so we can destruct GeneratorInfo's
    196        // HeapPtrs.
    197        JSCLASS_FOREGROUND_FINALIZE,
    198    &DebuggerFrame::classOps_,
    199 };
    200 
    201 enum { JSSLOT_DEBUGARGUMENTS_FRAME, JSSLOT_DEBUGARGUMENTS_COUNT };
    202 
    203 const JSClass DebuggerArguments::class_ = {
    204    "Arguments",
    205    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT),
    206 };
    207 
    208 bool DebuggerFrame::resume(const FrameIter& iter) {
    209  FrameIter::Data* data = iter.copyData();
    210  if (!data) {
    211    return false;
    212  }
    213  setFrameIterData(data);
    214  return true;
    215 }
    216 
    217 void DebuggerFrame::suspendWasmFrame(JS::GCContext* gcx) {
    218  freeFrameIterData(gcx);
    219 }
    220 
    221 bool DebuggerFrame::hasAnyHooks() const {
    222  return !getReservedSlot(ONSTEP_HANDLER_SLOT).isUndefined() ||
    223         !getReservedSlot(ONPOP_HANDLER_SLOT).isUndefined();
    224 }
    225 
    226 /* static */
    227 NativeObject* DebuggerFrame::initClass(JSContext* cx,
    228                                       Handle<GlobalObject*> global,
    229                                       HandleObject dbgCtor) {
    230  return InitClass(cx, dbgCtor, nullptr, nullptr, "Frame", construct, 0,
    231                   properties_, methods_, nullptr, nullptr);
    232 }
    233 
    234 /* static */
    235 DebuggerFrame* DebuggerFrame::create(
    236    JSContext* cx, HandleObject proto, Handle<NativeObject*> debugger,
    237    const FrameIter* maybeIter,
    238    Handle<AbstractGeneratorObject*> maybeGenerator) {
    239  Rooted<DebuggerFrame*> frame(
    240      cx, NewObjectWithGivenProto<DebuggerFrame>(cx, proto));
    241  if (!frame) {
    242    return nullptr;
    243  }
    244 
    245  frame->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
    246 
    247  if (maybeIter) {
    248    FrameIter::Data* data = maybeIter->copyData();
    249    if (!data) {
    250      return nullptr;
    251    }
    252 
    253    frame->setFrameIterData(data);
    254  }
    255 
    256  if (maybeGenerator) {
    257    if (!DebuggerFrame::setGeneratorInfo(cx, frame, maybeGenerator)) {
    258      frame->freeFrameIterData(cx->gcContext());
    259      return nullptr;
    260    }
    261  }
    262 
    263  return frame;
    264 }
    265 
    266 /**
    267 * Information held by a DebuggerFrame about a generator/async call. A
    268 * Debugger.Frame's GENERATOR_INFO_SLOT, if set, holds a PrivateValue pointing
    269 * to one of these.
    270 *
    271 * This is created and attached as soon as a generator object is created for a
    272 * debuggee generator/async frame, retained across suspensions and resumptions,
    273 * and cleared when the generator call ends permanently.
    274 *
    275 * It may seem like this information might belong in ordinary reserved slots on
    276 * the DebuggerFrame object. But that isn't possible:
    277 *
    278 * 1) Slots cannot contain cross-compartment references directly.
    279 * 2) Ordinary cross-compartment wrappers aren't good enough, because the
    280 *    debugger must create its own magic entries in the wrapper table for the GC
    281 *    to get zone collection groups right.
    282 * 3) Even if we make debugger wrapper table entries by hand, hiding
    283 *    cross-compartment edges as PrivateValues doesn't call post-barriers, and
    284 *    the generational GC won't update our pointer when the generator object
    285 *    gets tenured.
    286 *
    287 * Yes, officer, I definitely knew all this in advance and designed it this way
    288 * the first time.
    289 *
    290 * Note that it is not necessary to have a second cross-compartment wrapper
    291 * table entry to cover the pointer to the generator's script. The wrapper table
    292 * entries play two roles: they help the GC put a debugger zone in the same zone
    293 * group as its debuggee, and they serve as roots when collecting the debuggee
    294 * zone, but not the debugger zone. Since an AbstractGeneratorObject holds a
    295 * strong reference to its callee's script (via the callee), and the AGO and the
    296 * script are always in the same compartment, it suffices to add a
    297 * cross-compartment wrapper table entry for the Debugger.Frame -> AGO edge.
    298 */
    299 class DebuggerFrame::GeneratorInfo {
    300  // An unwrapped cross-compartment reference to the generator object.
    301  //
    302  // Always an object.
    303  //
    304  // This cannot be GCPtr because we are not always destructed during sweeping;
    305  // a Debugger.Frame's generator is also cleared when the generator returns
    306  // permanently.
    307  const HeapPtr<Value> unwrappedGenerator_;
    308 
    309  // A cross-compartment reference to the generator's script.
    310  const HeapPtr<JSScript*> generatorScript_;
    311 
    312 public:
    313  GeneratorInfo(Handle<AbstractGeneratorObject*> unwrappedGenerator,
    314                HandleScript generatorScript)
    315      : unwrappedGenerator_(ObjectValue(*unwrappedGenerator)),
    316        generatorScript_(generatorScript) {}
    317 
    318  // Trace a rooted instance of this class, e.g. a Rooted<GeneratorInfo>.
    319  void trace(JSTracer* tracer) {
    320    TraceRoot(tracer, &unwrappedGenerator_, "Debugger.Frame generator object");
    321    TraceRoot(tracer, &generatorScript_, "Debugger.Frame generator script");
    322  }
    323  // Trace a GeneratorInfo from a DebuggerFrame object.
    324  void trace(JSTracer* tracer, DebuggerFrame& frameObj) {
    325    TraceCrossCompartmentEdge(tracer, &frameObj, &unwrappedGenerator_,
    326                              "Debugger.Frame generator object");
    327    TraceCrossCompartmentEdge(tracer, &frameObj, &generatorScript_,
    328                              "Debugger.Frame generator script");
    329  }
    330 
    331  AbstractGeneratorObject& unwrappedGenerator() const {
    332    return unwrappedGenerator_.toObject().as<AbstractGeneratorObject>();
    333  }
    334 
    335  JSScript* generatorScript() { return generatorScript_; }
    336 
    337  bool isGeneratorScriptAboutToBeFinalized() {
    338    return IsAboutToBeFinalized(generatorScript_);
    339  }
    340 };
    341 
    342 bool js::DebuggerFrame::isSuspended() const {
    343  return hasGeneratorInfo() &&
    344         generatorInfo()->unwrappedGenerator().isSuspended();
    345 }
    346 
    347 js::AbstractGeneratorObject& js::DebuggerFrame::unwrappedGenerator() const {
    348  return generatorInfo()->unwrappedGenerator();
    349 }
    350 
    351 #ifdef DEBUG
    352 JSScript* js::DebuggerFrame::generatorScript() const {
    353  return generatorInfo()->generatorScript();
    354 }
    355 #endif
    356 
    357 /* static */
    358 bool DebuggerFrame::setGeneratorInfo(JSContext* cx,
    359                                     Handle<DebuggerFrame*> frame,
    360                                     Handle<AbstractGeneratorObject*> genObj) {
    361  cx->check(frame);
    362 
    363  MOZ_ASSERT(!frame->hasGeneratorInfo());
    364  MOZ_ASSERT(!genObj->isClosed());
    365 
    366  // When we initialize the generator information, we do not need to adjust
    367  // the stepper increment, because either it was already incremented when
    368  // the step hook was added, or we're setting this into on a new DebuggerFrame
    369  // that has not yet had the chance for a hook to be added to it.
    370  MOZ_ASSERT_IF(frame->onStepHandler(), frame->frameIterData());
    371  MOZ_ASSERT_IF(!frame->frameIterData(), !frame->onStepHandler());
    372 
    373  // There are two relations we must establish:
    374  //
    375  // 1) The DebuggerFrame must point to the AbstractGeneratorObject.
    376  //
    377  // 2) The generator's script's observer count must be bumped.
    378 
    379  RootedScript script(cx, genObj->callee().nonLazyScript());
    380  Rooted<UniquePtr<GeneratorInfo>> info(
    381      cx, cx->make_unique<GeneratorInfo>(genObj, script));
    382  if (!info) {
    383    return false;
    384  }
    385 
    386  AutoRealm ar(cx, script);
    387 
    388  // All frames running a debuggee script must themselves be marked as
    389  // debuggee frames. Bumping a script's generator observer count makes it a
    390  // debuggee, so we need to mark all frames on the stack running it as
    391  // debuggees as well, not just this one. This call takes care of all that.
    392  if (!Debugger::ensureExecutionObservabilityOfScript(cx, script)) {
    393    return false;
    394  }
    395 
    396  if (!DebugScript::incrementGeneratorObserverCount(cx, script)) {
    397    return false;
    398  }
    399 
    400  InitReservedSlot(frame, GENERATOR_INFO_SLOT, info.release(),
    401                   MemoryUse::DebuggerFrameGeneratorInfo);
    402  return true;
    403 }
    404 
    405 void DebuggerFrame::terminate(JS::GCContext* gcx, AbstractFramePtr frame) {
    406  if (frameIterData()) {
    407    // If no frame pointer was provided to decrement the stepper counter,
    408    // then we must be terminating a generator, otherwise the stepper count
    409    // would have no way to synchronize properly.
    410    MOZ_ASSERT_IF(!frame, hasGeneratorInfo());
    411 
    412    freeFrameIterData(gcx);
    413    if (frame && !hasGeneratorInfo() && onStepHandler()) {
    414      // If we are terminating a non-generator frame that had a step handler,
    415      // we need to decrement the counter to keep things in sync.
    416      decrementStepperCounter(gcx, frame);
    417    }
    418  }
    419 
    420  if (!hasGeneratorInfo()) {
    421    return;
    422  }
    423 
    424  GeneratorInfo* info = generatorInfo();
    425 
    426  // 3) The generator's script's observer count must be dropped.
    427  //
    428  // For ordinary calls, Debugger.Frame objects drop the script's stepper count
    429  // when the frame is popped, but for generators, they leave the stepper count
    430  // incremented across suspensions. This means that, whereas ordinary calls
    431  // never need to drop the stepper count from the D.F finalizer, generator
    432  // calls may.
    433  if (!info->isGeneratorScriptAboutToBeFinalized()) {
    434    JSScript* generatorScript = info->generatorScript();
    435    DebugScript::decrementGeneratorObserverCount(gcx, generatorScript);
    436    if (onStepHandler()) {
    437      // If we are terminating a generator frame that had a step handler,
    438      // we need to decrement the counter to keep things in sync.
    439      decrementStepperCounter(gcx, generatorScript);
    440    }
    441  }
    442 
    443  // 1) The DebuggerFrame must no longer point to the AbstractGeneratorObject.
    444  setReservedSlot(GENERATOR_INFO_SLOT, UndefinedValue());
    445  gcx->delete_(this, info, MemoryUse::DebuggerFrameGeneratorInfo);
    446 }
    447 
    448 void DebuggerFrame::onGeneratorClosed(JS::GCContext* gcx) {
    449  GeneratorInfo* info = generatorInfo();
    450 
    451  // If the generator is closed, eagerly drop the onStep handler, to make sure
    452  // the stepper counter matches in the assertion in DebugAPI::onSingleStep.
    453  // Also clear the slot in order to suppress the decrementStepperCounter in
    454  // DebuggerFrame::terminate.
    455  if (!info->isGeneratorScriptAboutToBeFinalized()) {
    456    JSScript* generatorScript = info->generatorScript();
    457    OnStepHandler* handler = onStepHandler();
    458    if (handler) {
    459      decrementStepperCounter(gcx, generatorScript);
    460      setReservedSlot(ONSTEP_HANDLER_SLOT, UndefinedValue());
    461      handler->drop(gcx, this);
    462    }
    463  }
    464 }
    465 
    466 void DebuggerFrame::suspend(JS::GCContext* gcx) {
    467  // There must be generator info because otherwise this would be the same
    468  // overall behavior as terminate() except that here we do not properly
    469  // adjust stepper counts.
    470  MOZ_ASSERT(hasGeneratorInfo());
    471 
    472  freeFrameIterData(gcx);
    473 }
    474 
    475 /* static */
    476 bool DebuggerFrame::getCallee(JSContext* cx, Handle<DebuggerFrame*> frame,
    477                              MutableHandle<DebuggerObject*> result) {
    478  RootedObject callee(cx);
    479  if (frame->isOnStack()) {
    480    AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    481    if (referent.isFunctionFrame()) {
    482      callee = referent.callee();
    483    }
    484  } else {
    485    MOZ_ASSERT(frame->isSuspended());
    486 
    487    callee = &frame->generatorInfo()->unwrappedGenerator().callee();
    488  }
    489 
    490  return frame->owner()->wrapNullableDebuggeeObject(cx, callee, result);
    491 }
    492 
    493 /* static */
    494 bool DebuggerFrame::getIsConstructing(JSContext* cx,
    495                                      Handle<DebuggerFrame*> frame,
    496                                      bool& result) {
    497  if (frame->isOnStack()) {
    498    FrameIter iter = frame->getFrameIter(cx);
    499 
    500    result = iter.isFunctionFrame() && iter.isConstructing();
    501  } else {
    502    MOZ_ASSERT(frame->isSuspended());
    503 
    504    // Generators and async functions can't be constructed.
    505    result = false;
    506  }
    507  return true;
    508 }
    509 
    510 static void UpdateFrameIterPc(FrameIter& iter) {
    511  if (iter.abstractFramePtr().isWasmDebugFrame()) {
    512    // Wasm debug frames don't need their pc updated -- it's null.
    513    return;
    514  }
    515 
    516  if (iter.abstractFramePtr().isRematerializedFrame()) {
    517 #ifdef DEBUG
    518    // Rematerialized frames don't need their pc updated. The reason we
    519    // need to update pc is because we might get the same Debugger.Frame
    520    // object for multiple re-entries into debugger code from debuggee
    521    // code. This reentrancy is not possible with rematerialized frames,
    522    // because when returning to debuggee code, we would have bailed out
    523    // to baseline.
    524    //
    525    // We walk the stack to assert that it doesn't need updating.
    526    jit::RematerializedFrame* frame =
    527        iter.abstractFramePtr().asRematerializedFrame();
    528    jit::JitFrameLayout* jsFrame = (jit::JitFrameLayout*)frame->top();
    529    jit::JitActivation* activation = iter.activation()->asJit();
    530 
    531    JSContext* cx = TlsContext.get();
    532    MOZ_ASSERT(cx == activation->cx());
    533 
    534    ActivationIterator activationIter(cx);
    535    while (activationIter.activation() != activation) {
    536      ++activationIter;
    537    }
    538 
    539    OnlyJSJitFrameIter jitIter(activationIter);
    540    while (!jitIter.frame().isIonJS() || jitIter.frame().jsFrame() != jsFrame) {
    541      ++jitIter;
    542    }
    543 
    544    jit::InlineFrameIterator ionInlineIter(cx, &jitIter.frame());
    545    while (ionInlineIter.frameNo() != frame->frameNo()) {
    546      ++ionInlineIter;
    547    }
    548 
    549    MOZ_ASSERT(ionInlineIter.pc() == iter.pc());
    550 #endif
    551    return;
    552  }
    553 
    554  iter.updatePcQuadratic();
    555 }
    556 
    557 /* static */
    558 bool DebuggerFrame::getEnvironment(JSContext* cx, Handle<DebuggerFrame*> frame,
    559                                   MutableHandle<DebuggerEnvironment*> result) {
    560  Debugger* dbg = frame->owner();
    561  Rooted<Env*> env(cx);
    562 
    563  if (frame->isOnStack()) {
    564    FrameIter iter = frame->getFrameIter(cx);
    565 
    566    {
    567      AutoRealm ar(cx, iter.abstractFramePtr().environmentChain());
    568      UpdateFrameIterPc(iter);
    569      env = GetDebugEnvironmentForFrame(cx, iter.abstractFramePtr(), iter.pc());
    570    }
    571  } else {
    572    MOZ_ASSERT(frame->isSuspended());
    573 
    574    AbstractGeneratorObject& genObj =
    575        frame->generatorInfo()->unwrappedGenerator();
    576    JSScript* script = frame->generatorInfo()->generatorScript();
    577 
    578    {
    579      AutoRealm ar(cx, &genObj.environmentChain());
    580      env = GetDebugEnvironmentForSuspendedGenerator(cx, script, genObj);
    581    }
    582  }
    583 
    584  if (!env) {
    585    return false;
    586  }
    587 
    588  return dbg->wrapEnvironment(cx, env, result);
    589 }
    590 
    591 /* static */
    592 bool DebuggerFrame::getOffset(JSContext* cx, Handle<DebuggerFrame*> frame,
    593                              size_t& result) {
    594  if (frame->isOnStack()) {
    595    FrameIter iter = frame->getFrameIter(cx);
    596 
    597    AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    598    if (referent.isWasmDebugFrame()) {
    599      iter.wasmUpdateBytecodeOffset();
    600      result = iter.wasmBytecodeOffset();
    601    } else {
    602      JSScript* script = iter.script();
    603      UpdateFrameIterPc(iter);
    604      jsbytecode* pc = iter.pc();
    605      result = script->pcToOffset(pc);
    606    }
    607  } else {
    608    MOZ_ASSERT(frame->isSuspended());
    609 
    610    AbstractGeneratorObject& genObj =
    611        frame->generatorInfo()->unwrappedGenerator();
    612    JSScript* script = frame->generatorInfo()->generatorScript();
    613    result = script->resumeOffsets()[genObj.resumeIndex()];
    614  }
    615  return true;
    616 }
    617 
    618 /* static */
    619 bool DebuggerFrame::getOlder(JSContext* cx, Handle<DebuggerFrame*> frame,
    620                             MutableHandle<DebuggerFrame*> result) {
    621  if (frame->isOnStack()) {
    622    Debugger* dbg = frame->owner();
    623    FrameIter iter = frame->getFrameIter(cx);
    624 
    625    while (true) {
    626      Activation& activation = *iter.activation();
    627      ++iter;
    628 
    629      // If the parent frame crosses an explicit async stack boundary, we
    630      // treat that as an indication to stop traversing sync frames, so that
    631      // the on-stack Debugger.Frame instances align with what you would
    632      // see in a stringified stack trace.
    633      if (iter.activation() != &activation && activation.asyncStack() &&
    634          activation.asyncCallIsExplicit()) {
    635        break;
    636      }
    637 
    638      // If there is no parent frame, we're done.
    639      if (iter.done()) {
    640        break;
    641      }
    642 
    643      if (dbg->observesFrame(iter)) {
    644        if (iter.isIon() && !iter.ensureHasRematerializedFrame(cx)) {
    645          return false;
    646        }
    647        return dbg->getFrame(cx, iter, result);
    648      }
    649    }
    650  } else {
    651    MOZ_ASSERT(frame->isSuspended());
    652 
    653    // If the frame is suspended, there is no older frame.
    654  }
    655 
    656  result.set(nullptr);
    657  return true;
    658 }
    659 
    660 /* static */
    661 bool DebuggerFrame::getAsyncPromise(JSContext* cx, Handle<DebuggerFrame*> frame,
    662                                    MutableHandle<DebuggerObject*> result) {
    663  MOZ_ASSERT(frame->isOnStack() || frame->isSuspended());
    664 
    665  if (!frame->hasGeneratorInfo()) {
    666    // An on-stack frame may not have an associated generator yet when the
    667    // frame is initially entered.
    668    result.set(nullptr);
    669    return true;
    670  }
    671 
    672  RootedObject resultObject(cx);
    673  AbstractGeneratorObject& generator = frame->unwrappedGenerator();
    674  if (generator.is<AsyncFunctionGeneratorObject>()) {
    675    resultObject = generator.as<AsyncFunctionGeneratorObject>().promise();
    676  } else if (generator.is<AsyncGeneratorObject>()) {
    677    Rooted<AsyncGeneratorObject*> asyncGen(
    678        cx, &generator.as<AsyncGeneratorObject>());
    679    // In initial function execution, there is no promise.
    680    if (!asyncGen->isQueueEmpty()) {
    681      resultObject = AsyncGeneratorObject::peekRequest(asyncGen)->promise();
    682    }
    683  } else {
    684    MOZ_CRASH("Unknown async generator type");
    685  }
    686 
    687  return frame->owner()->wrapNullableDebuggeeObject(cx, resultObject, result);
    688 }
    689 
    690 /* static */
    691 bool DebuggerFrame::getThis(JSContext* cx, Handle<DebuggerFrame*> frame,
    692                            MutableHandleValue result) {
    693  Debugger* dbg = frame->owner();
    694 
    695  if (frame->isOnStack()) {
    696    if (!requireScriptReferent(cx, frame)) {
    697      return false;
    698    }
    699    FrameIter iter = frame->getFrameIter(cx);
    700 
    701    {
    702      AbstractFramePtr frame = iter.abstractFramePtr();
    703      AutoRealm ar(cx, frame.environmentChain());
    704 
    705      UpdateFrameIterPc(iter);
    706 
    707      if (!GetThisValueForDebuggerFrameMaybeOptimizedOut(cx, frame, iter.pc(),
    708                                                         result)) {
    709        return false;
    710      }
    711    }
    712  } else {
    713    MOZ_ASSERT(frame->isSuspended());
    714 
    715    AbstractGeneratorObject& genObj =
    716        frame->generatorInfo()->unwrappedGenerator();
    717    AutoRealm ar(cx, &genObj);
    718    JSScript* script = frame->generatorInfo()->generatorScript();
    719 
    720    if (!GetThisValueForDebuggerSuspendedGeneratorMaybeOptimizedOut(
    721            cx, genObj, script, result)) {
    722      return false;
    723    }
    724  }
    725 
    726  return dbg->wrapDebuggeeValue(cx, result);
    727 }
    728 
    729 /* static */
    730 DebuggerFrameType DebuggerFrame::getType(Handle<DebuggerFrame*> frame) {
    731  if (frame->isOnStack()) {
    732    AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    733 
    734    // Indirect eval frames are both isGlobalFrame() and isEvalFrame(), so the
    735    // order of checks here is significant.
    736    if (referent.isEvalFrame()) {
    737      return DebuggerFrameType::Eval;
    738    }
    739 
    740    if (referent.isGlobalFrame()) {
    741      return DebuggerFrameType::Global;
    742    }
    743 
    744    if (referent.isFunctionFrame()) {
    745      return DebuggerFrameType::Call;
    746    }
    747 
    748    if (referent.isModuleFrame()) {
    749      return DebuggerFrameType::Module;
    750    }
    751 
    752    if (referent.isWasmDebugFrame()) {
    753      return DebuggerFrameType::WasmCall;
    754    }
    755  } else {
    756    MOZ_ASSERT(frame->isSuspended());
    757 
    758    return DebuggerFrameType::Call;
    759  }
    760 
    761  MOZ_CRASH("Unknown frame type");
    762 }
    763 
    764 /* static */
    765 DebuggerFrameImplementation DebuggerFrame::getImplementation(
    766    Handle<DebuggerFrame*> frame) {
    767  AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    768 
    769  if (referent.isBaselineFrame()) {
    770    return DebuggerFrameImplementation::Baseline;
    771  }
    772 
    773  if (referent.isRematerializedFrame()) {
    774    return DebuggerFrameImplementation::Ion;
    775  }
    776 
    777  if (referent.isWasmDebugFrame()) {
    778    return DebuggerFrameImplementation::Wasm;
    779  }
    780 
    781  return DebuggerFrameImplementation::Interpreter;
    782 }
    783 
    784 /*
    785 * If succesful, transfers the ownership of the given `handler` to this
    786 * Debugger.Frame. Note that on failure, the ownership of `handler` is not
    787 * transferred, and the caller is responsible for cleaning it up.
    788 */
    789 /* static */
    790 bool DebuggerFrame::setOnStepHandler(JSContext* cx,
    791                                     Handle<DebuggerFrame*> frame,
    792                                     UniquePtr<OnStepHandler> handlerArg) {
    793  // Handler has never been successfully associated with the frame so allow
    794  // UniquePtr to delete it rather than calling drop() if we return early from
    795  // this method..
    796  Rooted<UniquePtr<OnStepHandler>> handler(cx, std::move(handlerArg));
    797 
    798  OnStepHandler* prior = frame->onStepHandler();
    799  if (handler.get() == prior) {
    800    return true;
    801  }
    802 
    803  JS::GCContext* gcx = cx->gcContext();
    804  if (frame->isOnStack()) {
    805    AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    806 
    807    // Adjust execution observability and step counts on whatever code (JS or
    808    // Wasm) this frame is running.
    809    if (handler && !prior) {
    810      if (!frame->incrementStepperCounter(cx, referent)) {
    811        return false;
    812      }
    813    } else if (!handler && prior) {
    814      frame->decrementStepperCounter(cx->gcContext(), referent);
    815    }
    816  } else if (frame->isSuspended()) {
    817    RootedScript script(cx, frame->generatorInfo()->generatorScript());
    818 
    819    if (handler && !prior) {
    820      if (!frame->incrementStepperCounter(cx, script)) {
    821        return false;
    822      }
    823    } else if (!handler && prior) {
    824      frame->decrementStepperCounter(cx->gcContext(), script);
    825    }
    826  } else {
    827    // If the frame is entirely dead, we still allow setting the onStep
    828    // handler, but it has no effect.
    829  }
    830 
    831  // Now that the stepper counts and observability are set correctly, we can
    832  // actually switch the handler.
    833  if (prior) {
    834    prior->drop(gcx, frame);
    835  }
    836 
    837  if (handler) {
    838    handler->hold(frame);
    839    frame->setReservedSlot(ONSTEP_HANDLER_SLOT,
    840                           PrivateValue(handler.get().release()));
    841  } else {
    842    frame->setReservedSlot(ONSTEP_HANDLER_SLOT, UndefinedValue());
    843  }
    844 
    845  return true;
    846 }
    847 
    848 bool DebuggerFrame::incrementStepperCounter(JSContext* cx,
    849                                            AbstractFramePtr referent) {
    850  if (!referent.isWasmDebugFrame()) {
    851    RootedScript script(cx, referent.script());
    852    return incrementStepperCounter(cx, script);
    853  }
    854 
    855  wasm::Instance* instance = referent.asWasmDebugFrame()->instance();
    856  wasm::DebugFrame* wasmFrame = referent.asWasmDebugFrame();
    857  // Single stepping toggled off->on.
    858  if (!instance->debug().incrementStepperCount(cx, instance,
    859                                               wasmFrame->funcIndex())) {
    860    return false;
    861  }
    862 
    863  return true;
    864 }
    865 
    866 bool DebuggerFrame::incrementStepperCounter(JSContext* cx,
    867                                            HandleScript script) {
    868  // Single stepping toggled off->on.
    869  AutoRealm ar(cx, script);
    870  // Ensure observability *before* incrementing the step mode count.
    871  // Calling this function after calling incrementStepperCount
    872  // will make it a no-op.
    873  if (!Debugger::ensureExecutionObservabilityOfScript(cx, script)) {
    874    return false;
    875  }
    876  if (!DebugScript::incrementStepperCount(cx, script)) {
    877    return false;
    878  }
    879 
    880  return true;
    881 }
    882 
    883 void DebuggerFrame::decrementStepperCounter(JS::GCContext* gcx,
    884                                            AbstractFramePtr referent) {
    885  if (!referent.isWasmDebugFrame()) {
    886    decrementStepperCounter(gcx, referent.script());
    887    return;
    888  }
    889 
    890  wasm::Instance* instance = referent.asWasmDebugFrame()->instance();
    891  wasm::DebugFrame* wasmFrame = referent.asWasmDebugFrame();
    892  // Single stepping toggled on->off.
    893  instance->debug().decrementStepperCount(gcx, instance,
    894                                          wasmFrame->funcIndex());
    895 }
    896 
    897 void DebuggerFrame::decrementStepperCounter(JS::GCContext* gcx,
    898                                            JSScript* script) {
    899  // Single stepping toggled on->off.
    900  DebugScript::decrementStepperCount(gcx, script);
    901 }
    902 
    903 /* static */
    904 bool DebuggerFrame::getArguments(JSContext* cx, Handle<DebuggerFrame*> frame,
    905                                 MutableHandle<DebuggerArguments*> result) {
    906  Value argumentsv = frame->getReservedSlot(ARGUMENTS_SLOT);
    907  if (!argumentsv.isUndefined()) {
    908    result.set(argumentsv.isObject()
    909                   ? &argumentsv.toObject().as<DebuggerArguments>()
    910                   : nullptr);
    911    return true;
    912  }
    913 
    914  AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
    915 
    916  Rooted<DebuggerArguments*> arguments(cx);
    917  if (referent.hasArgs()) {
    918    Rooted<GlobalObject*> global(cx, &frame->global());
    919    RootedObject proto(cx, GlobalObject::getOrCreateArrayPrototype(cx, global));
    920    if (!proto) {
    921      return false;
    922    }
    923    arguments = DebuggerArguments::create(cx, proto, frame);
    924    if (!arguments) {
    925      return false;
    926    }
    927  } else {
    928    arguments = nullptr;
    929  }
    930 
    931  result.set(arguments);
    932  frame->setReservedSlot(ARGUMENTS_SLOT, ObjectOrNullValue(result));
    933  return true;
    934 }
    935 
    936 static WithEnvironmentObject* CreateBindingsEnv(
    937    JSContext* cx, JS::Handle<JSObject*> enclosingEnv,
    938    JS::Handle<JS::StackGCVector<JS::PropertyKey>> bindingKeys,
    939    JS::Handle<JS::StackGCVector<JS::Value>> bindingValues) {
    940  JS::Rooted<PlainObject*> bindingsObj(cx,
    941                                       NewPlainObjectWithProto(cx, nullptr));
    942  if (!bindingsObj) {
    943    return nullptr;
    944  }
    945  JS::Rooted<JS::PropertyKey> id(cx);
    946  JS::Rooted<JS::Value> val(cx);
    947  for (size_t i = 0; i < bindingKeys.length(); i++) {
    948    id = bindingKeys[i];
    949    cx->markId(id);
    950    val = bindingValues[i];
    951    if (!cx->compartment()->wrap(cx, &val) ||
    952        !NativeDefineDataProperty(cx, bindingsObj, id, val, 0)) {
    953      return nullptr;
    954    }
    955  }
    956 
    957  JS::EnvironmentChain envChain(cx, JS::SupportUnscopables::No);
    958  if (!envChain.append(bindingsObj)) {
    959    return nullptr;
    960  }
    961 
    962  return CreateObjectsForEnvironmentChain(cx, envChain, enclosingEnv);
    963 }
    964 
    965 /*
    966 * Evaluate |chars| in the environment |envArg|, treating that source as
    967 * appearing starting at |evalOptions.lineno()| in |evalOptions.filename()|.
    968 * Store the return value in |*rval|.
    969 *
    970 * If |evalOptions.kind()| is either `Frame` or |FrameWithExtraBindings|,
    971 * evaluate as for a direct eval in |frame|; |envArg| must be |frame|'s
    972 * DebugScopeObject; either way,
    973 * |frame|'s scope is where newly declared variables go. In this case,
    974 * |frame| must have a computed 'this' value.
    975 *
    976 * If |evalOptions.kind()| is one of the following, |bindingKeys| and
    977 * |bindingValues| should represent the bindings, and a new
    978 * |WithEnvironmentObject| is created with |envArg| as enclosing environment,
    979 * and used for the evaluation.
    980 *   - FrameWithExtraBindings
    981 *   - GlobalWithExtraInnerBindings
    982 *   - GlobalWithExtraOuterBindings
    983 */
    984 static bool EvaluateInEnv(
    985    JSContext* cx, Handle<Env*> envArg, AbstractFramePtr frame,
    986    mozilla::Range<const char16_t> chars, const EvalOptions& evalOptions,
    987    JS::Handle<JS::StackGCVector<JS::PropertyKey>> bindingKeys,
    988    JS::Handle<JS::StackGCVector<JS::Value>> bindingValues,
    989    MutableHandleValue rval) {
    990 #ifdef DEBUG
    991  switch (evalOptions.kind()) {
    992    case EvalOptions::EnvKind::Frame:
    993    case EvalOptions::EnvKind::FrameWithExtraBindings:
    994      MOZ_ASSERT(frame);
    995      break;
    996    case EvalOptions::EnvKind::Global:
    997      MOZ_ASSERT(!frame);
    998      break;
    999    case EvalOptions::EnvKind::GlobalWithExtraInnerBindings:
   1000    case EvalOptions::EnvKind::GlobalWithExtraOuterBindings:
   1001      MOZ_ASSERT(!frame);
   1002      break;
   1003  }
   1004 #endif
   1005 
   1006  cx->check(envArg, frame);
   1007 
   1008  AutoSetBypassCSPForDebugger setFlag(cx, evalOptions.bypassCSP());
   1009 
   1010  CompileOptions options(cx);
   1011  const char* filename =
   1012      evalOptions.filename() ? evalOptions.filename() : "debugger eval code";
   1013  options.setIsRunOnce(true)
   1014      .setNoScriptRval(false)
   1015      .setFileAndLine(filename, evalOptions.lineno())
   1016      .setHideScriptFromDebugger(evalOptions.hideFromDebugger())
   1017      .setIntroductionType("debugger eval")
   1018      /* Do not perform the Javascript filename validation security check for
   1019       * javascript executions sent through the debugger. Besides making up
   1020       * a filename for these codepaths, we must allow arbitrary JS execution
   1021       * for the Browser toolbox to function. */
   1022      .setSkipFilenameValidation(true)
   1023      /* Don't lazy parse. We need full-parsing to correctly support bytecode
   1024       * emission for private fields/methods. See EmitterScope::lookupPrivate.
   1025       */
   1026      .setForceFullParse();
   1027 
   1028  if (frame && frame.hasScript() && frame.script()->strict()) {
   1029    options.setForceStrictMode();
   1030  }
   1031 
   1032  SourceText<char16_t> srcBuf;
   1033  if (!srcBuf.init(cx, chars.begin().get(), chars.length(),
   1034                   SourceOwnership::Borrowed)) {
   1035    return false;
   1036  }
   1037 
   1038  // Compile the script and compute the environment object.
   1039  JS::Rooted<JSScript*> script(cx);
   1040  JS::Rooted<JSObject*> env(cx);
   1041  switch (evalOptions.kind()) {
   1042    case EvalOptions::EnvKind::FrameWithExtraBindings: {
   1043      env = CreateBindingsEnv(cx, envArg, bindingKeys, bindingValues);
   1044      if (!env) {
   1045        return false;
   1046      }
   1047      [[fallthrough]];
   1048    }
   1049    case EvalOptions::EnvKind::Frame: {
   1050      // Default to |envArg| when no extra bindings are used.
   1051      if (!env) {
   1052        env = envArg;
   1053      }
   1054 
   1055      options.setNonSyntacticScope(true);
   1056 
   1057      Rooted<Scope*> scope(
   1058          cx, GlobalScope::createEmpty(cx, ScopeKind::NonSyntactic));
   1059      if (!scope) {
   1060        return false;
   1061      }
   1062 
   1063      script = frontend::CompileEvalScript(cx, options, srcBuf, scope, env);
   1064      if (!script) {
   1065        return false;
   1066      }
   1067      break;
   1068    }
   1069    case EvalOptions::EnvKind::Global: {
   1070      AutoReportFrontendContext fc(cx);
   1071      script = frontend::CompileGlobalScript(cx, &fc, options, srcBuf,
   1072                                             ScopeKind::Global);
   1073      if (!script) {
   1074        return false;
   1075      }
   1076 
   1077      env = envArg;
   1078      break;
   1079    }
   1080    case EvalOptions::EnvKind::GlobalWithExtraOuterBindings: {
   1081      // Do not consider executeInGlobal{,WithBindings} as an eval, but instead
   1082      // as executing a series of statements at the global level. This is to
   1083      // circumvent the fresh lexical scope that all eval have, so that the
   1084      // users of executeInGlobal{,WithBindings}, like the web console, may add
   1085      // new bindings to the global scope.
   1086 
   1087      MOZ_ASSERT(envArg == &cx->global()->lexicalEnvironment());
   1088 
   1089      options.setNonSyntacticScope(true);
   1090 
   1091      AutoReportFrontendContext fc(cx);
   1092      script = frontend::CompileGlobalScriptWithExtraBindings(
   1093          cx, &fc, options, srcBuf, bindingKeys, bindingValues, &env);
   1094      if (!script) {
   1095        return false;
   1096      }
   1097      break;
   1098    }
   1099    case EvalOptions::EnvKind::GlobalWithExtraInnerBindings: {
   1100      env = CreateBindingsEnv(cx, envArg, bindingKeys, bindingValues);
   1101      if (!env) {
   1102        return false;
   1103      }
   1104 
   1105      options.setNonSyntacticScope(true);
   1106 
   1107      AutoReportFrontendContext fc(cx);
   1108      script = frontend::CompileGlobalScript(cx, &fc, options, srcBuf,
   1109                                             ScopeKind::NonSyntactic);
   1110      if (!script) {
   1111        return false;
   1112      }
   1113      break;
   1114    }
   1115  }
   1116 
   1117  return ExecuteKernel(cx, script, env, frame, rval);
   1118 }
   1119 
   1120 Result<Completion> js::DebuggerGenericEval(
   1121    JSContext* cx, const mozilla::Range<const char16_t> chars,
   1122    HandleObject bindings, const EvalOptions& options, Debugger* dbg,
   1123    HandleObject envArg, FrameIter* iter) {
   1124 #ifdef DEBUG
   1125  switch (options.kind()) {
   1126    case EvalOptions::EnvKind::Frame:
   1127      MOZ_ASSERT(iter);
   1128      MOZ_ASSERT(!envArg);
   1129      MOZ_ASSERT(!bindings);
   1130      break;
   1131    case EvalOptions::EnvKind::FrameWithExtraBindings:
   1132      MOZ_ASSERT(iter);
   1133      MOZ_ASSERT(!envArg);
   1134      MOZ_ASSERT(bindings);
   1135      break;
   1136    case EvalOptions::EnvKind::Global:
   1137      MOZ_ASSERT(!iter);
   1138      MOZ_ASSERT(envArg);
   1139      MOZ_ASSERT(envArg->is<GlobalLexicalEnvironmentObject>());
   1140      MOZ_ASSERT(!bindings);
   1141      break;
   1142    case EvalOptions::EnvKind::GlobalWithExtraInnerBindings:
   1143    case EvalOptions::EnvKind::GlobalWithExtraOuterBindings:
   1144      MOZ_ASSERT(!iter);
   1145      MOZ_ASSERT(envArg);
   1146      MOZ_ASSERT(envArg->is<GlobalLexicalEnvironmentObject>());
   1147      MOZ_ASSERT(bindings);
   1148      break;
   1149  }
   1150 #endif
   1151 
   1152  // Gather keys and values of bindings, if any. This must be done in the
   1153  // debugger compartment, since that is where any exceptions must be thrown.
   1154  RootedIdVector keys(cx);
   1155  RootedValueVector values(cx);
   1156  if (bindings) {
   1157    if (!GetPropertyKeys(cx, bindings, JSITER_OWNONLY, &keys) ||
   1158        !values.growBy(keys.length())) {
   1159      return cx->alreadyReportedError();
   1160    }
   1161    for (size_t i = 0; i < keys.length(); i++) {
   1162      MutableHandleValue valp = values[i];
   1163      if (!GetProperty(cx, bindings, bindings, keys[i], valp) ||
   1164          !dbg->unwrapDebuggeeValue(cx, valp)) {
   1165        return cx->alreadyReportedError();
   1166      }
   1167    }
   1168  }
   1169 
   1170  Maybe<AutoRealm> ar;
   1171  if (iter) {
   1172    ar.emplace(cx, iter->environmentChain(cx));
   1173  } else {
   1174    ar.emplace(cx, envArg);
   1175  }
   1176 
   1177  Rooted<Env*> env(cx);
   1178  if (iter) {
   1179    env = GetDebugEnvironmentForFrame(cx, iter->abstractFramePtr(), iter->pc());
   1180    if (!env) {
   1181      return cx->alreadyReportedError();
   1182    }
   1183  } else {
   1184    env = envArg;
   1185  }
   1186 
   1187  if (iter && iter->hasScript() && iter->script()->allowRelazify()) {
   1188    // This is a function that was first lazy, and delazified, and it's marked
   1189    // as relazifyable because there was no inner function.
   1190    //
   1191    // Evaluating a script can create inner function, which should prevent the
   1192    // relazification.
   1193    iter->script()->clearAllowRelazify();
   1194  }
   1195 
   1196  // Note whether we are in an evaluation that might invoke the OnNativeCall
   1197  // hook, so that the JITs will be disabled.
   1198  Maybe<AutoNoteExclusiveDebuggerOnEval> noteEvaluation;
   1199  if (dbg->isExclusiveDebuggerOnEval()) {
   1200    noteEvaluation.emplace(cx, dbg);
   1201  }
   1202 
   1203  // Run the code and produce the completion value.
   1204  LeaveDebuggeeNoExecute nnx(cx);
   1205  RootedValue rval(cx);
   1206  AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
   1207 
   1208  bool ok = EvaluateInEnv(cx, env, frame, chars, options, keys, values, &rval);
   1209  Rooted<Completion> completion(cx, Completion::fromJSResult(cx, ok, rval));
   1210  ar.reset();
   1211  return completion.get();
   1212 }
   1213 
   1214 /* static */
   1215 Result<Completion> DebuggerFrame::eval(JSContext* cx,
   1216                                       Handle<DebuggerFrame*> frame,
   1217                                       mozilla::Range<const char16_t> chars,
   1218                                       HandleObject bindings,
   1219                                       const EvalOptions& options) {
   1220  MOZ_ASSERT(options.kind() == EvalOptions::EnvKind::Frame ||
   1221             options.kind() == EvalOptions::EnvKind::FrameWithExtraBindings);
   1222  MOZ_ASSERT(frame->isOnStack());
   1223 
   1224  Debugger* dbg = frame->owner();
   1225  FrameIter iter = frame->getFrameIter(cx);
   1226 
   1227  UpdateFrameIterPc(iter);
   1228 
   1229  return DebuggerGenericEval(cx, chars, bindings, options, dbg, nullptr, &iter);
   1230 }
   1231 
   1232 bool DebuggerFrame::isOnStack() const {
   1233  // Note: this is equivalent to checking frameIterData() != nullptr.
   1234  return !getFixedSlot(FRAME_ITER_SLOT).isUndefined();
   1235 }
   1236 
   1237 bool DebuggerFrame::isOnStackOrSuspendedWasmStack() const {
   1238  // Note: this is equivalent to checking `frameIterData() != nullptr &&
   1239  // !hasGeneratorInfo()`, but works also when called from the trace hook
   1240  // during a moving GC.
   1241  return !getFixedSlot(FRAME_ITER_SLOT).isUndefined() ||
   1242         getFixedSlot(GENERATOR_INFO_SLOT).isUndefined();
   1243 }
   1244 
   1245 OnStepHandler* DebuggerFrame::onStepHandler() const {
   1246  return maybePtrFromReservedSlot<OnStepHandler>(ONSTEP_HANDLER_SLOT);
   1247 }
   1248 
   1249 OnPopHandler* DebuggerFrame::onPopHandler() const {
   1250  return maybePtrFromReservedSlot<OnPopHandler>(ONPOP_HANDLER_SLOT);
   1251 }
   1252 
   1253 void DebuggerFrame::setOnPopHandler(JSContext* cx, OnPopHandler* handler) {
   1254  OnPopHandler* prior = onPopHandler();
   1255  if (handler == prior) {
   1256    return;
   1257  }
   1258 
   1259  JS::GCContext* gcx = cx->gcContext();
   1260 
   1261  if (prior) {
   1262    prior->drop(gcx, this);
   1263  }
   1264 
   1265  if (handler) {
   1266    setReservedSlot(ONPOP_HANDLER_SLOT, PrivateValue(handler));
   1267    handler->hold(this);
   1268  } else {
   1269    setReservedSlot(ONPOP_HANDLER_SLOT, UndefinedValue());
   1270  }
   1271 }
   1272 
   1273 FrameIter::Data* DebuggerFrame::frameIterData() const {
   1274  return maybePtrFromReservedSlot<FrameIter::Data>(FRAME_ITER_SLOT);
   1275 }
   1276 
   1277 /* static */
   1278 AbstractFramePtr DebuggerFrame::getReferent(Handle<DebuggerFrame*> frame) {
   1279  FrameIter iter(*frame->frameIterData());
   1280  return iter.abstractFramePtr();
   1281 }
   1282 
   1283 FrameIter DebuggerFrame::getFrameIter(JSContext* cx) {
   1284  FrameIter::Data* data = frameIterData();
   1285  MOZ_ASSERT(data);
   1286  MOZ_ASSERT(data->cx_ == cx);
   1287 
   1288  return FrameIter(*data);
   1289 }
   1290 
   1291 /* static */
   1292 bool DebuggerFrame::requireScriptReferent(JSContext* cx,
   1293                                          Handle<DebuggerFrame*> frame) {
   1294  AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
   1295  if (!referent.hasScript()) {
   1296    RootedValue frameobj(cx, ObjectValue(*frame));
   1297    ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, frameobj,
   1298                     nullptr, "a script frame");
   1299    return false;
   1300  }
   1301  return true;
   1302 }
   1303 
   1304 void DebuggerFrame::setFrameIterData(FrameIter::Data* data) {
   1305  MOZ_ASSERT(data);
   1306  MOZ_ASSERT(!frameIterData());
   1307  InitReservedSlot(this, FRAME_ITER_SLOT, data,
   1308                   MemoryUse::DebuggerFrameIterData);
   1309 }
   1310 
   1311 void DebuggerFrame::freeFrameIterData(JS::GCContext* gcx) {
   1312  if (FrameIter::Data* data = frameIterData()) {
   1313    gcx->delete_(this, data, MemoryUse::DebuggerFrameIterData);
   1314    setReservedSlot(FRAME_ITER_SLOT, UndefinedValue());
   1315  }
   1316 }
   1317 
   1318 bool DebuggerFrame::replaceFrameIterData(JSContext* cx, const FrameIter& iter) {
   1319  FrameIter::Data* data = iter.copyData();
   1320  if (!data) {
   1321    return false;
   1322  }
   1323  freeFrameIterData(cx->gcContext());
   1324  setFrameIterData(data);
   1325  return true;
   1326 }
   1327 
   1328 /* static */
   1329 void DebuggerFrame::finalize(JS::GCContext* gcx, JSObject* obj) {
   1330  MOZ_ASSERT(gcx->onMainThread());
   1331 
   1332  DebuggerFrame& frameobj = obj->as<DebuggerFrame>();
   1333 
   1334  // Connections between dying Debugger.Frames and their
   1335  // AbstractGeneratorObjects, as well as the frame's stack data should have
   1336  // been by a call to terminate() from sweepAll or some other place.
   1337  MOZ_ASSERT(!frameobj.hasGeneratorInfo());
   1338  MOZ_ASSERT(!frameobj.frameIterData());
   1339  OnStepHandler* onStepHandler = frameobj.onStepHandler();
   1340  if (onStepHandler) {
   1341    onStepHandler->drop(gcx, &frameobj);
   1342  }
   1343  OnPopHandler* onPopHandler = frameobj.onPopHandler();
   1344  if (onPopHandler) {
   1345    onPopHandler->drop(gcx, &frameobj);
   1346  }
   1347 }
   1348 
   1349 void DebuggerFrame::trace(JSTracer* trc) {
   1350  OnStepHandler* onStepHandler = this->onStepHandler();
   1351  if (onStepHandler) {
   1352    onStepHandler->trace(trc);
   1353  }
   1354  OnPopHandler* onPopHandler = this->onPopHandler();
   1355  if (onPopHandler) {
   1356    onPopHandler->trace(trc);
   1357  }
   1358 
   1359  if (hasGeneratorInfo()) {
   1360    generatorInfo()->trace(trc, *this);
   1361  }
   1362 }
   1363 
   1364 /* static */
   1365 DebuggerFrame* DebuggerFrame::check(JSContext* cx, HandleValue thisv) {
   1366  JSObject* thisobj = RequireObject(cx, thisv);
   1367  if (!thisobj) {
   1368    return nullptr;
   1369  }
   1370  if (!thisobj->is<DebuggerFrame>()) {
   1371    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1372                              JSMSG_INCOMPATIBLE_PROTO, "Debugger.Frame",
   1373                              "method", thisobj->getClass()->name);
   1374    return nullptr;
   1375  }
   1376 
   1377  return &thisobj->as<DebuggerFrame>();
   1378 }
   1379 
   1380 struct MOZ_STACK_CLASS DebuggerFrame::CallData {
   1381  JSContext* cx;
   1382  const CallArgs& args;
   1383 
   1384  Handle<DebuggerFrame*> frame;
   1385 
   1386  CallData(JSContext* cx, const CallArgs& args, Handle<DebuggerFrame*> frame)
   1387      : cx(cx), args(args), frame(frame) {}
   1388 
   1389  bool argumentsGetter();
   1390  bool calleeGetter();
   1391  bool constructingGetter();
   1392  bool environmentGetter();
   1393  bool generatorGetter();
   1394  bool asyncPromiseGetter();
   1395  bool olderSavedFrameGetter();
   1396  bool liveGetter();
   1397  bool onStackGetter();
   1398  bool terminatedGetter();
   1399  bool offsetGetter();
   1400  bool olderGetter();
   1401  bool getScript();
   1402  bool thisGetter();
   1403  bool typeGetter();
   1404  bool implementationGetter();
   1405  bool onStepGetter();
   1406  bool onStepSetter();
   1407  bool onPopGetter();
   1408  bool onPopSetter();
   1409  bool evalMethod();
   1410  bool evalWithBindingsMethod();
   1411 
   1412  using Method = bool (CallData::*)();
   1413 
   1414  template <Method MyMethod>
   1415  static bool ToNative(JSContext* cx, unsigned argc, Value* vp);
   1416 
   1417  bool ensureOnStack() const;
   1418  bool ensureOnStackOrSuspended() const;
   1419 };
   1420 
   1421 template <DebuggerFrame::CallData::Method MyMethod>
   1422 /* static */
   1423 bool DebuggerFrame::CallData::ToNative(JSContext* cx, unsigned argc,
   1424                                       Value* vp) {
   1425  CallArgs args = CallArgsFromVp(argc, vp);
   1426 
   1427  Rooted<DebuggerFrame*> frame(cx, DebuggerFrame::check(cx, args.thisv()));
   1428  if (!frame) {
   1429    return false;
   1430  }
   1431 
   1432  CallData data(cx, args, frame);
   1433  return (data.*MyMethod)();
   1434 }
   1435 
   1436 static bool EnsureOnStack(JSContext* cx, Handle<DebuggerFrame*> frame) {
   1437  MOZ_ASSERT(frame);
   1438  if (!frame->isOnStack()) {
   1439    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1440                              JSMSG_DEBUG_NOT_ON_STACK, "Debugger.Frame");
   1441    return false;
   1442  }
   1443 
   1444  return true;
   1445 }
   1446 static bool EnsureOnStackOrSuspended(JSContext* cx,
   1447                                     Handle<DebuggerFrame*> frame) {
   1448  MOZ_ASSERT(frame);
   1449  if (!frame->isOnStack() && !frame->isSuspended()) {
   1450    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1451                              JSMSG_DEBUG_NOT_ON_STACK_OR_SUSPENDED,
   1452                              "Debugger.Frame");
   1453    return false;
   1454  }
   1455 
   1456  return true;
   1457 }
   1458 
   1459 bool DebuggerFrame::CallData::ensureOnStack() const {
   1460  return EnsureOnStack(cx, frame);
   1461 }
   1462 bool DebuggerFrame::CallData::ensureOnStackOrSuspended() const {
   1463  return EnsureOnStackOrSuspended(cx, frame);
   1464 }
   1465 
   1466 bool DebuggerFrame::CallData::typeGetter() {
   1467  if (!ensureOnStackOrSuspended()) {
   1468    return false;
   1469  }
   1470 
   1471  DebuggerFrameType type = DebuggerFrame::getType(frame);
   1472 
   1473  JSString* str;
   1474  switch (type) {
   1475    case DebuggerFrameType::Eval:
   1476      str = cx->names().eval;
   1477      break;
   1478    case DebuggerFrameType::Global:
   1479      str = cx->names().global;
   1480      break;
   1481    case DebuggerFrameType::Call:
   1482      str = cx->names().call;
   1483      break;
   1484    case DebuggerFrameType::Module:
   1485      str = cx->names().module;
   1486      break;
   1487    case DebuggerFrameType::WasmCall:
   1488      str = cx->names().wasmcall;
   1489      break;
   1490    default:
   1491      MOZ_CRASH("bad DebuggerFrameType value");
   1492  }
   1493 
   1494  args.rval().setString(str);
   1495  return true;
   1496 }
   1497 
   1498 bool DebuggerFrame::CallData::implementationGetter() {
   1499  if (!ensureOnStack()) {
   1500    return false;
   1501  }
   1502 
   1503  DebuggerFrameImplementation implementation =
   1504      DebuggerFrame::getImplementation(frame);
   1505 
   1506  const char* s;
   1507  switch (implementation) {
   1508    case DebuggerFrameImplementation::Baseline:
   1509      s = "baseline";
   1510      break;
   1511    case DebuggerFrameImplementation::Ion:
   1512      s = "ion";
   1513      break;
   1514    case DebuggerFrameImplementation::Interpreter:
   1515      s = "interpreter";
   1516      break;
   1517    case DebuggerFrameImplementation::Wasm:
   1518      s = "wasm";
   1519      break;
   1520    default:
   1521      MOZ_CRASH("bad DebuggerFrameImplementation value");
   1522  }
   1523 
   1524  JSAtom* str = Atomize(cx, s, strlen(s));
   1525  if (!str) {
   1526    return false;
   1527  }
   1528 
   1529  args.rval().setString(str);
   1530  return true;
   1531 }
   1532 
   1533 bool DebuggerFrame::CallData::environmentGetter() {
   1534  if (!ensureOnStackOrSuspended()) {
   1535    return false;
   1536  }
   1537 
   1538  Rooted<DebuggerEnvironment*> result(cx);
   1539  if (!DebuggerFrame::getEnvironment(cx, frame, &result)) {
   1540    return false;
   1541  }
   1542 
   1543  args.rval().setObject(*result);
   1544  return true;
   1545 }
   1546 
   1547 bool DebuggerFrame::CallData::calleeGetter() {
   1548  if (!ensureOnStackOrSuspended()) {
   1549    return false;
   1550  }
   1551 
   1552  Rooted<DebuggerObject*> result(cx);
   1553  if (!DebuggerFrame::getCallee(cx, frame, &result)) {
   1554    return false;
   1555  }
   1556 
   1557  args.rval().setObjectOrNull(result);
   1558  return true;
   1559 }
   1560 
   1561 bool DebuggerFrame::CallData::generatorGetter() {
   1562  JS_ReportErrorASCII(cx,
   1563                      "Debugger.Frame.prototype.generator has been removed. "
   1564                      "Use frame.script.isGeneratorFunction instead.");
   1565  return false;
   1566 }
   1567 
   1568 bool DebuggerFrame::CallData::constructingGetter() {
   1569  if (!ensureOnStackOrSuspended()) {
   1570    return false;
   1571  }
   1572 
   1573  bool result;
   1574  if (!DebuggerFrame::getIsConstructing(cx, frame, result)) {
   1575    return false;
   1576  }
   1577 
   1578  args.rval().setBoolean(result);
   1579  return true;
   1580 }
   1581 
   1582 bool DebuggerFrame::CallData::asyncPromiseGetter() {
   1583  if (!ensureOnStackOrSuspended()) {
   1584    return false;
   1585  }
   1586 
   1587  RootedScript script(cx);
   1588  if (frame->isOnStack()) {
   1589    FrameIter iter = frame->getFrameIter(cx);
   1590    AbstractFramePtr framePtr = iter.abstractFramePtr();
   1591 
   1592    if (!framePtr.isWasmDebugFrame()) {
   1593      script = framePtr.script();
   1594    }
   1595  } else {
   1596    MOZ_ASSERT(frame->isSuspended());
   1597    script = frame->generatorInfo()->generatorScript();
   1598  }
   1599  // The async promise value is only provided for async functions and
   1600  // async generator functions.
   1601  if (!script || !script->isAsync()) {
   1602    args.rval().setUndefined();
   1603    return true;
   1604  }
   1605 
   1606  Rooted<DebuggerObject*> result(cx);
   1607  if (!DebuggerFrame::getAsyncPromise(cx, frame, &result)) {
   1608    return false;
   1609  }
   1610 
   1611  args.rval().setObjectOrNull(result);
   1612  return true;
   1613 }
   1614 
   1615 bool DebuggerFrame::CallData::olderSavedFrameGetter() {
   1616  if (!ensureOnStackOrSuspended()) {
   1617    return false;
   1618  }
   1619 
   1620  Rooted<SavedFrame*> result(cx);
   1621  if (!DebuggerFrame::getOlderSavedFrame(cx, frame, &result)) {
   1622    return false;
   1623  }
   1624 
   1625  args.rval().setObjectOrNull(result);
   1626  return true;
   1627 }
   1628 
   1629 /* static */
   1630 bool DebuggerFrame::getOlderSavedFrame(JSContext* cx,
   1631                                       Handle<DebuggerFrame*> frame,
   1632                                       MutableHandle<SavedFrame*> result) {
   1633  if (frame->isOnStack()) {
   1634    Debugger* dbg = frame->owner();
   1635    FrameIter iter = frame->getFrameIter(cx);
   1636 
   1637    while (true) {
   1638      Activation& activation = *iter.activation();
   1639      ++iter;
   1640 
   1641      // If the parent frame crosses an explicit async stack boundary, or we
   1642      // have hit the end of the synchronous frames, we want to switch over
   1643      // to using SavedFrames.
   1644      if (iter.activation() != &activation && activation.asyncStack() &&
   1645          (activation.asyncCallIsExplicit() || iter.done())) {
   1646        const char* cause = activation.asyncCause();
   1647        Rooted<JSAtom*> causeAtom(cx,
   1648                                  AtomizeUTF8Chars(cx, cause, strlen(cause)));
   1649        if (!causeAtom) {
   1650          return false;
   1651        }
   1652        Rooted<SavedFrame*> stackObj(cx, activation.asyncStack());
   1653 
   1654        return cx->realm()->savedStacks().copyAsyncStack(
   1655            cx, stackObj, causeAtom, result, mozilla::Nothing());
   1656      }
   1657 
   1658      // If there are no more parent frames, we're done.
   1659      if (iter.done()) {
   1660        break;
   1661      }
   1662 
   1663      // If we hit another frame that we observe, then there is no saved
   1664      // frame that we'd want to return.
   1665      if (dbg->observesFrame(iter)) {
   1666        break;
   1667      }
   1668    }
   1669  } else {
   1670    MOZ_ASSERT(frame->isSuspended());
   1671  }
   1672 
   1673  result.set(nullptr);
   1674  return true;
   1675 }
   1676 
   1677 bool DebuggerFrame::CallData::thisGetter() {
   1678  if (!ensureOnStackOrSuspended()) {
   1679    return false;
   1680  }
   1681 
   1682  return DebuggerFrame::getThis(cx, frame, args.rval());
   1683 }
   1684 
   1685 bool DebuggerFrame::CallData::olderGetter() {
   1686  if (!ensureOnStackOrSuspended()) {
   1687    return false;
   1688  }
   1689 
   1690  Rooted<DebuggerFrame*> result(cx);
   1691  if (!DebuggerFrame::getOlder(cx, frame, &result)) {
   1692    return false;
   1693  }
   1694 
   1695  args.rval().setObjectOrNull(result);
   1696  return true;
   1697 }
   1698 
   1699 // The getter used for each element of frame.arguments.
   1700 // See DebuggerFrame::getArguments.
   1701 static bool DebuggerArguments_getArg(JSContext* cx, unsigned argc, Value* vp) {
   1702  CallArgs args = CallArgsFromVp(argc, vp);
   1703  int32_t i = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
   1704 
   1705  // Check that the this value is an Arguments object.
   1706  RootedObject argsobj(cx, RequireObject(cx, args.thisv()));
   1707  if (!argsobj) {
   1708    return false;
   1709  }
   1710  if (argsobj->getClass() != &DebuggerArguments::class_) {
   1711    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1712                              JSMSG_INCOMPATIBLE_PROTO, "Arguments",
   1713                              "getArgument", argsobj->getClass()->name);
   1714    return false;
   1715  }
   1716 
   1717  RootedValue framev(cx, argsobj->as<NativeObject>().getReservedSlot(
   1718                             JSSLOT_DEBUGARGUMENTS_FRAME));
   1719  Rooted<DebuggerFrame*> thisobj(cx, DebuggerFrame::check(cx, framev));
   1720  if (!thisobj || !EnsureOnStack(cx, thisobj)) {
   1721    return false;
   1722  }
   1723 
   1724  FrameIter iter = thisobj->getFrameIter(cx);
   1725  AbstractFramePtr frame = iter.abstractFramePtr();
   1726 
   1727  // TODO handle wasm frame arguments -- they are not yet reflectable.
   1728  MOZ_ASSERT(!frame.isWasmDebugFrame(), "a wasm frame args");
   1729 
   1730  // Since getters can be extracted and applied to other objects,
   1731  // there is no guarantee this object has an ith argument.
   1732  MOZ_ASSERT(i >= 0);
   1733  RootedValue arg(cx);
   1734  RootedScript script(cx);
   1735  if (unsigned(i) < frame.numActualArgs()) {
   1736    script = frame.script();
   1737    if (unsigned(i) < frame.numFormalArgs()) {
   1738      for (PositionalFormalParameterIter fi(script); fi; fi++) {
   1739        if (fi.argumentSlot() == unsigned(i)) {
   1740          // We might've been called before the CallObject was created or
   1741          // initialized in the prologue.
   1742          if (fi.closedOver() && frame.hasInitialEnvironment() &&
   1743              iter.pc() >= script->main()) {
   1744            arg = frame.callObj().aliasedBinding(fi);
   1745          } else {
   1746            arg = frame.unaliasedActual(i, DONT_CHECK_ALIASING);
   1747          }
   1748          break;
   1749        }
   1750      }
   1751    } else if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
   1752      arg = frame.argsObj().arg(i);
   1753    } else {
   1754      arg = frame.unaliasedActual(i, DONT_CHECK_ALIASING);
   1755    }
   1756  } else {
   1757    arg.setUndefined();
   1758  }
   1759 
   1760  if (!thisobj->owner()->wrapDebuggeeValue(cx, &arg)) {
   1761    return false;
   1762  }
   1763  args.rval().set(arg);
   1764  return true;
   1765 }
   1766 
   1767 /* static */
   1768 DebuggerArguments* DebuggerArguments::create(JSContext* cx, HandleObject proto,
   1769                                             Handle<DebuggerFrame*> frame) {
   1770  AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
   1771 
   1772  Rooted<DebuggerArguments*> obj(
   1773      cx, NewObjectWithGivenProto<DebuggerArguments>(cx, proto));
   1774  if (!obj) {
   1775    return nullptr;
   1776  }
   1777 
   1778  JS::SetReservedSlot(obj, FRAME_SLOT, ObjectValue(*frame));
   1779 
   1780  MOZ_ASSERT(referent.numActualArgs() <= 0x7fffffff);
   1781  unsigned fargc = referent.numActualArgs();
   1782  RootedValue fargcVal(cx, Int32Value(fargc));
   1783  if (!NativeDefineDataProperty(cx, obj, cx->names().length, fargcVal,
   1784                                JSPROP_PERMANENT | JSPROP_READONLY)) {
   1785    return nullptr;
   1786  }
   1787 
   1788  Rooted<jsid> id(cx);
   1789  for (unsigned i = 0; i < fargc; i++) {
   1790    RootedFunction getobj(cx);
   1791    getobj = NewNativeFunction(cx, DebuggerArguments_getArg, 0, nullptr,
   1792                               gc::AllocKind::FUNCTION_EXTENDED);
   1793    if (!getobj) {
   1794      return nullptr;
   1795    }
   1796    id = PropertyKey::Int(i);
   1797    if (!NativeDefineAccessorProperty(cx, obj, id, getobj, nullptr,
   1798                                      JSPROP_ENUMERATE)) {
   1799      return nullptr;
   1800    }
   1801    getobj->setExtendedSlot(0, Int32Value(i));
   1802  }
   1803 
   1804  return obj;
   1805 }
   1806 
   1807 bool DebuggerFrame::CallData::argumentsGetter() {
   1808  if (!ensureOnStack()) {
   1809    return false;
   1810  }
   1811 
   1812  Rooted<DebuggerArguments*> result(cx);
   1813  if (!DebuggerFrame::getArguments(cx, frame, &result)) {
   1814    return false;
   1815  }
   1816 
   1817  args.rval().setObjectOrNull(result);
   1818  return true;
   1819 }
   1820 
   1821 bool DebuggerFrame::CallData::getScript() {
   1822  if (!ensureOnStackOrSuspended()) {
   1823    return false;
   1824  }
   1825 
   1826  Rooted<DebuggerScript*> scriptObject(cx);
   1827 
   1828  Debugger* debug = frame->owner();
   1829  if (frame->isOnStack()) {
   1830    FrameIter iter = frame->getFrameIter(cx);
   1831    AbstractFramePtr framePtr = iter.abstractFramePtr();
   1832 
   1833    if (framePtr.isWasmDebugFrame()) {
   1834      Rooted<WasmInstanceObject*> instance(cx,
   1835                                           framePtr.wasmInstance()->object());
   1836      scriptObject = debug->wrapWasmScript(cx, instance);
   1837    } else {
   1838      RootedScript script(cx, framePtr.script());
   1839      scriptObject = debug->wrapScript(cx, script);
   1840    }
   1841  } else {
   1842    MOZ_ASSERT(frame->isSuspended());
   1843    RootedScript script(cx, frame->generatorInfo()->generatorScript());
   1844    scriptObject = debug->wrapScript(cx, script);
   1845  }
   1846  if (!scriptObject) {
   1847    return false;
   1848  }
   1849 
   1850  args.rval().setObject(*scriptObject);
   1851  return true;
   1852 }
   1853 
   1854 bool DebuggerFrame::CallData::offsetGetter() {
   1855  if (!ensureOnStackOrSuspended()) {
   1856    return false;
   1857  }
   1858 
   1859  size_t result;
   1860  if (!DebuggerFrame::getOffset(cx, frame, result)) {
   1861    return false;
   1862  }
   1863 
   1864  args.rval().setNumber(double(result));
   1865  return true;
   1866 }
   1867 
   1868 bool DebuggerFrame::CallData::liveGetter() {
   1869  JS_ReportErrorASCII(
   1870      cx, "Debugger.Frame.prototype.live has been renamed to .onStack");
   1871  return false;
   1872 }
   1873 
   1874 bool DebuggerFrame::CallData::onStackGetter() {
   1875  args.rval().setBoolean(frame->isOnStack());
   1876  return true;
   1877 }
   1878 
   1879 bool DebuggerFrame::CallData::terminatedGetter() {
   1880  args.rval().setBoolean(!frame->isOnStack() && !frame->isSuspended());
   1881  return true;
   1882 }
   1883 
   1884 static bool IsValidHook(const Value& v) {
   1885  return v.isUndefined() || (v.isObject() && v.toObject().isCallable());
   1886 }
   1887 
   1888 bool DebuggerFrame::CallData::onStepGetter() {
   1889  OnStepHandler* handler = frame->onStepHandler();
   1890  RootedValue value(
   1891      cx, handler ? ObjectOrNullValue(handler->object()) : UndefinedValue());
   1892  MOZ_ASSERT(IsValidHook(value));
   1893  args.rval().set(value);
   1894  return true;
   1895 }
   1896 
   1897 bool DebuggerFrame::CallData::onStepSetter() {
   1898  if (!args.requireAtLeast(cx, "Debugger.Frame.set onStep", 1)) {
   1899    return false;
   1900  }
   1901  if (!IsValidHook(args[0])) {
   1902    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1903                              JSMSG_NOT_CALLABLE_OR_UNDEFINED);
   1904    return false;
   1905  }
   1906 
   1907  UniquePtr<ScriptedOnStepHandler> handler;
   1908  if (!args[0].isUndefined()) {
   1909    handler = cx->make_unique<ScriptedOnStepHandler>(&args[0].toObject());
   1910    if (!handler) {
   1911      return false;
   1912    }
   1913  }
   1914 
   1915  if (!DebuggerFrame::setOnStepHandler(cx, frame, std::move(handler))) {
   1916    return false;
   1917  }
   1918 
   1919  args.rval().setUndefined();
   1920  return true;
   1921 }
   1922 
   1923 bool DebuggerFrame::CallData::onPopGetter() {
   1924  OnPopHandler* handler = frame->onPopHandler();
   1925  RootedValue value(
   1926      cx, handler ? ObjectValue(*handler->object()) : UndefinedValue());
   1927  MOZ_ASSERT(IsValidHook(value));
   1928  args.rval().set(value);
   1929  return true;
   1930 }
   1931 
   1932 bool DebuggerFrame::CallData::onPopSetter() {
   1933  if (!args.requireAtLeast(cx, "Debugger.Frame.set onPop", 1)) {
   1934    return false;
   1935  }
   1936  if (!IsValidHook(args[0])) {
   1937    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1938                              JSMSG_NOT_CALLABLE_OR_UNDEFINED);
   1939    return false;
   1940  }
   1941 
   1942  ScriptedOnPopHandler* handler = nullptr;
   1943  if (!args[0].isUndefined()) {
   1944    handler = cx->new_<ScriptedOnPopHandler>(&args[0].toObject());
   1945    if (!handler) {
   1946      return false;
   1947    }
   1948  }
   1949 
   1950  frame->setOnPopHandler(cx, handler);
   1951 
   1952  args.rval().setUndefined();
   1953  return true;
   1954 }
   1955 
   1956 bool DebuggerFrame::CallData::evalMethod() {
   1957  if (!ensureOnStack()) {
   1958    return false;
   1959  }
   1960 
   1961  if (!args.requireAtLeast(cx, "Debugger.Frame.prototype.eval", 1)) {
   1962    return false;
   1963  }
   1964 
   1965  AutoStableStringChars stableChars(cx);
   1966  if (!ValueToStableChars(cx, "Debugger.Frame.prototype.eval", args[0],
   1967                          stableChars)) {
   1968    return false;
   1969  }
   1970  mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
   1971 
   1972  EvalOptions options(EvalOptions::EnvKind::Frame);
   1973  if (!ParseEvalOptions(cx, args.get(1), options)) {
   1974    return false;
   1975  }
   1976 
   1977  Rooted<Completion> comp(cx);
   1978  JS_TRY_VAR_OR_RETURN_FALSE(
   1979      cx, comp, DebuggerFrame::eval(cx, frame, chars, nullptr, options));
   1980  return comp.get().buildCompletionValue(cx, frame->owner(), args.rval());
   1981 }
   1982 
   1983 bool DebuggerFrame::CallData::evalWithBindingsMethod() {
   1984  if (!ensureOnStack()) {
   1985    return false;
   1986  }
   1987 
   1988  if (!args.requireAtLeast(cx, "Debugger.Frame.prototype.evalWithBindings",
   1989                           2)) {
   1990    return false;
   1991  }
   1992 
   1993  AutoStableStringChars stableChars(cx);
   1994  if (!ValueToStableChars(cx, "Debugger.Frame.prototype.evalWithBindings",
   1995                          args[0], stableChars)) {
   1996    return false;
   1997  }
   1998  mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
   1999 
   2000  RootedObject bindings(cx, RequireObject(cx, args[1]));
   2001  if (!bindings) {
   2002    return false;
   2003  }
   2004 
   2005  EvalOptions options(EvalOptions::EnvKind::FrameWithExtraBindings);
   2006  if (!ParseEvalOptions(cx, args.get(2), options)) {
   2007    return false;
   2008  }
   2009 
   2010  Rooted<Completion> comp(cx);
   2011  JS_TRY_VAR_OR_RETURN_FALSE(
   2012      cx, comp, DebuggerFrame::eval(cx, frame, chars, bindings, options));
   2013  return comp.get().buildCompletionValue(cx, frame->owner(), args.rval());
   2014 }
   2015 
   2016 /* static */
   2017 bool DebuggerFrame::construct(JSContext* cx, unsigned argc, Value* vp) {
   2018  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
   2019                            "Debugger.Frame");
   2020  return false;
   2021 }
   2022 
   2023 const JSPropertySpec DebuggerFrame::properties_[] = {
   2024    JS_DEBUG_PSG("arguments", argumentsGetter),
   2025    JS_DEBUG_PSG("callee", calleeGetter),
   2026    JS_DEBUG_PSG("constructing", constructingGetter),
   2027    JS_DEBUG_PSG("environment", environmentGetter),
   2028    JS_DEBUG_PSG("generator", generatorGetter),
   2029    JS_DEBUG_PSG("live", liveGetter),
   2030    JS_DEBUG_PSG("onStack", onStackGetter),
   2031    JS_DEBUG_PSG("terminated", terminatedGetter),
   2032    JS_DEBUG_PSG("offset", offsetGetter),
   2033    JS_DEBUG_PSG("older", olderGetter),
   2034    JS_DEBUG_PSG("olderSavedFrame", olderSavedFrameGetter),
   2035    JS_DEBUG_PSG("script", getScript),
   2036    JS_DEBUG_PSG("this", thisGetter),
   2037    JS_DEBUG_PSG("asyncPromise", asyncPromiseGetter),
   2038    JS_DEBUG_PSG("type", typeGetter),
   2039    JS_DEBUG_PSG("implementation", implementationGetter),
   2040    JS_DEBUG_PSGS("onStep", onStepGetter, onStepSetter),
   2041    JS_DEBUG_PSGS("onPop", onPopGetter, onPopSetter),
   2042    JS_PS_END,
   2043 };
   2044 
   2045 const JSFunctionSpec DebuggerFrame::methods_[] = {
   2046    JS_DEBUG_FN("eval", evalMethod, 1),
   2047    JS_DEBUG_FN("evalWithBindings", evalWithBindingsMethod, 1),
   2048    JS_FS_END,
   2049 };
   2050 
   2051 JSObject* js::IdVectorToArray(JSContext* cx, HandleIdVector ids) {
   2052  if (MOZ_UNLIKELY(ids.length() > UINT32_MAX)) {
   2053    ReportAllocationOverflow(cx);
   2054    return nullptr;
   2055  }
   2056 
   2057  Rooted<ArrayObject*> arr(cx, NewDenseFullyAllocatedArray(cx, ids.length()));
   2058  if (!arr) {
   2059    return nullptr;
   2060  }
   2061 
   2062  arr->ensureDenseInitializedLength(0, ids.length());
   2063 
   2064  for (size_t i = 0, len = ids.length(); i < len; i++) {
   2065    jsid id = ids[i];
   2066    Value v;
   2067    if (id.isInt()) {
   2068      JSString* str = Int32ToString<CanGC>(cx, id.toInt());
   2069      if (!str) {
   2070        return nullptr;
   2071      }
   2072      v = StringValue(str);
   2073    } else if (id.isAtom()) {
   2074      v = StringValue(id.toAtom());
   2075    } else if (id.isSymbol()) {
   2076      v = SymbolValue(id.toSymbol());
   2077    } else {
   2078      MOZ_CRASH("IdVector must contain only string, int, and Symbol jsids");
   2079    }
   2080 
   2081    arr->initDenseElement(i, v);
   2082  }
   2083 
   2084  return arr;
   2085 }