/*
* Copyright (C) 1999-2001 Harri Porten ([email protected])
* Copyright (C) 2001 Peter Kelly ([email protected])
* Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef Debugger_h
#define Debugger_h
#include "Breakpoint.h"
#include "DebuggerCallFrame.h"
#include "DebuggerPrimitives.h"
#include "JSCJSValue.h"
#include
#include
#include
#include
#include
namespace JSC {
class ExecState;
class JSGlobalObject;
class SourceProvider;
class VM;
typedef ExecState CallFrame;
#if ENABLE(JAVASCRIPT_DEBUGGER)
class JS_EXPORT_PRIVATE Debugger {
public:
Debugger(bool isInWorkerThread = false);
virtual ~Debugger();
bool needsOpDebugCallbacks() const { return m_needsOpDebugCallbacks; }
static ptrdiff_t needsOpDebugCallbacksOffset() { return OBJECT_OFFSETOF(Debugger, m_needsOpDebugCallbacks); }
JSC::DebuggerCallFrame* currentDebuggerCallFrame() const;
bool hasHandlerForExceptionCallback() const
{
ASSERT(m_reasonForPause == PausedForException);
return m_hasHandlerForExceptionCallback;
}
JSValue currentException()
{
ASSERT(m_reasonForPause == PausedForException);
return m_currentException;
}
bool needsExceptionCallbacks() const { return m_pauseOnExceptionsState != DontPauseOnExceptions; }
void attach(JSGlobalObject*);
virtual void detach(JSGlobalObject*);
BreakpointID setBreakpoint(Breakpoint, unsigned& actualLine, unsigned& actualColumn);
void removeBreakpoint(BreakpointID);
void clearBreakpoints();
void setBreakpointsActivated(bool);
void activateBreakpoints() { setBreakpointsActivated(true); }
void deactivateBreakpoints() { setBreakpointsActivated(false); }
enum PauseOnExceptionsState {
DontPauseOnExceptions,
PauseOnAllExceptions,
PauseOnUncaughtExceptions
};
PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; }
void setPauseOnExceptionsState(PauseOnExceptionsState);
void setPauseOnNextStatement(bool);
void breakProgram();
void continueProgram();
void stepIntoStatement();
void stepOverStatement();
void stepOutOfFunction();
bool isPaused() { return m_isPaused; }
virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
void exception(CallFrame*, JSValue exceptionValue, bool hasHandler);
void atStatement(CallFrame*);
void callEvent(CallFrame*);
void returnEvent(CallFrame*);
void willExecuteProgram(CallFrame*);
void didExecuteProgram(CallFrame*);
void didReachBreakpoint(CallFrame*);
void recompileAllJSFunctions(VM*);
protected:
virtual bool needPauseHandling(JSGlobalObject*) { return false; }
virtual void handleBreakpointHit(const Breakpoint&) { }
virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }
enum ReasonForPause {
NotPaused,
PausedForException,
PausedAtStatement,
PausedAfterCall,
PausedBeforeReturn,
PausedAtStartOfProgram,
PausedAtEndOfProgram,
PausedForBreakpoint
};
virtual void handlePause(ReasonForPause, JSGlobalObject*) { }
virtual void notifyDoneProcessingDebuggerEvents() { }
private:
typedef HashMap BreakpointIDToBreakpointMap;
typedef Vector BreakpointsInLine;
typedef HashMap, WTF::UnsignedWithZeroKeyHashTraits> LineToBreakpointsMap;
typedef HashMap SourceIDToBreakpointsMap;
class PauseReasonDeclaration {
public:
PauseReasonDeclaration(Debugger& debugger, ReasonForPause reason)
: m_debugger(debugger)
{
m_debugger.m_reasonForPause = reason;
}
~PauseReasonDeclaration()
{
m_debugger.m_reasonForPause = NotPaused;
}
private:
Debugger& m_debugger;
};
bool hasBreakpoint(SourceID, const TextPosition&, Breakpoint* hitBreakpoint);
bool shouldPause() const { return m_shouldPause; }
void setShouldPause(bool);
void updateNeedForOpDebugCallbacks();
// These update functions are only needed because our current breakpoints are
// key'ed off the source position instead of the bytecode PC. This ensures
// that we don't break on the same line more than once. Once we switch to a
// bytecode PC key'ed breakpoint, we will not need these anymore and should
// be able to remove them.
void updateCallFrame(JSC::CallFrame*);
void updateCallFrameAndPauseIfNeeded(JSC::CallFrame*);
void pauseIfNeeded(JSC::CallFrame*);
HashSet m_globalObjects;
PauseOnExceptionsState m_pauseOnExceptionsState;
bool m_pauseOnNextStatement : 1;
bool m_isPaused : 1;
bool m_breakpointsActivated : 1;
bool m_hasHandlerForExceptionCallback : 1;
bool m_isInWorkerThread : 1;
ReasonForPause m_reasonForPause;
JSValue m_currentException;
CallFrame* m_pauseOnCallFrame;
CallFrame* m_currentCallFrame;
unsigned m_lastExecutedLine;
SourceID m_lastExecutedSourceID;
BreakpointID m_topBreakpointID;
BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
SourceIDToBreakpointsMap m_sourceIDToBreakpoints;
bool m_needsOpDebugCallbacks;
bool m_shouldPause;
RefPtr<:debuggercallframe> m_currentDebuggerCallFrame;
friend class DebuggerCallFrameScope;
friend class TemporaryPausedState;
friend class LLIntOffsetsExtractor;
};
#else // ENABLE(JAVASCRIPT_DEBUGGER)
class Debugger {
public:
Debugger(bool = false) { }
bool needsOpDebugCallbacks() const { return false; }
bool needsExceptionCallbacks() const { return false; }
void detach(JSGlobalObject*) { }
void sourceParsed(ExecState*, SourceProvider*, int, const WTF::String&) { }
void exception(CallFrame*, JSValue, bool) { }
void atStatement(CallFrame*) { }
void callEvent(CallFrame*) { }
void returnEvent(CallFrame*) { }
void willExecuteProgram(CallFrame*) { }
void didExecuteProgram(CallFrame*) { }
void didReachBreakpoint(CallFrame*) { }
};
#endif // ENABLE(JAVASCRIPT_DEBUGGER)
} // namespace JSC
#endif // Debugger_h