tor-browser

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

DebugScript.h (5479B)


      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 dbg_DebugScript_h
      8 #define dbg_DebugScript_h
      9 
     10 #include <stddef.h>  // for offsetof
     11 #include <stddef.h>  // for size_t
     12 #include <stdint.h>  // for uint32_t
     13 
     14 #include "jstypes.h"
     15 
     16 #include "gc/WeakMap.h"
     17 #include "vm/NativeObject.h"
     18 
     19 namespace JS {
     20 class JS_PUBLIC_API Realm;
     21 }
     22 
     23 namespace js {
     24 
     25 class JSBreakpointSite;
     26 class Debugger;
     27 class DebugScriptObject;
     28 
     29 // DebugScript manages the internal debugger state for a JSScript, which may be
     30 // associated with multiple Debuggers.
     31 class DebugScript {
     32  friend class DebugAPI;
     33  friend class DebugScriptObject;
     34 
     35  /*
     36   * If this is a generator script, this is the number of Debugger.Frames
     37   * referring to calls to this generator, whether live or suspended. Closed
     38   * generators do not contribute a count.
     39   *
     40   * When greater than zero, this script should be compiled with debug
     41   * instrumentation to call Debugger::onResumeFrame at each resumption site, so
     42   * that Debugger can reconnect any extant Debugger.Frames with the new
     43   * concrete frame.
     44   */
     45  uint32_t generatorObserverCount;
     46 
     47  /*
     48   * The number of Debugger.Frame objects that refer to frames running this
     49   * script and that have onStep handlers. When nonzero, the interpreter and JIT
     50   * must arrange to call Debugger::onSingleStep before each bytecode, or at
     51   * least at some useful granularity.
     52   */
     53  uint32_t stepperCount;
     54 
     55  /*
     56   * The size of the script as reported by BaseScript::length. This is the
     57   * length of the DebugScript::breakpoints array, below.
     58   */
     59  size_t codeLength;
     60 
     61  /*
     62   * Number of breakpoint sites at opcodes in the script. This is the number
     63   * of populated entries in DebugScript::breakpoints.
     64   */
     65  uint32_t numSites;
     66 
     67  /*
     68   * Breakpoints set in our script. For speed and simplicity, this array is
     69   * parallel to script->code(): the JSBreakpointSite for the opcode at
     70   * script->code()[offset] is debugScript->breakpoints[offset].
     71   */
     72  JSBreakpointSite* breakpoints[1];
     73 
     74  /*
     75   * True if this DebugScript carries any useful information. If false, it
     76   * should be removed from its JSScript.
     77   */
     78  bool needed() const {
     79    return generatorObserverCount > 0 || stepperCount > 0 || numSites > 0;
     80  }
     81 
     82  static size_t allocSize(size_t codeLength) {
     83    return offsetof(DebugScript, breakpoints) +
     84           codeLength * sizeof(JSBreakpointSite*);
     85  }
     86 
     87  void trace(JSTracer* trc);
     88  void delete_(JS::GCContext* gcx, DebugScriptObject* owner);
     89 
     90  static DebugScript* get(JSScript* script);
     91  static DebugScript* getUnbarriered(JSScript* script);
     92  static DebugScript* getOrCreate(JSContext* cx, HandleScript script);
     93 
     94 public:
     95  static bool hasBreakpointSite(JSScript* script, jsbytecode* pc);
     96  static JSBreakpointSite* getBreakpointSite(JSScript* script, jsbytecode* pc);
     97  static JSBreakpointSite* getOrCreateBreakpointSite(JSContext* cx,
     98                                                     HandleScript script,
     99                                                     jsbytecode* pc);
    100  static void destroyBreakpointSite(JS::GCContext* gcx, JSScript* script,
    101                                    jsbytecode* pc);
    102 
    103  static void clearBreakpointsIn(JS::GCContext* gcx, JSScript* script,
    104                                 Debugger* dbg, JSObject* handler);
    105 
    106 #ifdef DEBUG
    107  static uint32_t getStepperCount(JSScript* script);
    108 #endif
    109 
    110  /*
    111   * Increment or decrement the single-step count. If the count is non-zero
    112   * then the script is in single-step mode.
    113   *
    114   * Only incrementing is fallible, as it could allocate a DebugScript.
    115   */
    116  [[nodiscard]] static bool incrementStepperCount(JSContext* cx,
    117                                                  HandleScript script);
    118  static void decrementStepperCount(JS::GCContext* gcx, JSScript* script);
    119 
    120  /*
    121   * Increment or decrement the generator observer count. If the count is
    122   * non-zero then the script reports resumptions to the debugger.
    123   *
    124   * Only incrementing is fallible, as it could allocate a DebugScript.
    125   */
    126  [[nodiscard]] static bool incrementGeneratorObserverCount(
    127      JSContext* cx, HandleScript script);
    128  static void decrementGeneratorObserverCount(JS::GCContext* gcx,
    129                                              JSScript* script);
    130 };
    131 
    132 using UniqueDebugScript = js::UniquePtr<DebugScript, JS::FreePolicy>;
    133 
    134 // A JSObject that wraps a DebugScript, so we can use it as the value in a
    135 // WeakMap. This object owns the DebugScript and is responsible for deleting it.
    136 class DebugScriptObject : public NativeObject {
    137 public:
    138  static const JSClass class_;
    139 
    140  enum { ScriptSlot, SlotCount };
    141 
    142  static DebugScriptObject* create(JSContext* cx, UniqueDebugScript debugScript,
    143                                   size_t nbytes);
    144 
    145  DebugScript* debugScript() const;
    146 
    147 private:
    148  static const JSClassOps classOps_;
    149 
    150  static void trace(JSTracer* trc, JSObject* obj);
    151  static void finalize(JS::GCContext* gcx, JSObject* obj);
    152 };
    153 
    154 // A weak map from JSScripts to DebugScriptObjects.
    155 class DebugScriptMap
    156    : public WeakMap<JSScript*, DebugScriptObject*, ZoneAllocPolicy> {
    157 public:
    158  explicit DebugScriptMap(JSContext* cx) : WeakMap(cx) {}
    159 };
    160 
    161 } /* namespace js */
    162 
    163 #endif /* dbg_DebugScript_h */