Bug 1813941 [wpt PR 38271] - Add slot=marker and ::part(marker) for selectmenu, a...
[gecko.git] / js / public / Debug.h
blob6d7fd8a4be5eef87dc97340f3b4b6e0ca97d9c08
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/. */
7 // Interfaces by which the embedding can interact with the Debugger API.
9 #ifndef js_Debug_h
10 #define js_Debug_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/MemoryReporting.h"
16 #include <utility>
18 #include "jstypes.h"
20 #include "js/GCAPI.h"
21 #include "js/RootingAPI.h"
22 #include "js/TypeDecls.h"
24 namespace js {
25 class Debugger;
26 } // namespace js
28 /* Defined in vm/Debugger.cpp. */
29 extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
30 JS::HandleObject obj);
32 namespace JS {
33 namespace dbg {
35 // [SMDOC] Debugger builder API
37 // Helping embedding code build objects for Debugger
38 // -------------------------------------------------
40 // Some Debugger API features lean on the embedding application to construct
41 // their result values. For example, Debugger.Frame.prototype.scriptEntryReason
42 // calls hooks provided by the embedding to construct values explaining why it
43 // invoked JavaScript; if F is a frame called from a mouse click event handler,
44 // F.scriptEntryReason would return an object of the form:
46 // { eventType: "mousedown", event: <object> }
48 // where <object> is a Debugger.Object whose referent is the event being
49 // dispatched.
51 // However, Debugger implements a trust boundary. Debuggee code may be
52 // considered untrusted; debugger code needs to be protected from debuggee
53 // getters, setters, proxies, Object.watch watchpoints, and any other feature
54 // that might accidentally cause debugger code to set the debuggee running. The
55 // Debugger API tries to make it easy to write safe debugger code by only
56 // offering access to debuggee objects via Debugger.Object instances, which
57 // ensure that only those operations whose explicit purpose is to invoke
58 // debuggee code do so. But this protective membrane is only helpful if we
59 // interpose Debugger.Object instances in all the necessary spots.
61 // SpiderMonkey's compartment system also implements a trust boundary. The
62 // debuggee and debugger are always in different compartments. Inter-compartment
63 // work requires carefully tracking which compartment each JSObject or JS::Value
64 // belongs to, and ensuring that is is correctly wrapped for each operation.
66 // It seems precarious to expect the embedding's hooks to implement these trust
67 // boundaries. Instead, the JS::dbg::Builder API segregates the code which
68 // constructs trusted objects from that which deals with untrusted objects.
69 // Trusted objects have an entirely different C++ type, so code that improperly
70 // mixes trusted and untrusted objects is caught at compile time.
72 // In the structure shown above, there are two trusted objects, and one
73 // untrusted object:
75 // - The overall object, with the 'eventType' and 'event' properties, is a
76 // trusted object. We're going to return it to D.F.p.scriptEntryReason's
77 // caller, which will handle it directly.
79 // - The Debugger.Object instance appearing as the value of the 'event' property
80 // is a trusted object. It belongs to the same Debugger instance as the
81 // Debugger.Frame instance whose scriptEntryReason accessor was called, and
82 // presents a safe reflection-oriented API for inspecting its referent, which
83 // is:
85 // - The actual event object, an untrusted object, and the referent of the
86 // Debugger.Object above. (Content can do things like replacing accessors on
87 // Event.prototype.)
89 // Using JS::dbg::Builder, all objects and values the embedding deals with
90 // directly are considered untrusted, and are assumed to be debuggee values. The
91 // only way to construct trusted objects is to use Builder's own methods, which
92 // return a separate Object type. The only way to set a property on a trusted
93 // object is through that Object type. The actual trusted object is never
94 // exposed to the embedding.
96 // So, for example, the embedding might use code like the following to construct
97 // the object shown above, given a Builder passed to it by Debugger:
99 // bool
100 // MyScriptEntryReason::explain(JSContext* cx,
101 // Builder& builder,
102 // Builder::Object& result)
103 // {
104 // JSObject* eventObject = ... obtain debuggee event object somehow ...;
105 // if (!eventObject) {
106 // return false;
107 // }
108 // result = builder.newObject(cx);
109 // return result &&
110 // result.defineProperty(cx, "eventType",
111 // SafelyFetchType(eventObject)) &&
112 // result.defineProperty(cx, "event", eventObject);
113 // }
116 // Object::defineProperty also accepts an Object as the value to store on the
117 // property. By its type, we know that the value is trusted, so we set it
118 // directly as the property's value, without interposing a Debugger.Object
119 // wrapper. This allows the embedding to builted nested structures of trusted
120 // objects.
122 // The Builder and Builder::Object methods take care of doing whatever
123 // compartment switching and wrapping are necessary to construct the trusted
124 // values in the Debugger's compartment.
126 // The Object type is self-rooting. Construction, assignment, and destruction
127 // all properly root the referent object.
129 class BuilderOrigin;
131 class Builder {
132 // The Debugger instance whose client we are building a value for. We build
133 // objects in this object's compartment.
134 PersistentRootedObject debuggerObject;
136 // debuggerObject's Debugger structure, for convenience.
137 js::Debugger* debugger;
139 // Check that |thing| is in the same compartment as our debuggerObject. Used
140 // for assertions when constructing BuiltThings. We can overload this as we
141 // add more instantiations of BuiltThing.
142 #ifdef DEBUG
143 void assertBuilt(JSObject* obj);
144 #else
145 void assertBuilt(JSObject* obj) {}
146 #endif
148 protected:
149 // A reference to a trusted object or value. At the moment, we only use it
150 // with JSObject*.
151 template <typename T>
152 class BuiltThing {
153 friend class BuilderOrigin;
155 protected:
156 // The Builder to which this trusted thing belongs.
157 Builder& owner;
159 // A rooted reference to our value.
160 PersistentRooted<T> value;
162 BuiltThing(JSContext* cx, Builder& owner_,
163 T value_ = SafelyInitialized<T>::create())
164 : owner(owner_), value(cx, value_) {
165 owner.assertBuilt(value_);
168 // Forward some things from our owner, for convenience.
169 js::Debugger* debugger() const { return owner.debugger; }
170 JSObject* debuggerObject() const { return owner.debuggerObject; }
172 public:
173 BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) {}
174 BuiltThing& operator=(const BuiltThing& rhs) {
175 MOZ_ASSERT(&owner == &rhs.owner);
176 owner.assertBuilt(rhs.value);
177 value = rhs.value;
178 return *this;
181 explicit operator bool() const {
182 // If we ever instantiate BuiltThing<Value>, this might not suffice.
183 return value;
186 private:
187 BuiltThing() = delete;
190 public:
191 // A reference to a trusted object, possibly null. Instances of Object are
192 // always properly rooted. They can be copied and assigned, as if they were
193 // pointers.
194 class Object : private BuiltThing<JSObject*> {
195 friend class Builder; // for construction
196 friend class BuilderOrigin; // for unwrapping
198 typedef BuiltThing<JSObject*> Base;
200 // This is private, because only Builders can create Objects that
201 // actually point to something (hence the 'friend' declaration).
202 Object(JSContext* cx, Builder& owner_, HandleObject obj)
203 : Base(cx, owner_, obj.get()) {}
205 bool definePropertyToTrusted(JSContext* cx, const char* name,
206 JS::MutableHandleValue value);
208 public:
209 Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) {}
210 Object(const Object& rhs) = default;
212 // Our automatically-generated assignment operator can see our base
213 // class's assignment operator, so we don't need to write one out here.
215 // Set the property named |name| on this object to |value|.
217 // If |value| is a string or primitive, re-wrap it for the debugger's
218 // compartment.
220 // If |value| is an object, assume it is a debuggee object and make a
221 // Debugger.Object instance referring to it. Set that as the propery's
222 // value.
224 // If |value| is another trusted object, store it directly as the
225 // property's value.
227 // On error, report the problem on cx and return false.
228 bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value);
229 bool defineProperty(JSContext* cx, const char* name,
230 JS::HandleObject value);
231 bool defineProperty(JSContext* cx, const char* name, Object& value);
233 using Base::operator bool;
236 // Build an empty object for direct use by debugger code, owned by this
237 // Builder. If an error occurs, report it on cx and return a false Object.
238 Object newObject(JSContext* cx);
240 protected:
241 Builder(JSContext* cx, js::Debugger* debugger);
244 // Debugger itself instantiates this subclass of Builder, which can unwrap
245 // BuiltThings that belong to it.
246 class BuilderOrigin : public Builder {
247 template <typename T>
248 T unwrapAny(const BuiltThing<T>& thing) {
249 MOZ_ASSERT(&thing.owner == this);
250 return thing.value.get();
253 public:
254 BuilderOrigin(JSContext* cx, js::Debugger* debugger_)
255 : Builder(cx, debugger_) {}
257 JSObject* unwrap(Object& object) { return unwrapAny(object); }
260 // Finding the size of blocks allocated with malloc
261 // ------------------------------------------------
263 // Debugger.Memory wants to be able to report how many bytes items in memory are
264 // consuming. To do this, it needs a function that accepts a pointer to a block,
265 // and returns the number of bytes allocated to that block. SpiderMonkey itself
266 // doesn't know which function is appropriate to use, but the embedding does.
268 // Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of
269 // malloc'd blocks.
270 JS_PUBLIC_API void SetDebuggerMallocSizeOf(JSContext* cx,
271 mozilla::MallocSizeOf mallocSizeOf);
273 // Get the MallocSizeOf function that the given context is using to find the
274 // size of malloc'd blocks.
275 JS_PUBLIC_API mozilla::MallocSizeOf GetDebuggerMallocSizeOf(JSContext* cx);
277 // Debugger and Garbage Collection Events
278 // --------------------------------------
280 // The Debugger wants to report about its debuggees' GC cycles, however entering
281 // JS after a GC is troublesome since SpiderMonkey will often do something like
282 // force a GC and then rely on the nursery being empty. If we call into some
283 // Debugger's hook after the GC, then JS runs and the nursery won't be
284 // empty. Instead, we rely on embedders to call back into SpiderMonkey after a
285 // GC and notify Debuggers to call their onGarbageCollection hook.
287 // Determine whether it's necessary to call FireOnGarbageCollectionHook() after
288 // a GC. This is only required if there are debuggers with an
289 // onGarbageCollection hook observing a global in the set of collected zones.
290 JS_PUBLIC_API bool FireOnGarbageCollectionHookRequired(JSContext* cx);
292 // For each Debugger that observed a debuggee involved in the given GC event,
293 // call its `onGarbageCollection` hook.
294 JS_PUBLIC_API bool FireOnGarbageCollectionHook(
295 JSContext* cx, GarbageCollectionEvent::Ptr&& data);
297 // Return true if the given value is a Debugger object, false otherwise.
298 JS_PUBLIC_API bool IsDebugger(JSObject& obj);
300 // Append each of the debuggee global objects observed by the Debugger object
301 // |dbgObj| to |vector|. Returns true on success, false on failure.
302 JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
303 MutableHandleObjectVector vector);
305 // Hooks for reporting where JavaScript execution began.
307 // Our performance tools would like to be able to label blocks of JavaScript
308 // execution with the function name and source location where execution began:
309 // the event handler, the callback, etc.
311 // Construct an instance of this class on the stack, providing a JSContext
312 // belonging to the runtime in which execution will occur. Each time we enter
313 // JavaScript --- specifically, each time we push a JavaScript stack frame that
314 // has no older JS frames younger than this AutoEntryMonitor --- we will
315 // call the appropriate |Entry| member function to indicate where we've begun
316 // execution.
318 class MOZ_STACK_CLASS JS_PUBLIC_API AutoEntryMonitor {
319 JSContext* cx_;
320 AutoEntryMonitor* savedMonitor_;
322 public:
323 explicit AutoEntryMonitor(JSContext* cx);
324 ~AutoEntryMonitor();
326 // SpiderMonkey reports the JavaScript entry points occuring within this
327 // AutoEntryMonitor's scope to the following member functions, which the
328 // embedding is expected to override.
330 // It is important to note that |asyncCause| is owned by the caller and its
331 // lifetime must outlive the lifetime of the AutoEntryMonitor object. It is
332 // strongly encouraged that |asyncCause| be a string constant or similar
333 // statically allocated string.
335 // We have begun executing |function|. Note that |function| may not be the
336 // actual closure we are running, but only the canonical function object to
337 // which the script refers.
338 virtual void Entry(JSContext* cx, JSFunction* function,
339 HandleValue asyncStack, const char* asyncCause) = 0;
341 // Execution has begun at the entry point of |script|, which is not a
342 // function body. (This is probably being executed by 'eval' or some
343 // JSAPI equivalent.)
344 virtual void Entry(JSContext* cx, JSScript* script, HandleValue asyncStack,
345 const char* asyncCause) = 0;
347 // Execution of the function or script has ended.
348 virtual void Exit(JSContext* cx) {}
351 } // namespace dbg
352 } // namespace JS
354 #endif /* js_Debug_h */