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