9820215d153e9066a40b3dbfbf5789e4550af478
[WebKit-https.git] / Source / JavaScriptCore / debugger / Debugger.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved.
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 #ifndef Debugger_h
23 #define Debugger_h
24
25 #include "Breakpoint.h"
26 #include "DebuggerCallFrame.h"
27 #include "DebuggerPrimitives.h"
28 #include "JSCJSValue.h"
29 #include <wtf/HashMap.h>
30 #include <wtf/HashSet.h>
31 #include <wtf/RefPtr.h>
32 #include <wtf/text/TextPosition.h>
33
34 namespace JSC {
35
36 class CodeBlock;
37 class ExecState;
38 class JSGlobalObject;
39 class SourceProvider;
40 class VM;
41
42 typedef ExecState CallFrame;
43
44 class JS_EXPORT_PRIVATE Debugger {
45 public:
46     Debugger(bool isInWorkerThread = false);
47     virtual ~Debugger();
48
49     JSC::DebuggerCallFrame* currentDebuggerCallFrame() const;
50     bool hasHandlerForExceptionCallback() const
51     {
52         ASSERT(m_reasonForPause == PausedForException);
53         return m_hasHandlerForExceptionCallback;
54     }
55     JSValue currentException()
56     {
57         ASSERT(m_reasonForPause == PausedForException);
58         return m_currentException;
59     }
60
61     bool needsExceptionCallbacks() const { return m_pauseOnExceptionsState != DontPauseOnExceptions; }
62
63     void attach(JSGlobalObject*);
64     enum ReasonForDetach {
65         TerminatingDebuggingSession,
66         GlobalObjectIsDestructing
67     };
68     virtual void detach(JSGlobalObject*, ReasonForDetach);
69
70     BreakpointID setBreakpoint(Breakpoint, unsigned& actualLine, unsigned& actualColumn);
71     void removeBreakpoint(BreakpointID);
72     void clearBreakpoints();
73     void setBreakpointsActivated(bool);
74     void activateBreakpoints() { setBreakpointsActivated(true); }
75     void deactivateBreakpoints() { setBreakpointsActivated(false); }
76
77     enum PauseOnExceptionsState {
78         DontPauseOnExceptions,
79         PauseOnAllExceptions,
80         PauseOnUncaughtExceptions
81     };
82     PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; }
83     void setPauseOnExceptionsState(PauseOnExceptionsState);
84
85     void setPauseOnNextStatement(bool);
86     void breakProgram();
87     void continueProgram();
88     void stepIntoStatement();
89     void stepOverStatement();
90     void stepOutOfFunction();
91
92     bool isPaused() { return m_isPaused; }
93     bool isStepping() const { return m_steppingMode == SteppingModeEnabled; }
94
95     virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
96
97     void exception(CallFrame*, JSValue exceptionValue, bool hasHandler);
98     void atStatement(CallFrame*);
99     void callEvent(CallFrame*);
100     void returnEvent(CallFrame*);
101     void willExecuteProgram(CallFrame*);
102     void didExecuteProgram(CallFrame*);
103     void didReachBreakpoint(CallFrame*);
104
105     void recompileAllJSFunctions(VM*);
106
107     void registerCodeBlock(CodeBlock*);
108
109 protected:
110     virtual bool needPauseHandling(JSGlobalObject*) { return false; }
111     virtual void handleBreakpointHit(const Breakpoint&) { }
112     virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }
113
114     enum ReasonForPause {
115         NotPaused,
116         PausedForException,
117         PausedAtStatement,
118         PausedAfterCall,
119         PausedBeforeReturn,
120         PausedAtStartOfProgram,
121         PausedAtEndOfProgram,
122         PausedForBreakpoint
123     };
124
125     virtual void handlePause(ReasonForPause, JSGlobalObject*) { }
126     virtual void notifyDoneProcessingDebuggerEvents() { }
127
128 private:
129     typedef HashMap<BreakpointID, Breakpoint*> BreakpointIDToBreakpointMap;
130
131     typedef HashMap<unsigned, RefPtr<BreakpointsList>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> LineToBreakpointsMap;
132     typedef HashMap<SourceID, LineToBreakpointsMap, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> SourceIDToBreakpointsMap;
133
134     class ClearCodeBlockDebuggerRequestsFunctor;
135     class ClearDebuggerRequestsFunctor;
136     class SetSteppingModeFunctor;
137     class ToggleBreakpointFunctor;
138
139     class PauseReasonDeclaration {
140     public:
141         PauseReasonDeclaration(Debugger& debugger, ReasonForPause reason)
142             : m_debugger(debugger)
143         {
144             m_debugger.m_reasonForPause = reason;
145         }
146
147         ~PauseReasonDeclaration()
148         {
149             m_debugger.m_reasonForPause = NotPaused;
150         }
151     private:
152         Debugger& m_debugger;
153     };
154
155     bool hasBreakpoint(SourceID, const TextPosition&, Breakpoint* hitBreakpoint);
156
157     void updateNeedForOpDebugCallbacks();
158
159     // These update functions are only needed because our current breakpoints are
160     // key'ed off the source position instead of the bytecode PC. This ensures
161     // that we don't break on the same line more than once. Once we switch to a
162     // bytecode PC key'ed breakpoint, we will not need these anymore and should
163     // be able to remove them.
164     void updateCallFrame(JSC::CallFrame*);
165     void updateCallFrameAndPauseIfNeeded(JSC::CallFrame*);
166     void pauseIfNeeded(JSC::CallFrame*);
167
168     enum SteppingMode {
169         SteppingModeDisabled,
170         SteppingModeEnabled
171     };
172     void setSteppingMode(SteppingMode);
173
174     enum BreakpointState {
175         BreakpointDisabled,
176         BreakpointEnabled
177     };
178     void toggleBreakpoint(CodeBlock*, Breakpoint&, BreakpointState);
179     void applyBreakpoints(CodeBlock*);
180     void toggleBreakpoint(Breakpoint&, BreakpointState);
181
182     void clearDebuggerRequests(JSGlobalObject*);
183
184     template<typename Functor> inline void forEachCodeBlock(Functor&);
185
186     VM* m_vm;
187     HashSet<JSGlobalObject*> m_globalObjects;
188
189     PauseOnExceptionsState m_pauseOnExceptionsState;
190     bool m_pauseOnNextStatement : 1;
191     bool m_isPaused : 1;
192     bool m_breakpointsActivated : 1;
193     bool m_hasHandlerForExceptionCallback : 1;
194     bool m_isInWorkerThread : 1;
195     unsigned m_steppingMode : 1; // SteppingMode
196
197     ReasonForPause m_reasonForPause;
198     JSValue m_currentException;
199     CallFrame* m_pauseOnCallFrame;
200     CallFrame* m_currentCallFrame;
201     unsigned m_lastExecutedLine;
202     SourceID m_lastExecutedSourceID;
203
204     BreakpointID m_topBreakpointID;
205     BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
206     SourceIDToBreakpointsMap m_sourceIDToBreakpoints;
207
208     RefPtr<JSC::DebuggerCallFrame> m_currentDebuggerCallFrame;
209
210     friend class DebuggerPausedScope;
211     friend class TemporaryPausedState;
212     friend class LLIntOffsetsExtractor;
213 };
214
215 } // namespace JSC
216
217 #endif // Debugger_h