1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99 ft=cpp:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey Debugger object.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998-1999
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributors:
25 : * Jim Blandy <jimb@mozilla.com>
26 : * Jason Orendorff <jorendorff@mozilla.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #ifndef Debugger_h__
43 : #define Debugger_h__
44 :
45 : #include "mozilla/Attributes.h"
46 :
47 : #include "jsapi.h"
48 : #include "jsclist.h"
49 : #include "jscntxt.h"
50 : #include "jscompartment.h"
51 : #include "jsgc.h"
52 : #include "jsweakmap.h"
53 : #include "jswrapper.h"
54 :
55 : #include "gc/Barrier.h"
56 : #include "js/HashTable.h"
57 : #include "vm/GlobalObject.h"
58 :
59 : namespace js {
60 :
61 : class Debugger {
62 : friend class Breakpoint;
63 : friend JSBool (::JS_DefineDebuggerObject)(JSContext *cx, JSObject *obj);
64 :
65 : public:
66 : enum Hook {
67 : OnDebuggerStatement,
68 : OnExceptionUnwind,
69 : OnNewScript,
70 : OnEnterFrame,
71 : HookCount
72 : };
73 :
74 : enum {
75 : JSSLOT_DEBUG_PROTO_START,
76 : JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START,
77 : JSSLOT_DEBUG_ENV_PROTO,
78 : JSSLOT_DEBUG_OBJECT_PROTO,
79 : JSSLOT_DEBUG_SCRIPT_PROTO,
80 : JSSLOT_DEBUG_PROTO_STOP,
81 : JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP,
82 : JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount,
83 : JSSLOT_DEBUG_COUNT = JSSLOT_DEBUG_HOOK_STOP
84 : };
85 :
86 : private:
87 : JSCList link; /* See JSRuntime::debuggerList. */
88 : HeapPtrObject object; /* The Debugger object. Strong reference. */
89 : GlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */
90 : js::HeapPtrObject uncaughtExceptionHook; /* Strong reference. */
91 : bool enabled;
92 : JSCList breakpoints; /* cyclic list of all js::Breakpoints in this debugger */
93 :
94 : /*
95 : * Map from stack frames that are currently on the stack to Debugger.Frame
96 : * instances.
97 : *
98 : * The keys are always live stack frames. We drop them from this map as
99 : * soon as they leave the stack (see slowPathOnLeaveFrame) and in
100 : * removeDebuggee.
101 : *
102 : * We don't trace the keys of this map (the frames are on the stack and
103 : * thus necessarily live), but we do trace the values. It's like a WeakMap
104 : * that way, but since stack frames are not gc-things, the implementation
105 : * has to be different.
106 : */
107 : typedef HashMap<StackFrame *, HeapPtrObject, DefaultHasher<StackFrame *>, RuntimeAllocPolicy>
108 : FrameMap;
109 : FrameMap frames;
110 :
111 : /* An ephemeral map from JSScript* to Debugger.Script instances. */
112 : typedef WeakMap<HeapPtrScript, HeapPtrObject> ScriptWeakMap;
113 : ScriptWeakMap scripts;
114 :
115 : /* The map from debuggee objects to their Debugger.Object instances. */
116 : typedef WeakMap<HeapPtrObject, HeapPtrObject> ObjectWeakMap;
117 : ObjectWeakMap objects;
118 :
119 : /* The map from debuggee Envs to Debugger.Environment instances. */
120 : ObjectWeakMap environments;
121 :
122 : class FrameRange;
123 : class ScriptQuery;
124 :
125 : bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj);
126 : void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
127 : GlobalObjectSet::Enum *compartmentEnum,
128 : GlobalObjectSet::Enum *debugEnum);
129 :
130 : /*
131 : * Cope with an error or exception in a debugger hook.
132 : *
133 : * If callHook is true, then call the uncaughtExceptionHook, if any. If, in
134 : * addition, vp is non-null, then parse the value returned by
135 : * uncaughtExceptionHook as a resumption value.
136 : *
137 : * If there is no uncaughtExceptionHook, or if it fails, report and clear
138 : * the pending exception on ac.context and return JSTRAP_ERROR.
139 : *
140 : * This always calls ac.leave(); ac is a parameter because this method must
141 : * do some things in the debugger compartment and some things in the
142 : * debuggee compartment.
143 : */
144 : JSTrapStatus handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook);
145 :
146 : /*
147 : * Handle the result of a hook that is expected to return a resumption
148 : * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called
149 : * when we return from a debugging hook to debuggee code. The interpreter wants
150 : * a (JSTrapStatus, Value) pair telling it how to proceed.
151 : *
152 : * Precondition: ac is entered. We are in the debugger compartment.
153 : *
154 : * Postcondition: This called ac.leave(). See handleUncaughtException.
155 : *
156 : * If ok is false, the hook failed. If an exception is pending in
157 : * ac.context(), return handleUncaughtException(ac, vp, callhook).
158 : * Otherwise just return JSTRAP_ERROR.
159 : *
160 : * If ok is true, there must be no exception pending in ac.context(). rv may be:
161 : * undefined - Return JSTRAP_CONTINUE to continue execution normally.
162 : * {return: value} or {throw: value} - Call unwrapDebuggeeValue to
163 : * unwrap value. Store the result in *vp and return JSTRAP_RETURN
164 : * or JSTRAP_THROW. The interpreter will force the current frame to
165 : * return or throw an exception.
166 : * null - Return JSTRAP_ERROR to terminate the debuggee with an
167 : * uncatchable error.
168 : * anything else - Make a new TypeError the pending exception and
169 : * return handleUncaughtException(ac, vp, callHook).
170 : */
171 : JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
172 : bool callHook = true);
173 :
174 : JSObject *unwrapDebuggeeArgument(JSContext *cx, const Value &v);
175 :
176 : static void traceObject(JSTracer *trc, JSObject *obj);
177 : void trace(JSTracer *trc);
178 : static void finalize(FreeOp *fop, JSObject *obj);
179 : void markKeysInCompartment(JSTracer *tracer);
180 :
181 : static Class jsclass;
182 :
183 : static Debugger *fromThisValue(JSContext *cx, const CallArgs &ca, const char *fnname);
184 : static JSBool getEnabled(JSContext *cx, unsigned argc, Value *vp);
185 : static JSBool setEnabled(JSContext *cx, unsigned argc, Value *vp);
186 : static JSBool getHookImpl(JSContext *cx, unsigned argc, Value *vp, Hook which);
187 : static JSBool setHookImpl(JSContext *cx, unsigned argc, Value *vp, Hook which);
188 : static JSBool getOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
189 : static JSBool setOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
190 : static JSBool getOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
191 : static JSBool setOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
192 : static JSBool getOnNewScript(JSContext *cx, unsigned argc, Value *vp);
193 : static JSBool setOnNewScript(JSContext *cx, unsigned argc, Value *vp);
194 : static JSBool getOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
195 : static JSBool setOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
196 : static JSBool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
197 : static JSBool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
198 : static JSBool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
199 : static JSBool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);
200 : static JSBool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
201 : static JSBool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
202 : static JSBool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
203 : static JSBool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
204 : static JSBool findScripts(JSContext *cx, unsigned argc, Value *vp);
205 : static JSBool wrap(JSContext *cx, unsigned argc, Value *vp);
206 : static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
207 : static JSPropertySpec properties[];
208 : static JSFunctionSpec methods[];
209 :
210 : JSObject *getHook(Hook hook) const;
211 : bool hasAnyLiveHooks() const;
212 :
213 : static JSTrapStatus slowPathOnEnterFrame(JSContext *cx, Value *vp);
214 : static bool slowPathOnLeaveFrame(JSContext *cx, bool ok);
215 : static void slowPathOnNewScript(JSContext *cx, JSScript *script,
216 : GlobalObject *compileAndGoGlobal);
217 : static JSTrapStatus dispatchHook(JSContext *cx, Value *vp, Hook which);
218 :
219 : JSTrapStatus fireDebuggerStatement(JSContext *cx, Value *vp);
220 : JSTrapStatus fireExceptionUnwind(JSContext *cx, Value *vp);
221 : JSTrapStatus fireEnterFrame(JSContext *cx, Value *vp);
222 :
223 : /*
224 : * Allocate and initialize a Debugger.Script instance whose referent is
225 : * |script|.
226 : */
227 : JSObject *newDebuggerScript(JSContext *cx, JSScript *script);
228 :
229 : /*
230 : * Receive a "new script" event from the engine. A new script was compiled
231 : * or deserialized.
232 : */
233 : void fireNewScript(JSContext *cx, JSScript *script);
234 :
235 : static inline Debugger *fromLinks(JSCList *links);
236 : inline Breakpoint *firstBreakpoint() const;
237 :
238 : public:
239 : Debugger(JSContext *cx, JSObject *dbg);
240 : ~Debugger();
241 :
242 : bool init(JSContext *cx);
243 : inline const js::HeapPtrObject &toJSObject() const;
244 : inline js::HeapPtrObject &toJSObjectRef();
245 : static inline Debugger *fromJSObject(JSObject *obj);
246 : static Debugger *fromChildJSObject(JSObject *obj);
247 :
248 : /*********************************** Methods for interaction with the GC. */
249 :
250 : /*
251 : * A Debugger object is live if:
252 : * * the Debugger JSObject is live (Debugger::trace handles this case); OR
253 : * * it is in the middle of dispatching an event (the event dispatching
254 : * code roots it in this case); OR
255 : * * it is enabled, and it is debugging at least one live compartment,
256 : * and at least one of the following is true:
257 : * - it has a debugger hook installed
258 : * - it has a breakpoint set on a live script
259 : * - it has a watchpoint set on a live object.
260 : *
261 : * Debugger::markAllIteratively handles the last case. If it finds any
262 : * Debugger objects that are definitely live but not yet marked, it marks
263 : * them and returns true. If not, it returns false.
264 : */
265 : static void markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer);
266 : static bool markAllIteratively(GCMarker *trc);
267 : static void sweepAll(FreeOp *fop);
268 : static void detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global,
269 : GlobalObjectSet::Enum *compartmentEnum);
270 :
271 : static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp);
272 : static inline bool onLeaveFrame(JSContext *cx, bool ok);
273 : static inline JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp);
274 : static inline JSTrapStatus onExceptionUnwind(JSContext *cx, Value *vp);
275 : static inline void onNewScript(JSContext *cx, JSScript *script,
276 : GlobalObject *compileAndGoGlobal);
277 : static JSTrapStatus onTrap(JSContext *cx, Value *vp);
278 : static JSTrapStatus onSingleStep(JSContext *cx, Value *vp);
279 :
280 : /************************************* Functions for use by Debugger.cpp. */
281 :
282 : inline bool observesEnterFrame() const;
283 : inline bool observesNewScript() const;
284 : inline bool observesGlobal(GlobalObject *global) const;
285 : inline bool observesFrame(StackFrame *fp) const;
286 :
287 : /*
288 : * If env is NULL, call vp->setNull() and return true. Otherwise, find or
289 : * create a Debugger.Environment object for the given Env. On success,
290 : * store the Environment object in *vp and return true.
291 : */
292 : bool wrapEnvironment(JSContext *cx, Env *env, Value *vp);
293 :
294 : /*
295 : * Like cx->compartment->wrap(cx, vp), but for the debugger compartment.
296 : *
297 : * Preconditions: *vp is a value from a debuggee compartment; cx is in the
298 : * debugger's compartment.
299 : *
300 : * If *vp is an object, this produces a (new or existing) Debugger.Object
301 : * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
302 : */
303 : bool wrapDebuggeeValue(JSContext *cx, Value *vp);
304 :
305 : /*
306 : * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
307 : * compartment.
308 : *
309 : * Preconditions: cx is in the debugger compartment. *vp is a value in that
310 : * compartment. (*vp should be a "debuggee value", meaning it is the
311 : * debugger's reflection of a value in the debuggee.)
312 : *
313 : * If *vp is a Debugger.Object, store the referent in *vp. Otherwise, if *vp
314 : * is an object, throw a TypeError, because it is not a debuggee
315 : * value. Otherwise *vp is a primitive, so leave it alone.
316 : *
317 : * When passing values from the debuggee to the debugger:
318 : * enter debugger compartment;
319 : * call wrapDebuggeeValue; // compartment- and debugger-wrapping
320 : *
321 : * When passing values from the debugger to the debuggee:
322 : * call unwrapDebuggeeValue; // debugger-unwrapping
323 : * enter debuggee compartment;
324 : * call cx->compartment->wrap; // compartment-rewrapping
325 : *
326 : * (Extreme nerd sidebar: Unwrapping happens in two steps because there are
327 : * two different kinds of symmetry at work: regardless of which direction
328 : * we're going, we want any exceptions to be created and thrown in the
329 : * debugger compartment--mirror symmetry. But compartment wrapping always
330 : * happens in the target compartment--rotational symmetry.)
331 : */
332 : bool unwrapDebuggeeValue(JSContext *cx, Value *vp);
333 :
334 : /* Store the Debugger.Frame object for the frame fp in *vp. */
335 : bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
336 :
337 : /*
338 : * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
339 : * standard SpiderMonkey call state: a boolean success value |ok|, a return
340 : * value |rv|, and a context |cx| that may or may not have an exception set.
341 : * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
342 : * to be false).
343 : */
344 : static void resultToCompletion(JSContext *cx, bool ok, const Value &rv,
345 : JSTrapStatus *status, Value *value);
346 :
347 : /*
348 : * Set |*result| to a JavaScript completion value corresponding to |status|
349 : * and |value|. |value| should be the return value or exception value, not
350 : * wrapped as a debuggee value. |cx| must be in the debugger compartment.
351 : */
352 : bool newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result);
353 :
354 : /*
355 : * Precondition: we are in the debuggee compartment (ac is entered) and ok
356 : * is true if the operation in the debuggee compartment succeeded, false on
357 : * error or exception.
358 : *
359 : * Postcondition: we are in the debugger compartment, having called
360 : * ac.leave() even if an error occurred.
361 : *
362 : * On success, a completion value is in vp and ac.context does not have a
363 : * pending exception. (This ordinarily returns true even if the ok argument
364 : * is false.)
365 : */
366 : bool receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
367 :
368 : /*
369 : * Return the Debugger.Script object for |script|, or create a new one if
370 : * needed. The context |cx| must be in the debugger compartment; |script|
371 : * must be a script in a debuggee compartment.
372 : */
373 : JSObject *wrapScript(JSContext *cx, JSScript *script);
374 :
375 : private:
376 : Debugger(const Debugger &) MOZ_DELETE;
377 : Debugger & operator=(const Debugger &) MOZ_DELETE;
378 : };
379 :
380 1172 : class BreakpointSite {
381 : friend class Breakpoint;
382 : friend struct ::JSCompartment;
383 : friend struct ::JSScript;
384 : friend class Debugger;
385 :
386 : public:
387 : JSScript * const script;
388 : jsbytecode * const pc;
389 :
390 : private:
391 : /*
392 : * The holder object for script, if known, else NULL. This is NULL for
393 : * cached eval scripts and for JSD1 traps. It is always non-null for JSD2
394 : * breakpoints in held scripts.
395 : */
396 : GlobalObject *scriptGlobal;
397 :
398 : JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */
399 : size_t enabledCount; /* number of breakpoints in the list that are enabled */
400 : JSTrapHandler trapHandler; /* jsdbgapi trap state */
401 : HeapValue trapClosure;
402 :
403 : void recompile(FreeOp *fop);
404 :
405 : public:
406 : BreakpointSite(JSScript *script, jsbytecode *pc);
407 : Breakpoint *firstBreakpoint() const;
408 : bool hasBreakpoint(Breakpoint *bp);
409 : bool hasTrap() const { return !!trapHandler; }
410 : GlobalObject *getScriptGlobal() const { return scriptGlobal; }
411 :
412 : void inc(FreeOp *fop);
413 : void dec(FreeOp *fop);
414 : void setTrap(FreeOp *fop, JSTrapHandler handler, const Value &closure);
415 : void clearTrap(FreeOp *fop, JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
416 : void destroyIfEmpty(FreeOp *fop);
417 : };
418 :
419 : /*
420 : * Each Breakpoint is a member of two linked lists: its debugger's list and its
421 : * site's list.
422 : *
423 : * GC rules:
424 : * - script is live, breakpoint exists, and debugger is enabled
425 : * ==> debugger is live
426 : * - script is live, breakpoint exists, and debugger is live
427 : * ==> retain the breakpoint and the handler object is live
428 : *
429 : * Debugger::markAllIteratively implements these two rules. It uses
430 : * Debugger::hasAnyLiveHooks to check for rule 1.
431 : *
432 : * Nothing else causes a breakpoint to be retained, so if its script or
433 : * debugger is collected, the breakpoint is destroyed during GC sweep phase,
434 : * even if the debugger compartment isn't being GC'd. This is implemented in
435 : * JSCompartment::sweepBreakpoints.
436 : */
437 1269 : class Breakpoint {
438 : friend struct ::JSCompartment;
439 : friend class Debugger;
440 :
441 : public:
442 : Debugger * const debugger;
443 : BreakpointSite * const site;
444 : private:
445 : js::HeapPtrObject handler;
446 : JSCList debuggerLinks;
447 : JSCList siteLinks;
448 :
449 : public:
450 : static Breakpoint *fromDebuggerLinks(JSCList *links);
451 : static Breakpoint *fromSiteLinks(JSCList *links);
452 : Breakpoint(Debugger *debugger, BreakpointSite *site, JSObject *handler);
453 : void destroy(FreeOp *fop);
454 : Breakpoint *nextInDebugger();
455 : Breakpoint *nextInSite();
456 873 : const HeapPtrObject &getHandler() const { return handler; }
457 163 : HeapPtrObject &getHandlerRef() { return handler; }
458 : };
459 :
460 : Debugger *
461 14434 : Debugger::fromLinks(JSCList *links)
462 : {
463 14434 : unsigned char *p = reinterpret_cast<unsigned char *>(links);
464 14434 : return reinterpret_cast<Debugger *>(p - offsetof(Debugger, link));
465 : }
466 :
467 : Breakpoint *
468 6940 : Debugger::firstBreakpoint() const
469 : {
470 6940 : if (JS_CLIST_IS_EMPTY(&breakpoints))
471 6519 : return NULL;
472 421 : return Breakpoint::fromDebuggerLinks(JS_NEXT_LINK(&breakpoints));
473 : }
474 :
475 : const js::HeapPtrObject &
476 34638 : Debugger::toJSObject() const
477 : {
478 34638 : JS_ASSERT(object);
479 34638 : return object;
480 : }
481 :
482 : js::HeapPtrObject &
483 6857 : Debugger::toJSObjectRef()
484 : {
485 6857 : JS_ASSERT(object);
486 6857 : return object;
487 : }
488 :
489 : Debugger *
490 178220 : Debugger::fromJSObject(JSObject *obj)
491 : {
492 178220 : JS_ASSERT(js::GetObjectClass(obj) == &jsclass);
493 178220 : return (Debugger *) obj->getPrivate();
494 : }
495 :
496 : bool
497 33903 : Debugger::observesEnterFrame() const
498 : {
499 33903 : return enabled && getHook(OnEnterFrame);
500 : }
501 :
502 : bool
503 11110 : Debugger::observesNewScript() const
504 : {
505 11110 : return enabled && getHook(OnNewScript);
506 : }
507 :
508 : bool
509 36443 : Debugger::observesGlobal(GlobalObject *global) const
510 : {
511 36443 : return debuggees.has(global);
512 : }
513 :
514 : bool
515 35903 : Debugger::observesFrame(StackFrame *fp) const
516 : {
517 35903 : return !fp->isDummyFrame() && observesGlobal(&fp->scopeChain().global());
518 : }
519 :
520 : JSTrapStatus
521 12393915 : Debugger::onEnterFrame(JSContext *cx, Value *vp)
522 : {
523 12393915 : if (cx->compartment->getDebuggees().empty())
524 12365741 : return JSTRAP_CONTINUE;
525 28174 : return slowPathOnEnterFrame(cx, vp);
526 : }
527 :
528 : bool
529 12394644 : Debugger::onLeaveFrame(JSContext *cx, bool ok)
530 : {
531 : /* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */
532 12394644 : bool evalTraps = cx->fp()->isEvalFrame() &&
533 12394644 : cx->fp()->script()->hasAnyBreakpointsOrStepMode();
534 12394644 : if (!cx->compartment->getDebuggees().empty() || evalTraps)
535 28368 : ok = slowPathOnLeaveFrame(cx, ok);
536 12394644 : return ok;
537 : }
538 :
539 : JSTrapStatus
540 8173 : Debugger::onDebuggerStatement(JSContext *cx, Value *vp)
541 : {
542 8173 : return cx->compartment->getDebuggees().empty()
543 : ? JSTRAP_CONTINUE
544 8173 : : dispatchHook(cx, vp, OnDebuggerStatement);
545 : }
546 :
547 : JSTrapStatus
548 1116 : Debugger::onExceptionUnwind(JSContext *cx, Value *vp)
549 : {
550 1116 : return cx->compartment->getDebuggees().empty()
551 : ? JSTRAP_CONTINUE
552 1116 : : dispatchHook(cx, vp, OnExceptionUnwind);
553 : }
554 :
555 : void
556 107244 : Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal)
557 : {
558 107244 : JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
559 107244 : JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
560 107244 : if (!script->compartment()->getDebuggees().empty())
561 9834 : slowPathOnNewScript(cx, script, compileAndGoGlobal);
562 107244 : }
563 :
564 : extern JSBool
565 : EvaluateInEnv(JSContext *cx, Env *env, StackFrame *fp, const jschar *chars,
566 : unsigned length, const char *filename, unsigned lineno, Value *rval);
567 :
568 : }
569 :
570 : #endif /* Debugger_h__ */
|