diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
commit | 41386e9cb918eed93b3f13648cbef387e371e451 (patch) | |
tree | a97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/debugger/Debugger.cpp | |
parent | e15dd966d523731101f70ccf768bba12435a0208 (diff) | |
download | WebKitGtk-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.cpp | 181 |
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); |