Merge V8 5.8.283.32
Test: Build V8 for arm, arm64, x86, x86_64, mips, mips64 and
set a PAC script from the UI on bullhead
Change-Id: I7cc773b5daca34d869e768a1deebae3876f2dfac
diff --git a/src/inspector/v8-debugger-agent-impl.cc b/src/inspector/v8-debugger-agent-impl.cc
index 224ae28..7de46a1 100644
--- a/src/inspector/v8-debugger-agent-impl.cc
+++ b/src/inspector/v8-debugger-agent-impl.cc
@@ -54,14 +54,33 @@
} // namespace DebuggerAgentState
-static const int kMaxSkipStepFrameCount = 128;
static const char kBacktraceObjectGroup[] = "backtrace";
static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
static const char kDebuggerNotPaused[] =
"Can only perform operation while paused.";
-static String16 breakpointIdSuffix(
- V8DebuggerAgentImpl::BreakpointSource source) {
+namespace {
+
+void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
+ WasmTranslation* wasmTranslation) {
+ for (size_t i = 0, e = stackTrace->length(); i != e; ++i) {
+ protocol::Debugger::Location* location = stackTrace->get(i)->getLocation();
+ String16 scriptId = location->getScriptId();
+ int lineNumber = location->getLineNumber();
+ int columnNumber = location->getColumnNumber(-1);
+
+ if (!wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
+ &scriptId, &lineNumber, &columnNumber)) {
+ continue;
+ }
+
+ location->setScriptId(std::move(scriptId));
+ location->setLineNumber(lineNumber);
+ location->setColumnNumber(columnNumber);
+ }
+}
+
+String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source) {
switch (source) {
case V8DebuggerAgentImpl::UserBreakpointSource:
break;
@@ -73,26 +92,25 @@
return String16();
}
-static String16 generateBreakpointId(
- const String16& scriptId, int lineNumber, int columnNumber,
- V8DebuggerAgentImpl::BreakpointSource source) {
+String16 generateBreakpointId(const ScriptBreakpoint& breakpoint,
+ V8DebuggerAgentImpl::BreakpointSource source) {
String16Builder builder;
- builder.append(scriptId);
+ builder.append(breakpoint.script_id);
builder.append(':');
- builder.appendNumber(lineNumber);
+ builder.appendNumber(breakpoint.line_number);
builder.append(':');
- builder.appendNumber(columnNumber);
+ builder.appendNumber(breakpoint.column_number);
builder.append(breakpointIdSuffix(source));
return builder.toString();
}
-static bool positionComparator(const std::pair<int, int>& a,
- const std::pair<int, int>& b) {
+bool positionComparator(const std::pair<int, int>& a,
+ const std::pair<int, int>& b) {
if (a.first != b.first) return a.first < b.first;
return a.second < b.second;
}
-static std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation(
+std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation(
const String16& scriptId, int lineNumber, int columnNumber) {
return protocol::Debugger::Location::create()
.setScriptId(scriptId)
@@ -101,6 +119,8 @@
.build();
}
+} // namespace
+
V8DebuggerAgentImpl::V8DebuggerAgentImpl(
V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
protocol::DictionaryValue* state)
@@ -111,24 +131,14 @@
m_state(state),
m_frontend(frontendChannel),
m_isolate(m_inspector->isolate()),
- m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other),
m_scheduledDebuggerStep(NoStep),
- m_skipNextDebuggerStepOut(false),
m_javaScriptPauseScheduled(false),
- m_steppingFromFramework(false),
- m_pausingOnNativeEvent(false),
- m_skippedStepFrameCount(0),
- m_recursionLevelForStepOut(0),
- m_recursionLevelForStepFrame(0),
- m_skipAllPauses(false) {
- clearBreakDetails();
+ m_recursionLevelForStepOut(0) {
}
V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
void V8DebuggerAgentImpl::enableImpl() {
- // m_inspector->addListener may result in reporting all parsed scripts to
- // the agent so it should already be in enabled state by then.
m_enabled = true;
m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
m_debugger->enable();
@@ -161,29 +171,25 @@
m_state->setObject(DebuggerAgentState::javaScriptBreakpoints,
protocol::DictionaryValue::create());
m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
- v8::DebugInterface::NoBreakOnException);
+ v8::debug::NoBreakOnException);
m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
- if (!m_pausedContext.IsEmpty()) m_debugger->continueProgram();
+ if (isPaused()) m_debugger->continueProgram();
m_debugger->disable();
- m_pausedContext.Reset();
JavaScriptCallFrames emptyCallFrames;
m_pausedCallFrames.swap(emptyCallFrames);
- m_scripts.clear();
m_blackboxedPositions.clear();
+ m_blackboxPattern.reset();
+ resetBlackboxedStateCache();
+ m_scripts.clear();
m_breakpointIdToDebuggerBreakpointIds.clear();
m_debugger->setAsyncCallStackDepth(this, 0);
m_continueToLocationBreakpointId = String16();
clearBreakDetails();
m_scheduledDebuggerStep = NoStep;
- m_skipNextDebuggerStepOut = false;
m_javaScriptPauseScheduled = false;
- m_steppingFromFramework = false;
- m_pausingOnNativeEvent = false;
- m_skippedStepFrameCount = 0;
- m_recursionLevelForStepFrame = 0;
m_skipAllPauses = false;
- m_blackboxPattern = nullptr;
+ m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
m_state->remove(DebuggerAgentState::blackboxPattern);
m_enabled = false;
m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
@@ -199,7 +205,7 @@
enableImpl();
- int pauseState = v8::DebugInterface::NoBreakOnException;
+ int pauseState = v8::debug::NoBreakOnException;
m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState);
setPauseOnExceptionsImpl(pauseState);
@@ -225,8 +231,8 @@
}
Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
+ m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
m_skipAllPauses = skip;
- m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
return Response::OK();
}
@@ -291,12 +297,13 @@
breakpointId, buildObjectForBreakpointCookie(
url, lineNumber, columnNumber, condition, isRegex));
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
+ ScriptBreakpoint breakpoint(String16(), lineNumber, columnNumber, condition);
for (const auto& script : m_scripts) {
if (!matches(m_inspector, script.second->sourceURL(), url, isRegex))
continue;
- std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint(
- breakpointId, script.first, breakpoint, UserBreakpointSource);
+ breakpoint.script_id = script.first;
+ std::unique_ptr<protocol::Debugger::Location> location =
+ resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
if (location) (*locations)->addItem(std::move(location));
}
@@ -308,21 +315,18 @@
std::unique_ptr<protocol::Debugger::Location> location,
Maybe<String16> optionalCondition, String16* outBreakpointId,
std::unique_ptr<protocol::Debugger::Location>* actualLocation) {
- String16 scriptId = location->getScriptId();
- int lineNumber = location->getLineNumber();
- int columnNumber = location->getColumnNumber(0);
+ ScriptBreakpoint breakpoint(
+ location->getScriptId(), location->getLineNumber(),
+ location->getColumnNumber(0), optionalCondition.fromMaybe(String16()));
- String16 condition = optionalCondition.fromMaybe("");
-
- String16 breakpointId = generateBreakpointId(
- scriptId, lineNumber, columnNumber, UserBreakpointSource);
+ String16 breakpointId =
+ generateBreakpointId(breakpoint, UserBreakpointSource);
if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
m_breakpointIdToDebuggerBreakpointIds.end()) {
return Response::Error("Breakpoint at specified location already exists.");
}
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
- *actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint,
- UserBreakpointSource);
+ *actualLocation =
+ resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
*outBreakpointId = breakpointId;
return Response::OK();
@@ -365,9 +369,9 @@
return Response::Error(
"start.lineNumber and start.columnNumber should be >= 0");
- v8::DebugInterface::Location v8Start(start->getLineNumber(),
- start->getColumnNumber(0));
- v8::DebugInterface::Location v8End;
+ v8::debug::Location v8Start(start->getLineNumber(),
+ start->getColumnNumber(0));
+ v8::debug::Location v8End;
if (end.isJust()) {
if (end.fromJust()->getScriptId() != scriptId)
return Response::Error("Locations should contain the same scriptId");
@@ -376,12 +380,12 @@
if (line < 0 || column < 0)
return Response::Error(
"end.lineNumber and end.columnNumber should be >= 0");
- v8End = v8::DebugInterface::Location(line, column);
+ v8End = v8::debug::Location(line, column);
}
auto it = m_scripts.find(scriptId);
if (it == m_scripts.end()) return Response::Error("Script not found");
- std::vector<v8::DebugInterface::Location> v8Locations;
+ std::vector<v8::debug::Location> v8Locations;
if (!it->second->getPossibleBreakpoints(v8Start, v8End, &v8Locations))
return Response::InternalError();
@@ -405,38 +409,20 @@
m_continueToLocationBreakpointId = "";
}
- String16 scriptId = location->getScriptId();
- int lineNumber = location->getLineNumber();
- int columnNumber = location->getColumnNumber(0);
+ ScriptBreakpoint breakpoint(location->getScriptId(),
+ location->getLineNumber(),
+ location->getColumnNumber(0), String16());
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
m_continueToLocationBreakpointId = m_debugger->setBreakpoint(
- scriptId, breakpoint, &lineNumber, &columnNumber);
+ breakpoint, &breakpoint.line_number, &breakpoint.column_number);
+ // TODO(kozyatinskiy): Return actual line and column number.
return resume();
}
-bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed() {
- DCHECK(enabled());
- JavaScriptCallFrames callFrames = m_debugger->currentCallFrames();
- for (size_t index = 0; index < callFrames.size(); ++index) {
- if (!isCallFrameWithUnknownScriptOrBlackboxed(callFrames[index].get()))
- return false;
- }
- return true;
-}
-
-bool V8DebuggerAgentImpl::isTopPausedCallFrameBlackboxed() {
- DCHECK(enabled());
- JavaScriptCallFrame* frame =
- m_pausedCallFrames.size() ? m_pausedCallFrames[0].get() : nullptr;
- return isCallFrameWithUnknownScriptOrBlackboxed(frame);
-}
-
-bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(
- JavaScriptCallFrame* frame) {
- if (!frame) return true;
- ScriptsMap::iterator it =
- m_scripts.find(String16::fromInteger(frame->sourceID()));
+bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
+ const v8::debug::Location& start,
+ const v8::debug::Location& end) {
+ ScriptsMap::iterator it = m_scripts.find(scriptId);
if (it == m_scripts.end()) {
// Unknown scripts are blackboxed.
return true;
@@ -447,78 +433,65 @@
m_blackboxPattern->match(scriptSourceURL) != -1)
return true;
}
- auto itBlackboxedPositions =
- m_blackboxedPositions.find(String16::fromInteger(frame->sourceID()));
+ auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
const std::vector<std::pair<int, int>>& ranges =
itBlackboxedPositions->second;
- auto itRange = std::lower_bound(
+ auto itStartRange = std::lower_bound(
ranges.begin(), ranges.end(),
- std::make_pair(frame->line(), frame->column()), positionComparator);
+ std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
+ positionComparator);
+ auto itEndRange = std::lower_bound(
+ itStartRange, ranges.end(),
+ std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
+ positionComparator);
// Ranges array contains positions in script where blackbox state is changed.
// [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
// blackboxed...
- return std::distance(ranges.begin(), itRange) % 2;
-}
-
-V8DebuggerAgentImpl::SkipPauseRequest
-V8DebuggerAgentImpl::shouldSkipExceptionPause(
- JavaScriptCallFrame* topCallFrame) {
- if (m_steppingFromFramework) return RequestNoSkip;
- if (isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
- return RequestContinue;
- return RequestNoSkip;
-}
-
-V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipStepPause(
- JavaScriptCallFrame* topCallFrame) {
- if (m_steppingFromFramework) return RequestNoSkip;
-
- if (m_skipNextDebuggerStepOut) {
- m_skipNextDebuggerStepOut = false;
- if (m_scheduledDebuggerStep == StepOut) return RequestStepOut;
- }
-
- if (!isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
- return RequestNoSkip;
-
- if (m_skippedStepFrameCount >= kMaxSkipStepFrameCount) return RequestStepOut;
-
- if (!m_skippedStepFrameCount) m_recursionLevelForStepFrame = 1;
-
- ++m_skippedStepFrameCount;
- return RequestStepFrame;
+ return itStartRange == itEndRange &&
+ std::distance(ranges.begin(), itStartRange) % 2;
}
std::unique_ptr<protocol::Debugger::Location>
V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
- const String16& scriptId,
const ScriptBreakpoint& breakpoint,
BreakpointSource source) {
+ v8::HandleScope handles(m_isolate);
DCHECK(enabled());
// FIXME: remove these checks once crbug.com/520702 is resolved.
CHECK(!breakpointId.isEmpty());
- CHECK(!scriptId.isEmpty());
- ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
+ CHECK(!breakpoint.script_id.isEmpty());
+ ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id);
if (scriptIterator == m_scripts.end()) return nullptr;
- if (breakpoint.lineNumber < scriptIterator->second->startLine() ||
- scriptIterator->second->endLine() < breakpoint.lineNumber)
+ if (breakpoint.line_number < scriptIterator->second->startLine() ||
+ scriptIterator->second->endLine() < breakpoint.line_number)
return nullptr;
+ // Translate from protocol location to v8 location for the debugger.
+ ScriptBreakpoint translatedBreakpoint = breakpoint;
+ m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation(
+ &translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
+ &translatedBreakpoint.column_number);
+
int actualLineNumber;
int actualColumnNumber;
String16 debuggerBreakpointId = m_debugger->setBreakpoint(
- scriptId, breakpoint, &actualLineNumber, &actualColumnNumber);
+ translatedBreakpoint, &actualLineNumber, &actualColumnNumber);
if (debuggerBreakpointId.isEmpty()) return nullptr;
+ // Translate back from v8 location to protocol location for the return value.
+ m_debugger->wasmTranslation()->TranslateWasmScriptLocationToProtocolLocation(
+ &translatedBreakpoint.script_id, &actualLineNumber, &actualColumnNumber);
+
m_serverBreakpoints[debuggerBreakpointId] =
std::make_pair(breakpointId, source);
CHECK(!breakpointId.isEmpty());
m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
debuggerBreakpointId);
- return buildProtocolLocation(scriptId, actualLineNumber, actualColumnNumber);
+ return buildProtocolLocation(translatedBreakpoint.script_id, actualLineNumber,
+ actualColumnNumber);
}
Response V8DebuggerAgentImpl::searchInContent(
@@ -531,9 +504,8 @@
return Response::Error("No script for id: " + scriptId);
std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
- searchInTextByLinesImpl(m_session,
- toProtocolString(it->second->source(m_isolate)),
- query, optionalCaseSensitive.fromMaybe(false),
+ searchInTextByLinesImpl(m_session, it->second->source(m_isolate), query,
+ optionalCaseSensitive.fromMaybe(false),
optionalIsRegex.fromMaybe(false));
*results = protocol::Array<protocol::Debugger::SearchMatch>::create();
for (size_t i = 0; i < matches.size(); ++i)
@@ -548,6 +520,15 @@
Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
+ ScriptsMap::iterator it = m_scripts.find(scriptId);
+ if (it == m_scripts.end()) {
+ return Response::Error("No script with given id found");
+ }
+ if (it->second->isModule()) {
+ // TODO(kozyatinskiy): LiveEdit should support ES6 module
+ return Response::Error("Editing module's script is not supported.");
+ }
+
v8::HandleScope handles(m_isolate);
v8::Local<v8::String> newSource = toV8String(m_isolate, newContent);
bool compileError = false;
@@ -556,9 +537,7 @@
&m_pausedCallFrames, stackChanged, &compileError);
if (!response.isSuccess() || compileError) return response;
- ScriptsMap::iterator it = m_scripts.find(scriptId);
- if (it != m_scripts.end()) it->second->setSource(newSource);
-
+ it->second->setSource(newSource);
std::unique_ptr<Array<CallFrame>> callFrames;
response = currentCallFrames(&callFrames);
if (!response.isSuccess()) return response;
@@ -571,7 +550,7 @@
const String16& callFrameId,
std::unique_ptr<Array<CallFrame>>* newCallFrames,
Maybe<StackTrace>* asyncStackTrace) {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
callFrameId);
Response response = scope.initialize();
@@ -604,93 +583,93 @@
if (it == m_scripts.end())
return Response::Error("No script for id: " + scriptId);
v8::HandleScope handles(m_isolate);
- *scriptSource = toProtocolString(it->second->source(m_isolate));
+ *scriptSource = it->second->source(m_isolate);
return Response::OK();
}
+void V8DebuggerAgentImpl::pushBreakDetails(
+ const String16& breakReason,
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData) {
+ m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData)));
+}
+
+void V8DebuggerAgentImpl::popBreakDetails() {
+ if (m_breakReason.empty()) return;
+ m_breakReason.pop_back();
+}
+
+void V8DebuggerAgentImpl::clearBreakDetails() {
+ std::vector<BreakReason> emptyBreakReason;
+ m_breakReason.swap(emptyBreakReason);
+}
+
void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data) {
if (!enabled() || m_scheduledDebuggerStep == StepInto ||
- m_javaScriptPauseScheduled || m_debugger->isPaused() ||
+ m_javaScriptPauseScheduled || isPaused() ||
!m_debugger->breakpointsActivated())
return;
- m_breakReason = breakReason;
- m_breakAuxData = std::move(data);
- m_pausingOnNativeEvent = true;
- m_skipNextDebuggerStepOut = false;
- m_debugger->setPauseOnNextStatement(true);
+ if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true);
+ pushBreakDetails(breakReason, std::move(data));
}
void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
DCHECK(enabled());
if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
- m_debugger->isPaused())
+ isPaused())
return;
- clearBreakDetails();
- m_pausingOnNativeEvent = false;
- m_skippedStepFrameCount = 0;
- m_recursionLevelForStepFrame = 0;
m_debugger->setPauseOnNextStatement(true);
}
void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
- if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return;
- clearBreakDetails();
- m_pausingOnNativeEvent = false;
- m_debugger->setPauseOnNextStatement(false);
+ if (m_javaScriptPauseScheduled || isPaused()) return;
+ popBreakDetails();
+ if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false);
}
Response V8DebuggerAgentImpl::pause() {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
- if (m_javaScriptPauseScheduled || m_debugger->isPaused())
- return Response::OK();
+ if (m_javaScriptPauseScheduled || isPaused()) return Response::OK();
clearBreakDetails();
m_javaScriptPauseScheduled = true;
m_scheduledDebuggerStep = NoStep;
- m_skippedStepFrameCount = 0;
- m_steppingFromFramework = false;
m_debugger->setPauseOnNextStatement(true);
return Response::OK();
}
Response V8DebuggerAgentImpl::resume() {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = NoStep;
- m_steppingFromFramework = false;
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->continueProgram();
return Response::OK();
}
Response V8DebuggerAgentImpl::stepOver() {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
// StepOver at function return point should fallback to StepInto.
JavaScriptCallFrame* frame =
!m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
if (frame && frame->isAtReturn()) return stepInto();
m_scheduledDebuggerStep = StepOver;
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepOverStatement();
return Response::OK();
}
Response V8DebuggerAgentImpl::stepInto() {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepInto;
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepIntoStatement();
return Response::OK();
}
Response V8DebuggerAgentImpl::stepOut() {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepOut;
- m_skipNextDebuggerStepOut = false;
m_recursionLevelForStepOut = 1;
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepOutOfFunction();
return Response::OK();
@@ -699,13 +678,13 @@
Response V8DebuggerAgentImpl::setPauseOnExceptions(
const String16& stringPauseState) {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
- v8::DebugInterface::ExceptionBreakState pauseState;
+ v8::debug::ExceptionBreakState pauseState;
if (stringPauseState == "none") {
- pauseState = v8::DebugInterface::NoBreakOnException;
+ pauseState = v8::debug::NoBreakOnException;
} else if (stringPauseState == "all") {
- pauseState = v8::DebugInterface::BreakOnAnyException;
+ pauseState = v8::debug::BreakOnAnyException;
} else if (stringPauseState == "uncaught") {
- pauseState = v8::DebugInterface::BreakOnUncaughtException;
+ pauseState = v8::debug::BreakOnUncaughtException;
} else {
return Response::Error("Unknown pause on exceptions mode: " +
stringPauseState);
@@ -716,7 +695,7 @@
void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
m_debugger->setPauseOnExceptionsState(
- static_cast<v8::DebugInterface::ExceptionBreakState>(pauseState));
+ static_cast<v8::debug::ExceptionBreakState>(pauseState));
m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState);
}
@@ -724,9 +703,9 @@
const String16& callFrameId, const String16& expression,
Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
- std::unique_ptr<RemoteObject>* result,
+ Maybe<bool> throwOnSideEffect, std::unique_ptr<RemoteObject>* result,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
callFrameId);
Response response = scope.initialize();
@@ -739,7 +718,8 @@
v8::MaybeLocal<v8::Value> maybeResultValue =
m_pausedCallFrames[scope.frameOrdinal()]->evaluate(
- toV8String(m_isolate, expression));
+ toV8String(m_isolate, expression),
+ throwOnSideEffect.fromMaybe(false));
// Re-initialize after running client's code, as it could have destroyed
// context or session.
@@ -756,7 +736,7 @@
std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
const String16& callFrameId) {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
- if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
+ if (!isPaused()) return Response::Error(kDebuggerNotPaused);
InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
callFrameId);
Response response = scope.initialize();
@@ -787,6 +767,7 @@
std::unique_ptr<protocol::Array<String16>> patterns) {
if (!patterns->length()) {
m_blackboxPattern = nullptr;
+ resetBlackboxedStateCache();
m_state->remove(DebuggerAgentState::blackboxPattern);
return Response::OK();
}
@@ -802,6 +783,7 @@
String16 pattern = patternBuilder.toString();
Response response = setBlackboxPattern(pattern);
if (!response.isSuccess()) return response;
+ resetBlackboxedStateCache();
m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
return Response::OK();
}
@@ -815,15 +797,23 @@
return Response::OK();
}
+void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
+ for (const auto& it : m_scripts) {
+ it.second->resetBlackboxedStateCache();
+ }
+}
+
Response V8DebuggerAgentImpl::setBlackboxedRanges(
const String16& scriptId,
std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
inPositions) {
- if (m_scripts.find(scriptId) == m_scripts.end())
+ auto it = m_scripts.find(scriptId);
+ if (it == m_scripts.end())
return Response::Error("No script with passed id.");
if (!inPositions->length()) {
m_blackboxedPositions.erase(scriptId);
+ it->second->resetBlackboxedStateCache();
return Response::OK();
}
@@ -849,12 +839,12 @@
}
m_blackboxedPositions[scriptId] = positions;
+ it->second->resetBlackboxedStateCache();
return Response::OK();
}
void V8DebuggerAgentImpl::willExecuteScript(int scriptId) {
changeJavaScriptRecursionLevel(+1);
- // Fast return.
if (m_scheduledDebuggerStep != StepInto) return;
schedulePauseOnNextStatementIfSteppingInto();
}
@@ -864,8 +854,7 @@
}
void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
- if (m_javaScriptPauseScheduled && !m_skipAllPauses &&
- !m_debugger->isPaused()) {
+ if (m_javaScriptPauseScheduled && !m_skipAllPauses && !isPaused()) {
// Do not ever loose user's pause request until we have actually paused.
m_debugger->setPauseOnNextStatement(true);
}
@@ -877,40 +866,19 @@
// switch stepping to step into a next JS task, as if we exited to a
// blackboxed framework.
m_scheduledDebuggerStep = StepInto;
- m_skipNextDebuggerStepOut = false;
- }
- }
- if (m_recursionLevelForStepFrame) {
- m_recursionLevelForStepFrame += step;
- if (!m_recursionLevelForStepFrame) {
- // We have walked through a blackboxed framework and got back to where we
- // started.
- // If there was no stepping scheduled, we should cancel the stepping
- // explicitly,
- // since there may be a scheduled StepFrame left.
- // Otherwise, if we were stepping in/over, the StepFrame will stop at the
- // right location,
- // whereas if we were stepping out, we should continue doing so after
- // debugger pauses
- // from the old StepFrame.
- m_skippedStepFrameCount = 0;
- if (m_scheduledDebuggerStep == NoStep)
- m_debugger->clearStepping();
- else if (m_scheduledDebuggerStep == StepOut)
- m_skipNextDebuggerStepOut = true;
}
}
}
Response V8DebuggerAgentImpl::currentCallFrames(
std::unique_ptr<Array<CallFrame>>* result) {
- if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) {
+ if (!isPaused()) {
*result = Array<CallFrame>::create();
return Response::OK();
}
v8::HandleScope handles(m_isolate);
v8::Local<v8::Context> debuggerContext =
- v8::DebugInterface::GetDebugContext(m_isolate);
+ v8::debug::GetDebugContext(m_isolate);
v8::Context::Scope contextScope(debuggerContext);
v8::Local<v8::Array> objects = v8::Array::New(m_isolate);
@@ -920,8 +888,9 @@
const std::unique_ptr<JavaScriptCallFrame>& currentCallFrame =
m_pausedCallFrames[frameOrdinal];
- v8::Local<v8::Object> details = currentCallFrame->details();
- if (details.IsEmpty()) return Response::InternalError();
+ v8::Local<v8::Object> details;
+ if (!currentCallFrame->details().ToLocal(&details))
+ return Response::InternalError();
int contextId = currentCallFrame->contextId();
@@ -1004,54 +973,77 @@
Response response = toProtocolValue(debuggerContext, objects, &protocolValue);
if (!response.isSuccess()) return response;
protocol::ErrorSupport errorSupport;
- *result = Array<CallFrame>::parse(protocolValue.get(), &errorSupport);
+ *result = Array<CallFrame>::fromValue(protocolValue.get(), &errorSupport);
if (!*result) return Response::Error(errorSupport.errors());
+ TranslateWasmStackTraceLocations(result->get(),
+ m_debugger->wasmTranslation());
return Response::OK();
}
std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() {
- if (m_pausedContext.IsEmpty()) return nullptr;
+ if (!isPaused()) return nullptr;
V8StackTraceImpl* stackTrace = m_debugger->currentAsyncCallChain();
return stackTrace ? stackTrace->buildInspectorObjectForTail(m_debugger)
: nullptr;
}
+bool V8DebuggerAgentImpl::isPaused() const { return m_debugger->isPaused(); }
+
void V8DebuggerAgentImpl::didParseSource(
std::unique_ptr<V8DebuggerScript> script, bool success) {
v8::HandleScope handles(m_isolate);
- String16 scriptSource = toProtocolString(script->source(m_isolate));
+ String16 scriptSource = script->source(m_isolate);
if (!success) script->setSourceURL(findSourceURL(scriptSource, false));
if (!success)
script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
+ int contextId = script->executionContextId();
+ int contextGroupId = m_inspector->contextGroupId(contextId);
+ InspectedContext* inspected =
+ m_inspector->getContext(contextGroupId, contextId);
std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
- if (!script->executionContextAuxData().isEmpty())
+ if (inspected) {
+ // Script reused between different groups/sessions can have a stale
+ // execution context id.
executionContextAuxData = protocol::DictionaryValue::cast(
- protocol::parseJSON(script->executionContextAuxData()));
+ protocol::StringUtil::parseJSON(inspected->auxData()));
+ }
bool isLiveEdit = script->isLiveEdit();
bool hasSourceURL = script->hasSourceURL();
+ bool isModule = script->isModule();
String16 scriptId = script->scriptId();
String16 scriptURL = script->sourceURL();
- Maybe<String16> sourceMapURLParam = script->sourceMappingURL();
+ m_scripts[scriptId] = std::move(script);
+
+ ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
+ DCHECK(scriptIterator != m_scripts.end());
+ V8DebuggerScript* scriptRef = scriptIterator->second.get();
+ // V8 could create functions for parsed scripts before reporting and asks
+ // inspector about blackboxed state, we should reset state each time when we
+ // make any change that change isFunctionBlackboxed output - adding parsed
+ // script is changing.
+ scriptRef->resetBlackboxedStateCache();
+
+ Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
std::move(executionContextAuxData));
const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
+ const bool* isModuleParam = isModule ? &isModule : nullptr;
if (success)
m_frontend.scriptParsed(
- scriptId, scriptURL, script->startLine(), script->startColumn(),
- script->endLine(), script->endColumn(), script->executionContextId(),
- script->hash(), std::move(executionContextAuxDataParam),
- isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam);
+ scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
+ scriptRef->endLine(), scriptRef->endColumn(), contextId,
+ scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
+ isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
+ isModuleParam);
else
m_frontend.scriptFailedToParse(
- scriptId, scriptURL, script->startLine(), script->startColumn(),
- script->endLine(), script->endColumn(), script->executionContextId(),
- script->hash(), std::move(executionContextAuxDataParam),
- std::move(sourceMapURLParam), hasSourceURLParam);
-
- m_scripts[scriptId] = std::move(script);
+ scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
+ scriptRef->endLine(), scriptRef->endColumn(), contextId,
+ scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
+ std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam);
if (scriptURL.isEmpty() || !success) return;
@@ -1069,76 +1061,60 @@
breakpointObject->getString(DebuggerAgentState::url, &url);
if (!matches(m_inspector, scriptURL, url, isRegex)) continue;
ScriptBreakpoint breakpoint;
+ breakpoint.script_id = scriptId;
breakpointObject->getInteger(DebuggerAgentState::lineNumber,
- &breakpoint.lineNumber);
+ &breakpoint.line_number);
breakpointObject->getInteger(DebuggerAgentState::columnNumber,
- &breakpoint.columnNumber);
+ &breakpoint.column_number);
breakpointObject->getString(DebuggerAgentState::condition,
&breakpoint.condition);
- std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint(
- cookie.first, scriptId, breakpoint, UserBreakpointSource);
+ std::unique_ptr<protocol::Debugger::Location> location =
+ resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource);
if (location)
m_frontend.breakpointResolved(cookie.first, std::move(location));
}
}
-V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(
- v8::Local<v8::Context> context, v8::Local<v8::Value> exception,
- const std::vector<String16>& hitBreakpoints, bool isPromiseRejection,
- bool isUncaught) {
- JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
- JavaScriptCallFrame* topCallFrame =
- !callFrames.empty() ? callFrames.begin()->get() : nullptr;
-
- V8DebuggerAgentImpl::SkipPauseRequest result;
- if (m_skipAllPauses)
- result = RequestContinue;
- else if (!hitBreakpoints.empty())
- result = RequestNoSkip; // Don't skip explicit breakpoints even if set in
- // frameworks.
- else if (!exception.IsEmpty())
- result = shouldSkipExceptionPause(topCallFrame);
- else if (m_scheduledDebuggerStep != NoStep || m_javaScriptPauseScheduled ||
- m_pausingOnNativeEvent)
- result = shouldSkipStepPause(topCallFrame);
- else
- result = RequestNoSkip;
-
- m_skipNextDebuggerStepOut = false;
- if (result != RequestNoSkip) return result;
- // Skip pauses inside V8 internal scripts and on syntax errors.
- if (!topCallFrame) return RequestContinue;
-
- DCHECK(m_pausedContext.IsEmpty());
+void V8DebuggerAgentImpl::didPause(int contextId,
+ v8::Local<v8::Value> exception,
+ const std::vector<String16>& hitBreakpoints,
+ bool isPromiseRejection, bool isUncaught,
+ bool isOOMBreak) {
JavaScriptCallFrames frames = m_debugger->currentCallFrames();
m_pausedCallFrames.swap(frames);
- m_pausedContext.Reset(m_isolate, context);
v8::HandleScope handles(m_isolate);
- if (!exception.IsEmpty()) {
+ std::vector<BreakReason> hitReasons;
+
+ if (isOOMBreak) {
+ hitReasons.push_back(
+ std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr));
+ } else if (!exception.IsEmpty()) {
InjectedScript* injectedScript = nullptr;
- m_session->findInjectedScript(V8Debugger::contextId(context),
- injectedScript);
+ m_session->findInjectedScript(contextId, injectedScript);
if (injectedScript) {
- m_breakReason =
+ String16 breakReason =
isPromiseRejection
? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
: protocol::Debugger::Paused::ReasonEnum::Exception;
std::unique_ptr<protocol::Runtime::RemoteObject> obj;
injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false,
&obj);
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData;
if (obj) {
- m_breakAuxData = obj->serialize();
- m_breakAuxData->setBoolean("uncaught", isUncaught);
+ breakAuxData = obj->toValue();
+ breakAuxData->setBoolean("uncaught", isUncaught);
} else {
- m_breakAuxData = nullptr;
+ breakAuxData = nullptr;
}
- // m_breakAuxData might be null after this.
+ hitReasons.push_back(
+ std::make_pair(breakReason, std::move(breakAuxData)));
}
}
std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
+ bool hasDebugCommandBreakpointReason = false;
for (const auto& point : hitBreakpoints) {
DebugServerBreakpointToBreakpointIdAndSourceMap::iterator
breakpointIterator = m_serverBreakpoints.find(point);
@@ -1147,34 +1123,57 @@
hitBreakpointIds->addItem(localId);
BreakpointSource source = breakpointIterator->second.second;
- if (m_breakReason == protocol::Debugger::Paused::ReasonEnum::Other &&
- source == DebugCommandBreakpointSource)
- m_breakReason = protocol::Debugger::Paused::ReasonEnum::DebugCommand;
+ if (!hasDebugCommandBreakpointReason &&
+ source == DebugCommandBreakpointSource) {
+ hasDebugCommandBreakpointReason = true;
+ hitReasons.push_back(std::make_pair(
+ protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr));
+ }
}
}
+ for (size_t i = 0; i < m_breakReason.size(); ++i) {
+ hitReasons.push_back(std::move(m_breakReason[i]));
+ }
+ clearBreakDetails();
+
+ String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData;
+ if (hitReasons.size() == 1) {
+ breakReason = hitReasons[0].first;
+ breakAuxData = std::move(hitReasons[0].second);
+ } else if (hitReasons.size() > 1) {
+ breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous;
+ std::unique_ptr<protocol::ListValue> reasons =
+ protocol::ListValue::create();
+ for (size_t i = 0; i < hitReasons.size(); ++i) {
+ std::unique_ptr<protocol::DictionaryValue> reason =
+ protocol::DictionaryValue::create();
+ reason->setString("reason", hitReasons[i].first);
+ if (hitReasons[i].second)
+ reason->setObject("auxData", std::move(hitReasons[i].second));
+ reasons->pushValue(std::move(reason));
+ }
+ breakAuxData = protocol::DictionaryValue::create();
+ breakAuxData->setArray("reasons", std::move(reasons));
+ }
+
std::unique_ptr<Array<CallFrame>> protocolCallFrames;
Response response = currentCallFrames(&protocolCallFrames);
if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
- m_frontend.paused(std::move(protocolCallFrames), m_breakReason,
- std::move(m_breakAuxData), std::move(hitBreakpointIds),
+ m_frontend.paused(std::move(protocolCallFrames), breakReason,
+ std::move(breakAuxData), std::move(hitBreakpointIds),
currentAsyncStackTrace());
m_scheduledDebuggerStep = NoStep;
m_javaScriptPauseScheduled = false;
- m_steppingFromFramework = false;
- m_pausingOnNativeEvent = false;
- m_skippedStepFrameCount = 0;
- m_recursionLevelForStepFrame = 0;
if (!m_continueToLocationBreakpointId.isEmpty()) {
m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
m_continueToLocationBreakpointId = "";
}
- return result;
}
void V8DebuggerAgentImpl::didContinue() {
- m_pausedContext.Reset();
JavaScriptCallFrames emptyCallFrames;
m_pausedCallFrames.swap(emptyCallFrames);
clearBreakDetails();
@@ -1184,55 +1183,48 @@
void V8DebuggerAgentImpl::breakProgram(
const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data) {
- if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() ||
- isCurrentCallStackEmptyOrBlackboxed() ||
- !m_debugger->breakpointsActivated())
- return;
- m_breakReason = breakReason;
- m_breakAuxData = std::move(data);
+ if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return;
+ std::vector<BreakReason> currentScheduledReason;
+ currentScheduledReason.swap(m_breakReason);
+ pushBreakDetails(breakReason, std::move(data));
m_scheduledDebuggerStep = NoStep;
- m_steppingFromFramework = false;
- m_pausingOnNativeEvent = false;
m_debugger->breakProgram();
+ popBreakDetails();
+ m_breakReason.swap(currentScheduledReason);
}
void V8DebuggerAgentImpl::breakProgramOnException(
const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data) {
if (!enabled() ||
- m_debugger->getPauseOnExceptionsState() ==
- v8::DebugInterface::NoBreakOnException)
+ m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException)
return;
breakProgram(breakReason, std::move(data));
}
-void V8DebuggerAgentImpl::clearBreakDetails() {
- m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
- m_breakAuxData = nullptr;
-}
-
void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
int lineNumber, int columnNumber,
BreakpointSource source,
const String16& condition) {
- String16 breakpointId =
- generateBreakpointId(scriptId, lineNumber, columnNumber, source);
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
- resolveBreakpoint(breakpointId, scriptId, breakpoint, source);
+ ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition);
+ String16 breakpointId = generateBreakpointId(breakpoint, source);
+ resolveBreakpoint(breakpointId, breakpoint, source);
}
void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
int lineNumber, int columnNumber,
BreakpointSource source) {
- removeBreakpointImpl(
- generateBreakpointId(scriptId, lineNumber, columnNumber, source));
+ removeBreakpointImpl(generateBreakpointId(
+ ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()),
+ source));
}
void V8DebuggerAgentImpl::reset() {
if (!enabled()) return;
m_scheduledDebuggerStep = NoStep;
- m_scripts.clear();
m_blackboxedPositions.clear();
+ resetBlackboxedStateCache();
+ m_scripts.clear();
m_breakpointIdToDebuggerBreakpointIds.clear();
}