Chromium Code Reviews| Index: third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
| diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
| index 0ff1a071fd808891a28337cfcb2005bec08c23f4..3fdb8a498ff1c7471d8445a592ba81a3fc9dc564 100644 |
| --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
| +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
| @@ -14,7 +14,6 @@ |
| #include "platform/v8_inspector/PromiseTracker.h" |
| #include "platform/v8_inspector/RemoteObjectId.h" |
| #include "platform/v8_inspector/V8AsyncCallTracker.h" |
| -#include "platform/v8_inspector/V8JavaScriptCallFrame.h" |
| #include "platform/v8_inspector/V8Regex.h" |
| #include "platform/v8_inspector/V8RuntimeAgentImpl.h" |
| #include "platform/v8_inspector/V8StackTraceImpl.h" |
| @@ -150,6 +149,96 @@ static bool hasInternalError(ErrorString* errorString, bool hasError) |
| return hasError; |
| } |
| +static PassOwnPtr<protocol::Debugger::Location> createProtocolLocation(const String16& scriptId, int lineNumber, int columnNumber) |
| +{ |
| + return protocol::Debugger::Location::create() |
| + .setScriptId(scriptId) |
| + .setLineNumber(lineNumber) |
| + .setColumnNumber(columnNumber).build(); |
| +} |
| + |
| +static PassOwnPtr<Array<protocol::Debugger::Scope>> toProtocolScopeChain(ErrorString* errorString, InjectedScript* injectedScript, JavaScriptCallFrame* callFrame) |
| +{ |
| + v8::Local<v8::Value> scopeChainValue = callFrame->scopeChain(); |
| + if (hasInternalError(errorString, scopeChainValue.IsEmpty() || !scopeChainValue->IsArray())) |
| + return nullptr; |
| + v8::Local<v8::Array> scopeChainArray = scopeChainValue.As<v8::Array>(); |
| + if (!injectedScript->wrapObjectsInArray(errorString, scopeChainArray, V8DebuggerAgent::backtraceObjectGroup)) |
| + return nullptr; |
| + OwnPtr<Array<protocol::Debugger::Scope>> outScopeChain = Array<protocol::Debugger::Scope>::create(); |
| + for (size_t i = 0; i < scopeChainArray->Length(); ++i) { |
| + v8::Local<v8::Value> scopeValue; |
| + if (hasInternalError(errorString, !scopeChainArray->Get(injectedScript->context(), i).ToLocal(&scopeValue))) |
| + return nullptr; |
| + protocol::ErrorSupport errorSupport; |
| + OwnPtr<RemoteObject> scopeRemoteObject = RemoteObject::parse(toProtocolValue(injectedScript->context(), scopeValue).get(), &errorSupport); |
| + if (hasInternalError(errorString, !scopeRemoteObject)) |
| + return nullptr; |
| + |
| + OwnPtr<protocol::Debugger::Scope> protocolScope = protocol::Debugger::Scope::create() |
| + .setType(toProtocolStringWithTypeCheck(callFrame->scopeType(i))) |
| + .setObject(scopeRemoteObject.release()) |
| + .setName(toProtocolStringWithTypeCheck(callFrame->scopeName(i))) |
| + .build(); |
| + |
| + v8::Local<v8::Value> startLocationValue = callFrame->scopeStartLocation(i); |
| + if (hasInternalError(errorString, startLocationValue.IsEmpty())) |
| + return nullptr; |
| + |
| + if (!startLocationValue->IsUndefined() && !startLocationValue->IsNull()) { |
| + OwnPtr<protocol::Debugger::Location> startLocation = protocol::Debugger::Location::parse(toProtocolValue(injectedScript->context(), startLocationValue).get(), &errorSupport); |
| + if (hasInternalError(errorString, !startLocation)) |
| + return nullptr; |
| + protocolScope->setStartLocation(startLocation.release()); |
| + } |
| + |
| + v8::Local<v8::Value> endLocationValue = callFrame->scopeEndLocation(i); |
| + if (hasInternalError(errorString, endLocationValue.IsEmpty())) |
| + return nullptr; |
| + |
| + if (!endLocationValue->IsUndefined() && !endLocationValue->IsNull()) { |
| + OwnPtr<protocol::Debugger::Location> endLocation = protocol::Debugger::Location::parse(toProtocolValue(injectedScript->context(), endLocationValue).get(), &errorSupport); |
| + if (hasInternalError(errorString, !endLocation)) |
| + return nullptr; |
| + protocolScope->setEndLocation(endLocation.release()); |
| + } |
| + |
| + outScopeChain->addItem(protocolScope.release()); |
| + } |
| + return outScopeChain.release(); |
| +} |
| + |
| +static PassOwnPtr<CallFrame> toProtocolCallFrame(ErrorString* errorString, InjectedScript* injectedScript, int callFrameIndex, JavaScriptCallFrame* callFrame) |
| +{ |
| + String16 callFrameId = "{\"ordinal\":" + String16::number(callFrameIndex) + ",\"injectedScriptId\":" + String16::number(injectedScript->contextId()) + "}"; |
| + String16 scriptId = String16::number(callFrame->sourceID()); |
| + OwnPtr<Array<protocol::Debugger::Scope>> scopeChainArray = toProtocolScopeChain(errorString, injectedScript, callFrame); |
| + if (hasInternalError(errorString, !scopeChainArray)) |
| + return nullptr; |
| + OwnPtr<RemoteObject> thisRemoteObject = injectedScript->wrapObject(errorString, callFrame->thisObject(), V8DebuggerAgent::backtraceObjectGroup); |
| + if (hasInternalError(errorString, !thisRemoteObject)) |
| + return nullptr; |
| + OwnPtr<CallFrame> outCallFrame = CallFrame::create() |
| + .setCallFrameId(callFrameId) |
| + .setFunctionName(callFrame->functionName()) |
| + .setFunctionLocation(createProtocolLocation(scriptId, callFrame->functionLine(), callFrame->functionColumn())) |
| + .setLocation(createProtocolLocation(scriptId, callFrame->line(), callFrame->column())) |
| + .setScopeChain(scopeChainArray.release()) |
| + .setThis(thisRemoteObject.release()) |
| + .build(); |
| + |
| + v8::Local<v8::Value> returnValue = callFrame->returnValue(); |
| + if (hasInternalError(errorString, returnValue.IsEmpty())) |
| + return nullptr; |
| + if (!returnValue->IsUndefined()) { |
| + OwnPtr<RemoteObject> returnRemoteValue = injectedScript->wrapObject(errorString, returnValue, V8DebuggerAgent::backtraceObjectGroup); |
| + if (hasInternalError(errorString, !returnRemoteValue)) |
| + return nullptr; |
| + outCallFrame->setReturnValue(returnRemoteValue.release()); |
| + } |
| + return outCallFrame.release(); |
| +} |
| + |
| PassOwnPtr<V8DebuggerAgent> V8DebuggerAgent::create(V8RuntimeAgent* runtimeAgent) |
| { |
| V8RuntimeAgentImpl* runtimeAgentImpl = static_cast<V8RuntimeAgentImpl*>(runtimeAgent); |
| @@ -242,7 +331,7 @@ void V8DebuggerAgentImpl::disable(ErrorString*) |
| debugger().removeDebuggerAgent(m_contextGroupId); |
| m_pausedContext.Reset(); |
| - m_currentCallStack.Reset(); |
| + m_currentCallStack.clear(); |
| m_scripts.clear(); |
| m_blackboxedPositions.clear(); |
| m_breakpointIdToDebuggerBreakpointIds.clear(); |
| @@ -486,8 +575,8 @@ void V8DebuggerAgentImpl::getBacktrace(ErrorString* errorString, OwnPtr<Array<Ca |
| { |
| if (!assertPaused(errorString)) |
| return; |
| - m_currentCallStack.Reset(m_isolate, debugger().currentCallFrames()); |
| - *callFrames = currentCallFrames(); |
| + m_currentCallStack = debugger().currentCallFrames(); |
| + *callFrames = currentCallFrames(errorString); |
|
dgozman
2016/03/23 00:12:35
if error - return nothing?
kozy
2016/03/23 02:13:10
Done.
|
| *asyncStackTrace = currentAsyncStackTrace(); |
| } |
| @@ -590,11 +679,7 @@ PassOwnPtr<protocol::Debugger::Location> V8DebuggerAgentImpl::resolveBreakpoint( |
| BreakpointIdToDebuggerBreakpointIdsMap::iterator debuggerBreakpointIdsIterator = m_breakpointIdToDebuggerBreakpointIds.find(breakpointId); |
| debuggerBreakpointIdsIterator->second->append(debuggerBreakpointId); |
| - OwnPtr<protocol::Debugger::Location> location = protocol::Debugger::Location::create() |
| - .setScriptId(scriptId) |
| - .setLineNumber(actualLineNumber) |
| - .setColumnNumber(actualColumnNumber).build(); |
| - return location.release(); |
| + return createProtocolLocation(scriptId, actualLineNumber, actualColumnNumber); |
|
dgozman
2016/03/23 00:12:35
buildLocation
kozy
2016/03/23 02:13:10
Done.
|
| } |
| void V8DebuggerAgentImpl::searchInContent(ErrorString* error, const String16& scriptId, const String16& query, |
| @@ -609,7 +694,7 @@ void V8DebuggerAgentImpl::searchInContent(ErrorString* error, const String16& sc |
| *error = String16("No script for id: " + scriptId); |
| } |
| -void V8DebuggerAgentImpl::setScriptSource(ErrorString* error, |
| +void V8DebuggerAgentImpl::setScriptSource(ErrorString* errorString, |
| const String16& scriptId, |
| const String16& newContent, |
| const Maybe<bool>& preview, |
| @@ -618,12 +703,14 @@ void V8DebuggerAgentImpl::setScriptSource(ErrorString* error, |
| Maybe<StackTrace>* asyncStackTrace, |
| Maybe<protocol::Debugger::SetScriptSourceError>* optOutCompileError) |
| { |
| - if (!checkEnabled(error)) |
| + if (!checkEnabled(errorString)) |
| return; |
| - if (!debugger().setScriptSource(scriptId, newContent, preview.fromMaybe(false), error, optOutCompileError, &m_currentCallStack, stackChanged)) |
| + if (!debugger().setScriptSource(scriptId, newContent, preview.fromMaybe(false), errorString, optOutCompileError, &m_currentCallStack, stackChanged)) |
| return; |
| - *newCallFrames = currentCallFrames(); |
| + *newCallFrames = currentCallFrames(errorString); |
| + if (!errorString->isEmpty()) |
| + return; |
| *asyncStackTrace = currentAsyncStackTrace(); |
| ScriptsMap::iterator it = m_scripts.find(scriptId); |
| @@ -637,7 +724,7 @@ void V8DebuggerAgentImpl::restartFrame(ErrorString* errorString, |
| OwnPtr<Array<CallFrame>>* newCallFrames, |
| Maybe<StackTrace>* asyncStackTrace) |
| { |
| - if (!isPaused() || m_currentCallStack.IsEmpty()) { |
| + if (!isPaused() || !m_currentCallStack) { |
| *errorString = "Attempt to access call frame when debugger is not on pause"; |
| return; |
| } |
| @@ -665,9 +752,11 @@ void V8DebuggerAgentImpl::restartFrame(ErrorString* errorString, |
| return; |
| } |
| - m_currentCallStack.Reset(m_isolate, debugger().currentCallFrames()); |
| + m_currentCallStack = debugger().currentCallFrames(); |
| - *newCallFrames = currentCallFrames(); |
| + *newCallFrames = currentCallFrames(errorString); |
| + if (!errorString->isEmpty()) |
|
dgozman
2016/03/23 00:12:35
should we check newCallFrames instead?
kozy
2016/03/23 02:13:10
Done.
|
| + return; |
| *asyncStackTrace = currentAsyncStackTrace(); |
| } |
| @@ -716,13 +805,8 @@ void V8DebuggerAgentImpl::getFunctionDetails(ErrorString* errorString, const Str |
| return; |
| } |
| - OwnPtr<protocol::Debugger::Location> location = protocol::Debugger::Location::create() |
| - .setScriptId(String16::number(function->ScriptId())) |
| - .setLineNumber(function->GetScriptLineNumber()) |
| - .setColumnNumber(function->GetScriptColumnNumber()).build(); |
| - |
| OwnPtr<FunctionDetails> functionDetails = FunctionDetails::create() |
| - .setLocation(location.release()) |
| + .setLocation(createProtocolLocation(String16::number(function->ScriptId()), function->GetScriptLineNumber(), function->GetScriptColumnNumber())) |
| .setFunctionName(toProtocolStringWithTypeCheck(function->GetDebugName())) |
| .setIsGenerator(function->IsGeneratorFunction()).build(); |
| @@ -992,7 +1076,7 @@ void V8DebuggerAgentImpl::evaluateOnCallFrame(ErrorString* errorString, |
| Maybe<bool>* wasThrown, |
| Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) |
| { |
| - if (!isPaused() || m_currentCallStack.IsEmpty()) { |
| + if (!isPaused() || !m_currentCallStack) { |
| *errorString = "Attempt to access callframe when debugger is not on pause"; |
| return; |
| } |
| @@ -1050,7 +1134,7 @@ void V8DebuggerAgentImpl::setVariableValue(ErrorString* errorString, |
| { |
| if (!checkEnabled(errorString)) |
| return; |
| - if (!isPaused() || m_currentCallStack.IsEmpty()) { |
| + if (!isPaused() || !m_currentCallStack) { |
| *errorString = "Attempt to access callframe when debugger is not on pause"; |
| return; |
| } |
| @@ -1406,19 +1490,36 @@ void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) |
| } |
| } |
| -PassOwnPtr<Array<CallFrame>> V8DebuggerAgentImpl::currentCallFrames() |
| +PassOwnPtr<Array<CallFrame>> V8DebuggerAgentImpl::currentCallFrames(ErrorString* errorString) |
| { |
| - if (m_pausedContext.IsEmpty() || m_currentCallStack.IsEmpty()) |
| + if (m_pausedContext.IsEmpty() || !m_currentCallStack) |
| return Array<CallFrame>::create(); |
| - v8::HandleScope handles(m_isolate); |
| InjectedScript* injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedContext.Get(m_isolate)); |
| if (!injectedScript) { |
| // Context has been reported as removed while on pause. |
| return Array<CallFrame>::create(); |
| } |
| - v8::Local<v8::Object> currentCallStack = m_currentCallStack.Get(m_isolate); |
| - return injectedScript->wrapCallFrames(currentCallStack); |
| + v8::HandleScope handles(injectedScript->isolate()); |
| + v8::Local<v8::Context> context = injectedScript->context(); |
| + v8::Context::Scope contextScope(context); |
| + |
| + OwnPtr<Array<CallFrame>> callFrames = Array<CallFrame>::create(); |
| + |
| + JavaScriptCallFrame* currentCallFrame = m_currentCallStack.get(); |
| + int callFrameIndex = 0; |
| + OwnPtr<JavaScriptCallFrame> currentCallFrameOwner; |
| + while (currentCallFrame) { |
| + OwnPtr<CallFrame> callFrame = toProtocolCallFrame(errorString, injectedScript, callFrameIndex, currentCallFrame); |
| + if (!callFrame) |
| + return Array<CallFrame>::create(); |
| + callFrames->addItem(callFrame.release()); |
| + |
| + currentCallFrameOwner = currentCallFrame->caller(); |
| + currentCallFrame = currentCallFrameOwner.get(); |
| + ++callFrameIndex; |
| + } |
| + return callFrames.release(); |
| } |
| PassOwnPtr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() |
| @@ -1500,7 +1601,7 @@ void V8DebuggerAgentImpl::didParseSource(const V8DebuggerParsedScript& parsedScr |
| } |
| } |
| -V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8::Context> context, v8::Local<v8::Object> callFrames, v8::Local<v8::Value> exception, const protocol::Vector<String16>& hitBreakpoints, bool isPromiseRejection) |
| +V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8::Context> context, PassOwnPtr<JavaScriptCallFrame> callFrames, v8::Local<v8::Value> exception, const protocol::Vector<String16>& hitBreakpoints, bool isPromiseRejection) |
| { |
| V8DebuggerAgentImpl::SkipPauseRequest result; |
| if (m_skipAllPauses) |
| @@ -1519,12 +1620,13 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8 |
| return result; |
| // Skip pauses inside V8 internal scripts and on syntax errors. |
| - if (callFrames.IsEmpty()) |
| + if (!callFrames) |
| return RequestContinue; |
| ASSERT(m_pausedContext.IsEmpty()); |
| m_pausedContext.Reset(m_isolate, context); |
| - m_currentCallStack.Reset(m_isolate, callFrames); |
| + |
|
dgozman
2016/03/23 00:12:35
nit: extra blank line
kozy
2016/03/23 02:13:10
Done.
|
| + m_currentCallStack = callFrames; |
| v8::HandleScope handles(m_isolate); |
| if (!exception.IsEmpty()) { |
| @@ -1559,7 +1661,8 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8 |
| if (!m_asyncOperationNotifications.isEmpty()) |
| flushAsyncOperationEvents(nullptr); |
| - m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData.release(), hitBreakpointIds.release(), currentAsyncStackTrace()); |
| + ErrorString errorString; |
| + m_frontend->paused(currentCallFrames(&errorString), m_breakReason, m_breakAuxData.release(), hitBreakpointIds.release(), currentAsyncStackTrace()); |
| m_scheduledDebuggerStep = NoStep; |
| m_javaScriptPauseScheduled = false; |
| m_steppingFromFramework = false; |
| @@ -1578,7 +1681,7 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8 |
| void V8DebuggerAgentImpl::didContinue() |
| { |
| m_pausedContext.Reset(); |
| - m_currentCallStack.Reset(); |
| + m_currentCallStack.clear(); |
| clearBreakDetails(); |
| m_frontend->resumed(); |
| } |