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