Index: Source/core/inspector/InspectorDebuggerAgent.cpp |
diff --git a/Source/core/inspector/InspectorDebuggerAgent.cpp b/Source/core/inspector/InspectorDebuggerAgent.cpp |
index b95de81a82054a004a522b05426118e6e4caac5d..22ed08e3c11ed9e9ea027f353b907efe66b07a02 100644 |
--- a/Source/core/inspector/InspectorDebuggerAgent.cpp |
+++ b/Source/core/inspector/InspectorDebuggerAgent.cpp |
@@ -47,6 +47,7 @@ |
#include "core/inspector/ScriptCallFrame.h" |
#include "core/inspector/ScriptCallStack.h" |
#include "platform/JSONValues.h" |
+#include "wtf/Vector.h" |
#include "wtf/text/WTFString.h" |
using WebCore::TypeBuilder::Array; |
@@ -453,7 +454,7 @@ void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const |
return; |
} |
- injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrameId, positions); |
+ injectedScript.getStepInPositions(errorString, m_currentCallStack.lookup(injectedScript.scriptState()), callFrameId, positions); |
} |
void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array<CallFrame> >& callFrames, WTF::RefPtr<WebCore::TypeBuilder::Debugger::StackTrace>& asyncStackTrace) |
@@ -611,7 +612,7 @@ void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String |
return; |
} |
- injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result); |
+ injectedScript.restartFrame(errorString, m_currentCallStack.lookup(injectedScript.scriptState()), callFrameId, &result); |
m_currentCallStack = scriptDebugServer().currentCallFrames(); |
newCallFrames = currentCallFrames(); |
asyncStackTrace = currentAsyncStackTrace(); |
@@ -833,7 +834,7 @@ void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, |
m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState); |
} |
-void InspectorDebuggerAgent::collectAsyncCallStacks(Vector<StackTrace>& asyncCallStacks) |
+void InspectorDebuggerAgent::collectAsyncCallStacks(Vector<StackTrace>& asyncCallStacks, ScriptState* scriptState) |
{ |
const AsyncCallStackTracker::AsyncCallChain* asyncChain = m_asyncCallStackTracker.isEnabled() ? m_asyncCallStackTracker.currentAsyncCallChain() : 0; |
if (asyncChain) { |
@@ -841,7 +842,7 @@ void InspectorDebuggerAgent::collectAsyncCallStacks(Vector<StackTrace>& asyncCal |
asyncCallStacks.resize(callStacks.size()); |
AsyncCallStackTracker::AsyncCallStackVector::const_iterator it = callStacks.begin(); |
for (size_t i = 0; it != callStacks.end(); ++it, ++i) |
- asyncCallStacks[i] = (*it)->callFrames(); |
+ asyncCallStacks[i] = (*it)->callFrames().lookup(scriptState); |
} |
} |
@@ -865,8 +866,8 @@ void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const |
} |
Vector<StackTrace> asyncCallStacks; |
- collectAsyncCallStacks(asyncCallStacks); |
- injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, asyncCallStacks, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown); |
+ collectAsyncCallStacks(asyncCallStacks, injectedScript.scriptState()); |
+ injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack.lookup(injectedScript.scriptState()), asyncCallStacks, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown); |
if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) { |
unmuteConsole(); |
@@ -893,8 +894,8 @@ void InspectorDebuggerAgent::getCompletionsOnCallFrame(ErrorString* errorString, |
muteConsole(); |
Vector<StackTrace> asyncCallStacks; |
- collectAsyncCallStacks(asyncCallStacks); |
- injectedScript.getCompletionsOnCallFrame(errorString, m_currentCallStack, asyncCallStacks, callFrameId, expression, &result); |
+ collectAsyncCallStacks(asyncCallStacks, injectedScript.scriptState()); |
+ injectedScript.getCompletionsOnCallFrame(errorString, m_currentCallStack.lookup(injectedScript.scriptState()), asyncCallStacks, callFrameId, expression, &result); |
unmuteConsole(); |
if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState) |
@@ -1001,7 +1002,7 @@ void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scop |
} |
String newValueString = newValue->toJSONString(); |
ASSERT(injectedScript); |
- injectedScript->setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString); |
+ injectedScript->setVariableValue(errorString, m_currentCallStack.lookup(injectedScript->scriptState()), callFrameId, functionObjectId, scopeNumber, variableName, newValueString); |
} |
void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const String* pattern) |
@@ -1034,16 +1035,72 @@ void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directive |
} |
} |
+uint32_t lookupFramePointerHigh(PassRefPtr<CallFrame> frame) |
+{ |
+ double framePointerHigh = 0; |
+ bool ALLOW_UNUSED hasFramePointerHigh = frame->asObject()->getNumber("framePointerHigh", &framePointerHigh); |
+ ASSERT(hasFramePointerHigh); |
+ return static_cast<uint32_t>(framePointerHigh); |
+} |
+ |
+uint32_t lookupFramePointerLow(PassRefPtr<CallFrame> frame) |
+{ |
+ double framePointerLow = 0; |
+ bool ALLOW_UNUSED hasFramePointerLow = frame->asObject()->getNumber("framePointerLow", &framePointerLow); |
+ ASSERT(hasFramePointerLow); |
+ return static_cast<uint32_t>(framePointerLow); |
+} |
+ |
+static inline bool compareCallFramePointers(RefPtr<CallFrame> frame1, RefPtr<CallFrame> frame2) |
+{ |
+ uint32_t highFrame1 = lookupFramePointerHigh(frame1); |
+ uint32_t highFrame2 = lookupFramePointerHigh(frame2); |
+ if (highFrame1 != highFrame2) |
+ return highFrame1 < highFrame2; |
+ |
+ return lookupFramePointerLow(frame1) < lookupFramePointerLow(frame2); |
+} |
+ |
+void addFramesToVector(PassRefPtr<Array<CallFrame> > trace, Vector<RefPtr<CallFrame> > & v) |
+{ |
+ RefPtr<JSONArray> traceArray = trace->asArray(); |
+ for (JSONArray::iterator it = traceArray->begin(); it != traceArray->end(); ++it) { |
+ v.append(CallFrame::runtimeCast(*it)); |
+ } |
+} |
+ |
PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames() |
{ |
+ return callFrames(m_currentCallStack, 0); |
+} |
+ |
+PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::callFrames(StackTraces stackTraces, int asyncOrdinal) |
+{ |
if (!m_pausedScriptState || m_currentCallStack.isNull()) |
return Array<TypeBuilder::Debugger::CallFrame>::create(); |
- InjectedScript& injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState.get()); |
- if (injectedScript.isEmpty()) { |
- ASSERT_NOT_REACHED(); |
- return Array<CallFrame>::create(); |
+ |
+ Vector<RefPtr<CallFrame> > mergedFrames; |
+ for (StackTraces::iterator it = m_currentCallStack.begin(); it != m_currentCallStack.end(); ++it) { |
+ ScriptState* scriptState = it->key; |
+ StackTrace& stackTrace = it->value; |
+ // FIXMEDART: passing in -1 as hack to force AsyncStack mode |
+ // evaluation as V8 cannot handle regular evaluation of a call |
+ // frame if not stopped at a v8 breakpoint due to an assert |
+ // in the V8 code base that should probably be removed. |
+ // Async call frame evaluation works almost as well as regular |
+ // call frame evaluation with the only difference being that |
+ // local variable modifications have no impact. |
+ if (asyncOrdinal == 0 && m_pausedScriptState != scriptState) { |
+ asyncOrdinal = -1; |
+ } |
+ addFramesToVector(m_injectedScriptManager->injectedScriptFor(scriptState).wrapCallFrames(stackTrace, asyncOrdinal), mergedFrames); |
} |
- return injectedScript.wrapCallFrames(m_currentCallStack, 0); |
+ std::stable_sort(mergedFrames.begin(), mergedFrames.end(), compareCallFramePointers); |
+ |
+ RefPtr<Array<CallFrame> > ret = Array<CallFrame>::create(); |
+ for (size_t i = 0; i < mergedFrames.size(); ++i) |
+ ret->addItem(mergedFrames[i]); |
+ return ret; |
} |
PassRefPtr<WebCore::TypeBuilder::Debugger::StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace() |
@@ -1065,7 +1122,7 @@ PassRefPtr<WebCore::TypeBuilder::Debugger::StackTrace> InspectorDebuggerAgent::c |
int asyncOrdinal = callStacks.size(); |
for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it) { |
RefPtr<WebCore::TypeBuilder::Debugger::StackTrace> next = WebCore::TypeBuilder::Debugger::StackTrace::create() |
- .setCallFrames(injectedScript.wrapCallFrames((*it)->callFrames(), asyncOrdinal--)) |
+ .setCallFrames(callFrames((*it)->callFrames(), asyncOrdinal--)) |
.release(); |
next->setDescription((*it)->description()); |
if (result) |
@@ -1147,8 +1204,9 @@ void InspectorDebuggerAgent::failedToParseSource(const String& url, const String |
m_frontend->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage); |
} |
-ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptState* scriptState, const StackTrace& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints) |
+ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& exception, const Vector<String>& hitBreakpoints) |
{ |
+ const StackTraces& callFrames = scriptDebugServer().currentCallFrames(); |
ScriptDebugListener::SkipPauseRequest result; |
if (m_javaScriptPauseScheduled) |
result = ScriptDebugListener::NoSkip; // Don't skip explicit pause requests from front-end. |
@@ -1211,7 +1269,7 @@ ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptSta |
void InspectorDebuggerAgent::didContinue() |
{ |
m_pausedScriptState = nullptr; |
- m_currentCallStack = StackTrace(); |
+ m_currentCallStack = StackTraces(); |
clearBreakDetails(); |
m_frontend->resumed(); |
} |
@@ -1235,7 +1293,7 @@ void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::E |
void InspectorDebuggerAgent::clear() |
{ |
m_pausedScriptState = nullptr; |
- m_currentCallStack = StackTrace(); |
+ m_currentCallStack = StackTraces(); |
m_scripts.clear(); |
m_breakpointIdToDebugServerBreakpointIds.clear(); |
m_asyncCallStackTracker.clear(); |