summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/debugger/Debugger.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
commit41386e9cb918eed93b3f13648cbef387e371e451 (patch)
treea97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/debugger/Debugger.cpp
parente15dd966d523731101f70ccf768bba12435a0208 (diff)
downloadWebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/debugger/Debugger.cpp')
-rw-r--r--Source/JavaScriptCore/debugger/Debugger.cpp181
1 files changed, 67 insertions, 114 deletions
diff --git a/Source/JavaScriptCore/debugger/Debugger.cpp b/Source/JavaScriptCore/debugger/Debugger.cpp
index 4d7871ff8..afa7546c8 100644
--- a/Source/JavaScriptCore/debugger/Debugger.cpp
+++ b/Source/JavaScriptCore/debugger/Debugger.cpp
@@ -25,12 +25,13 @@
#include "CodeBlock.h"
#include "DebuggerCallFrame.h"
#include "Error.h"
+
#include "HeapIterationScope.h"
#include "Interpreter.h"
#include "JSCJSValueInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "JSCInlines.h"
+#include "Operations.h"
#include "Parser.h"
#include "Protect.h"
#include "VMEntryScope.h"
@@ -43,14 +44,12 @@ class Recompiler : public MarkedBlock::VoidFunctor {
public:
Recompiler(JSC::Debugger*);
~Recompiler();
- IterationStatus operator()(JSCell*);
+ void 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;
@@ -70,7 +69,7 @@ inline Recompiler::~Recompiler()
m_debugger->sourceParsed(iter->value, iter->key, -1, String());
}
-inline void Recompiler::visit(JSCell* cell)
+inline void Recompiler::operator()(JSCell* cell)
{
if (!cell->inherits(JSFunction::info()))
return;
@@ -87,25 +86,19 @@ inline void Recompiler::visit(JSCell* cell)
return;
ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec();
- executable->clearCode();
- executable->clearUnlinkedCodeForRecompilation();
+ executable->clearCodeIfNotCompiling();
+ executable->clearUnlinkedCodeForRecompilationIfNotCompiling();
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 DebuggerPausedScope {
+class DebuggerCallFrameScope {
public:
- DebuggerPausedScope(Debugger& debugger)
+ DebuggerCallFrameScope(Debugger& debugger)
: m_debugger(debugger)
{
ASSERT(!m_debugger.m_currentDebuggerCallFrame);
@@ -113,11 +106,11 @@ public:
m_debugger.m_currentDebuggerCallFrame = DebuggerCallFrame::create(debugger.m_currentCallFrame);
}
- ~DebuggerPausedScope()
+ ~DebuggerCallFrameScope()
{
if (m_debugger.m_currentDebuggerCallFrame) {
m_debugger.m_currentDebuggerCallFrame->invalidate();
- m_debugger.m_currentDebuggerCallFrame = nullptr;
+ m_debugger.m_currentDebuggerCallFrame = 0;
}
}
@@ -145,13 +138,6 @@ private:
Debugger& m_debugger;
};
-template<typename Functor>
-void Debugger::forEachCodeBlock(Functor& functor)
-{
- m_vm->prepareToDeleteCode();
- m_vm->heap.forEachCodeBlock(functor);
-}
-
Debugger::Debugger(bool isInWorkerThread)
: m_vm(nullptr)
, m_pauseOnExceptionsState(DontPauseOnExceptions)
@@ -167,7 +153,6 @@ Debugger::Debugger(bool isInWorkerThread)
, m_lastExecutedLine(UINT_MAX)
, m_lastExecutedSourceID(noSourceID)
, m_topBreakpointID(noBreakpointID)
- , m_pausingBreakpointID(noBreakpointID)
{
}
@@ -214,11 +199,6 @@ void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason)
m_vm = nullptr;
}
-bool Debugger::isAttached(JSGlobalObject* globalObject)
-{
- return globalObject->debugger() == this;
-}
-
class Debugger::SetSteppingModeFunctor {
public:
SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode)
@@ -245,22 +225,18 @@ private:
void Debugger::setSteppingMode(SteppingMode mode)
{
- if (mode == m_steppingMode || !m_vm)
+ if (mode == m_steppingMode)
return;
-
- m_vm->prepareToDeleteCode();
-
m_steppingMode = mode;
+
+ if (!m_vm)
+ return;
SetSteppingModeFunctor functor(this, mode);
m_vm->heap.forEachCodeBlock(functor);
}
void Debugger::registerCodeBlock(CodeBlock* codeBlock)
{
- // FIXME: We should never have to jettison a code block (due to pending breakpoints
- // or stepping mode) that is being registered. operationOptimize() should have
- // prevented the optimizing of such code blocks in the first place. Find a way to
- // express this with greater clarity in the code. See <https://webkit.org/b131771>.
applyBreakpoints(codeBlock);
if (isStepping())
codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
@@ -277,7 +253,7 @@ void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, Br
unsigned line = breakpoint.line;
unsigned column = breakpoint.column;
- unsigned startLine = executable->firstLine();
+ unsigned startLine = executable->lineNo();
unsigned startColumn = executable->startColumn();
unsigned endLine = executable->lastLine();
unsigned endColumn = executable->endColumn();
@@ -340,7 +316,7 @@ void Debugger::toggleBreakpoint(Breakpoint& breakpoint, Debugger::BreakpointStat
if (!m_vm)
return;
ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
- forEachCodeBlock(functor);
+ m_vm->heap.forEachCodeBlock(functor);
}
void Debugger::recompileAllJSFunctions(VM* vm)
@@ -348,17 +324,11 @@ void Debugger::recompileAllJSFunctions(VM* vm)
// 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) {
- auto listener = [] (VM& vm, JSGlobalObject* globalObject)
- {
- if (Debugger* debugger = globalObject->debugger())
- debugger->recompileAllJSFunctions(&vm);
- };
-
- vm->entryScope->setEntryScopeDidPopListener(this, listener);
+ vm->entryScope->setRecompilationNeeded(true);
return;
}
- vm->prepareToDeleteCode();
+ vm->prepareToDiscardCode();
Recompiler recompiler(this);
HeapIterationScope iterationScope(vm->heap);
@@ -376,18 +346,18 @@ BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine
it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator;
LineToBreakpointsMap::iterator breaksIt = it->value.find(line);
if (breaksIt == it->value.end())
- breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator;
+ breaksIt = it->value.set(line, BreakpointsInLine()).iterator;
- BreakpointsList& breakpoints = *breaksIt->value;
- for (Breakpoint* current = breakpoints.head(); current; current = current->next()) {
- if (current->column == column) {
+ BreakpointsInLine& breakpoints = breaksIt->value;
+ unsigned breakpointsCount = breakpoints.size();
+ for (unsigned i = 0; i < breakpointsCount; i++)
+ if (breakpoints[i].column == column) {
// The breakpoint already exists. We're not allowed to create a new
// breakpoint at this location. Rather than returning the breakpointID
// of the pre-existing breakpoint, we need to return noBreakpointID
// to indicate that we're not creating a new one.
return noBreakpointID;
}
- }
BreakpointID id = ++m_topBreakpointID;
RELEASE_ASSERT(id != noBreakpointID);
@@ -396,9 +366,8 @@ BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine
actualLine = line;
actualColumn = column;
- Breakpoint* newBreakpoint = new Breakpoint(breakpoint);
- breakpoints.append(newBreakpoint);
- m_breakpointIDToBreakpoint.set(id, newBreakpoint);
+ breakpoints.append(breakpoint);
+ m_breakpointIDToBreakpoint.set(id, &breakpoints.last());
toggleBreakpoint(breakpoint, BreakpointEnabled);
@@ -411,35 +380,31 @@ void Debugger::removeBreakpoint(BreakpointID id)
BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id);
ASSERT(idIt != m_breakpointIDToBreakpoint.end());
- Breakpoint* breakpoint = idIt->value;
+ Breakpoint& breakpoint = *idIt->value;
- SourceID sourceID = breakpoint->sourceID;
+ SourceID sourceID = breakpoint.sourceID;
ASSERT(sourceID);
SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
ASSERT(it != m_sourceIDToBreakpoints.end());
- LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line);
+ LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint.line);
ASSERT(breaksIt != it->value.end());
- toggleBreakpoint(*breakpoint, BreakpointDisabled);
+ toggleBreakpoint(breakpoint, BreakpointDisabled);
- BreakpointsList& breakpoints = *breaksIt->value;
-#if !ASSERT_DISABLED
- bool found = false;
- for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) {
- if (current->id == breakpoint->id)
- found = true;
- }
- ASSERT(found);
-#endif
+ BreakpointsInLine& breakpoints = breaksIt->value;
+ unsigned breakpointsCount = breakpoints.size();
+ for (unsigned i = 0; i < breakpointsCount; i++) {
+ if (breakpoints[i].id == breakpoint.id) {
+ breakpoints.remove(i);
+ m_breakpointIDToBreakpoint.remove(idIt);
- m_breakpointIDToBreakpoint.remove(idIt);
- breakpoints.remove(breakpoint);
- delete breakpoint;
-
- if (breakpoints.isEmpty()) {
- it->value.remove(breaksIt);
- if (it->value.isEmpty())
- m_sourceIDToBreakpoints.remove(it);
+ if (breakpoints.isEmpty()) {
+ it->value.remove(breaksIt);
+ if (it->value.isEmpty())
+ m_sourceIDToBreakpoints.remove(it);
+ }
+ break;
+ }
}
}
@@ -460,11 +425,12 @@ bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Br
return false;
bool hit = false;
- const BreakpointsList& breakpoints = *breaksIt->value;
- Breakpoint* breakpoint;
- for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) {
- unsigned breakLine = breakpoint->line;
- unsigned breakColumn = breakpoint->column;
+ const BreakpointsInLine& breakpoints = breaksIt->value;
+ unsigned breakpointsCount = breakpoints.size();
+ unsigned i;
+ for (i = 0; i < breakpointsCount; i++) {
+ unsigned breakLine = breakpoints[i].line;
+ unsigned breakColumn = breakpoints[i].column;
// Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger());
if ((line != m_lastExecutedLine && line == breakLine && !breakColumn)
@@ -477,18 +443,17 @@ bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Br
return false;
if (hitBreakpoint)
- *hitBreakpoint = *breakpoint;
+ *hitBreakpoint = breakpoints[i];
- if (breakpoint->condition.isEmpty())
+ if (breakpoints[i].condition.isEmpty())
return true;
// We cannot stop in the debugger while executing condition code,
// so make it looks like the debugger is already paused.
TemporaryPausedState pausedState(*this);
- NakedPtr<Exception> exception;
- DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
- JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception);
+ JSValue exception;
+ JSValue result = DebuggerCallFrame::evaluateWithCallFrame(m_currentCallFrame, breakpoints[i].condition, exception);
// We can lose the debugger while executing JavaScript.
if (!m_currentCallFrame)
@@ -530,7 +495,7 @@ void Debugger::clearBreakpoints()
if (!m_vm)
return;
ClearCodeBlockDebuggerRequestsFunctor functor(this);
- forEachCodeBlock(functor);
+ m_vm->heap.forEachCodeBlock(functor);
}
class Debugger::ClearDebuggerRequestsFunctor {
@@ -555,7 +520,7 @@ void Debugger::clearDebuggerRequests(JSGlobalObject* globalObject)
{
ASSERT(m_vm);
ClearDebuggerRequestsFunctor functor(globalObject);
- forEachCodeBlock(functor);
+ m_vm->heap.forEachCodeBlock(functor);
}
void Debugger::setBreakpointsActivated(bool activated)
@@ -620,8 +585,7 @@ void Debugger::stepOutOfFunction()
if (!m_isPaused)
return;
- VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
- m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topVMEntryFrame) : 0;
+ m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrameSkippingVMEntrySentinel() : 0;
notifyDoneProcessingDebuggerEvents();
}
@@ -657,8 +621,6 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
bool pauseNow = m_pauseOnNextStatement;
pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
- DebuggerPausedScope debuggerPausedScope(*this);
-
intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame);
pauseNow |= didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint);
@@ -666,6 +628,8 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
if (!pauseNow)
return;
+ DebuggerCallFrameScope debuggerCallFrameScope(*this);
+
// Make sure we are not going to pause again on breakpoint actions by
// reseting the pause state before executing any breakpoint actions.
TemporaryPausedState pausedState(*this);
@@ -673,20 +637,14 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
m_pauseOnNextStatement = false;
if (didHitBreakpoint) {
- handleBreakpointHit(vmEntryGlobalObject, breakpoint);
+ handleBreakpointHit(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;
- }
-
- {
- PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
- handlePause(vmEntryGlobalObject, m_reasonForPause);
}
- m_pausingBreakpointID = noBreakpointID;
+ handlePause(m_reasonForPause, vmEntryGlobalObject);
if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
setSteppingMode(SteppingModeDisabled);
@@ -694,13 +652,13 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
}
}
-void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
+void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasHandler)
{
if (m_isPaused)
return;
PauseReasonDeclaration reason(*this, PausedForException);
- if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
+ if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler)) {
m_pauseOnNextStatement = true;
setSteppingMode(SteppingModeEnabled);
}
@@ -743,13 +701,10 @@ void Debugger::returnEvent(CallFrame* callFrame)
return;
// Treat stepping over a return statement like stepping out.
- if (m_currentCallFrame == m_pauseOnCallFrame) {
- VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
- m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
- }
+ if (m_currentCallFrame == m_pauseOnCallFrame)
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
- VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
- m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
+ m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
}
void Debugger::willExecuteProgram(CallFrame* callFrame)
@@ -779,13 +734,11 @@ void Debugger::didExecuteProgram(CallFrame* callFrame)
if (!m_currentCallFrame)
return;
if (m_currentCallFrame == m_pauseOnCallFrame) {
- VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
- m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
if (!m_currentCallFrame)
return;
}
- VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame;
- m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
+ m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
}
void Debugger::didReachBreakpoint(CallFrame* callFrame)
@@ -793,7 +746,7 @@ void Debugger::didReachBreakpoint(CallFrame* callFrame)
if (m_isPaused)
return;
- PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
+ PauseReasonDeclaration reason(*this, PausedForBreakpoint);
m_pauseOnNextStatement = true;
setSteppingMode(SteppingModeEnabled);
updateCallFrameAndPauseIfNeeded(callFrame);