X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..refs/heads/master:/debugger/Debugger.h diff --git a/debugger/Debugger.h b/debugger/Debugger.h index ec5cf37..d70f3b7 100644 --- a/debugger/Debugger.h +++ b/debugger/Debugger.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2013, 2014 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 @@ -22,43 +22,200 @@ #ifndef Debugger_h #define Debugger_h +#include "Breakpoint.h" +#include "DebuggerCallFrame.h" +#include "DebuggerPrimitives.h" +#include "JSCJSValue.h" +#include #include +#include +#include namespace JSC { - class DebuggerCallFrame; - class ExecState; - class JSGlobalData; - class JSGlobalObject; - class JSValue; - class SourceProvider; - class UString; +class CodeBlock; +class Exception; +class ExecState; +class JSGlobalObject; +class SourceProvider; +class VM; - class Debugger { - public: - virtual ~Debugger(); +typedef ExecState CallFrame; + +class JS_EXPORT_PRIVATE Debugger { +public: + Debugger(bool isInWorkerThread = false); + virtual ~Debugger(); + + 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; } + + enum ReasonForDetach { + TerminatingDebuggingSession, + GlobalObjectIsDestructing + }; + void attach(JSGlobalObject*); + void detach(JSGlobalObject*, ReasonForDetach); + bool isAttached(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); + + enum ReasonForPause { + NotPaused, + PausedForException, + PausedAtStatement, + PausedAfterCall, + PausedBeforeReturn, + PausedAtStartOfProgram, + PausedAtEndOfProgram, + PausedForBreakpoint, + PausedForDebuggerStatement, + }; + ReasonForPause reasonForPause() const { return m_reasonForPause; } + BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; } + + void setPauseOnNextStatement(bool); + void breakProgram(); + void continueProgram(); + void stepIntoStatement(); + void stepOverStatement(); + void stepOutOfFunction(); + + bool isPaused() const { return m_isPaused; } + bool isStepping() const { return m_steppingMode == SteppingModeEnabled; } + + virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0; + + void exception(CallFrame*, JSValue exceptionValue, bool hasCatchHandler); + void atStatement(CallFrame*); + void callEvent(CallFrame*); + void returnEvent(CallFrame*); + void willExecuteProgram(CallFrame*); + void didExecuteProgram(CallFrame*); + void didReachBreakpoint(CallFrame*); + + void recompileAllJSFunctions(VM*); + + void registerCodeBlock(CodeBlock*); - void attach(JSGlobalObject*); - virtual void detach(JSGlobalObject*); +protected: + virtual bool needPauseHandling(JSGlobalObject*) { return false; } + virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { } + virtual void handleExceptionInBreakpointCondition(ExecState*, Exception*) const { } + virtual void handlePause(JSGlobalObject*, ReasonForPause) { } + virtual void notifyDoneProcessingDebuggerEvents() { } - virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const UString& errorMessage) = 0; - virtual void exception(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber, bool hasHandler) = 0; - virtual void atStatement(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; - virtual void callEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; - virtual void returnEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; +private: + typedef HashMap BreakpointIDToBreakpointMap; - virtual void willExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; - virtual void didExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; - virtual void didReachBreakpoint(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + typedef HashMap, WTF::IntHash, WTF::UnsignedWithZeroKeyHashTraits> LineToBreakpointsMap; + typedef HashMap, WTF::UnsignedWithZeroKeyHashTraits> SourceIDToBreakpointsMap; - void recompileAllJSFunctions(JSGlobalData*); + class ClearCodeBlockDebuggerRequestsFunctor; + class ClearDebuggerRequestsFunctor; + class SetSteppingModeFunctor; + class ToggleBreakpointFunctor; + class PauseReasonDeclaration { + public: + PauseReasonDeclaration(Debugger& debugger, ReasonForPause reason) + : m_debugger(debugger) + { + m_debugger.m_reasonForPause = reason; + } + + ~PauseReasonDeclaration() + { + m_debugger.m_reasonForPause = NotPaused; + } private: - HashSet m_globalObjects; + Debugger& m_debugger; + }; + + bool hasBreakpoint(SourceID, const TextPosition&, Breakpoint* hitBreakpoint); + + 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*); + + enum SteppingMode { + SteppingModeDisabled, + SteppingModeEnabled + }; + void setSteppingMode(SteppingMode); + + enum BreakpointState { + BreakpointDisabled, + BreakpointEnabled }; + void toggleBreakpoint(CodeBlock*, Breakpoint&, BreakpointState); + void applyBreakpoints(CodeBlock*); + void toggleBreakpoint(Breakpoint&, BreakpointState); + + void clearDebuggerRequests(JSGlobalObject*); + + template inline void forEachCodeBlock(Functor&); + + VM* m_vm; + 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; + unsigned m_steppingMode : 1; // SteppingMode + + ReasonForPause m_reasonForPause; + JSValue m_currentException; + CallFrame* m_pauseOnCallFrame; + CallFrame* m_currentCallFrame; + unsigned m_lastExecutedLine; + SourceID m_lastExecutedSourceID; + + BreakpointID m_topBreakpointID; + BreakpointID m_pausingBreakpointID; + BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint; + SourceIDToBreakpointsMap m_sourceIDToBreakpoints; + + RefPtr m_currentDebuggerCallFrame; - // This function exists only for backwards compatibility with existing WebScriptDebugger clients. - JSValue evaluateInGlobalCallFrame(const UString&, JSValue& exception, JSGlobalObject*); + friend class DebuggerPausedScope; + friend class TemporaryPausedState; + friend class LLIntOffsetsExtractor; +}; } // namespace JSC