tor-browser

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

Frame.h (11802B)


      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 #ifndef debugger_Frame_h
      8 #define debugger_Frame_h
      9 
     10 #include "mozilla/Maybe.h"   // for Maybe
     11 #include "mozilla/Range.h"   // for Range
     12 #include "mozilla/Result.h"  // for Result
     13 
     14 #include <stddef.h>  // for size_t
     15 
     16 #include "NamespaceImports.h"   // for Value, MutableHandleValue, HandleObject
     17 #include "debugger/DebugAPI.h"  // for ResumeMode
     18 #include "debugger/Debugger.h"  // for ResumeMode, Handler, Debugger
     19 #include "gc/Barrier.h"         // for HeapPtr
     20 #include "vm/FrameIter.h"       // for FrameIter
     21 #include "vm/JSObject.h"        // for JSObject
     22 #include "vm/NativeObject.h"    // for NativeObject
     23 #include "vm/Stack.h"           // for AbstractFramePtr
     24 
     25 struct JS_PUBLIC_API JSContext;
     26 
     27 namespace js {
     28 
     29 class AbstractGeneratorObject;
     30 class GlobalObject;
     31 
     32 /*
     33 * An OnStepHandler represents a handler function that is called when a small
     34 * amount of progress is made in a frame.
     35 */
     36 struct OnStepHandler : Handler {
     37  /*
     38   * If we have made a small amount of progress in a frame, this method is
     39   * called with the frame as argument. If succesful, this method should
     40   * return true, with `resumeMode` and `vp` set to a resumption value
     41   * specifiying how execution should continue.
     42   */
     43  virtual bool onStep(JSContext* cx, Handle<DebuggerFrame*> frame,
     44                      ResumeMode& resumeMode, MutableHandleValue vp) = 0;
     45 };
     46 
     47 class ScriptedOnStepHandler final : public OnStepHandler {
     48 public:
     49  explicit ScriptedOnStepHandler(JSObject* object);
     50  virtual JSObject* object() const override;
     51  virtual void hold(JSObject* owner) override;
     52  virtual void drop(JS::GCContext* gcx, JSObject* owner) override;
     53  virtual void trace(JSTracer* tracer) override;
     54  virtual size_t allocSize() const override;
     55  virtual bool onStep(JSContext* cx, Handle<DebuggerFrame*> frame,
     56                      ResumeMode& resumeMode, MutableHandleValue vp) override;
     57 
     58 private:
     59  const HeapPtr<JSObject*> object_;
     60 };
     61 
     62 /*
     63 * An OnPopHandler represents a handler function that is called just before a
     64 * frame is popped.
     65 */
     66 struct OnPopHandler : Handler {
     67  /*
     68   * The given `frame` is about to be popped; `completion` explains why.
     69   *
     70   * When this method returns true, it must set `resumeMode` and `vp` to a
     71   * resumption value specifying how execution should continue.
     72   *
     73   * When this method returns false, it should set an exception on `cx`.
     74   */
     75  virtual bool onPop(JSContext* cx, Handle<DebuggerFrame*> frame,
     76                     const Completion& completion, ResumeMode& resumeMode,
     77                     MutableHandleValue vp) = 0;
     78 };
     79 
     80 class ScriptedOnPopHandler final : public OnPopHandler {
     81 public:
     82  explicit ScriptedOnPopHandler(JSObject* object);
     83  virtual JSObject* object() const override;
     84  virtual void hold(JSObject* owner) override;
     85  virtual void drop(JS::GCContext* gcx, JSObject* owner) override;
     86  virtual void trace(JSTracer* tracer) override;
     87  virtual size_t allocSize() const override;
     88  virtual bool onPop(JSContext* cx, Handle<DebuggerFrame*> frame,
     89                     const Completion& completion, ResumeMode& resumeMode,
     90                     MutableHandleValue vp) override;
     91 
     92 private:
     93  const HeapPtr<JSObject*> object_;
     94 };
     95 
     96 enum class DebuggerFrameType { Eval, Global, Call, Module, WasmCall };
     97 
     98 enum class DebuggerFrameImplementation { Interpreter, Baseline, Ion, Wasm };
     99 
    100 class DebuggerArguments : public NativeObject {
    101 public:
    102  static const JSClass class_;
    103 
    104  static DebuggerArguments* create(JSContext* cx, HandleObject proto,
    105                                   Handle<DebuggerFrame*> frame);
    106 
    107 private:
    108  enum { FRAME_SLOT };
    109 
    110  static const unsigned RESERVED_SLOTS = 1;
    111 };
    112 
    113 class DebuggerFrame : public NativeObject {
    114  friend class DebuggerArguments;
    115  friend class ScriptedOnStepHandler;
    116  friend class ScriptedOnPopHandler;
    117 
    118 public:
    119  static const JSClass class_;
    120 
    121  enum {
    122    FRAME_ITER_SLOT = 0,
    123    OWNER_SLOT,
    124    ARGUMENTS_SLOT,
    125    ONSTEP_HANDLER_SLOT,
    126    ONPOP_HANDLER_SLOT,
    127 
    128    // If this is a frame for a generator call, and the generator object has
    129    // been created (which doesn't happen until after default argument
    130    // evaluation and destructuring), then this is a PrivateValue pointing to a
    131    // GeneratorInfo struct that points to the call's AbstractGeneratorObject.
    132    // This allows us to implement Debugger.Frame methods even while the call is
    133    // suspended, and we have no FrameIter::Data.
    134    //
    135    // While Debugger::generatorFrames maps an AbstractGeneratorObject to its
    136    // Debugger.Frame, this link represents the reverse relation, from a
    137    // Debugger.Frame to its generator object. This slot is set if and only if
    138    // there is a corresponding entry in generatorFrames.
    139    GENERATOR_INFO_SLOT,
    140 
    141    RESERVED_SLOTS,
    142  };
    143 
    144  void trace(JSTracer* trc);
    145 
    146  static NativeObject* initClass(JSContext* cx, Handle<GlobalObject*> global,
    147                                 HandleObject dbgCtor);
    148  static DebuggerFrame* create(JSContext* cx, HandleObject proto,
    149                               Handle<NativeObject*> debugger,
    150                               const FrameIter* maybeIter,
    151                               Handle<AbstractGeneratorObject*> maybeGenerator);
    152 
    153  [[nodiscard]] static bool getArguments(
    154      JSContext* cx, Handle<DebuggerFrame*> frame,
    155      MutableHandle<DebuggerArguments*> result);
    156  [[nodiscard]] static bool getCallee(JSContext* cx,
    157                                      Handle<DebuggerFrame*> frame,
    158                                      MutableHandle<DebuggerObject*> result);
    159  [[nodiscard]] static bool getIsConstructing(JSContext* cx,
    160                                              Handle<DebuggerFrame*> frame,
    161                                              bool& result);
    162  [[nodiscard]] static bool getEnvironment(
    163      JSContext* cx, Handle<DebuggerFrame*> frame,
    164      MutableHandle<DebuggerEnvironment*> result);
    165  [[nodiscard]] static bool getOffset(JSContext* cx,
    166                                      Handle<DebuggerFrame*> frame,
    167                                      size_t& result);
    168  [[nodiscard]] static bool getOlder(JSContext* cx,
    169                                     Handle<DebuggerFrame*> frame,
    170                                     MutableHandle<DebuggerFrame*> result);
    171  [[nodiscard]] static bool getAsyncPromise(
    172      JSContext* cx, Handle<DebuggerFrame*> frame,
    173      MutableHandle<DebuggerObject*> result);
    174  [[nodiscard]] static bool getOlderSavedFrame(
    175      JSContext* cx, Handle<DebuggerFrame*> frame,
    176      MutableHandle<SavedFrame*> result);
    177  [[nodiscard]] static bool getThis(JSContext* cx, Handle<DebuggerFrame*> frame,
    178                                    MutableHandleValue result);
    179  static DebuggerFrameType getType(Handle<DebuggerFrame*> frame);
    180  static DebuggerFrameImplementation getImplementation(
    181      Handle<DebuggerFrame*> frame);
    182  [[nodiscard]] static bool setOnStepHandler(JSContext* cx,
    183                                             Handle<DebuggerFrame*> frame,
    184                                             UniquePtr<OnStepHandler> handler);
    185 
    186  [[nodiscard]] static JS::Result<Completion> eval(
    187      JSContext* cx, Handle<DebuggerFrame*> frame,
    188      mozilla::Range<const char16_t> chars, HandleObject bindings,
    189      const EvalOptions& options);
    190 
    191  [[nodiscard]] static DebuggerFrame* check(JSContext* cx, HandleValue thisv);
    192 
    193  bool isOnStack() const;
    194  bool isOnStackOrSuspendedWasmStack() const;
    195 
    196  bool isSuspended() const;
    197 
    198  OnStepHandler* onStepHandler() const;
    199  OnPopHandler* onPopHandler() const;
    200  void setOnPopHandler(JSContext* cx, OnPopHandler* handler);
    201 
    202  inline bool hasGeneratorInfo() const;
    203 
    204  // If hasGeneratorInfo(), return an direct cross-compartment reference to this
    205  // Debugger.Frame's generator object.
    206  AbstractGeneratorObject& unwrappedGenerator() const;
    207 
    208 #ifdef DEBUG
    209  JSScript* generatorScript() const;
    210 #endif
    211 
    212  /*
    213   * Associate the generator object genObj with this Debugger.Frame. This
    214   * association allows the Debugger.Frame to track the generator's execution
    215   * across suspensions and resumptions, and to implement some methods even
    216   * while the generator is suspended.
    217   *
    218   * The context `cx` must be in the Debugger.Frame's realm, and `genObj` must
    219   * be in a debuggee realm.
    220   *
    221   * Technically, the generator activation need not actually be on the stack
    222   * right now; it's okay to call this method on a Debugger.Frame that has no
    223   * ScriptFrameIter::Data at present. However, this function has no way to
    224   * verify that genObj really is the generator associated with the call for
    225   * which this Debugger.Frame was originally created, so it's best to make the
    226   * association while the call is on the stack, and the relationships are easy
    227   * to discern.
    228   */
    229  [[nodiscard]] static bool setGeneratorInfo(
    230      JSContext* cx, Handle<DebuggerFrame*> frame,
    231      Handle<AbstractGeneratorObject*> genObj);
    232 
    233  /*
    234   * Undo the effects of a prior call to setGenerator.
    235   *
    236   * If provided, owner must be the Debugger to which this Debugger.Frame
    237   * belongs; remove this frame's entry from its generatorFrames map, and clean
    238   * up its cross-compartment wrapper table entry. The owner must be passed
    239   * unless this method is being called from the Debugger.Frame's finalizer. (In
    240   * that case, the owner is not reliably available, and is not actually
    241   * necessary.)
    242   *
    243   * If maybeGeneratorFramesEnum is non-null, use it to remove this frame's
    244   * entry from the Debugger's generatorFrames weak map. In this case, this
    245   * function will not otherwise disturb generatorFrames. Passing the enum
    246   * allows this function to be used while iterating over generatorFrames.
    247   */
    248  void clearGeneratorInfo(JS::GCContext* gcx);
    249 
    250  /*
    251   * Called after a generator/async frame is resumed, before exposing this
    252   * Debugger.Frame object to any hooks.
    253   */
    254  bool resume(const FrameIter& iter);
    255 
    256  /*
    257   * Called when JS PI sets aside the suspendable stack frames.
    258   */
    259  void suspendWasmFrame(JS::GCContext* gcx);
    260 
    261  bool hasAnyHooks() const;
    262 
    263  Debugger* owner() const;
    264 
    265 private:
    266  static const JSClassOps classOps_;
    267 
    268  static const JSPropertySpec properties_[];
    269  static const JSFunctionSpec methods_[];
    270 
    271  static void finalize(JS::GCContext* gcx, JSObject* obj);
    272 
    273  static AbstractFramePtr getReferent(Handle<DebuggerFrame*> frame);
    274  [[nodiscard]] static bool requireScriptReferent(JSContext* cx,
    275                                                  Handle<DebuggerFrame*> frame);
    276 
    277  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
    278 
    279  struct CallData;
    280 
    281  [[nodiscard]] bool incrementStepperCounter(JSContext* cx,
    282                                             AbstractFramePtr referent);
    283  [[nodiscard]] bool incrementStepperCounter(JSContext* cx,
    284                                             HandleScript script);
    285  void decrementStepperCounter(JS::GCContext* gcx, JSScript* script);
    286  void decrementStepperCounter(JS::GCContext* gcx, AbstractFramePtr referent);
    287 
    288  FrameIter::Data* frameIterData() const;
    289  void setFrameIterData(FrameIter::Data*);
    290  void freeFrameIterData(JS::GCContext* gcx);
    291 
    292 public:
    293  FrameIter getFrameIter(JSContext* cx);
    294 
    295  void terminate(JS::GCContext* gcx, AbstractFramePtr frame);
    296  void onGeneratorClosed(JS::GCContext* gcx);
    297  void suspend(JS::GCContext* gcx);
    298 
    299  [[nodiscard]] bool replaceFrameIterData(JSContext* cx, const FrameIter&);
    300 
    301  class GeneratorInfo;
    302  inline GeneratorInfo* generatorInfo() const;
    303 };
    304 
    305 } /* namespace js */
    306 
    307 #endif /* debugger_Frame_h */