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