Move vmEntryGlobalObject() to VM from CallFrame.
[WebKit-https.git] / Source / JavaScriptCore / debugger / Debugger.cpp
1 /*
2  *  Copyright (C) 2008-2017 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 "JSCInlines.h"
31 #include "JSCJSValueInlines.h"
32 #include "JSFunction.h"
33 #include "JSGlobalObject.h"
34 #include "MarkedSpaceInlines.h"
35 #include "Parser.h"
36 #include "Protect.h"
37 #include "VMEntryScope.h"
38
39 namespace {
40
41 using namespace JSC;
42
43 struct GatherSourceProviders : public MarkedBlock::VoidFunctor {
44     // FIXME: This is a mutable field because this isn't a C++ lambda.
45     // https://bugs.webkit.org/show_bug.cgi?id=159644
46     mutable HashSet<SourceProvider*> sourceProviders;
47     JSGlobalObject* m_globalObject;
48
49     GatherSourceProviders(JSGlobalObject* globalObject)
50         : m_globalObject(globalObject) { }
51
52     IterationStatus operator()(HeapCell* heapCell, HeapCell::Kind kind) const
53     {
54         if (!isJSCellKind(kind))
55             return IterationStatus::Continue;
56         
57         JSCell* cell = static_cast<JSCell*>(heapCell);
58         
59         JSFunction* function = jsDynamicCast<JSFunction*>(*cell->vm(), cell);
60         if (!function)
61             return IterationStatus::Continue;
62
63         if (function->scope()->globalObject() != m_globalObject)
64             return IterationStatus::Continue;
65
66         if (!function->executable()->isFunctionExecutable())
67             return IterationStatus::Continue;
68
69         if (function->isHostOrBuiltinFunction())
70             return IterationStatus::Continue;
71
72         sourceProviders.add(
73             jsCast<FunctionExecutable*>(function->executable())->source().provider());
74         return IterationStatus::Continue;
75     }
76 };
77
78 } // namespace
79
80 namespace JSC {
81
82 class DebuggerPausedScope {
83 public:
84     DebuggerPausedScope(Debugger& debugger)
85         : m_debugger(debugger)
86     {
87         ASSERT(!m_debugger.m_currentDebuggerCallFrame);
88     }
89
90     ~DebuggerPausedScope()
91     {
92         if (m_debugger.m_currentDebuggerCallFrame) {
93             m_debugger.m_currentDebuggerCallFrame->invalidate();
94             m_debugger.m_currentDebuggerCallFrame = nullptr;
95         }
96     }
97
98 private:
99     Debugger& m_debugger;
100 };
101
102 // This is very similar to SetForScope<bool>, but that cannot be used
103 // as the m_isPaused field uses only one bit.
104 class TemporaryPausedState {
105 public:
106     TemporaryPausedState(Debugger& debugger)
107         : m_debugger(debugger)
108     {
109         ASSERT(!m_debugger.m_isPaused);
110         m_debugger.m_isPaused = true;
111     }
112
113     ~TemporaryPausedState()
114     {
115         m_debugger.m_isPaused = false;
116     }
117
118 private:
119     Debugger& m_debugger;
120 };
121
122
123 Debugger::ProfilingClient::~ProfilingClient()
124 {
125 }
126
127 Debugger::Debugger(VM& vm)
128     : m_vm(vm)
129     , m_pauseOnExceptionsState(DontPauseOnExceptions)
130     , m_pauseAtNextOpportunity(false)
131     , m_pastFirstExpressionInStatement(false)
132     , m_isPaused(false)
133     , m_breakpointsActivated(false)
134     , m_hasHandlerForExceptionCallback(false)
135     , m_suppressAllPauses(false)
136     , m_steppingMode(SteppingModeDisabled)
137     , m_reasonForPause(NotPaused)
138     , m_lastExecutedLine(UINT_MAX)
139     , m_lastExecutedSourceID(noSourceID)
140     , m_topBreakpointID(noBreakpointID)
141     , m_pausingBreakpointID(noBreakpointID)
142 {
143 }
144
145 Debugger::~Debugger()
146 {
147     HashSet<JSGlobalObject*>::iterator end = m_globalObjects.end();
148     for (HashSet<JSGlobalObject*>::iterator it = m_globalObjects.begin(); it != end; ++it)
149         (*it)->setDebugger(nullptr);
150 }
151
152 void Debugger::attach(JSGlobalObject* globalObject)
153 {
154     ASSERT(!globalObject->debugger());
155     globalObject->setDebugger(this);
156     m_globalObjects.add(globalObject);
157
158     m_vm.setShouldBuildPCToCodeOriginMapping();
159
160     // Call sourceParsed because it will execute JavaScript in the inspector.
161     GatherSourceProviders gatherSourceProviders(globalObject);
162     {
163         HeapIterationScope iterationScope(m_vm.heap);
164         m_vm.heap.objectSpace().forEachLiveCell(iterationScope, gatherSourceProviders);
165     }
166     for (auto* sourceProvider : gatherSourceProviders.sourceProviders)
167         sourceParsed(globalObject->globalExec(), sourceProvider, -1, String());
168 }
169
170 void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason)
171 {
172     // If we're detaching from the currently executing global object, manually tear down our
173     // stack, since we won't get further debugger callbacks to do so. Also, resume execution,
174     // since there's no point in staying paused once a window closes.
175     // We know there is an entry scope, otherwise, m_currentCallFrame would be null.
176     VM& vm = globalObject->vm();
177     if (m_isPaused && m_currentCallFrame && vm.entryScope->globalObject() == globalObject) {
178         m_currentCallFrame = nullptr;
179         m_pauseOnCallFrame = nullptr;
180         continueProgram();
181     }
182
183     ASSERT(m_globalObjects.contains(globalObject));
184     m_globalObjects.remove(globalObject);
185
186     // If the globalObject is destructing, then its CodeBlocks will also be
187     // destructed. There is no need to do the debugger requests clean up, and
188     // it is not safe to access those CodeBlocks at this time anyway.
189     if (reason != GlobalObjectIsDestructing)
190         clearDebuggerRequests(globalObject);
191
192     globalObject->setDebugger(nullptr);
193
194     if (m_globalObjects.isEmpty())
195         clearParsedData();
196 }
197
198 bool Debugger::isAttached(JSGlobalObject* globalObject)
199 {
200     return globalObject->debugger() == this;
201 }
202
203 class Debugger::SetSteppingModeFunctor {
204 public:
205     SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode)
206         : m_debugger(debugger)
207         , m_mode(mode)
208     {
209     }
210
211     void operator()(CodeBlock* codeBlock) const
212     {
213         if (m_debugger == codeBlock->globalObject()->debugger()) {
214             if (m_mode == SteppingModeEnabled)
215                 codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
216             else
217                 codeBlock->setSteppingMode(CodeBlock::SteppingModeDisabled);
218         }
219     }
220
221 private:
222     Debugger* m_debugger;
223     SteppingMode m_mode;
224 };
225
226 void Debugger::setSteppingMode(SteppingMode mode)
227 {
228     if (mode == m_steppingMode)
229         return;
230
231     m_vm.heap.completeAllJITPlans();
232
233     m_steppingMode = mode;
234     SetSteppingModeFunctor functor(this, mode);
235     m_vm.heap.forEachCodeBlock(functor);
236 }
237
238 void Debugger::registerCodeBlock(CodeBlock* codeBlock)
239 {
240     applyBreakpoints(codeBlock);
241     if (isStepping())
242         codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
243 }
244
245 void Debugger::setProfilingClient(ProfilingClient* client)
246 {
247     ASSERT(!!m_profilingClient != !!client);
248     m_profilingClient = client;
249 }
250
251 Seconds Debugger::willEvaluateScript()
252 {
253     return m_profilingClient->willEvaluateScript();
254 }
255
256 void Debugger::didEvaluateScript(Seconds startTime, ProfilingReason reason)
257 {
258     m_profilingClient->didEvaluateScript(startTime, reason);
259 }
260
261 void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
262 {
263     ASSERT(breakpoint.resolved);
264
265     ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
266
267     SourceID sourceID = static_cast<SourceID>(executable->sourceID());
268     if (breakpoint.sourceID != sourceID)
269         return;
270
271     unsigned line = breakpoint.line;
272     unsigned column = breakpoint.column;
273
274     unsigned startLine = executable->firstLine();
275     unsigned startColumn = executable->startColumn();
276     unsigned endLine = executable->lastLine();
277     unsigned endColumn = executable->endColumn();
278
279     // Inspector breakpoint line and column values are zero-based but the executable
280     // and CodeBlock line and column values are one-based.
281     line += 1;
282     column = column ? column + 1 : Breakpoint::unspecifiedColumn;
283
284     if (line < startLine || line > endLine)
285         return;
286     if (column != Breakpoint::unspecifiedColumn) {
287         if (line == startLine && column < startColumn)
288             return;
289         if (line == endLine && column > endColumn)
290             return;
291     }
292
293     if (!codeBlock->hasOpDebugForLineAndColumn(line, column))
294         return;
295
296     if (enabledOrNot == BreakpointEnabled)
297         codeBlock->addBreakpoint(1);
298     else
299         codeBlock->removeBreakpoint(1);
300 }
301
302 void Debugger::applyBreakpoints(CodeBlock* codeBlock)
303 {
304     BreakpointIDToBreakpointMap& breakpoints = m_breakpointIDToBreakpoint;
305     for (auto* breakpoint : breakpoints.values())
306         toggleBreakpoint(codeBlock, *breakpoint, BreakpointEnabled);
307 }
308
309 class Debugger::ToggleBreakpointFunctor {
310 public:
311     ToggleBreakpointFunctor(Debugger* debugger, Breakpoint& breakpoint, BreakpointState enabledOrNot)
312         : m_debugger(debugger)
313         , m_breakpoint(breakpoint)
314         , m_enabledOrNot(enabledOrNot)
315     {
316     }
317
318     void operator()(CodeBlock* codeBlock) const
319     {
320         if (m_debugger == codeBlock->globalObject()->debugger())
321             m_debugger->toggleBreakpoint(codeBlock, m_breakpoint, m_enabledOrNot);
322     }
323
324 private:
325     Debugger* m_debugger;
326     Breakpoint& m_breakpoint;
327     BreakpointState m_enabledOrNot;
328 };
329
330 void Debugger::toggleBreakpoint(Breakpoint& breakpoint, Debugger::BreakpointState enabledOrNot)
331 {
332     m_vm.heap.completeAllJITPlans();
333
334     ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
335     m_vm.heap.forEachCodeBlock(functor);
336 }
337
338 void Debugger::recompileAllJSFunctions()
339 {
340     m_vm.deleteAllCode(PreventCollectionAndDeleteAllCode);
341 }
342
343 DebuggerParseData& Debugger::debuggerParseData(SourceID sourceID, SourceProvider* provider)
344 {
345     auto iter = m_parseDataMap.find(sourceID);
346     if (iter != m_parseDataMap.end())
347         return iter->value;
348
349     DebuggerParseData parseData;
350     gatherDebuggerParseDataForSource(m_vm, provider, parseData);
351     auto result = m_parseDataMap.add(sourceID, parseData);
352     return result.iterator->value;
353 }
354
355 void Debugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceProvider)
356 {
357     RELEASE_ASSERT(!breakpoint.resolved);
358     ASSERT(breakpoint.sourceID != noSourceID);
359
360     // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity
361     // Inspector breakpoint line and column values are zero-based but the executable
362     // and CodeBlock line and column values are one-based.
363     unsigned line = breakpoint.line + 1;
364     unsigned column = breakpoint.column ? breakpoint.column : Breakpoint::unspecifiedColumn;
365
366     DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID, sourceProvider);
367     std::optional<JSTextPosition> resolvedPosition = parseData.pausePositions.breakpointLocationForLineColumn((int)line, (int)column);
368     if (!resolvedPosition)
369         return;
370
371     unsigned resolvedLine = resolvedPosition->line;
372     unsigned resolvedColumn = resolvedPosition->offset - resolvedPosition->lineStartOffset + 1;
373
374     breakpoint.line = resolvedLine - 1;
375     breakpoint.column = resolvedColumn - 1;
376     breakpoint.resolved = true;
377 }
378
379 BreakpointID Debugger::setBreakpoint(Breakpoint& breakpoint, bool& existing)
380 {
381     ASSERT(breakpoint.resolved);
382     ASSERT(breakpoint.sourceID != noSourceID);
383
384     SourceID sourceID = breakpoint.sourceID;
385     unsigned line = breakpoint.line;
386     unsigned column = breakpoint.column;
387
388     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(breakpoint.sourceID);
389     if (it == m_sourceIDToBreakpoints.end())
390         it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator;
391
392     LineToBreakpointsMap::iterator breaksIt = it->value.find(line);
393     if (breaksIt == it->value.end())
394         breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator;
395
396     BreakpointsList& breakpoints = *breaksIt->value;
397     for (Breakpoint* current = breakpoints.head(); current; current = current->next()) {
398         if (current->column == column) {
399             // Found existing breakpoint. Do not create a duplicate at this location.
400             existing = true;
401             return current->id;
402         }
403     }
404
405     existing = false;
406     BreakpointID id = ++m_topBreakpointID;
407     RELEASE_ASSERT(id != noBreakpointID);
408
409     breakpoint.id = id;
410
411     Breakpoint* newBreakpoint = new Breakpoint(breakpoint);
412     breakpoints.append(newBreakpoint);
413     m_breakpointIDToBreakpoint.set(id, newBreakpoint);
414
415     toggleBreakpoint(*newBreakpoint, BreakpointEnabled);
416
417     return id;
418 }
419
420 void Debugger::removeBreakpoint(BreakpointID id)
421 {
422     ASSERT(id != noBreakpointID);
423
424     BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id);
425     ASSERT(idIt != m_breakpointIDToBreakpoint.end());
426     Breakpoint* breakpoint = idIt->value;
427
428     SourceID sourceID = breakpoint->sourceID;
429     ASSERT(sourceID);
430     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
431     ASSERT(it != m_sourceIDToBreakpoints.end());
432     LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line);
433     ASSERT(breaksIt != it->value.end());
434
435     toggleBreakpoint(*breakpoint, BreakpointDisabled);
436
437     BreakpointsList& breakpoints = *breaksIt->value;
438 #if !ASSERT_DISABLED
439     bool found = false;
440     for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) {
441         if (current->id == breakpoint->id)
442             found = true;
443     }
444     ASSERT(found);
445 #endif
446
447     m_breakpointIDToBreakpoint.remove(idIt);
448     breakpoints.remove(breakpoint);
449     delete breakpoint;
450
451     if (breakpoints.isEmpty()) {
452         it->value.remove(breaksIt);
453         if (it->value.isEmpty())
454             m_sourceIDToBreakpoints.remove(it);
455     }
456 }
457
458 bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint)
459 {
460     if (!m_breakpointsActivated)
461         return false;
462
463     SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID);
464     if (it == m_sourceIDToBreakpoints.end())
465         return false;
466
467     unsigned line = position.m_line.zeroBasedInt();
468     unsigned column = position.m_column.zeroBasedInt();
469     
470     LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line);
471     if (breaksIt == it->value.end())
472         return false;
473
474     bool hit = false;
475     const BreakpointsList& breakpoints = *breaksIt->value;
476     Breakpoint* breakpoint;
477     for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) {
478         unsigned breakLine = breakpoint->line;
479         unsigned breakColumn = breakpoint->column;
480         // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
481         ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger());
482         if ((line != m_lastExecutedLine && line == breakLine && !breakColumn)
483             || (line == breakLine && column == breakColumn)) {
484             hit = true;
485             break;
486         }
487     }
488     if (!hit)
489         return false;
490
491     if (hitBreakpoint)
492         *hitBreakpoint = *breakpoint;
493
494     breakpoint->hitCount++;
495     if (breakpoint->ignoreCount >= breakpoint->hitCount)
496         return false;
497
498     if (breakpoint->condition.isEmpty())
499         return true;
500
501     // We cannot stop in the debugger while executing condition code,
502     // so make it looks like the debugger is already paused.
503     TemporaryPausedState pausedState(*this);
504
505     NakedPtr<Exception> exception;
506     DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame();
507     JSObject* scopeExtensionObject = nullptr;
508     JSValue result = debuggerCallFrame.evaluateWithScopeExtension(breakpoint->condition, scopeExtensionObject, exception);
509
510     // We can lose the debugger while executing JavaScript.
511     if (!m_currentCallFrame)
512         return false;
513
514     if (exception) {
515         // An erroneous condition counts as "false".
516         handleExceptionInBreakpointCondition(m_currentCallFrame, exception);
517         return false;
518     }
519
520     return result.toBoolean(m_currentCallFrame);
521 }
522
523 class Debugger::ClearCodeBlockDebuggerRequestsFunctor {
524 public:
525     ClearCodeBlockDebuggerRequestsFunctor(Debugger* debugger)
526         : m_debugger(debugger)
527     {
528     }
529
530     void operator()(CodeBlock* codeBlock) const
531     {
532         if (codeBlock->hasDebuggerRequests() && m_debugger == codeBlock->globalObject()->debugger())
533             codeBlock->clearDebuggerRequests();
534     }
535
536 private:
537     Debugger* m_debugger;
538 };
539
540 void Debugger::clearBreakpoints()
541 {
542     m_vm.heap.completeAllJITPlans();
543
544     m_topBreakpointID = noBreakpointID;
545     m_breakpointIDToBreakpoint.clear();
546     m_sourceIDToBreakpoints.clear();
547
548     ClearCodeBlockDebuggerRequestsFunctor functor(this);
549     m_vm.heap.forEachCodeBlock(functor);
550 }
551
552 class Debugger::ClearDebuggerRequestsFunctor {
553 public:
554     ClearDebuggerRequestsFunctor(JSGlobalObject* globalObject)
555         : m_globalObject(globalObject)
556     {
557     }
558
559     void operator()(CodeBlock* codeBlock) const
560     {
561         if (codeBlock->hasDebuggerRequests() && m_globalObject == codeBlock->globalObject())
562             codeBlock->clearDebuggerRequests();
563     }
564
565 private:
566     JSGlobalObject* m_globalObject;
567 };
568
569 void Debugger::clearDebuggerRequests(JSGlobalObject* globalObject)
570 {
571     m_vm.heap.completeAllJITPlans();
572
573     ClearDebuggerRequestsFunctor functor(globalObject);
574     m_vm.heap.forEachCodeBlock(functor);
575 }
576
577 void Debugger::clearParsedData()
578 {
579     m_parseDataMap.clear();
580 }
581
582 void Debugger::setBreakpointsActivated(bool activated)
583 {
584     if (activated == m_breakpointsActivated)
585         return;
586
587     m_breakpointsActivated = activated;
588     recompileAllJSFunctions();
589 }
590
591 void Debugger::setPauseOnExceptionsState(PauseOnExceptionsState pause)
592 {
593     m_pauseOnExceptionsState = pause;
594 }
595
596 void Debugger::setPauseOnNextStatement(bool pause)
597 {
598     m_pauseAtNextOpportunity = pause;
599     if (pause)
600         setSteppingMode(SteppingModeEnabled);
601 }
602
603 void Debugger::breakProgram()
604 {
605     if (m_isPaused)
606         return;
607
608     if (!m_vm.topCallFrame)
609         return;
610
611     m_pauseAtNextOpportunity = true;
612     setSteppingMode(SteppingModeEnabled);
613     m_currentCallFrame = m_vm.topCallFrame;
614     pauseIfNeeded(m_currentCallFrame);
615 }
616
617 void Debugger::continueProgram()
618 {
619     clearNextPauseState();
620
621     if (!m_isPaused)
622         return;
623
624     notifyDoneProcessingDebuggerEvents();
625 }
626
627 void Debugger::stepIntoStatement()
628 {
629     if (!m_isPaused)
630         return;
631
632     m_pauseAtNextOpportunity = true;
633     setSteppingMode(SteppingModeEnabled);
634     notifyDoneProcessingDebuggerEvents();
635 }
636
637 void Debugger::stepOverStatement()
638 {
639     if (!m_isPaused)
640         return;
641
642     m_pauseOnCallFrame = m_currentCallFrame;
643     setSteppingMode(SteppingModeEnabled);
644     notifyDoneProcessingDebuggerEvents();
645 }
646
647 void Debugger::stepOutOfFunction()
648 {
649     if (!m_isPaused)
650         return;
651
652     EntryFrame* topEntryFrame = m_vm.topEntryFrame;
653     m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topEntryFrame) : nullptr;
654     m_pauseOnStepOut = true;
655     setSteppingMode(SteppingModeEnabled);
656     notifyDoneProcessingDebuggerEvents();
657 }
658
659 void Debugger::updateCallFrame(CallFrame* callFrame, CallFrameUpdateAction action)
660 {
661     if (!callFrame) {
662         m_currentCallFrame = nullptr;
663         return;
664     }
665
666     updateCallFrameInternal(callFrame);
667
668     if (action == AttemptPause)
669         pauseIfNeeded(callFrame);
670
671     if (!isStepping())
672         m_currentCallFrame = nullptr;
673 }
674
675 void Debugger::updateCallFrameInternal(CallFrame* callFrame)
676 {
677     m_currentCallFrame = callFrame;
678     SourceID sourceID = DebuggerCallFrame::sourceIDForCallFrame(callFrame);
679     if (m_lastExecutedSourceID != sourceID) {
680         m_lastExecutedLine = UINT_MAX;
681         m_lastExecutedSourceID = sourceID;
682     }
683 }
684
685 void Debugger::pauseIfNeeded(CallFrame* callFrame)
686 {
687     VM& vm = m_vm;
688     auto scope = DECLARE_THROW_SCOPE(vm);
689
690     if (m_isPaused)
691         return;
692
693     if (m_suppressAllPauses)
694         return;
695
696     intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
697     if (isBlacklisted(sourceID))
698         return;
699
700     DebuggerPausedScope debuggerPausedScope(*this);
701
702     bool pauseNow = m_pauseAtNextOpportunity;
703     pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
704
705     bool didPauseForStep = pauseNow;
706
707     Breakpoint breakpoint;
708     TextPosition position = DebuggerCallFrame::positionForCallFrame(vm, m_currentCallFrame);
709     bool didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint);
710     pauseNow |= didHitBreakpoint;
711     m_lastExecutedLine = position.m_line.zeroBasedInt();
712     if (!pauseNow)
713         return;
714
715     clearNextPauseState();
716
717     // Make sure we are not going to pause again on breakpoint actions by
718     // reseting the pause state before executing any breakpoint actions.
719     TemporaryPausedState pausedState(*this);
720
721     JSGlobalObject* vmEntryGlobalObject = vm.vmEntryGlobalObject(callFrame);
722
723     if (didHitBreakpoint) {
724         handleBreakpointHit(vmEntryGlobalObject, breakpoint);
725         // Note that the actions can potentially stop the debugger, so we need to check that
726         // we still have a current call frame when we get back.
727         if (!m_currentCallFrame)
728             return;
729
730         if (breakpoint.autoContinue) {
731             if (!didPauseForStep)
732                 return;
733             didHitBreakpoint = false;
734         } else
735             m_pausingBreakpointID = breakpoint.id;
736     }
737
738     {
739         PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
740         handlePause(vmEntryGlobalObject, m_reasonForPause);
741         scope.releaseAssertNoException();
742     }
743
744     m_pausingBreakpointID = noBreakpointID;
745
746     if (!m_pauseAtNextOpportunity && !m_pauseOnCallFrame) {
747         setSteppingMode(SteppingModeDisabled);
748         m_currentCallFrame = nullptr;
749     }
750 }
751
752 void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
753 {
754     if (m_isPaused)
755         return;
756
757     if (JSObject* object = jsDynamicCast<JSObject*>(m_vm, exception)) {
758         if (object->isErrorInstance()) {
759             ErrorInstance* error = static_cast<ErrorInstance*>(object);
760             // FIXME: <https://webkit.org/b/173625> Web Inspector: Should be able to pause and debug a StackOverflow Exception
761             // FIXME: <https://webkit.org/b/173627> Web Inspector: Should be able to pause and debug an OutOfMemory Exception
762             if (error->isStackOverflowError() || error->isOutOfMemoryError())
763                 return;
764         }
765     }
766
767     PauseReasonDeclaration reason(*this, PausedForException);
768     if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
769         m_pauseAtNextOpportunity = true;
770         setSteppingMode(SteppingModeEnabled);
771     }
772
773     m_hasHandlerForExceptionCallback = true;
774     m_currentException = exception;
775     updateCallFrame(callFrame, AttemptPause);
776     m_currentException = JSValue();
777     m_hasHandlerForExceptionCallback = false;
778 }
779
780 void Debugger::atStatement(CallFrame* callFrame)
781 {
782     if (m_isPaused)
783         return;
784
785     m_pastFirstExpressionInStatement = false;
786
787     PauseReasonDeclaration reason(*this, PausedAtStatement);
788     updateCallFrame(callFrame, AttemptPause);
789 }
790
791 void Debugger::atExpression(CallFrame* callFrame)
792 {
793     if (m_isPaused)
794         return;
795
796     // If this is the first call in a statement, then we would have paused at the statement.
797     if (!m_pastFirstExpressionInStatement) {
798         m_pastFirstExpressionInStatement = true;
799         return;
800     }
801
802     // Only pause at the next expression with step-in and step-out, not step-over.
803     bool shouldAttemptPause = m_pauseAtNextOpportunity || m_pauseOnStepOut;
804
805     PauseReasonDeclaration reason(*this, PausedAtExpression);
806     updateCallFrame(callFrame, shouldAttemptPause ? AttemptPause : NoPause);
807 }
808
809 void Debugger::callEvent(CallFrame* callFrame)
810 {
811     if (m_isPaused)
812         return;
813
814     updateCallFrame(callFrame, NoPause);
815 }
816
817 void Debugger::returnEvent(CallFrame* callFrame)
818 {
819     if (m_isPaused)
820         return;
821
822     {
823         PauseReasonDeclaration reason(*this, PausedBeforeReturn);
824         updateCallFrame(callFrame, AttemptPause);
825     }
826
827     // Detach may have been called during pauseIfNeeded.
828     if (!m_currentCallFrame)
829         return;
830
831     EntryFrame* topEntryFrame = m_vm.topEntryFrame;
832     CallFrame* callerFrame = m_currentCallFrame->callerFrame(topEntryFrame);
833
834     // Returning from a call, there was at least one expression on the statement we are returning to.
835     m_pastFirstExpressionInStatement = true;
836
837     // Treat stepping over a return statement like a step-out.
838     if (m_currentCallFrame == m_pauseOnCallFrame) {
839         m_pauseOnCallFrame = callerFrame;
840         m_pauseOnStepOut = true;
841     }
842
843     updateCallFrame(callerFrame, NoPause);
844 }
845
846 void Debugger::unwindEvent(CallFrame* callFrame)
847 {
848     if (m_isPaused)
849         return;
850
851     updateCallFrame(callFrame, NoPause);
852
853     if (!m_currentCallFrame)
854         return;
855
856     EntryFrame* topEntryFrame = m_vm.topEntryFrame;
857     CallFrame* callerFrame = m_currentCallFrame->callerFrame(topEntryFrame);
858
859     // Treat stepping over an exception location like a step-out.
860     if (m_currentCallFrame == m_pauseOnCallFrame)
861         m_pauseOnCallFrame = callerFrame;
862
863     updateCallFrame(callerFrame, NoPause);
864 }
865
866 void Debugger::willExecuteProgram(CallFrame* callFrame)
867 {
868     if (m_isPaused)
869         return;
870
871     updateCallFrame(callFrame, NoPause);
872 }
873
874 void Debugger::didExecuteProgram(CallFrame* callFrame)
875 {
876     if (m_isPaused)
877         return;
878
879     PauseReasonDeclaration reason(*this, PausedAtEndOfProgram);
880     updateCallFrame(callFrame, AttemptPause);
881
882     // Detach may have been called during pauseIfNeeded.
883     if (!m_currentCallFrame)
884         return;
885
886     EntryFrame* topEntryFrame = m_vm.topEntryFrame;
887     CallFrame* callerFrame = m_currentCallFrame->callerFrame(topEntryFrame);
888
889     // Returning from a program, could be eval(), there was at least one expression on the statement we are returning to.
890     m_pastFirstExpressionInStatement = true;
891
892     // Treat stepping over the end of a program like a step-out.
893     if (m_currentCallFrame == m_pauseOnCallFrame) {
894         m_pauseOnCallFrame = callerFrame;
895         m_pauseAtNextOpportunity = true;
896     }
897
898     updateCallFrame(callerFrame, NoPause);
899
900     // Do not continue stepping into an unknown future program.
901     if (!m_currentCallFrame)
902         clearNextPauseState();
903 }
904
905 void Debugger::clearNextPauseState()
906 {
907     m_pauseOnCallFrame = nullptr;
908     m_pauseAtNextOpportunity = false;
909     m_pauseOnStepOut = false;
910 }
911
912 void Debugger::didReachBreakpoint(CallFrame* callFrame)
913 {
914     if (m_isPaused)
915         return;
916
917     PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
918     m_pauseAtNextOpportunity = true;
919     setSteppingMode(SteppingModeEnabled);
920     updateCallFrame(callFrame, AttemptPause);
921 }
922
923 DebuggerCallFrame& Debugger::currentDebuggerCallFrame()
924 {
925     if (!m_currentDebuggerCallFrame)
926         m_currentDebuggerCallFrame = DebuggerCallFrame::create(m_vm, m_currentCallFrame);
927     return *m_currentDebuggerCallFrame;
928 }
929
930 bool Debugger::isBlacklisted(SourceID sourceID) const
931 {
932     return m_blacklistedScripts.contains(sourceID);
933 }
934
935 void Debugger::addToBlacklist(SourceID sourceID)
936 {
937     m_blacklistedScripts.add(sourceID);
938 }
939
940 void Debugger::clearBlacklist()
941 {
942     m_blacklistedScripts.clear();
943 }
944
945 } // namespace JSC