Source code

Revision control

Other Tools

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
#ifndef debugger_Frame_h
8
#define debugger_Frame_h
9
10
#include "mozilla/Attributes.h" // for MOZ_MUST_USE
11
#include "mozilla/Maybe.h" // for Maybe
12
#include "mozilla/Range.h" // for Range
13
#include "mozilla/Result.h" // for Result
14
15
#include <stddef.h> // for size_t
16
17
#include "jsapi.h" // for JSContext, CallArgs
18
19
#include "NamespaceImports.h" // for Value, MutableHandleValue, HandleObject
20
#include "debugger/DebugAPI.h" // for ResumeMode
21
#include "debugger/Debugger.h" // for ResumeMode, Handler, Debugger
22
#include "gc/Barrier.h" // for HeapPtr
23
#include "gc/Rooting.h" // for HandleDebuggerFrame, HandleNativeObject
24
#include "vm/FrameIter.h" // for FrameIter
25
#include "vm/JSObject.h" // for JSObject
26
#include "vm/NativeObject.h" // for NativeObject
27
#include "vm/Stack.h" // for AbstractFramePtr
28
29
namespace js {
30
31
class AbstractGeneratorObject;
32
class GlobalObject;
33
34
/*
35
* An OnStepHandler represents a handler function that is called when a small
36
* amount of progress is made in a frame.
37
*/
38
struct OnStepHandler : Handler {
39
/*
40
* If we have made a small amount of progress in a frame, this method is
41
* called with the frame as argument. If succesful, this method should
42
* return true, with `resumeMode` and `vp` set to a resumption value
43
* specifiying how execution should continue.
44
*/
45
virtual bool onStep(JSContext* cx, HandleDebuggerFrame frame,
46
ResumeMode& resumeMode, MutableHandleValue vp) = 0;
47
};
48
49
class ScriptedOnStepHandler final : public OnStepHandler {
50
public:
51
explicit ScriptedOnStepHandler(JSObject* object);
52
virtual JSObject* object() const override;
53
virtual void hold(JSObject* owner) override;
54
virtual void drop(JSFreeOp* fop, JSObject* owner) override;
55
virtual void trace(JSTracer* tracer) override;
56
virtual size_t allocSize() const override;
57
virtual bool onStep(JSContext* cx, HandleDebuggerFrame frame,
58
ResumeMode& resumeMode, MutableHandleValue vp) override;
59
60
private:
61
const HeapPtr<JSObject*> object_;
62
};
63
64
/*
65
* An OnPopHandler represents a handler function that is called just before a
66
* frame is popped.
67
*/
68
struct OnPopHandler : Handler {
69
/*
70
* The given `frame` is about to be popped; `completion` explains why.
71
*
72
* When this method returns true, it must set `resumeMode` and `vp` to a
73
* resumption value specifying how execution should continue.
74
*
75
* When this method returns false, it should set an exception on `cx`.
76
*/
77
virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame,
78
const Completion& completion, ResumeMode& resumeMode,
79
MutableHandleValue vp) = 0;
80
};
81
82
class ScriptedOnPopHandler final : public OnPopHandler {
83
public:
84
explicit ScriptedOnPopHandler(JSObject* object);
85
virtual JSObject* object() const override;
86
virtual void hold(JSObject* owner) override;
87
virtual void drop(JSFreeOp* fop, JSObject* owner) override;
88
virtual void trace(JSTracer* tracer) override;
89
virtual size_t allocSize() const override;
90
virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame,
91
const Completion& completion, ResumeMode& resumeMode,
92
MutableHandleValue vp) override;
93
94
private:
95
const HeapPtr<JSObject*> object_;
96
};
97
98
enum class DebuggerFrameType { Eval, Global, Call, Module, WasmCall };
99
100
enum class DebuggerFrameImplementation { Interpreter, Baseline, Ion, Wasm };
101
102
class DebuggerArguments : public NativeObject {
103
public:
104
static const JSClass class_;
105
106
static DebuggerArguments* create(JSContext* cx, HandleObject proto,
107
HandleDebuggerFrame frame);
108
109
private:
110
enum { FRAME_SLOT };
111
112
static const unsigned RESERVED_SLOTS = 1;
113
};
114
115
class DebuggerFrame : public NativeObject {
116
friend class DebuggerArguments;
117
friend class ScriptedOnStepHandler;
118
friend class ScriptedOnPopHandler;
119
120
public:
121
static const JSClass class_;
122
123
enum {
124
OWNER_SLOT = 0,
125
ARGUMENTS_SLOT,
126
ONSTEP_HANDLER_SLOT,
127
ONPOP_HANDLER_SLOT,
128
129
HAS_INCREMENTED_STEPPER_SLOT,
130
131
// If this is a frame for a generator call, and the generator object has
132
// been created (which doesn't happen until after default argument
133
// evaluation and destructuring), then this is a PrivateValue pointing to a
134
// GeneratorInfo struct that points to the call's AbstractGeneratorObject.
135
// This allows us to implement Debugger.Frame methods even while the call is
136
// suspended, and we have no FrameIter::Data.
137
//
138
// While Debugger::generatorFrames maps an AbstractGeneratorObject to its
139
// Debugger.Frame, this link represents the reverse relation, from a
140
// Debugger.Frame to its generator object. This slot is set if and only if
141
// there is a corresponding entry in generatorFrames.
142
GENERATOR_INFO_SLOT,
143
144
RESERVED_SLOTS,
145
};
146
147
void trace(JSTracer* trc);
148
149
static NativeObject* initClass(JSContext* cx, Handle<GlobalObject*> global,
150
HandleObject dbgCtor);
151
static DebuggerFrame* create(JSContext* cx, HandleObject proto,
152
const FrameIter& iter,
153
HandleNativeObject debugger);
154
155
static MOZ_MUST_USE bool getArguments(JSContext* cx,
156
HandleDebuggerFrame frame,
157
MutableHandleDebuggerArguments result);
158
static MOZ_MUST_USE bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
159
MutableHandleDebuggerObject result);
160
static MOZ_MUST_USE bool getIsConstructing(JSContext* cx,
161
HandleDebuggerFrame frame,
162
bool& result);
163
static MOZ_MUST_USE bool getEnvironment(
164
JSContext* cx, HandleDebuggerFrame frame,
165
MutableHandleDebuggerEnvironment result);
166
static MOZ_MUST_USE bool getOffset(JSContext* cx, HandleDebuggerFrame frame,
167
size_t& result);
168
static MOZ_MUST_USE bool getOlder(JSContext* cx, HandleDebuggerFrame frame,
169
MutableHandleDebuggerFrame result);
170
static MOZ_MUST_USE bool getAsyncPromise(JSContext* cx,
171
HandleDebuggerFrame frame,
172
MutableHandleDebuggerObject result);
173
static MOZ_MUST_USE bool getThis(JSContext* cx, HandleDebuggerFrame frame,
174
MutableHandleValue result);
175
static DebuggerFrameType getType(HandleDebuggerFrame frame);
176
static DebuggerFrameImplementation getImplementation(
177
HandleDebuggerFrame frame);
178
static MOZ_MUST_USE bool setOnStepHandler(JSContext* cx,
179
HandleDebuggerFrame frame,
180
OnStepHandler* handler);
181
182
static MOZ_MUST_USE JS::Result<Completion> eval(
183
JSContext* cx, HandleDebuggerFrame frame,
184
mozilla::Range<const char16_t> chars, HandleObject bindings,
185
const EvalOptions& options);
186
187
static MOZ_MUST_USE DebuggerFrame* check(JSContext* cx, HandleValue thisv);
188
189
bool isOnStack() const;
190
191
// Like isOnStack, but works even in the midst of a relocating GC.
192
bool isOnStackMaybeForwarded() const;
193
194
OnStepHandler* onStepHandler() const;
195
OnPopHandler* onPopHandler() const;
196
void setOnPopHandler(JSContext* cx, OnPopHandler* handler);
197
198
inline bool hasGenerator() const;
199
200
// If hasGenerator(), return an direct cross-compartment reference to this
201
// Debugger.Frame's generator object.
202
AbstractGeneratorObject& unwrappedGenerator() const;
203
204
#ifdef DEBUG
205
JSScript* generatorScript() const;
206
#endif
207
208
/*
209
* Associate the generator object genObj with this Debugger.Frame. This
210
* association allows the Debugger.Frame to track the generator's execution
211
* across suspensions and resumptions, and to implement some methods even
212
* while the generator is suspended.
213
*
214
* The context `cx` must be in the Debugger.Frame's realm, and `genObj` must
215
* be in a debuggee realm.
216
*
217
* Technically, the generator activation need not actually be on the stack
218
* right now; it's okay to call this method on a Debugger.Frame that has no
219
* ScriptFrameIter::Data at present. However, this function has no way to
220
* verify that genObj really is the generator associated with the call for
221
* which this Debugger.Frame was originally created, so it's best to make the
222
* association while the call is on the stack, and the relationships are easy
223
* to discern.
224
*/
225
MOZ_MUST_USE bool setGenerator(JSContext* cx,
226
Handle<AbstractGeneratorObject*> genObj);
227
228
/*
229
* Undo the effects of a prior call to setGenerator.
230
*
231
* If provided, owner must be the Debugger to which this Debugger.Frame
232
* belongs; remove this frame's entry from its generatorFrames map, and clean
233
* up its cross-compartment wrapper table entry. The owner must be passed
234
* unless this method is being called from the Debugger.Frame's finalizer. (In
235
* that case, the owner is not reliably available, and is not actually
236
* necessary.)
237
*
238
* If maybeGeneratorFramesEnum is non-null, use it to remove this frame's
239
* entry from the Debugger's generatorFrames weak map. In this case, this
240
* function will not otherwise disturb generatorFrames. Passing the enum
241
* allows this function to be used while iterating over generatorFrames.
242
*/
243
void clearGenerator(JSFreeOp* fop);
244
void clearGenerator(
245
JSFreeOp* fop, Debugger* owner,
246
Debugger::GeneratorWeakMap::Enum* maybeGeneratorFramesEnum = nullptr);
247
248
/*
249
* Called after a generator/async frame is resumed, before exposing this
250
* Debugger.Frame object to any hooks.
251
*/
252
bool resume(const FrameIter& iter);
253
254
bool hasAnyHooks() const;
255
256
private:
257
static const JSClassOps classOps_;
258
259
static const JSPropertySpec properties_[];
260
static const JSFunctionSpec methods_[];
261
262
static void finalize(JSFreeOp* fop, JSObject* obj);
263
264
static AbstractFramePtr getReferent(HandleDebuggerFrame frame);
265
static MOZ_MUST_USE bool getFrameIter(JSContext* cx,
266
HandleDebuggerFrame frame,
267
mozilla::Maybe<FrameIter>& result);
268
static MOZ_MUST_USE bool requireScriptReferent(JSContext* cx,
269
HandleDebuggerFrame frame);
270
271
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
272
273
struct CallData;
274
275
Debugger* owner() const;
276
277
bool hasIncrementedStepper() const;
278
void setHasIncrementedStepper(bool incremented);
279
280
MOZ_MUST_USE bool maybeIncrementStepperCounter(JSContext* cx,
281
AbstractFramePtr referent);
282
MOZ_MUST_USE bool maybeIncrementStepperCounter(JSContext* cx,
283
JSScript* script);
284
void maybeDecrementStepperCounter(JSFreeOp* fop, JSScript* script);
285
286
public:
287
FrameIter::Data* frameIterData() const;
288
void setFrameIterData(FrameIter::Data*);
289
void freeFrameIterData(JSFreeOp* fop);
290
void maybeDecrementStepperCounter(JSFreeOp* fop, AbstractFramePtr referent);
291
292
class GeneratorInfo;
293
inline GeneratorInfo* generatorInfo() const;
294
};
295
296
} /* namespace js */
297
298
#endif /* debugger_Frame_h */