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 */