716a65c8b39713a00b7527167db1e50e389ebf52
[WebKit-https.git] / Source / JavaScriptCore / debugger / Debugger.cpp
1 /*
2  *  Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
3  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "config.h"
23 #include "Debugger.h"
24
25 #include "CodeBlock.h"
26 #include "DebuggerCallFrame.h"
27 #include "Error.h"
28 #include "HeapIterationScope.h"
29 #include "Interpreter.h"
30 #include "JSCJSValueInlines.h"
31 #include "JSFunction.h"
32 #include "JSGlobalObject.h"
33 #include "JSCInlines.h"
34 #include "Parser.h"
35 #include "Protect.h"
36 #include "VMEntryScope.h"
37
38 namespace {
39
40 using namespace JSC;
41
42 struct GatherSourceProviders : public MarkedBlock::VoidFunctor {
43     HashSet<SourceProvider*> sourceProviders;
44     JSGlobalObject* m_globalObject;
45
46     GatherSourceProviders(JSGlobalObject* globalObject)
47         : m_globalObject(globalObject) { }
48
49     IterationStatus operator()(JSCell* cell)
50     {
51         JSFunction* function = jsDynamicCast<JSFunction*>(cell);
52         if (!function)
53             return IterationStatus::Continue;
54
55         if (function->scope()->globalObject() != m_globalObject)
56             return IterationStatus::Continue;
57
58         if (!function->executable()->isFunctionExecutable())
59             return IterationStatus::Continue;
60
61         if (function->isHostOrBuiltinFunction())
62             return IterationStatus::Continue;
63
64         sourceProviders.add(
65             jsCast<FunctionExecutable*>(function->executable())->source().provider());
66         return IterationStatus::Continue;
67     }
68 };
69
70 } // namespace
71
72 namespace JSC {
73
74 class DebuggerPausedScope {
75 public:
76     DebuggerPausedScope(Debugger& debugger)
77         : m_debugger(debugger)
78     {
79         ASSERT(!m_debugger.m_currentDebuggerCallFrame);
80         if (m_debugger.m_currentCallFrame)
81             m_debugger.m_currentDebuggerCallFrame = DebuggerCallFrame::create(debugger.m_currentCallFrame);
82     }
83
84     ~DebuggerPausedScope()
85     {
86         if (m_debugger.m_currentDebuggerCallFrame) {
87             m_debugger.m_currentDebuggerCallFrame->invalidate();
88             m_debugger.m_currentDebuggerCallFrame = nullptr;
89         }
90     }
91
92 private:
93     Debugger& m_debugger;
94 };
95
96 // This is very similar to TemporaryChange<bool>, but that cannot be used
97 // as the m_isPaused field uses only one bit.
98 class TemporaryPausedState {
99 public:
100     TemporaryPausedState(Debugger& debugger)
101         : m_debugger(debugger)
102     {
103         ASSERT(!m_debugger.m_isPaused);
104         m_debugger.m_isPaused = true;
105     }
106
107     ~TemporaryPausedState()
108     {
109         m_debugger.m_isPaused = false;
110     }
111
112 private:
113     Debugger& m_debugger;
114 };
115
116 Debugger::Debugger(VM& vm)
117     : m_vm(vm)
118     , m_pauseOnExceptionsState(DontPauseOnExceptions)
119     , m_pauseOnNextStatement(false)
120     , m_isPaused(false)
121     , m_breakpointsActivated(false)
122     , m_hasHandlerForExceptionCallback(false)
123     , m_suppressAllPauses(false)
124     , m_steppingMode(SteppingModeDisabled)
125     , m_reasonForPause(NotPaused)
126     , m_pauseOnCallFrame(0)
127     , m_currentCallFrame(0)
128     , m_lastExecutedLine(UINT_MAX)
129     , m_lastExecutedSourceID(noSourceID)
130     , m_topBreakpointID(noBreakpointID)
131     , m_pausingBreakpointID(noBreakpointID)
132 {
133 }
134
135 Debugger::~Debugger()
136 {
137     HashSet<JSGlobalObject*>::iterator end = m_globalObjects.end();
138     for (HashSet<JSGlobalObject*>::iterator it = m_globalObjects.begin(); it != end; ++it)
139         (*it)->setDebugger(0);
140 }
141
142 void Debugger::attach(JSGlobalObject* globalObject)
143 {
144     ASSERT(!globalObject->debugger());
145     globalObject->setDebugger(this);
146     m_globalObjects.add(globalObject);
147
148     m_vm.setShouldBuildPCToCodeOriginMapping();
149
150     // Call sourceParsed because it will execute JavaScript in the inspector.
151     GatherSourceProviders gatherSourceProviders(globalObject);
152     {
153         HeapIterationScope iterationScope(m_vm.heap);
154         m_vm.heap.objectSpace().forEachLiveCell(iterationScope, gatherSourceProviders);
155     }
156     for (auto* sourceProvider : gatherSourceProviders.sourceProviders)
157         sourceParsed(globalObject->globalExec(), sourceProvider, -1, String());
158 }
159
160 void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason)
161 {
162     // If we're detaching from the currently executing global object, manually tear down our
163     // stack, since we won't get further debugger callbacks to do so. Also, resume execution,
164     // since there's no point in staying paused once a window closes.
165     if (m_currentCallFrame && m_currentCallFrame->vmEntryGlobalObject() == globalObject) {
166         m_currentCallFrame = 0;
167         m_pauseOnCallFrame = 0;
168         continueProgram();
169     }
170
171     ASSERT(m_globalObjects.contains(globalObject));
172     m_globalObjects.remove(globalObject);
173
174     // If the globalObject is destructing, then its CodeBlocks will also be
175     // destructed. There is no need to do the debugger requests clean up, and
176     // it is not safe to access those CodeBlocks at this time anyway.
177     if (reason != GlobalObjectIsDestructing)
178         clearDebuggerRequests(globalObject);
179
180     globalObject->setDebugger(0);
181 }
182
183 bool Debugger::isAttached(JSGlobalObject* globalObject)
184 {
185     return globalObject->debugger() == this;
186 }
187
188 class Debugger::SetSteppingModeFunctor {
189 public:
190     SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode)
191         : m_debugger(debugger)
192         , m_mode(mode)
193     {
194     }
195
196     bool operator()(CodeBlock* codeBlock)
197     {
198         if (m_debugger == codeBlock->globalObject()->debugger()) {
199             if (m_mode == SteppingModeEnabled)
200                 codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
201             else
202                 codeBlock->setSteppingMode(CodeBlock::SteppingModeDisabled);
203         }
204         return false;
205     }
206
207 private:
208     Debugger* m_debugger;
209     SteppingMode m_mode;
210 };
211
212 void Debugger::setSteppingMode(SteppingMode mode)
213 {
214     if (mode == m_steppingMode)
215         return;
216
217     m_vm.heap.completeAllDFGPlans();
218
219     m_steppingMode = mode;
220     SetSteppingModeFunctor functor(this, mode);
221     m_vm.heap.forEachCodeBlock(functor);
222 }
223
224 void Debugger::registerCodeBlock(CodeBlock* codeBlock)
225 {
226     applyBreakpoints(codeBlock);
227     if (isStepping())
228         codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
229 }
230
231 void Debugger::setProfilingClient(ProfilingClient* client)
232 {
233     ASSERT(!!m_profilingClient != !!client);
234     m_profilingClient = client;
235 }
236
237 double Debugger::willEvaluateScript()
238 {
239     return m_profilingClient->willEvaluateScript();
240 }
241
242 void Debugger::didEvaluateScript(double startTime, ProfilingReason reason)
243 {
244     m_profilingClient->didEvaluateScript(startTime, reason);
245 }
246
247 void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
248 {
249     ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
250
251     SourceID sourceID = static_cast<SourceID>(executable->sourceID());
252     if (breakpoint.sourceID != sourceID)
253         return;
254
255     unsigned line = breakpoint.line;
256     unsigned column = breakpoint.column;
257
258     unsigned startLine = executable->firstLine();
259     unsigned startColumn = executable->startColumn();
260     unsigned endLine = executable->lastLine();
261     unsigned endColumn = executable->endColumn();
262
263     // Inspector breakpoint line and column values are zero-based but the executable
264     // and CodeBlock line and column values are one-based.
265     line += 1;
266     column = column ? column + 1 : Breakpoint::unspecifiedColumn;
267
268     if (line < startLine || line > endLine)
269         return;
270     if (column != Breakpoint::unspecifiedColumn) {
271         if (line == startLine && column < startColumn)
272             return;
273         if (line == endLine && column > endColumn)
274             return;
275     }
276     if (!codeBlock->hasOpDebugForLineAndColumn(line, column))
277         return;
278
279     if (enabledOrNot == BreakpointEnabled)
280         codeBlock->addBreakpoint(1);
281     else
282         codeBlock->removeBreakpoint(1);
283 }
284
285 void Debugger::applyBreakpoints(CodeBlock* codeBlock)
286 {
287     BreakpointIDToBreakpointMap& breakpoints = m_breakpointIDToBreakpoint;
288     for (auto it = breakpoints.begin(); it != breakpoints.end(); ++it) {
289         Breakpoint& breakpoint = *it->value;
290         toggleBreakpoint(codeBlock, breakpoint, BreakpointEnabled);
291     }
292 }
293
294 class Debugger::ToggleBreakpointFunctor {
295 public:
296     ToggleBreakpointFunctor(Debugger* debugger, Breakpoint& breakpoint, BreakpointState enabledOrNot)
297         : m_debugger(debugger)
298         , m_breakpoint(breakpoint)
299         , m_enabledOrNot(enabledOrNot)
300     {
301     }
302
303     bool operator()(CodeBlock* codeBlock)
304     {
305         if (m_debugger == codeBlock->globalObject()->debugger())
306             m_debugger->toggleBreakpoint(codeBlock, m_breakpoint, m_enabledOrNot);
307         return false;
308     }
309
310 private:
311     Debugger* m_debugger;
312     Breakpoint& m_breakpoint;
313     BreakpointState m_enabledOrNot;
314 };
315
316 void Debugger::toggleBreakpoint(Breakpoint& breakpoint, Debugger::BreakpointState enabledOrNot)
317 {
318     m_vm.heap.completeAllDFGPlans();
319
320     ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
321     m_vm.heap.forEachCodeBlock(functor);
322 }
323
324 void Debugger::recompileAllJSFunctions()
325 {
326     m_vm.deleteAllCode();
327 }
328
329 BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine, unsigned& actualColumn)
330 {
331     SourceID sourceID = breakpoint.sourceID;
332     unsigned line = breakpoint.line;
333     unsigned column = breakpoint.column;
334
335     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
336     if (it == m_sourceIDToBreakpoints.end())
337         it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator;
338     LineToBreakpointsMap::iterator breaksIt = it->value.find(line);
339     if (breaksIt == it->value.end())
340         breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator;
341
342     BreakpointsList& breakpoints = *breaksIt->value;
343     for (Breakpoint* current = breakpoints.head(); current; current = current->next()) {
344         if (current->column == column) {
345             // The breakpoint already exists. We're not allowed to create a new
346             // breakpoint at this location. Rather than returning the breakpointID
347             // of the pre-existing breakpoint, we need to return noBreakpointID
348             // to indicate that we're not creating a new one.
349             return noBreakpointID;
350         }
351     }
352
353     BreakpointID id = ++m_topBreakpointID;
354     RELEASE_ASSERT(id != noBreakpointID);
355
356     breakpoint.id = id;
357     actualLine = line;
358     actualColumn = column;
359
360     Breakpoint* newBreakpoint = new Breakpoint(breakpoint);
361     breakpoints.append(newBreakpoint);
362     m_breakpointIDToBreakpoint.set(id, newBreakpoint);
363
364     toggleBreakpoint(breakpoint, BreakpointEnabled);
365
366     return id;
367 }
368
369 void Debugger::removeBreakpoint(BreakpointID id)
370 {
371     ASSERT(id != noBreakpointID);
372
373     BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id);
374     ASSERT(idIt != m_breakpointIDToBreakpoint.end());
375     Breakpoint* breakpoint = idIt->value;
376
377     SourceID sourceID = breakpoint->sourceID;
378     ASSERT(sourceID);
379     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
380     ASSERT(it != m_sourceIDToBreakpoints.end());
381     LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line);
382     ASSERT(breaksIt != it->value.end());
383
384     toggleBreakpoint(*breakpoint, BreakpointDisabled);
385
386     BreakpointsList& breakpoints = *breaksIt->value;
387 #if !ASSERT_DISABLED
388     bool found = false;
389     for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) {
390         if (current->id == breakpoint->id)
391             found = true;
392     }
393     ASSERT(found);
394 #endif
395
396     m_breakpointIDToBreakpoint.remove(idIt);
397     breakpoints.remove(breakpoint);
398     delete breakpoint;
399
400     if (breakpoints.isEmpty()) {
401         it->value.remove(breaksIt);
402         if (it->value.isEmpty())
403             m_sourceIDToBreakpoints.remove(it);
404     }
405 }
406
407 bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint)
408 {
409     if (!m_breakpointsActivated)
410         return false;
411
412     SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID);
413     if (it == m_sourceIDToBreakpoints.end())
414         return false;
415
416     unsigned line = position.m_line.zeroBasedInt();
417     unsigned column = position.m_column.zeroBasedInt();
418
419     LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line);
420     if (breaksIt == it->value.end())
421         return false;
422
423     bool hit = false;
424     const BreakpointsList& breakpoints = *breaksIt->value;
425     Breakpoint* breakpoint;
426     for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) {
427         unsigned breakLine = breakpoint->line;
428         unsigned breakColumn = breakpoint->column;
429         // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
430         ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger());
431         if ((line != m_lastExecutedLine && line == breakLine && !breakColumn)
432             || (line == breakLine && column == breakColumn)) {
433             hit = true;
434             break;
435         }
436     }
437     if (!hit)
438         return false;
439
440     if (hitBreakpoint)
441         *hitBreakpoint = *breakpoint;
442
443     breakpoint->hitCount++;
444     if (breakpoint->ignoreCount >= breakpoint->hitCount)
445         return false;
446
447     if (breakpoint->condition.isEmpty())
448         return true;
449
450     // We cannot stop in the debugger while executing condition code,
451     // so make it looks like the debugger is already paused.
452     TemporaryPausedState pausedState(*this);
453
454     NakedPtr<Exception> exception;
455     DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
456     JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception);
457
458     // We can lose the debugger while executing JavaScript.
459     if (!m_currentCallFrame)
460         return false;
461
462     if (exception) {
463         // An erroneous condition counts as "false".
464         handleExceptionInBreakpointCondition(m_currentCallFrame, exception);
465         return false;
466     }
467
468     return result.toBoolean(m_currentCallFrame);
469 }
470
471 class Debugger::ClearCodeBlockDebuggerRequestsFunctor {
472 public:
473     ClearCodeBlockDebuggerRequestsFunctor(Debugger* debugger)
474         : m_debugger(debugger)
475     {
476     }
477
478     bool operator()(CodeBlock* codeBlock)
479     {
480         if (codeBlock->hasDebuggerRequests() && m_debugger == codeBlock->globalObject()->debugger())
481             codeBlock->clearDebuggerRequests();
482         return false;
483     }
484
485 private:
486     Debugger* m_debugger;
487 };
488
489 void Debugger::clearBreakpoints()
490 {
491     m_vm.heap.completeAllDFGPlans();
492
493     m_topBreakpointID = noBreakpointID;
494     m_breakpointIDToBreakpoint.clear();
495     m_sourceIDToBreakpoints.clear();
496
497     ClearCodeBlockDebuggerRequestsFunctor functor(this);
498     m_vm.heap.forEachCodeBlock(functor);
499 }
500
501 class Debugger::ClearDebuggerRequestsFunctor {
502 public:
503     ClearDebuggerRequestsFunctor(JSGlobalObject* globalObject)
504         : m_globalObject(globalObject)
505     {
506     }
507
508     bool operator()(CodeBlock* codeBlock)
509     {
510         if (codeBlock->hasDebuggerRequests() && m_globalObject == codeBlock->globalObject())
511             codeBlock->clearDebuggerRequests();
512         return false;
513     }
514
515 private:
516     JSGlobalObject* m_globalObject;
517 };
518
519 void Debugger::clearDebuggerRequests(JSGlobalObject* globalObject)
520 {
521     m_vm.heap.completeAllDFGPlans();
522
523     ClearDebuggerRequestsFunctor functor(globalObject);
524     m_vm.heap.forEachCodeBlock(functor);
525 }
526
527 void Debugger::setBreakpointsActivated(bool activated)
528 {
529     if (activated == m_breakpointsActivated)
530         return;
531
532     m_breakpointsActivated = activated;
533     recompileAllJSFunctions();
534 }
535
536 void Debugger::setPauseOnExceptionsState(PauseOnExceptionsState pause)
537 {
538     m_pauseOnExceptionsState = pause;
539 }
540
541 void Debugger::setPauseOnNextStatement(bool pause)
542 {
543     m_pauseOnNextStatement = pause;
544     if (pause)
545         setSteppingMode(SteppingModeEnabled);
546 }
547
548 void Debugger::breakProgram()
549 {
550     if (m_isPaused)
551         return;
552
553     if (!m_vm.topCallFrame)
554         return;
555
556     m_pauseOnNextStatement = true;
557     setSteppingMode(SteppingModeEnabled);
558     m_currentCallFrame = m_vm.topCallFrame;
559     pauseIfNeeded(m_currentCallFrame);
560 }
561
562 void Debugger::continueProgram()
563 {
564     if (!m_isPaused)
565         return;
566
567     m_pauseOnNextStatement = false;
568     notifyDoneProcessingDebuggerEvents();
569 }
570
571 void Debugger::stepIntoStatement()
572 {
573     if (!m_isPaused)
574         return;
575
576     m_pauseOnNextStatement = true;
577     setSteppingMode(SteppingModeEnabled);
578     notifyDoneProcessingDebuggerEvents();
579 }
580
581 void Debugger::stepOverStatement()
582 {
583     if (!m_isPaused)
584         return;
585
586     m_pauseOnCallFrame = m_currentCallFrame;
587     notifyDoneProcessingDebuggerEvents();
588 }
589
590 void Debugger::stepOutOfFunction()
591 {
592     if (!m_isPaused)
593         return;
594
595     VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
596     m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topVMEntryFrame) : 0;
597     notifyDoneProcessingDebuggerEvents();
598 }
599
600 void Debugger::updateCallFrame(CallFrame* callFrame)
601 {
602     m_currentCallFrame = callFrame;
603     SourceID sourceID = DebuggerCallFrame::sourceIDForCallFrame(callFrame);
604     if (m_lastExecutedSourceID != sourceID) {
605         m_lastExecutedLine = UINT_MAX;
606         m_lastExecutedSourceID = sourceID;
607     }
608 }
609
610 void Debugger::updateCallFrameAndPauseIfNeeded(CallFrame* callFrame)
611 {
612     updateCallFrame(callFrame);
613     pauseIfNeeded(callFrame);
614     if (!isStepping())
615         m_currentCallFrame = 0;
616 }
617
618 void Debugger::pauseIfNeeded(CallFrame* callFrame)
619 {
620     if (m_isPaused)
621         return;
622
623     if (m_suppressAllPauses)
624         return;
625
626     JSGlobalObject* vmEntryGlobalObject = callFrame->vmEntryGlobalObject();
627     if (!needPauseHandling(vmEntryGlobalObject))
628         return;
629
630     Breakpoint breakpoint;
631     bool didHitBreakpoint = false;
632     bool pauseNow = m_pauseOnNextStatement;
633     pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
634
635     DebuggerPausedScope debuggerPausedScope(*this);
636
637     intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
638     TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame);
639     pauseNow |= didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint);
640     m_lastExecutedLine = position.m_line.zeroBasedInt();
641     if (!pauseNow)
642         return;
643
644     // Make sure we are not going to pause again on breakpoint actions by
645     // reseting the pause state before executing any breakpoint actions.
646     TemporaryPausedState pausedState(*this);
647     m_pauseOnCallFrame = 0;
648     m_pauseOnNextStatement = false;
649
650     if (didHitBreakpoint) {
651         handleBreakpointHit(vmEntryGlobalObject, breakpoint);
652         // Note that the actions can potentially stop the debugger, so we need to check that
653         // we still have a current call frame when we get back.
654         if (breakpoint.autoContinue || !m_currentCallFrame)
655             return;
656         m_pausingBreakpointID = breakpoint.id;
657     }
658
659     {
660         PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
661         handlePause(vmEntryGlobalObject, m_reasonForPause);
662         RELEASE_ASSERT(!callFrame->hadException());
663     }
664
665     m_pausingBreakpointID = noBreakpointID;
666
667     if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
668         setSteppingMode(SteppingModeDisabled);
669         m_currentCallFrame = nullptr;
670     }
671 }
672
673 void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
674 {
675     if (m_isPaused)
676         return;
677
678     PauseReasonDeclaration reason(*this, PausedForException);
679     if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
680         m_pauseOnNextStatement = true;
681         setSteppingMode(SteppingModeEnabled);
682     }
683
684     m_hasHandlerForExceptionCallback = true;
685     m_currentException = exception;
686     updateCallFrameAndPauseIfNeeded(callFrame);
687     m_currentException = JSValue();
688     m_hasHandlerForExceptionCallback = false;
689 }
690
691 void Debugger::atStatement(CallFrame* callFrame)
692 {
693     if (m_isPaused)
694         return;
695
696     PauseReasonDeclaration reason(*this, PausedAtStatement);
697     updateCallFrameAndPauseIfNeeded(callFrame);
698 }
699
700 void Debugger::callEvent(CallFrame* callFrame)
701 {
702     if (m_isPaused)
703         return;
704
705     PauseReasonDeclaration reason(*this, PausedAfterCall);
706     updateCallFrameAndPauseIfNeeded(callFrame);
707 }
708
709 void Debugger::returnEvent(CallFrame* callFrame)
710 {
711     if (m_isPaused)
712         return;
713
714     PauseReasonDeclaration reason(*this, PausedBeforeReturn);
715     updateCallFrameAndPauseIfNeeded(callFrame);
716
717     // detach may have been called during pauseIfNeeded
718     if (!m_currentCallFrame)
719         return;
720
721     // Treat stepping over a return statement like stepping out.
722     if (m_currentCallFrame == m_pauseOnCallFrame) {
723         VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
724         m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
725     }
726
727     VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
728     m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
729 }
730
731 void Debugger::willExecuteProgram(CallFrame* callFrame)
732 {
733     if (m_isPaused)
734         return;
735
736     PauseReasonDeclaration reason(*this, PausedAtStartOfProgram);
737     updateCallFrameAndPauseIfNeeded(callFrame);
738 }
739
740 void Debugger::didExecuteProgram(CallFrame* callFrame)
741 {
742     if (m_isPaused)
743         return;
744
745     PauseReasonDeclaration reason(*this, PausedAtEndOfProgram);
746     updateCallFrameAndPauseIfNeeded(callFrame);
747
748     // Treat stepping over the end of a program like stepping out.
749     if (!m_currentCallFrame)
750         return;
751     if (m_currentCallFrame == m_pauseOnCallFrame) {
752         VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
753         m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
754         if (!m_currentCallFrame)
755             return;
756     }
757     VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
758     m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
759 }
760
761 void Debugger::didReachBreakpoint(CallFrame* callFrame)
762 {
763     if (m_isPaused)
764         return;
765
766     PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
767     m_pauseOnNextStatement = true;
768     setSteppingMode(SteppingModeEnabled);
769     updateCallFrameAndPauseIfNeeded(callFrame);
770 }
771
772 DebuggerCallFrame* Debugger::currentDebuggerCallFrame() const
773 {
774     ASSERT(m_currentDebuggerCallFrame);
775     return m_currentDebuggerCallFrame.get();
776 }
777
778 } // namespace JSC