tor-browser

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

Debug.h (32425B)


      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 // Interfaces by which the embedding can interact with the Debugger API.
      8 
      9 #ifndef js_Debug_h
     10 #define js_Debug_h
     11 
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/BaseProfilerUtils.h"
     14 #include "mozilla/MemoryReporting.h"
     15 #include "mozilla/Vector.h"
     16 
     17 #include "jstypes.h"
     18 
     19 #include "js/GCAPI.h"
     20 #include "js/RootingAPI.h"
     21 #include "js/TypeDecls.h"
     22 #include "js/Value.h"
     23 
     24 namespace js {
     25 class Debugger;
     26 }  // namespace js
     27 
     28 /* Defined in vm/Debugger.cpp. */
     29 extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
     30                                                  JS::HandleObject obj);
     31 
     32 extern JS_PUBLIC_API const char* JS_GetLastOOMStackTrace(JSContext* cx);
     33 
     34 // If the JS execution tracer is running, this will generate a
     35 // ENTRY_KIND_LABEL_ENTER entry with the specified label.
     36 // The consumer of the trace can then, for instance, correlate all code running
     37 // after this entry and before the corresponding ENTRY_KIND_LABEL_LEAVE with the
     38 // provided label.
     39 // If the tracer is not running, this does nothing.
     40 extern JS_PUBLIC_API void JS_TracerEnterLabelLatin1(JSContext* cx,
     41                                                    const char* label);
     42 extern JS_PUBLIC_API void JS_TracerEnterLabelTwoByte(JSContext* cx,
     43                                                     const char16_t* label);
     44 
     45 extern JS_PUBLIC_API bool JS_TracerIsTracing(JSContext* cx);
     46 
     47 // If the JS execution tracer is running, this will generate a
     48 // ENTRY_KIND_LABEL_LEAVE entry with the specified label.
     49 // It is up to the consumer to decide what to do with a ENTRY_KIND_LABEL_LEAVE
     50 // entry is encountered without a corresponding ENTRY_KIND_LABEL_ENTER.
     51 // If the tracer is not running, this does nothing.
     52 extern JS_PUBLIC_API void JS_TracerLeaveLabelLatin1(JSContext* cx,
     53                                                    const char* label);
     54 extern JS_PUBLIC_API void JS_TracerLeaveLabelTwoByte(JSContext* cx,
     55                                                     const char16_t* label);
     56 
     57 #ifdef MOZ_EXECUTION_TRACING
     58 
     59 // This will begin execution tracing for the JSContext, i.e., this will begin
     60 // recording every entrance into / exit from a function for the given context.
     61 // The trace can be read via JS_TracerSnapshotTrace, and populates the
     62 // ExecutionTrace struct defined below.
     63 //
     64 // This throws if the code coverage is active for any realm in the context.
     65 extern JS_PUBLIC_API bool JS_TracerBeginTracing(JSContext* cx);
     66 
     67 // This ends execution tracing for the JSContext, discards the tracing
     68 // buffers, and clears some caches used for tracing. JS_TracerSnapshotTrace
     69 // should be called *before* JS_TracerEndTracing if you want to read the trace
     70 // data for this JSContext.
     71 extern JS_PUBLIC_API bool JS_TracerEndTracing(JSContext* cx);
     72 
     73 namespace JS {
     74 
     75 // Encoding values used for strings recorded via the tracer.
     76 enum class TracerStringEncoding {
     77  Latin1,
     78  TwoByte,
     79  UTF8,
     80 };
     81 
     82 // Value Summary
     83 //
     84 // Value summaries are intended as a best effort, minimal representation of
     85 // values, for the purpose of understanding/debugging an application from a
     86 // recorded trace. At present, we record value summaries for the first
     87 // MAX_ARGUMENTS_TO_RECORD arguments of every function call we record when
     88 // tracing is enabled via JS_TracerBeginTracing above. Value summaries are
     89 // surfaced as a contiguous buffer which is intended to be read as needed
     90 // by looking up values as needed via the index in the `values` field of
     91 // FunctionEnter events in the recorded trace. There is a reader in the
     92 // Firefox Profiler frontend which unpacks the binary representation into
     93 // more easily understandable objects.
     94 //
     95 // Value Summary Types
     96 //
     97 // (NOTE: All values listed below use little-endian byte ordering)
     98 //
     99 // - List<T> - A list of at most MAX_COLLECTION_VALUES items and structured as
    100 //   follows:
    101 //      length:   uint32_t
    102 //      values:   T[min(length, MAX_COLLECTION_VALUES)]
    103 //
    104 // - NestedList<T> - If this is a field of ValueSummary which is not itself
    105 //   nested inside another ValueSummary, this will be the same as a List<T>.
    106 //   However, if it *is* nested, it will contain only the length:
    107 //      length:     uint32_t
    108 //      if not inside another ValueSummary ->
    109 //        values:   T[min(length, MAX_COLLECTION_VALUES)]
    110 //
    111 // - SmallString - a string limited to a length of SMALL_STRING_LENGTH_LIMIT,
    112 //   with the following structure:
    113 //      encodingAndLength:  uint16_t (encoding << 14 | length)
    114 //      payload:            CharT[length]
    115 //   The encoding is one of the values in TracerStringEncoding, and CharT is
    116 //   a char for Latin1 and UTF8, and a char16_t for TwoByte. It should be
    117 //   noted that the original string length before truncation to
    118 //   SMALL_STRING_LENGTH_LIMIT is not written, so it is not possible to
    119 //   distinguish between cases where a string had a true length of
    120 //   SMALL_STRING_LENGTH_LIMIT vs cases where a string was truncated.
    121 //
    122 // - Pair<T,U> - A pairing of a T followed immediately by a U
    123 //      first: T
    124 //      second: U
    125 //
    126 // Value Summary Structure
    127 //
    128 // (NOTE: Here and below, see Value Summary Types for more on what
    129 // the type annotations mean.)
    130 //
    131 //    typeAndFlags:   uint8_t (type << 4 | flags)
    132 //    payload:        see below
    133 //
    134 // The value payload's structure depends on the type and the flags:
    135 //
    136 //    JS::ValueType::Undefined ->       nothing
    137 //    JS::ValueType::Null ->            nothing
    138 //    JS::ValueType::Magic ->           nothing
    139 //      NOTE: JS::ValueType::Magic is only used for dense element holes.
    140 //    JS::ValueType::Boolean ->         nothing
    141 //      NOTE: For a JS::ValueType::Boolean, `flags` will hold `1` for `true`,
    142 //      and `0` for `false`.
    143 //    JS::ValueType::PrivateGCThing ->  unused
    144 //    JS::ValueType::BigInt ->          SmallString
    145 //    JS::ValueType::BigInt ->          SmallString
    146 //
    147 //    JS::ValueType::Int32:
    148 //      if flags != NUMBER_IS_OUT_OF_LINE_MAGIC -> nothing (see MIN_INLINE_INT)
    149 //      else ->                                    int32_t
    150 //
    151 //    JS::ValueType::Double:
    152 //      if flags != NUMBER_IS_OUT_OF_LINE_MAGIC -> nothing (value is +0)
    153 //      else ->                                    double
    154 //
    155 //    JS::ValueType::Symbol:
    156 //      if flags != SYMBOL_NO_DESCRIPTION ->       nothing
    157 //      else ->                                    SmallString
    158 //
    159 //    JS::ValueType::Object:
    160 //      See ObjectSummary
    161 struct ValueSummary {
    162  enum Flags : uint8_t {
    163    // If this is set, the object has an array of dense elements right
    164    // after the shape summary id, which are implicitly keyed as the
    165    // indices within the array.
    166    GENERIC_OBJECT_HAS_DENSE_ELEMENTS = 1,
    167 
    168    // If a symbol does not have a description, this is set.
    169    SYMBOL_NO_DESCRIPTION = 1,
    170 
    171    // If the type is numeric and the flags are equal to this, the value is
    172    // stored immediately after the header. Otherwise, the value is stored
    173    // directly in the flags. (See MIN_INLINE_INT)
    174    NUMBER_IS_OUT_OF_LINE_MAGIC = 0xf,
    175  };
    176 
    177  // This value is written to the start of the value summaries buffer (see
    178  // TracedJSContext::valueBuffer), and should be bumped every time the format
    179  // is changed.
    180  //
    181  // Keep in mind to update
    182  // js/src/jit-test/tests/debug/ExecutionTracer-traced-values.js
    183  // VALUE_SUMMARY_VERSION value.
    184  static const uint32_t VERSION = 2;
    185 
    186  // If the type is an int and flags != Flags::NUMBER_IS_OUT_OF_LINE_MAGIC,
    187  // the value is MIN_INLINE_INT + flags.
    188  static const int32_t MIN_INLINE_INT = -1;
    189  static const int32_t MAX_INLINE_INT = 13;
    190 
    191  // Limit on the length of strings in traced value summaries.
    192  static const size_t SMALL_STRING_LENGTH_LIMIT = 512;
    193 
    194  // The max number of entries to record for general collection objects, such
    195  // as arrays, sets, and maps. Additionally limits the number of indexed
    196  // properties recorded for objects. This also limits the number of parameter
    197  // names to record for Function objects.
    198  static const size_t MAX_COLLECTION_VALUES = 16;
    199 
    200  // The actual JS Value type.
    201  JS::ValueType type : 4;
    202 
    203  // See the Flags enum.
    204  uint8_t flags : 4;
    205 
    206  // A variable length payload may trail the type and flags. See the comment
    207  // above this class.
    208 };
    209 
    210 // An ObjectSummary has the following structure:
    211 //
    212 //    kind:     uint8_t
    213 //    payload:  see below
    214 //
    215 // a structure determined by that kind and by the flags on the ValueSummary
    216 // The structure is as follows:
    217 //
    218 //    Kind::NotImplemented ->
    219 //      shapeSummaryId:     uint32_t (summary will only contain class name)
    220 //        NOTE - above, and where noted below, `shapeSummaryId` is included for
    221 //        the class name, but no property values corresponding to the
    222 //        shapeSummary's property names are present in `values`.
    223 //    Kind::ArrayLike ->
    224 //      shapeSummaryId:     uint32_t (summary will only contain class name)
    225 //      values:             NestedList<ValueSummary>
    226 //        NOTE - at present, ArrayObjects as well as SetObjects are serialized
    227 //        using the ArrayLike structure.
    228 //    Kind::MapLike ->
    229 //      shapeSummaryId:     uint32_t (summary will only contain class name)
    230 //      values:             NestedList<Pair<SmallString, ValueSummary>>
    231 //        NOTE - similar to ArrayLike, the property values noted by the shape
    232 //        are not present here.
    233 //    Kind::Function ->
    234 //      functionName:       SmallString
    235 //      parameterNames:
    236 //        values:           List<SmallString>
    237 //        NOTE - destructuring parameters become an empty string
    238 //    Kind::WrappedPrimitiveObject ->
    239 //      wrappedValue:       ValueSummary
    240 //      object:             same as GenericObject (shapeSummaryId, props, etc.)
    241 //    Kind::GenericObject ->
    242 //      shapeSummaryId:     uint32_t
    243 //      props:              NestedList<PropertySummary> (see below)
    244 //      if flags & GENERIC_OBJECT_HAS_DENSE_ELEMENTS ->
    245 //        denseElements:    NestedList<Pair<SmallString, ValueSummary>>
    246 //    Kind::External ->
    247 //      shapeSummaryId:     uint32_t (summary will only contain class name)
    248 //      externalSize:       uint32_t
    249 //      payload:            (defined by embeddings)
    250 //      The structure for Kind::External entries is defined by embeddings.
    251 //      Embedders can use the JS_SetCustomObjectSummaryCallback, which will
    252 //      define a callback for the tracer to call when tracing objects whose
    253 //      classes have the JSCLASS_IS_DOMJSCLASS flag. From within this callback
    254 //      the embedder should use the JS_TracerSummaryWriter interface to write
    255 //      the data however they see fit. SpiderMonkey will then populate the
    256 //      externalSize field with the amount written.
    257 //      NOTE: it is the embedders' responsibility to manage the versioning of
    258 //      their format.
    259 //    Kind::Error ->
    260 //      shapeSummaryId:     uint32_t (summary will only contain class name)
    261 //      name:               SmallString
    262 //      message:            SmallString
    263 //      stack:              SmallString
    264 //      filename:           SmallString
    265 //      lineNumber:         uint32_t
    266 //      columnNumber        uint32_t
    267 //
    268 // WrappedPrimitiveObjects and GenericObjects make use of a PropertySummary
    269 // type, defined here:
    270 //
    271 // - PropertySummary - A union of either a ValueSummary or the value
    272 //   GETTER_SETTER_MAGIC followed by two value summaries. I.e.:
    273 //      if the current byte in the stream is GETTER_SETTER_MAGIC ->
    274 //        magic:  uint8_t  (GETTER_SETTER_MAGIC)
    275 //        getter: ValueSummary
    276 //        setter: ValueSummary
    277 //      else ->
    278 //        value:  ValueSummary
    279 struct ObjectSummary {
    280  // This is a special value for ValueSummary::typeAndFlags. It should be noted
    281  // that this only works as long as 0xf is not a valid JS::ValueType.
    282  static const uint8_t GETTER_SETTER_MAGIC = 0x0f;
    283 
    284  enum class Kind : uint8_t {
    285    NotImplemented,
    286    ArrayLike,
    287    MapLike,
    288    Function,
    289    WrappedPrimitiveObject,
    290    GenericObject,
    291    ProxyObject,
    292    External,
    293    Error,
    294  };
    295 
    296  Kind kind;
    297 
    298  // A variable length payload may trail the kind. See the comment above this
    299  // class.
    300 };
    301 
    302 // This is populated by JS_TracerSnapshotTrace and just represent a minimal
    303 // structure for natively representing an execution trace across a range of
    304 // JSContexts (see below). The core of the trace is an array of events, each of
    305 // which is a tagged union with data corresponding to that event. Events can
    306 // also point into various tables, and store all of their string data in a
    307 // contiguous UTF-8 stringBuffer (each string is null-terminated within the
    308 // buffer.)
    309 struct ExecutionTrace {
    310  enum class EventKind : uint8_t {
    311    FunctionEnter = 0,
    312    FunctionLeave = 1,
    313    LabelEnter = 2,
    314    LabelLeave = 3,
    315 
    316    // NOTE: the `Error` event has no TracedEvent payload, and will always
    317    // represent the end of the trace when encountered.
    318    Error = 4,
    319  };
    320 
    321  enum class ImplementationType : uint8_t {
    322    Interpreter = 0,
    323    Baseline = 1,
    324    Ion = 2,
    325    Wasm = 3,
    326  };
    327 
    328  // See the comment above the `values` field of TracedEvent::functionEvent
    329  // for an explanation of how these constants apply.
    330  static const uint32_t MAX_ARGUMENTS_TO_RECORD = 4;
    331  static const int32_t ZERO_ARGUMENTS_MAGIC = -2;
    332  static const int32_t EXPIRED_VALUES_MAGIC = -1;
    333  static const int32_t FUNCTION_LEAVE_VALUES = -1;
    334 
    335  struct TracedEvent {
    336    EventKind kind;
    337    union {
    338      // For FunctionEnter / FunctionLeave
    339      struct {
    340        ImplementationType implementation;
    341 
    342        // 1-origin line number of the function
    343        uint32_t lineNumber;
    344 
    345        // 1-origin column of the function
    346        uint32_t column;
    347 
    348        // Keys into the thread's scriptUrls HashMap. This key can be missing
    349        // from the HashMap, although ideally that situation is rare (it is
    350        // more likely in long running traces with *many* unique functions
    351        // and/or scripts)
    352        uint32_t scriptId;
    353 
    354        // ID to the realm that the frame was in. It's used for finding which
    355        // frame comes from which window/page.
    356        uint64_t realmID;
    357 
    358        // Keys into the thread's atoms HashMap. This key can be missing from
    359        // the HashMap as well (see comment above scriptId)
    360        uint32_t functionNameId;
    361 
    362        // If this value is negative,
    363        //    ZERO_ARGUMENTS_MAGIC indicates the function call had no arguments
    364        //    EXPIRED_VALUES_MAGIC indicates the argument values have been
    365        //      overwritten in the ring buffer.
    366        //    FUNCTION_LEAVE_VALUES is simply a placeholder value for if this
    367        //      functionEvent is a FunctionLeave
    368        //      (TODO: we leave this here because we want to record return
    369        //      values here, but this is not implemented yet.)
    370        //
    371        // If this value is non-negative, this is an index into the
    372        // TracedJSContext::valueBuffer. At the specified index, if
    373        // kind == EventKind::FunctionEnter, there will be a uint32_t
    374        // containing the argument count of the function call (argc), followed
    375        // by min(argc, MAX_ARGUMENTS_TO_RECORD) ValueSummary entries.
    376        int32_t values;
    377      } functionEvent;
    378 
    379      // For LabelEnter / LabelLeave
    380      struct {
    381        size_t label;  // Indexes directly into the trace's stringBuffer
    382      } labelEvent;
    383    };
    384    // Milliseconds since process creation
    385    double time;
    386  };
    387 
    388  // Represents the shape of a traced native object. Essentially this lets us
    389  // deduplicate the property key array to one location and only store the
    390  // dense array of property values for each object instance.
    391  struct ShapeSummary {
    392    // An identifier for the shape summary, which is referenced by object
    393    // summaries recorded in the TracedJSContext::valueBuffer.
    394    uint32_t id;
    395 
    396    // This is the total number of properties for the shape excluding any
    397    // dense elements on the object.
    398    uint32_t numProperties;
    399 
    400    // An index into the stringBuffer containing an array, beginning with the
    401    // class name followed by the array of properties, which will have a length
    402    // of min(numProperties, MAX_COLLECTION_VALUES). The property keys are for
    403    // best effort end user comprehension, so for simplicity's sake we just
    404    // represent all keys as strings, with symbols becoming
    405    // "Symbol(<description>)". Note that this can result in duplicate keys in
    406    // the array, when the keys are not actually duplicated on the underlying
    407    // objects.
    408    size_t stringBufferOffset;
    409 
    410    // Consider the following example object:
    411    //
    412    // {
    413    //    "0": 0,
    414    //    "1": 0,
    415    //    "2": 0,
    416    //    [Symbol.for("prop1")]: 0,
    417    //    "prop2": 0,
    418    //    ...
    419    //    "prop19": 0,
    420    //    "prop20": 0,
    421    // }
    422    //
    423    // This will result in a ShapeSummary with numProperties of 20, since "0",
    424    // "1", and "2" are dense elements, and an array at `stringBufferOffset`
    425    // looking something like:
    426    //
    427    // [
    428    //    "Object", // The class name
    429    //    "Symbol(prop1)",
    430    //    "prop2",
    431    //    ...
    432    //    "prop15",
    433    //    "prop16", // The sequence ends at MAX_COLLECTION_VALUES (16)
    434    // ]
    435  };
    436 
    437  struct TracedJSContext {
    438    mozilla::baseprofiler::BaseProfilerThreadId id;
    439 
    440    // Maps ids to indices into the trace's stringBuffer
    441    mozilla::HashMap<uint32_t, size_t> scriptUrls;
    442 
    443    // Similar to scriptUrls
    444    mozilla::HashMap<uint32_t, size_t> atoms;
    445 
    446    // Holds any traced values, in the format defined above (See the
    447    // ValueSummary type). The first 4 bytes of this buffer will contain
    448    // the VERSION constant defined above.
    449    mozilla::Vector<uint8_t> valueBuffer;
    450 
    451    // Holds shape information for objects traced in the valueBuffer
    452    mozilla::Vector<ShapeSummary> shapeSummaries;
    453 
    454    mozilla::Vector<TracedEvent> events;
    455  };
    456 
    457  mozilla::Vector<char> stringBuffer;
    458 
    459  // This will be populated with an entry for each context which had tracing
    460  // enabled via JS_TracerBeginTracing.
    461  mozilla::Vector<TracedJSContext> contexts;
    462 };
    463 }  // namespace JS
    464 
    465 // Captures the trace for all JSContexts in the process which are currently
    466 // tracing.
    467 extern JS_PUBLIC_API bool JS_TracerSnapshotTrace(JS::ExecutionTrace& trace);
    468 
    469 // Given that embeddings may want to add support for serializing their own
    470 // types, we expose here a means of registering a callback for serializing
    471 // them. The JS_TracerSummaryWriter exposes a means of writing common types
    472 // to the tracer's value ring buffer, and JS_SetCustomObjectSummaryCallback
    473 // sets a callback on the JSContext
    474 struct JS_TracerSummaryWriterImpl;
    475 
    476 struct JS_PUBLIC_API JS_TracerSummaryWriter {
    477  JS_TracerSummaryWriterImpl* impl;
    478 
    479  void writeUint8(uint8_t val);
    480  void writeUint16(uint16_t val);
    481  void writeUint32(uint32_t val);
    482  void writeUint64(uint64_t val);
    483 
    484  void writeInt8(int8_t val);
    485  void writeInt16(int16_t val);
    486  void writeInt32(int32_t val);
    487  void writeInt64(int64_t val);
    488 
    489  void writeUTF8String(const char* val);
    490  void writeTwoByteString(const char16_t* val);
    491 
    492  bool writeValue(JSContext* cx, JS::Handle<JS::Value> val);
    493 };
    494 
    495 // - `obj` is the object intended to be summarized.
    496 // - `nested` is true if this object is a nested property of another
    497 //   JS::ValueSummary being written.
    498 // - `writer` is an interface which should be used to write the serialized
    499 //   summary.
    500 using CustomObjectSummaryCallback = bool (*)(JSContext*,
    501                                             JS::Handle<JSObject*> obj,
    502                                             bool nested,
    503                                             JS_TracerSummaryWriter* writer);
    504 
    505 extern JS_PUBLIC_API void JS_SetCustomObjectSummaryCallback(
    506    JSContext* cx, CustomObjectSummaryCallback callback);
    507 
    508 #endif /* MOZ_EXECUTION_TRACING */
    509 
    510 namespace JS {
    511 namespace dbg {
    512 
    513 // [SMDOC] Debugger builder API
    514 //
    515 // Helping embedding code build objects for Debugger
    516 // -------------------------------------------------
    517 //
    518 // Some Debugger API features lean on the embedding application to construct
    519 // their result values. For example, Debugger.Frame.prototype.scriptEntryReason
    520 // calls hooks provided by the embedding to construct values explaining why it
    521 // invoked JavaScript; if F is a frame called from a mouse click event handler,
    522 // F.scriptEntryReason would return an object of the form:
    523 //
    524 //   { eventType: "mousedown", event: <object> }
    525 //
    526 // where <object> is a Debugger.Object whose referent is the event being
    527 // dispatched.
    528 //
    529 // However, Debugger implements a trust boundary. Debuggee code may be
    530 // considered untrusted; debugger code needs to be protected from debuggee
    531 // getters, setters, proxies, Object.watch watchpoints, and any other feature
    532 // that might accidentally cause debugger code to set the debuggee running. The
    533 // Debugger API tries to make it easy to write safe debugger code by only
    534 // offering access to debuggee objects via Debugger.Object instances, which
    535 // ensure that only those operations whose explicit purpose is to invoke
    536 // debuggee code do so. But this protective membrane is only helpful if we
    537 // interpose Debugger.Object instances in all the necessary spots.
    538 //
    539 // SpiderMonkey's compartment system also implements a trust boundary. The
    540 // debuggee and debugger are always in different compartments. Inter-compartment
    541 // work requires carefully tracking which compartment each JSObject or JS::Value
    542 // belongs to, and ensuring that is is correctly wrapped for each operation.
    543 //
    544 // It seems precarious to expect the embedding's hooks to implement these trust
    545 // boundaries. Instead, the JS::dbg::Builder API segregates the code which
    546 // constructs trusted objects from that which deals with untrusted objects.
    547 // Trusted objects have an entirely different C++ type, so code that improperly
    548 // mixes trusted and untrusted objects is caught at compile time.
    549 //
    550 // In the structure shown above, there are two trusted objects, and one
    551 // untrusted object:
    552 //
    553 // - The overall object, with the 'eventType' and 'event' properties, is a
    554 //   trusted object. We're going to return it to D.F.p.scriptEntryReason's
    555 //   caller, which will handle it directly.
    556 //
    557 // - The Debugger.Object instance appearing as the value of the 'event' property
    558 //   is a trusted object. It belongs to the same Debugger instance as the
    559 //   Debugger.Frame instance whose scriptEntryReason accessor was called, and
    560 //   presents a safe reflection-oriented API for inspecting its referent, which
    561 //   is:
    562 //
    563 // - The actual event object, an untrusted object, and the referent of the
    564 //   Debugger.Object above. (Content can do things like replacing accessors on
    565 //   Event.prototype.)
    566 //
    567 // Using JS::dbg::Builder, all objects and values the embedding deals with
    568 // directly are considered untrusted, and are assumed to be debuggee values. The
    569 // only way to construct trusted objects is to use Builder's own methods, which
    570 // return a separate Object type. The only way to set a property on a trusted
    571 // object is through that Object type. The actual trusted object is never
    572 // exposed to the embedding.
    573 //
    574 // So, for example, the embedding might use code like the following to construct
    575 // the object shown above, given a Builder passed to it by Debugger:
    576 //
    577 //    bool
    578 //    MyScriptEntryReason::explain(JSContext* cx,
    579 //                                 Builder& builder,
    580 //                                 Builder::Object& result)
    581 //    {
    582 //        JSObject* eventObject = ... obtain debuggee event object somehow ...;
    583 //        if (!eventObject) {
    584 //            return false;
    585 //        }
    586 //        result = builder.newObject(cx);
    587 //        return result &&
    588 //               result.defineProperty(cx, "eventType",
    589 //                                     SafelyFetchType(eventObject)) &&
    590 //               result.defineProperty(cx, "event", eventObject);
    591 //    }
    592 //
    593 //
    594 // Object::defineProperty also accepts an Object as the value to store on the
    595 // property. By its type, we know that the value is trusted, so we set it
    596 // directly as the property's value, without interposing a Debugger.Object
    597 // wrapper. This allows the embedding to builted nested structures of trusted
    598 // objects.
    599 //
    600 // The Builder and Builder::Object methods take care of doing whatever
    601 // compartment switching and wrapping are necessary to construct the trusted
    602 // values in the Debugger's compartment.
    603 //
    604 // The Object type is self-rooting. Construction, assignment, and destruction
    605 // all properly root the referent object.
    606 
    607 class BuilderOrigin;
    608 
    609 class Builder {
    610  // The Debugger instance whose client we are building a value for. We build
    611  // objects in this object's compartment.
    612  PersistentRootedObject debuggerObject;
    613 
    614  // debuggerObject's Debugger structure, for convenience.
    615  js::Debugger* debugger;
    616 
    617  // Check that |thing| is in the same compartment as our debuggerObject. Used
    618  // for assertions when constructing BuiltThings. We can overload this as we
    619  // add more instantiations of BuiltThing.
    620 #ifdef DEBUG
    621  void assertBuilt(JSObject* obj);
    622 #else
    623  void assertBuilt(JSObject* obj) {}
    624 #endif
    625 
    626 protected:
    627  // A reference to a trusted object or value. At the moment, we only use it
    628  // with JSObject*.
    629  template <typename T>
    630  class BuiltThing {
    631    friend class BuilderOrigin;
    632 
    633   protected:
    634    // The Builder to which this trusted thing belongs.
    635    Builder& owner;
    636 
    637    // A rooted reference to our value.
    638    PersistentRooted<T> value;
    639 
    640    BuiltThing(JSContext* cx, Builder& owner_,
    641               T value_ = SafelyInitialized<T>::create())
    642        : owner(owner_), value(cx, value_) {
    643      owner.assertBuilt(value_);
    644    }
    645 
    646    // Forward some things from our owner, for convenience.
    647    js::Debugger* debugger() const { return owner.debugger; }
    648    JSObject* debuggerObject() const { return owner.debuggerObject; }
    649 
    650   public:
    651    BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) {}
    652    BuiltThing& operator=(const BuiltThing& rhs) {
    653      MOZ_ASSERT(&owner == &rhs.owner);
    654      owner.assertBuilt(rhs.value);
    655      value = rhs.value;
    656      return *this;
    657    }
    658 
    659    explicit operator bool() const {
    660      // If we ever instantiate BuiltThing<Value>, this might not suffice.
    661      return value;
    662    }
    663 
    664   private:
    665    BuiltThing() = delete;
    666  };
    667 
    668 public:
    669  // A reference to a trusted object, possibly null. Instances of Object are
    670  // always properly rooted. They can be copied and assigned, as if they were
    671  // pointers.
    672  class Object : private BuiltThing<JSObject*> {
    673    friend class Builder;        // for construction
    674    friend class BuilderOrigin;  // for unwrapping
    675 
    676    typedef BuiltThing<JSObject*> Base;
    677 
    678    // This is private, because only Builders can create Objects that
    679    // actually point to something (hence the 'friend' declaration).
    680    Object(JSContext* cx, Builder& owner_, HandleObject obj)
    681        : Base(cx, owner_, obj.get()) {}
    682 
    683    bool definePropertyToTrusted(JSContext* cx, const char* name,
    684                                 JS::MutableHandleValue value);
    685 
    686   public:
    687    Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) {}
    688    Object(const Object& rhs) = default;
    689 
    690    // Our automatically-generated assignment operator can see our base
    691    // class's assignment operator, so we don't need to write one out here.
    692 
    693    // Set the property named |name| on this object to |value|.
    694    //
    695    // If |value| is a string or primitive, re-wrap it for the debugger's
    696    // compartment.
    697    //
    698    // If |value| is an object, assume it is a debuggee object and make a
    699    // Debugger.Object instance referring to it. Set that as the propery's
    700    // value.
    701    //
    702    // If |value| is another trusted object, store it directly as the
    703    // property's value.
    704    //
    705    // On error, report the problem on cx and return false.
    706    bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value);
    707    bool defineProperty(JSContext* cx, const char* name,
    708                        JS::HandleObject value);
    709    bool defineProperty(JSContext* cx, const char* name, Object& value);
    710 
    711    using Base::operator bool;
    712  };
    713 
    714  // Build an empty object for direct use by debugger code, owned by this
    715  // Builder. If an error occurs, report it on cx and return a false Object.
    716  Object newObject(JSContext* cx);
    717 
    718 protected:
    719  Builder(JSContext* cx, js::Debugger* debugger);
    720 };
    721 
    722 // Debugger itself instantiates this subclass of Builder, which can unwrap
    723 // BuiltThings that belong to it.
    724 class BuilderOrigin : public Builder {
    725  template <typename T>
    726  T unwrapAny(const BuiltThing<T>& thing) {
    727    MOZ_ASSERT(&thing.owner == this);
    728    return thing.value.get();
    729  }
    730 
    731 public:
    732  BuilderOrigin(JSContext* cx, js::Debugger* debugger_)
    733      : Builder(cx, debugger_) {}
    734 
    735  JSObject* unwrap(Object& object) { return unwrapAny(object); }
    736 };
    737 
    738 // Finding the size of blocks allocated with malloc
    739 // ------------------------------------------------
    740 //
    741 // Debugger.Memory wants to be able to report how many bytes items in memory are
    742 // consuming. To do this, it needs a function that accepts a pointer to a block,
    743 // and returns the number of bytes allocated to that block. SpiderMonkey itself
    744 // doesn't know which function is appropriate to use, but the embedding does.
    745 
    746 // Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of
    747 // malloc'd blocks.
    748 JS_PUBLIC_API void SetDebuggerMallocSizeOf(JSContext* cx,
    749                                           mozilla::MallocSizeOf mallocSizeOf);
    750 
    751 // Get the MallocSizeOf function that the given context is using to find the
    752 // size of malloc'd blocks.
    753 JS_PUBLIC_API mozilla::MallocSizeOf GetDebuggerMallocSizeOf(JSContext* cx);
    754 
    755 // Debugger and Garbage Collection Events
    756 // --------------------------------------
    757 //
    758 // The Debugger wants to report about its debuggees' GC cycles, however entering
    759 // JS after a GC is troublesome since SpiderMonkey will often do something like
    760 // force a GC and then rely on the nursery being empty. If we call into some
    761 // Debugger's hook after the GC, then JS runs and the nursery won't be
    762 // empty. Instead, we rely on embedders to call back into SpiderMonkey after a
    763 // GC and notify Debuggers to call their onGarbageCollection hook.
    764 
    765 // Determine whether it's necessary to call FireOnGarbageCollectionHook() after
    766 // a GC. This is only required if there are debuggers with an
    767 // onGarbageCollection hook observing a global in the set of collected zones.
    768 JS_PUBLIC_API bool FireOnGarbageCollectionHookRequired(JSContext* cx);
    769 
    770 // For each Debugger that observed a debuggee involved in the given GC event,
    771 // call its `onGarbageCollection` hook.
    772 JS_PUBLIC_API bool FireOnGarbageCollectionHook(
    773    JSContext* cx, GarbageCollectionEvent::Ptr&& data);
    774 
    775 // Return true if the given value is a Debugger object, false otherwise.
    776 JS_PUBLIC_API bool IsDebugger(JSObject& obj);
    777 
    778 // Append each of the debuggee global objects observed by the Debugger object
    779 // |dbgObj| to |vector|. Returns true on success, false on failure.
    780 JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
    781                                      MutableHandleObjectVector vector);
    782 
    783 // Returns true if there's any debugger attached to the given context where
    784 // the debugger's "shouldAvoidSideEffects" property is true.
    785 //
    786 // This is supposed to be used by native code that performs side-effectful
    787 // operations where the debugger cannot hook it.
    788 //
    789 // If this function returns true, the native function should throw an
    790 // uncatchable exception by returning `false` without setting any pending
    791 // exception. The debugger will handle this exception by aborting the eager
    792 // evaluation.
    793 //
    794 // The native code can opt into this behavior to help the debugger performing
    795 // the side-effect-free evaluation.
    796 //
    797 // Expected consumers of this API include JSClassOps.resolve hooks which have
    798 // any side-effect other than just resolving the property.
    799 //
    800 // Example:
    801 //   static bool ResolveHook(JSContext* cx, HandleObject obj, HandleId id,
    802 //                           bool* resolvedp) {
    803 //     *resolvedp = false;
    804 //     if (JS::dbg::ShouldAvoidSideEffects()) {
    805 //       return false;
    806 //     }
    807 //     // Resolve the property with the side-effect.
    808 //     ...
    809 //     return true;
    810 //   }
    811 bool ShouldAvoidSideEffects(JSContext* cx);
    812 
    813 }  // namespace dbg
    814 }  // namespace JS
    815 
    816 #endif /* js_Debug_h */