#include "CodeBlock.h"
#include "DebuggerCallFrame.h"
#include "Error.h"
-
#include "HeapIterationScope.h"
#include "Interpreter.h"
#include "JSCJSValueInlines.h"
public:
Recompiler(JSC::Debugger*);
~Recompiler();
- void operator()(JSCell*);
+ IterationStatus operator()(JSCell*);
private:
typedef HashSet<FunctionExecutable*> FunctionExecutableSet;
typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap;
+ void visit(JSCell*);
+
JSC::Debugger* m_debugger;
FunctionExecutableSet m_functionExecutables;
SourceProviderMap m_sourceProviders;
m_debugger->sourceParsed(iter->value, iter->key, -1, String());
}
-inline void Recompiler::operator()(JSCell* cell)
+inline void Recompiler::visit(JSCell* cell)
{
if (!cell->inherits(JSFunction::info()))
return;
return;
ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec();
- executable->clearCodeIfNotCompiling();
- executable->clearUnlinkedCodeForRecompilationIfNotCompiling();
+ executable->clearCode();
+ executable->clearUnlinkedCodeForRecompilation();
if (m_debugger == function->scope()->globalObject()->debugger())
m_sourceProviders.add(executable->source().provider(), exec);
}
+inline IterationStatus Recompiler::operator()(JSCell* cell)
+{
+ visit(cell);
+ return IterationStatus::Continue;
+}
+
} // namespace
namespace JSC {
-class DebuggerCallFrameScope {
+class DebuggerPausedScope {
public:
- DebuggerCallFrameScope(Debugger& debugger)
+ DebuggerPausedScope(Debugger& debugger)
: m_debugger(debugger)
{
ASSERT(!m_debugger.m_currentDebuggerCallFrame);
m_debugger.m_currentDebuggerCallFrame = DebuggerCallFrame::create(debugger.m_currentCallFrame);
}
- ~DebuggerCallFrameScope()
+ ~DebuggerPausedScope()
{
if (m_debugger.m_currentDebuggerCallFrame) {
m_debugger.m_currentDebuggerCallFrame->invalidate();
- m_debugger.m_currentDebuggerCallFrame = 0;
+ m_debugger.m_currentDebuggerCallFrame = nullptr;
}
}
template<typename Functor>
void Debugger::forEachCodeBlock(Functor& functor)
{
- m_vm->waitForCompilationsToComplete();
+ m_vm->prepareToDiscardCode();
m_vm->heap.forEachCodeBlock(functor);
}
, m_lastExecutedLine(UINT_MAX)
, m_lastExecutedSourceID(noSourceID)
, m_topBreakpointID(noBreakpointID)
+ , m_pausingBreakpointID(noBreakpointID)
{
}
m_vm = nullptr;
}
+bool Debugger::isAttached(JSGlobalObject* globalObject)
+{
+ return globalObject->debugger() == this;
+}
+
class Debugger::SetSteppingModeFunctor {
public:
SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode)
if (mode == m_steppingMode || !m_vm)
return;
- m_vm->waitForCompilationsToComplete();
+ m_vm->prepareToDiscardCode();
m_steppingMode = mode;
SetSteppingModeFunctor functor(this, mode);
unsigned line = breakpoint.line;
unsigned column = breakpoint.column;
- unsigned startLine = executable->lineNo();
+ unsigned startLine = executable->firstLine();
unsigned startColumn = executable->startColumn();
unsigned endLine = executable->lastLine();
unsigned endColumn = executable->endColumn();
// If JavaScript is running, it's not safe to recompile, since we'll end
// up throwing away code that is live on the stack.
if (vm->entryScope) {
- vm->entryScope->setRecompilationNeeded(true);
+ auto listener = [] (VM& vm, JSGlobalObject* globalObject)
+ {
+ if (Debugger* debugger = globalObject->debugger())
+ debugger->recompileAllJSFunctions(&vm);
+ };
+
+ vm->entryScope->setEntryScopeDidPopListener(this, listener);
return;
}
- vm->waitForCompilationsToComplete();
+ vm->prepareToDiscardCode();
Recompiler recompiler(this);
HeapIterationScope iterationScope(vm->heap);
// so make it looks like the debugger is already paused.
TemporaryPausedState pausedState(*this);
- JSValue exception;
+ NakedPtr<Exception> exception;
DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception);
if (!m_isPaused)
return;
- m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrameSkippingVMEntrySentinel() : 0;
+ VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
+ m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topVMEntryFrame) : 0;
notifyDoneProcessingDebuggerEvents();
}
bool pauseNow = m_pauseOnNextStatement;
pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
- DebuggerCallFrameScope debuggerCallFrameScope(*this);
+ DebuggerPausedScope debuggerPausedScope(*this);
intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame);
m_pauseOnNextStatement = false;
if (didHitBreakpoint) {
- handleBreakpointHit(breakpoint);
+ handleBreakpointHit(vmEntryGlobalObject, breakpoint);
// Note that the actions can potentially stop the debugger, so we need to check that
// we still have a current call frame when we get back.
if (breakpoint.autoContinue || !m_currentCallFrame)
return;
+ m_pausingBreakpointID = breakpoint.id;
}
- handlePause(m_reasonForPause, vmEntryGlobalObject);
+ {
+ PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
+ handlePause(vmEntryGlobalObject, m_reasonForPause);
+ }
+
+ m_pausingBreakpointID = noBreakpointID;
if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
setSteppingMode(SteppingModeDisabled);
}
}
-void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasHandler)
+void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
{
if (m_isPaused)
return;
PauseReasonDeclaration reason(*this, PausedForException);
- if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler)) {
+ if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
m_pauseOnNextStatement = true;
setSteppingMode(SteppingModeEnabled);
}
return;
// Treat stepping over a return statement like stepping out.
- if (m_currentCallFrame == m_pauseOnCallFrame)
- m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
+ if (m_currentCallFrame == m_pauseOnCallFrame) {
+ VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
+ }
- m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
+ VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
+ m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
}
void Debugger::willExecuteProgram(CallFrame* callFrame)
if (!m_currentCallFrame)
return;
if (m_currentCallFrame == m_pauseOnCallFrame) {
- m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
+ VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
if (!m_currentCallFrame)
return;
}
- m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
+ VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
+ m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
}
void Debugger::didReachBreakpoint(CallFrame* callFrame)
if (m_isPaused)
return;
- PauseReasonDeclaration reason(*this, PausedForBreakpoint);
+ PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
m_pauseOnNextStatement = true;
setSteppingMode(SteppingModeEnabled);
updateCallFrameAndPauseIfNeeded(callFrame);