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 :
124 : bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj);
125 : void removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
126 : GlobalObjectSet::Enum *compartmentEnum,
127 : GlobalObjectSet::Enum *debugEnum);
128 :
129 : /*
130 : * Cope with an error or exception in a debugger hook.
131 : *
132 : * If callHook is true, then call the uncaughtExceptionHook, if any. If, in
133 : * addition, vp is non-null, then parse the value returned by
134 : * uncaughtExceptionHook as a resumption value.
135 : *
136 : * If there is no uncaughtExceptionHook, or if it fails, report and clear
137 : * the pending exception on ac.context and return JSTRAP_ERROR.
138 : *
139 : * This always calls ac.leave(); ac is a parameter because this method must
140 : * do some things in the debugger compartment and some things in the
141 : * debuggee compartment.
142 : */
143 : JSTrapStatus handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook);
144 :
145 : /*
146 : * Handle the result of a hook that is expected to return a resumption
147 : * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called
148 : * when we return from a debugging hook to debuggee code. The interpreter wants
149 : * a (JSTrapStatus, Value) pair telling it how to proceed.
150 : *
151 : * Precondition: ac is entered. We are in the debugger compartment.
152 : *
153 : * Postcondition: This called ac.leave(). See handleUncaughtException.
154 : *
155 : * If ok is false, the hook failed. If an exception is pending in
156 : * ac.context(), return handleUncaughtException(ac, vp, callhook).
157 : * Otherwise just return JSTRAP_ERROR.
158 : *
159 : * If ok is true, there must be no exception pending in ac.context(). rv may be:
160 : * undefined - Return JSTRAP_CONTINUE to continue execution normally.
161 : * {return: value} or {throw: value} - Call unwrapDebuggeeValue to
162 : * unwrap value. Store the result in *vp and return JSTRAP_RETURN
163 : * or JSTRAP_THROW. The interpreter will force the current frame to
164 : * return or throw an exception.
165 : * null - Return JSTRAP_ERROR to terminate the debuggee with an
166 : * uncatchable error.
167 : * anything else - Make a new TypeError the pending exception and
168 : * return handleUncaughtException(ac, vp, callHook).
169 : */
170 : JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
171 : bool callHook = true);
172 :
173 : JSObject *unwrapDebuggeeArgument(JSContext *cx, const Value &v);
174 :
175 : static void traceObject(JSTracer *trc, JSObject *obj);
176 : void trace(JSTracer *trc);
177 : static void finalize(JSContext *cx, JSObject *obj);
178 : void markKeysInCompartment(JSTracer *tracer);
179 :
180 : static Class jsclass;
181 :
182 : static Debugger *fromThisValue(JSContext *cx, const CallArgs &ca, const char *fnname);
183 : static JSBool getEnabled(JSContext *cx, unsigned argc, Value *vp);
184 : static JSBool setEnabled(JSContext *cx, unsigned argc, Value *vp);
185 : static JSBool getHookImpl(JSContext *cx, unsigned argc, Value *vp, Hook which);
186 : static JSBool setHookImpl(JSContext *cx, unsigned argc, Value *vp, Hook which);
187 : static JSBool getOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
188 : static JSBool setOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
189 : static JSBool getOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
190 : static JSBool setOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
191 : static JSBool getOnNewScript(JSContext *cx, unsigned argc, Value *vp);
192 : static JSBool setOnNewScript(JSContext *cx, unsigned argc, Value *vp);
193 : static JSBool getOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
194 : static JSBool setOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
195 : static JSBool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
196 : static JSBool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
197 : static JSBool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
198 : static JSBool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);
199 : static JSBool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
200 : static JSBool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
201 : static JSBool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
202 : static JSBool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
203 : static JSBool findScripts(JSContext *cx, unsigned argc, Value *vp);
204 : static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
205 : static JSPropertySpec properties[];
206 : static JSFunctionSpec methods[];
207 :
208 : JSObject *getHook(Hook hook) const;
209 : bool hasAnyLiveHooks() const;
210 :
211 : static JSTrapStatus slowPathOnEnterFrame(JSContext *cx, Value *vp);
212 : static bool slowPathOnLeaveFrame(JSContext *cx, bool ok);
213 : static void slowPathOnNewScript(JSContext *cx, JSScript *script,
214 : GlobalObject *compileAndGoGlobal);
215 : static JSTrapStatus dispatchHook(JSContext *cx, Value *vp, Hook which);
216 :
217 : JSTrapStatus fireDebuggerStatement(JSContext *cx, Value *vp);
218 : JSTrapStatus fireExceptionUnwind(JSContext *cx, Value *vp);
219 : JSTrapStatus fireEnterFrame(JSContext *cx, Value *vp);
220 :
221 : /*
222 : * Allocate and initialize a Debugger.Script instance whose referent is
223 : * |script|.
224 : */
225 : JSObject *newDebuggerScript(JSContext *cx, JSScript *script);
226 :
227 : /*
228 : * Receive a "new script" event from the engine. A new script was compiled
229 : * or deserialized.
230 : */
231 : void fireNewScript(JSContext *cx, JSScript *script);
232 :
233 : static inline Debugger *fromLinks(JSCList *links);
234 : inline Breakpoint *firstBreakpoint() const;
235 :
236 : public:
237 : Debugger(JSContext *cx, JSObject *dbg);
238 : ~Debugger();
239 :
240 : bool init(JSContext *cx);
241 : inline const js::HeapPtrObject &toJSObject() const;
242 : inline js::HeapPtrObject &toJSObjectRef();
243 : static inline Debugger *fromJSObject(JSObject *obj);
244 : static Debugger *fromChildJSObject(JSObject *obj);
245 :
246 : /*********************************** Methods for interaction with the GC. */
247 :
248 : /*
249 : * A Debugger object is live if:
250 : * * the Debugger JSObject is live (Debugger::trace handles this case); OR
251 : * * it is in the middle of dispatching an event (the event dispatching
252 : * code roots it in this case); OR
253 : * * it is enabled, and it is debugging at least one live compartment,
254 : * and at least one of the following is true:
255 : * - it has a debugger hook installed
256 : * - it has a breakpoint set on a live script
257 : * - it has a watchpoint set on a live object.
258 : *
259 : * Debugger::markAllIteratively handles the last case. If it finds any
260 : * Debugger objects that are definitely live but not yet marked, it marks
261 : * them and returns true. If not, it returns false.
262 : */
263 : static void markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer);
264 : static bool markAllIteratively(GCMarker *trc);
265 : static void sweepAll(JSContext *cx);
266 : static void detachAllDebuggersFromGlobal(JSContext *cx, GlobalObject *global,
267 : GlobalObjectSet::Enum *compartmentEnum);
268 :
269 : static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp);
270 : static inline bool onLeaveFrame(JSContext *cx, bool ok);
271 : static inline JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp);
272 : static inline JSTrapStatus onExceptionUnwind(JSContext *cx, Value *vp);
273 : static inline void onNewScript(JSContext *cx, JSScript *script,
274 : GlobalObject *compileAndGoGlobal);
275 : static JSTrapStatus onTrap(JSContext *cx, Value *vp);
276 : static JSTrapStatus onSingleStep(JSContext *cx, Value *vp);
277 :
278 : /************************************* Functions for use by Debugger.cpp. */
279 :
280 : inline bool observesEnterFrame() const;
281 : inline bool observesNewScript() const;
282 : inline bool observesGlobal(GlobalObject *global) const;
283 : inline bool observesFrame(StackFrame *fp) const;
284 :
285 : /*
286 : * If env is NULL, call vp->setNull() and return true. Otherwise, find or
287 : * create a Debugger.Environment object for the given Env. On success,
288 : * store the Environment object in *vp and return true.
289 : */
290 : bool wrapEnvironment(JSContext *cx, Env *env, Value *vp);
291 :
292 : /*
293 : * Like cx->compartment->wrap(cx, vp), but for the debugger compartment.
294 : *
295 : * Preconditions: *vp is a value from a debuggee compartment; cx is in the
296 : * debugger's compartment.
297 : *
298 : * If *vp is an object, this produces a (new or existing) Debugger.Object
299 : * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
300 : */
301 : bool wrapDebuggeeValue(JSContext *cx, Value *vp);
302 :
303 : /*
304 : * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
305 : * compartment.
306 : *
307 : * Preconditions: cx is in the debugger compartment. *vp is a value in that
308 : * compartment. (*vp should be a "debuggee value", meaning it is the
309 : * debugger's reflection of a value in the debuggee.)
310 : *
311 : * If *vp is a Debugger.Object, store the referent in *vp. Otherwise, if *vp
312 : * is an object, throw a TypeError, because it is not a debuggee
313 : * value. Otherwise *vp is a primitive, so leave it alone.
314 : *
315 : * When passing values from the debuggee to the debugger:
316 : * enter debugger compartment;
317 : * call wrapDebuggeeValue; // compartment- and debugger-wrapping
318 : *
319 : * When passing values from the debugger to the debuggee:
320 : * call unwrapDebuggeeValue; // debugger-unwrapping
321 : * enter debuggee compartment;
322 : * call cx->compartment->wrap; // compartment-rewrapping
323 : *
324 : * (Extreme nerd sidebar: Unwrapping happens in two steps because there are
325 : * two different kinds of symmetry at work: regardless of which direction
326 : * we're going, we want any exceptions to be created and thrown in the
327 : * debugger compartment--mirror symmetry. But compartment wrapping always
328 : * happens in the target compartment--rotational symmetry.)
329 : */
330 : bool unwrapDebuggeeValue(JSContext *cx, Value *vp);
331 :
332 : /* Store the Debugger.Frame object for the frame fp in *vp. */
333 : bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
334 :
335 : /*
336 : * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
337 : * standard SpiderMonkey call state: a boolean success value |ok|, a return
338 : * value |rv|, and a context |cx| that may or may not have an exception set.
339 : * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
340 : * to be false).
341 : */
342 : static void resultToCompletion(JSContext *cx, bool ok, const Value &rv,
343 : JSTrapStatus *status, Value *value);
344 :
345 : /*
346 : * Set |*result| to a JavaScript completion value corresponding to |status|
347 : * and |value|. |value| should be the return value or exception value, not
348 : * wrapped as a debuggee value. |cx| must be in the debugger compartment.
349 : */
350 : bool newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result);
351 :
352 : /*
353 : * Precondition: we are in the debuggee compartment (ac is entered) and ok
354 : * is true if the operation in the debuggee compartment succeeded, false on
355 : * error or exception.
356 : *
357 : * Postcondition: we are in the debugger compartment, having called
358 : * ac.leave() even if an error occurred.
359 : *
360 : * On success, a completion value is in vp and ac.context does not have a
361 : * pending exception. (This ordinarily returns true even if the ok argument
362 : * is false.)
363 : */
364 : bool receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
365 :
366 : /*
367 : * Return the Debugger.Script object for |script|, or create a new one if
368 : * needed. The context |cx| must be in the debugger compartment; |script|
369 : * must be a script in a debuggee compartment.
370 : */
371 : JSObject *wrapScript(JSContext *cx, JSScript *script);
372 :
373 : private:
374 : Debugger(const Debugger &) MOZ_DELETE;
375 : Debugger & operator=(const Debugger &) MOZ_DELETE;
376 : };
377 :
378 1190 : class BreakpointSite {
379 : friend class Breakpoint;
380 : friend struct ::JSCompartment;
381 : friend struct ::JSScript;
382 : friend class Debugger;
383 :
384 : public:
385 : JSScript * const script;
386 : jsbytecode * const pc;
387 :
388 : private:
389 : /*
390 : * The holder object for script, if known, else NULL. This is NULL for
391 : * cached eval scripts and for JSD1 traps. It is always non-null for JSD2
392 : * breakpoints in held scripts.
393 : */
394 : GlobalObject *scriptGlobal;
395 :
396 : JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */
397 : size_t enabledCount; /* number of breakpoints in the list that are enabled */
398 : JSTrapHandler trapHandler; /* jsdbgapi trap state */
399 : HeapValue trapClosure;
400 :
401 : bool recompile(JSContext *cx, bool forTrap);
402 :
403 : public:
404 : BreakpointSite(JSScript *script, jsbytecode *pc);
405 : Breakpoint *firstBreakpoint() const;
406 : bool hasBreakpoint(Breakpoint *bp);
407 : bool hasTrap() const { return !!trapHandler; }
408 : GlobalObject *getScriptGlobal() const { return scriptGlobal; }
409 :
410 : bool inc(JSContext *cx);
411 : void dec(JSContext *cx);
412 : bool setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure);
413 : void clearTrap(JSContext *cx, JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
414 : void destroyIfEmpty(JSRuntime *rt);
415 : };
416 :
417 : /*
418 : * Each Breakpoint is a member of two linked lists: its debugger's list and its
419 : * site's list.
420 : *
421 : * GC rules:
422 : * - script is live, breakpoint exists, and debugger is enabled
423 : * ==> debugger is live
424 : * - script is live, breakpoint exists, and debugger is live
425 : * ==> retain the breakpoint and the handler object is live
426 : *
427 : * Debugger::markAllIteratively implements these two rules. It uses
428 : * Debugger::hasAnyLiveHooks to check for rule 1.
429 : *
430 : * Nothing else causes a breakpoint to be retained, so if its script or
431 : * debugger is collected, the breakpoint is destroyed during GC sweep phase,
432 : * even if the debugger compartment isn't being GC'd. This is implemented in
433 : * JSCompartment::sweepBreakpoints.
434 : */
435 1281 : class Breakpoint {
436 : friend struct ::JSCompartment;
437 : friend class Debugger;
438 :
439 : public:
440 : Debugger * const debugger;
441 : BreakpointSite * const site;
442 : private:
443 : js::HeapPtrObject handler;
444 : JSCList debuggerLinks;
445 : JSCList siteLinks;
446 :
447 : public:
448 : static Breakpoint *fromDebuggerLinks(JSCList *links);
449 : static Breakpoint *fromSiteLinks(JSCList *links);
450 : Breakpoint(Debugger *debugger, BreakpointSite *site, JSObject *handler);
451 : void destroy(JSContext *cx);
452 : Breakpoint *nextInDebugger();
453 : Breakpoint *nextInSite();
454 885 : const HeapPtrObject &getHandler() const { return handler; }
455 163 : HeapPtrObject &getHandlerRef() { return handler; }
456 : };
457 :
458 : Debugger *
459 7170 : Debugger::fromLinks(JSCList *links)
460 : {
461 7170 : unsigned char *p = reinterpret_cast<unsigned char *>(links);
462 7170 : return reinterpret_cast<Debugger *>(p - offsetof(Debugger, link));
463 : }
464 :
465 : Breakpoint *
466 6984 : Debugger::firstBreakpoint() const
467 : {
468 6984 : if (JS_CLIST_IS_EMPTY(&breakpoints))
469 6562 : return NULL;
470 422 : return Breakpoint::fromDebuggerLinks(JS_NEXT_LINK(&breakpoints));
471 : }
472 :
473 : const js::HeapPtrObject &
474 34647 : Debugger::toJSObject() const
475 : {
476 34647 : JS_ASSERT(object);
477 34647 : return object;
478 : }
479 :
480 : js::HeapPtrObject &
481 6831 : Debugger::toJSObjectRef()
482 : {
483 6831 : JS_ASSERT(object);
484 6831 : return object;
485 : }
486 :
487 : Debugger *
488 172057 : Debugger::fromJSObject(JSObject *obj)
489 : {
490 172057 : JS_ASSERT(js::GetObjectClass(obj) == &jsclass);
491 172057 : return (Debugger *) obj->getPrivate();
492 : }
493 :
494 : bool
495 33602 : Debugger::observesEnterFrame() const
496 : {
497 33602 : return enabled && getHook(OnEnterFrame);
498 : }
499 :
500 : bool
501 11080 : Debugger::observesNewScript() const
502 : {
503 11080 : return enabled && getHook(OnNewScript);
504 : }
505 :
506 : bool
507 36408 : Debugger::observesGlobal(GlobalObject *global) const
508 : {
509 36408 : return debuggees.has(global);
510 : }
511 :
512 : bool
513 35883 : Debugger::observesFrame(StackFrame *fp) const
514 : {
515 35883 : return !fp->isDummyFrame() && observesGlobal(&fp->scopeChain().global());
516 : }
517 :
518 : JSTrapStatus
519 15284752 : Debugger::onEnterFrame(JSContext *cx, Value *vp)
520 : {
521 15284752 : if (cx->compartment->getDebuggees().empty())
522 15256887 : return JSTRAP_CONTINUE;
523 27865 : return slowPathOnEnterFrame(cx, vp);
524 : }
525 :
526 : bool
527 15285465 : Debugger::onLeaveFrame(JSContext *cx, bool ok)
528 : {
529 : /* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */
530 15285465 : bool evalTraps = cx->fp()->isEvalFrame() &&
531 15285465 : cx->fp()->script()->hasAnyBreakpointsOrStepMode();
532 15285465 : if (!cx->compartment->getDebuggees().empty() || evalTraps)
533 28059 : ok = slowPathOnLeaveFrame(cx, ok);
534 15285465 : return ok;
535 : }
536 :
537 : JSTrapStatus
538 8213 : Debugger::onDebuggerStatement(JSContext *cx, Value *vp)
539 : {
540 8213 : return cx->compartment->getDebuggees().empty()
541 : ? JSTRAP_CONTINUE
542 8213 : : dispatchHook(cx, vp, OnDebuggerStatement);
543 : }
544 :
545 : JSTrapStatus
546 30098 : Debugger::onExceptionUnwind(JSContext *cx, Value *vp)
547 : {
548 30098 : return cx->compartment->getDebuggees().empty()
549 : ? JSTRAP_CONTINUE
550 30098 : : dispatchHook(cx, vp, OnExceptionUnwind);
551 : }
552 :
553 : void
554 133713 : Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal)
555 : {
556 133713 : JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
557 133713 : JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
558 133713 : if (!script->compartment()->getDebuggees().empty())
559 9804 : slowPathOnNewScript(cx, script, compileAndGoGlobal);
560 133713 : }
561 :
562 : extern JSBool
563 : EvaluateInEnv(JSContext *cx, Env *env, StackFrame *fp, const jschar *chars,
564 : unsigned length, const char *filename, unsigned lineno, Value *rval);
565 :
566 : }
567 :
568 : #endif /* Debugger_h__ */
|