Backed out 2 changesets (bug 1908320) for causing wr failures on align-items-baseline...
[gecko.git] / js / src / debugger / Frame.h
blob44ee39d9db8f13cab3a77cc38157a670c6386f6c
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 #ifndef debugger_Frame_h
8 #define debugger_Frame_h
10 #include "mozilla/Maybe.h" // for Maybe
11 #include "mozilla/Range.h" // for Range
12 #include "mozilla/Result.h" // for Result
14 #include <stddef.h> // for size_t
16 #include "NamespaceImports.h" // for Value, MutableHandleValue, HandleObject
17 #include "debugger/DebugAPI.h" // for ResumeMode
18 #include "debugger/Debugger.h" // for ResumeMode, Handler, Debugger
19 #include "gc/Barrier.h" // for HeapPtr
20 #include "vm/FrameIter.h" // for FrameIter
21 #include "vm/JSObject.h" // for JSObject
22 #include "vm/NativeObject.h" // for NativeObject
23 #include "vm/Stack.h" // for AbstractFramePtr
25 struct JS_PUBLIC_API JSContext;
27 namespace js {
29 class AbstractGeneratorObject;
30 class GlobalObject;
33 * An OnStepHandler represents a handler function that is called when a small
34 * amount of progress is made in a frame.
36 struct OnStepHandler : Handler {
38 * If we have made a small amount of progress in a frame, this method is
39 * called with the frame as argument. If succesful, this method should
40 * return true, with `resumeMode` and `vp` set to a resumption value
41 * specifiying how execution should continue.
43 virtual bool onStep(JSContext* cx, Handle<DebuggerFrame*> frame,
44 ResumeMode& resumeMode, MutableHandleValue vp) = 0;
47 class ScriptedOnStepHandler final : public OnStepHandler {
48 public:
49 explicit ScriptedOnStepHandler(JSObject* object);
50 virtual JSObject* object() const override;
51 virtual void hold(JSObject* owner) override;
52 virtual void drop(JS::GCContext* gcx, JSObject* owner) override;
53 virtual void trace(JSTracer* tracer) override;
54 virtual size_t allocSize() const override;
55 virtual bool onStep(JSContext* cx, Handle<DebuggerFrame*> frame,
56 ResumeMode& resumeMode, MutableHandleValue vp) override;
58 private:
59 const HeapPtr<JSObject*> object_;
63 * An OnPopHandler represents a handler function that is called just before a
64 * frame is popped.
66 struct OnPopHandler : Handler {
68 * The given `frame` is about to be popped; `completion` explains why.
70 * When this method returns true, it must set `resumeMode` and `vp` to a
71 * resumption value specifying how execution should continue.
73 * When this method returns false, it should set an exception on `cx`.
75 virtual bool onPop(JSContext* cx, Handle<DebuggerFrame*> frame,
76 const Completion& completion, ResumeMode& resumeMode,
77 MutableHandleValue vp) = 0;
80 class ScriptedOnPopHandler final : public OnPopHandler {
81 public:
82 explicit ScriptedOnPopHandler(JSObject* object);
83 virtual JSObject* object() const override;
84 virtual void hold(JSObject* owner) override;
85 virtual void drop(JS::GCContext* gcx, JSObject* owner) override;
86 virtual void trace(JSTracer* tracer) override;
87 virtual size_t allocSize() const override;
88 virtual bool onPop(JSContext* cx, Handle<DebuggerFrame*> frame,
89 const Completion& completion, ResumeMode& resumeMode,
90 MutableHandleValue vp) override;
92 private:
93 const HeapPtr<JSObject*> object_;
96 enum class DebuggerFrameType { Eval, Global, Call, Module, WasmCall };
98 enum class DebuggerFrameImplementation { Interpreter, Baseline, Ion, Wasm };
100 class DebuggerArguments : public NativeObject {
101 public:
102 static const JSClass class_;
104 static DebuggerArguments* create(JSContext* cx, HandleObject proto,
105 Handle<DebuggerFrame*> frame);
107 private:
108 enum { FRAME_SLOT };
110 static const unsigned RESERVED_SLOTS = 1;
113 class DebuggerFrame : public NativeObject {
114 friend class DebuggerArguments;
115 friend class ScriptedOnStepHandler;
116 friend class ScriptedOnPopHandler;
118 public:
119 static const JSClass class_;
121 enum {
122 FRAME_ITER_SLOT = 0,
123 OWNER_SLOT,
124 ARGUMENTS_SLOT,
125 ONSTEP_HANDLER_SLOT,
126 ONPOP_HANDLER_SLOT,
128 // If this is a frame for a generator call, and the generator object has
129 // been created (which doesn't happen until after default argument
130 // evaluation and destructuring), then this is a PrivateValue pointing to a
131 // GeneratorInfo struct that points to the call's AbstractGeneratorObject.
132 // This allows us to implement Debugger.Frame methods even while the call is
133 // suspended, and we have no FrameIter::Data.
135 // While Debugger::generatorFrames maps an AbstractGeneratorObject to its
136 // Debugger.Frame, this link represents the reverse relation, from a
137 // Debugger.Frame to its generator object. This slot is set if and only if
138 // there is a corresponding entry in generatorFrames.
139 GENERATOR_INFO_SLOT,
141 RESERVED_SLOTS,
144 void trace(JSTracer* trc);
146 static NativeObject* initClass(JSContext* cx, Handle<GlobalObject*> global,
147 HandleObject dbgCtor);
148 static DebuggerFrame* create(JSContext* cx, HandleObject proto,
149 Handle<NativeObject*> debugger,
150 const FrameIter* maybeIter,
151 Handle<AbstractGeneratorObject*> maybeGenerator);
153 [[nodiscard]] static bool getArguments(
154 JSContext* cx, Handle<DebuggerFrame*> frame,
155 MutableHandle<DebuggerArguments*> result);
156 [[nodiscard]] static bool getCallee(JSContext* cx,
157 Handle<DebuggerFrame*> frame,
158 MutableHandle<DebuggerObject*> result);
159 [[nodiscard]] static bool getIsConstructing(JSContext* cx,
160 Handle<DebuggerFrame*> frame,
161 bool& result);
162 [[nodiscard]] static bool getEnvironment(
163 JSContext* cx, Handle<DebuggerFrame*> frame,
164 MutableHandle<DebuggerEnvironment*> result);
165 [[nodiscard]] static bool getOffset(JSContext* cx,
166 Handle<DebuggerFrame*> frame,
167 size_t& result);
168 [[nodiscard]] static bool getOlder(JSContext* cx,
169 Handle<DebuggerFrame*> frame,
170 MutableHandle<DebuggerFrame*> result);
171 [[nodiscard]] static bool getAsyncPromise(
172 JSContext* cx, Handle<DebuggerFrame*> frame,
173 MutableHandle<DebuggerObject*> result);
174 [[nodiscard]] static bool getOlderSavedFrame(
175 JSContext* cx, Handle<DebuggerFrame*> frame,
176 MutableHandle<SavedFrame*> result);
177 [[nodiscard]] static bool getThis(JSContext* cx, Handle<DebuggerFrame*> frame,
178 MutableHandleValue result);
179 static DebuggerFrameType getType(Handle<DebuggerFrame*> frame);
180 static DebuggerFrameImplementation getImplementation(
181 Handle<DebuggerFrame*> frame);
182 [[nodiscard]] static bool setOnStepHandler(JSContext* cx,
183 Handle<DebuggerFrame*> frame,
184 UniquePtr<OnStepHandler> handler);
186 [[nodiscard]] static JS::Result<Completion> eval(
187 JSContext* cx, Handle<DebuggerFrame*> frame,
188 mozilla::Range<const char16_t> chars, HandleObject bindings,
189 const EvalOptions& options);
191 [[nodiscard]] static DebuggerFrame* check(JSContext* cx, HandleValue thisv);
193 bool isOnStack() const;
195 bool isSuspended() const;
197 OnStepHandler* onStepHandler() const;
198 OnPopHandler* onPopHandler() const;
199 void setOnPopHandler(JSContext* cx, OnPopHandler* handler);
201 inline bool hasGeneratorInfo() const;
203 // If hasGeneratorInfo(), return an direct cross-compartment reference to this
204 // Debugger.Frame's generator object.
205 AbstractGeneratorObject& unwrappedGenerator() const;
207 #ifdef DEBUG
208 JSScript* generatorScript() const;
209 #endif
212 * Associate the generator object genObj with this Debugger.Frame. This
213 * association allows the Debugger.Frame to track the generator's execution
214 * across suspensions and resumptions, and to implement some methods even
215 * while the generator is suspended.
217 * The context `cx` must be in the Debugger.Frame's realm, and `genObj` must
218 * be in a debuggee realm.
220 * Technically, the generator activation need not actually be on the stack
221 * right now; it's okay to call this method on a Debugger.Frame that has no
222 * ScriptFrameIter::Data at present. However, this function has no way to
223 * verify that genObj really is the generator associated with the call for
224 * which this Debugger.Frame was originally created, so it's best to make the
225 * association while the call is on the stack, and the relationships are easy
226 * to discern.
228 [[nodiscard]] static bool setGeneratorInfo(
229 JSContext* cx, Handle<DebuggerFrame*> frame,
230 Handle<AbstractGeneratorObject*> genObj);
233 * Undo the effects of a prior call to setGenerator.
235 * If provided, owner must be the Debugger to which this Debugger.Frame
236 * belongs; remove this frame's entry from its generatorFrames map, and clean
237 * up its cross-compartment wrapper table entry. The owner must be passed
238 * unless this method is being called from the Debugger.Frame's finalizer. (In
239 * that case, the owner is not reliably available, and is not actually
240 * necessary.)
242 * If maybeGeneratorFramesEnum is non-null, use it to remove this frame's
243 * entry from the Debugger's generatorFrames weak map. In this case, this
244 * function will not otherwise disturb generatorFrames. Passing the enum
245 * allows this function to be used while iterating over generatorFrames.
247 void clearGeneratorInfo(JS::GCContext* gcx);
250 * Called after a generator/async frame is resumed, before exposing this
251 * Debugger.Frame object to any hooks.
253 bool resume(const FrameIter& iter);
255 bool hasAnyHooks() const;
257 Debugger* owner() const;
259 private:
260 static const JSClassOps classOps_;
262 static const JSPropertySpec properties_[];
263 static const JSFunctionSpec methods_[];
265 static void finalize(JS::GCContext* gcx, JSObject* obj);
267 static AbstractFramePtr getReferent(Handle<DebuggerFrame*> frame);
268 [[nodiscard]] static bool requireScriptReferent(JSContext* cx,
269 Handle<DebuggerFrame*> frame);
271 [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
273 struct CallData;
275 [[nodiscard]] bool incrementStepperCounter(JSContext* cx,
276 AbstractFramePtr referent);
277 [[nodiscard]] bool incrementStepperCounter(JSContext* cx,
278 HandleScript script);
279 void decrementStepperCounter(JS::GCContext* gcx, JSScript* script);
280 void decrementStepperCounter(JS::GCContext* gcx, AbstractFramePtr referent);
282 FrameIter::Data* frameIterData() const;
283 void setFrameIterData(FrameIter::Data*);
284 void freeFrameIterData(JS::GCContext* gcx);
286 public:
287 FrameIter getFrameIter(JSContext* cx);
289 void terminate(JS::GCContext* gcx, AbstractFramePtr frame);
290 void onGeneratorClosed(JS::GCContext* gcx);
291 void suspend(JS::GCContext* gcx);
293 [[nodiscard]] bool replaceFrameIterData(JSContext* cx, const FrameIter&);
295 class GeneratorInfo;
296 inline GeneratorInfo* generatorInfo() const;
299 } /* namespace js */
301 #endif /* debugger_Frame_h */