Commit 8f8d2fe4 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[inspector] Fix `Runtime.setMaxCallStackSizeToCapture`.

This change fixes the implementation of the previously introduced API
`Runtime.setMaxCallStackSizeToCapture` to work correctly and also apply
(consistently) to stack traces captured by V8 when exceptions are
thrown. It does so in a fully backwards compatible manner.

This change thus makes the previous fix for catapult (which landed in
http://crrev.com/c/3347789) effective, and therefore ensures that real
world performance benchmarks aren't affected by the use of the `Runtime`
domain in the catapult test framework.

Note this is basically a reland of crrev.com/c/3361839, but without
touching the stack traces for console messages (which led to the
regressions in crbug/1283516, crbug/1283523, etc.).

Fixed: chromium:1280831
Bug: chromium:1283162, chromium:1278650, chromium:1258599
Bug: chromium:1280803, chromium:1280832, chromium:1280818
Doc: https://bit.ly/v8-cheaper-inspector-stack-traces
Change-Id: I3dcec7b75d76ca267fac8bd6fcb2cda60d5e60dd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3364086Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78479}
parent cbdde6fb
......@@ -77,6 +77,8 @@ V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
m_continueToLocationBreakpointId(kNoBreakpointId),
m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
m_maxAsyncCallStackDepth(0),
m_maxCallStackSizeToCapture(
V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture),
m_pauseOnExceptionsState(v8::debug::NoBreakOnException) {}
V8Debugger::~V8Debugger() {
......@@ -361,7 +363,8 @@ Response V8Debugger::continueToLocation(
m_continueToLocationTargetCallFrames = targetCallFrames;
if (m_continueToLocationTargetCallFrames !=
protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
m_continueToLocationStack = captureStackTrace(true);
m_continueToLocationStack = V8StackTraceImpl::capture(
this, V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture);
DCHECK(m_continueToLocationStack);
}
continueProgram(targetContextGroupId);
......@@ -377,7 +380,8 @@ bool V8Debugger::shouldContinueToCurrentLocation() {
protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
return true;
}
std::unique_ptr<V8StackTraceImpl> currentStack = captureStackTrace(true);
std::unique_ptr<V8StackTraceImpl> currentStack = V8StackTraceImpl::capture(
this, V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture);
if (m_continueToLocationTargetCallFrames ==
protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Current) {
return m_continueToLocationStack->isEqualIgnoringTopFrame(
......@@ -817,8 +821,8 @@ v8::Local<v8::Array> V8Debugger::queryObjects(v8::Local<v8::Context> context,
std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
v8::Local<v8::StackTrace> v8StackTrace) {
return V8StackTraceImpl::create(this, v8StackTrace,
V8StackTraceImpl::maxCallStackSizeToCapture);
return V8StackTraceImpl::create(
this, v8StackTrace, V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture);
}
void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
......@@ -843,6 +847,44 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
maxAsyncCallStackDepth ? this : nullptr);
}
void V8Debugger::setMaxCallStackSizeToCapture(V8RuntimeAgentImpl* agent,
int size) {
if (size < 0) {
m_maxCallStackSizeToCaptureMap.erase(agent);
} else {
m_maxCallStackSizeToCaptureMap[agent] = size;
}
// The following logic is a bit complicated to decipher because we
// want to retain backwards compatible semantics:
//
// (a) When no `Runtime` domain is enabled, we stick to the default
// maximum call stack size, but don't let V8 collect stack traces
// for uncaught exceptions.
// (b) When `Runtime` is enabled for at least one front-end, we compute
// the maximum of the requested maximum call stack sizes of all the
// front-ends whose `Runtime` domains are enabled (which might be 0),
// and ask V8 to collect stack traces for uncaught exceptions.
//
// The latter allows performance test automation infrastructure to drive
// browser via `Runtime` domain while still minimizing the performance
// overhead of having the inspector attached - see the relevant design
// document https://bit.ly/v8-cheaper-inspector-stack-traces for more
if (m_maxCallStackSizeToCaptureMap.empty()) {
m_maxCallStackSizeToCapture =
V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture;
m_isolate->SetCaptureStackTraceForUncaughtExceptions(false);
} else {
m_maxCallStackSizeToCapture = 0;
for (auto const& pair : m_maxCallStackSizeToCaptureMap) {
if (m_maxCallStackSizeToCapture < pair.second)
m_maxCallStackSizeToCapture = pair.second;
}
m_isolate->SetCaptureStackTraceForUncaughtExceptions(
m_maxCallStackSizeToCapture > 0, m_maxCallStackSizeToCapture);
}
}
std::shared_ptr<AsyncStackTrace> V8Debugger::stackTraceFor(
int contextGroupId, const V8StackTraceId& id) {
if (debuggerIdFor(contextGroupId).pair() != id.debugger_id) return nullptr;
......@@ -860,8 +902,7 @@ V8StackTraceId V8Debugger::storeCurrentStackTrace(
if (!contextGroupId) return V8StackTraceId();
std::shared_ptr<AsyncStackTrace> asyncStack =
AsyncStackTrace::capture(this, toString16(description),
V8StackTraceImpl::maxCallStackSizeToCapture);
AsyncStackTrace::capture(this, toString16(description));
if (!asyncStack) return V8StackTraceId();
uintptr_t id = AsyncStackTrace::store(this, asyncStack);
......@@ -938,9 +979,8 @@ void V8Debugger::asyncTaskScheduledForStack(const StringView& taskName,
bool skipTopFrame) {
if (!m_maxAsyncCallStackDepth) return;
v8::HandleScope scope(m_isolate);
std::shared_ptr<AsyncStackTrace> asyncStack = AsyncStackTrace::capture(
this, toString16(taskName), V8StackTraceImpl::maxCallStackSizeToCapture,
skipTopFrame);
std::shared_ptr<AsyncStackTrace> asyncStack =
AsyncStackTrace::capture(this, toString16(taskName), skipTopFrame);
if (asyncStack) {
m_asyncTaskStacks[task] = asyncStack;
if (recurring) m_recurringTasks.insert(task);
......@@ -1044,20 +1084,17 @@ void V8Debugger::unmuteScriptParsedEvents() {
std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
bool fullStack) {
if (!m_isolate->InContext()) return nullptr;
v8::HandleScope handles(m_isolate);
int contextGroupId = currentContextGroupId();
if (!contextGroupId) return nullptr;
int stackSize = 1;
if (fullStack) {
stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
stackSize = V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture;
} else {
m_inspector->forEachSession(
contextGroupId, [&stackSize](V8InspectorSessionImpl* session) {
contextGroupId, [this, &stackSize](V8InspectorSessionImpl* session) {
if (session->runtimeAgent()->enabled())
stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
stackSize = maxCallStackSizeToCapture();
});
}
return V8StackTraceImpl::capture(this, stackSize);
......
......@@ -27,6 +27,7 @@ class StackFrame;
class V8Debugger;
class V8DebuggerAgentImpl;
class V8InspectorImpl;
class V8RuntimeAgentImpl;
class V8StackTraceImpl;
struct V8StackTraceId;
......@@ -85,6 +86,9 @@ class V8Debugger : public v8::debug::DebugDelegate,
int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; }
void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int);
int maxCallStackSizeToCapture() const { return m_maxCallStackSizeToCapture; }
void setMaxCallStackSizeToCapture(V8RuntimeAgentImpl*, int);
std::shared_ptr<AsyncStackTrace> currentAsyncParent();
V8StackTraceId currentExternalParent();
......@@ -248,6 +252,7 @@ class V8Debugger : public v8::debug::DebugDelegate,
size_t m_maxAsyncCallStacks;
int m_maxAsyncCallStackDepth;
int m_maxCallStackSizeToCapture;
std::vector<void*> m_currentTasks;
std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncParent;
......@@ -259,6 +264,7 @@ class V8Debugger : public v8::debug::DebugDelegate,
std::list<std::shared_ptr<AsyncStackTrace>> m_allAsyncStacks;
std::unordered_map<V8DebuggerAgentImpl*, int> m_maxAsyncCallStackDepthMap;
std::unordered_map<V8RuntimeAgentImpl*, int> m_maxCallStackSizeToCaptureMap;
void* m_taskWithScheduledBreak = nullptr;
// If any of the following three is true, we schedule pause on next JS
......
......@@ -62,7 +62,6 @@ V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate,
: m_isolate(isolate),
m_client(client),
m_debugger(new V8Debugger(isolate, this)),
m_capturingStackTracesCount(0),
m_lastExceptionId(0),
m_lastContextId(0),
m_isolateId(generateUniqueId()) {
......@@ -112,19 +111,6 @@ v8::MaybeLocal<v8::Script> V8InspectorImpl::compileScript(
v8::ScriptCompiler::kNoCompileOptions);
}
void V8InspectorImpl::enableStackCapturingIfNeeded() {
if (!m_capturingStackTracesCount)
V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
true);
++m_capturingStackTracesCount;
}
void V8InspectorImpl::disableStackCapturingIfNeeded() {
if (!(--m_capturingStackTracesCount))
V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
false);
}
void V8InspectorImpl::muteExceptions(int contextGroupId) {
m_muteExceptionsMap[contextGroupId]++;
}
......
......@@ -115,8 +115,6 @@ class V8InspectorImpl : public V8Inspector {
v8::Local<v8::Name> key, v8::Local<v8::Value> value) override;
unsigned nextExceptionId() { return ++m_lastExceptionId; }
void enableStackCapturingIfNeeded();
void disableStackCapturingIfNeeded();
void muteExceptions(int contextGroupId);
void unmuteExceptions(int contextGroupId);
V8ConsoleMessageStorage* ensureConsoleMessageStorage(int contextGroupId);
......@@ -160,7 +158,6 @@ class V8InspectorImpl : public V8Inspector {
v8::Global<v8::Context> m_regexContext;
v8::Global<v8::Context> m_exceptionMetaDataContext;
v8::Global<v8::debug::EphemeronTable> m_exceptionMetaData;
int m_capturingStackTracesCount;
unsigned m_lastExceptionId;
int m_lastContextId;
int m_lastSessionId = 0;
......
......@@ -145,15 +145,14 @@ std::unique_ptr<protocol::Profiler::Profile> createCPUProfile(
std::unique_ptr<protocol::Debugger::Location> currentDebugLocation(
V8InspectorImpl* inspector) {
std::unique_ptr<V8StackTraceImpl> callStack =
inspector->debugger()->captureStackTrace(false /* fullStack */);
auto location =
protocol::Debugger::Location::create()
.setScriptId(String16::fromInteger(callStack->topScriptId()))
.setLineNumber(callStack->topLineNumber())
.build();
location->setColumnNumber(callStack->topColumnNumber());
return location;
auto stackTrace = V8StackTraceImpl::capture(inspector->debugger(), 1);
CHECK(stackTrace);
CHECK(!stackTrace->isEmpty());
return protocol::Debugger::Location::create()
.setScriptId(String16::fromInteger(stackTrace->topScriptId()))
.setLineNumber(stackTrace->topLineNumber())
.setColumnNumber(stackTrace->topColumnNumber())
.build();
}
volatile int s_lastProfileId = 0;
......@@ -213,10 +212,9 @@ void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) {
std::unique_ptr<protocol::Profiler::Profile> profile =
stopProfiling(id, true);
if (!profile) return;
std::unique_ptr<protocol::Debugger::Location> location =
currentDebugLocation(m_session->inspector());
m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile),
resolvedTitle);
m_frontend.consoleProfileFinished(
id, currentDebugLocation(m_session->inspector()), std::move(profile),
resolvedTitle);
}
Response V8ProfilerAgentImpl::enable() {
......
......@@ -57,6 +57,7 @@ namespace v8_inspector {
namespace V8RuntimeAgentImplState {
static const char customObjectFormatterEnabled[] =
"customObjectFormatterEnabled";
static const char maxCallStackSizeToCapture[] = "maxCallStackSizeToCapture";
static const char runtimeEnabled[] = "runtimeEnabled";
static const char bindings[] = "bindings";
static const char globalBindingsKey[] = "";
......@@ -503,7 +504,9 @@ Response V8RuntimeAgentImpl::setMaxCallStackSizeToCapture(int size) {
TRACE_DISABLED_BY_DEFAULT("v8.inspector"),
"V8RuntimeAgentImpl::setMaxCallStackSizeToCapture", this,
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "size", size);
V8StackTraceImpl::maxCallStackSizeToCapture = size;
if (!m_enabled) return Response::ServerError("Runtime agent is not enabled");
m_state->setInteger(V8RuntimeAgentImplState::maxCallStackSizeToCapture, size);
m_inspector->debugger()->setMaxCallStackSizeToCapture(this, size);
return Response::Success();
}
......@@ -843,6 +846,11 @@ void V8RuntimeAgentImpl::restore() {
V8RuntimeAgentImplState::customObjectFormatterEnabled, false))
m_session->setCustomObjectFormatterEnabled(true);
int size;
if (m_state->getInteger(V8RuntimeAgentImplState::maxCallStackSizeToCapture,
&size))
m_inspector->debugger()->setMaxCallStackSizeToCapture(this, size);
m_inspector->forEachContext(
m_session->contextGroupId(),
[this](InspectedContext* context) { addBindings(context); });
......@@ -857,7 +865,8 @@ Response V8RuntimeAgentImpl::enable() {
m_session->contextGroupId());
m_enabled = true;
m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true);
m_inspector->enableStackCapturingIfNeeded();
m_inspector->debugger()->setMaxCallStackSizeToCapture(
this, V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture);
m_session->reportAllContexts(this);
V8ConsoleMessageStorage* storage =
m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
......@@ -875,7 +884,7 @@ Response V8RuntimeAgentImpl::disable() {
m_enabled = false;
m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false);
m_state->remove(V8RuntimeAgentImplState::bindings);
m_inspector->disableStackCapturingIfNeeded();
m_inspector->debugger()->setMaxCallStackSizeToCapture(this, -1);
m_session->setCustomObjectFormatterEnabled(false);
reset();
m_inspector->client()->endEnsureAllContextsInGroup(
......
......@@ -22,9 +22,6 @@ using v8_crdtp::json::ConvertCBORToJSON;
using v8_crdtp::json::ConvertJSONToCBOR;
namespace v8_inspector {
int V8StackTraceImpl::maxCallStackSizeToCapture = 200;
namespace {
static const char kId[] = "id";
......@@ -223,13 +220,6 @@ bool StackFrame::isEqual(StackFrame* frame) const {
m_columnNumber == frame->m_columnNumber;
}
// static
void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(
v8::Isolate* isolate, bool capture) {
isolate->SetCaptureStackTraceForUncaughtExceptions(
capture, V8StackTraceImpl::maxCallStackSizeToCapture);
}
// static
std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create(
V8Debugger* debugger, v8::Local<v8::StackTrace> v8StackTrace,
......@@ -402,10 +392,10 @@ StackFrame* V8StackTraceImpl::StackFrameIterator::frame() {
// static
std::shared_ptr<AsyncStackTrace> AsyncStackTrace::capture(
V8Debugger* debugger, const String16& description, int maxStackSize,
bool skipTopFrame) {
V8Debugger* debugger, const String16& description, bool skipTopFrame) {
DCHECK(debugger);
int maxStackSize = debugger->maxCallStackSizeToCapture();
TRACE_EVENT1(
TRACE_DISABLED_BY_DEFAULT("v8.inspector") "," TRACE_DISABLED_BY_DEFAULT(
"v8.stack_trace"),
......
......@@ -51,9 +51,8 @@ class StackFrame {
class V8StackTraceImpl : public V8StackTrace {
public:
static void setCaptureStackTraceForUncaughtExceptions(v8::Isolate*,
bool capture);
static int maxCallStackSizeToCapture;
static constexpr int kDefaultMaxCallStackSizeToCapture = 200;
static std::unique_ptr<V8StackTraceImpl> create(V8Debugger*,
v8::Local<v8::StackTrace>,
int maxStackSize);
......@@ -117,7 +116,6 @@ class AsyncStackTrace {
AsyncStackTrace& operator=(const AsyncStackTrace&) = delete;
static std::shared_ptr<AsyncStackTrace> capture(V8Debugger*,
const String16& description,
int maxStackSize,
bool skipTopFrame = false);
static uintptr_t store(V8Debugger* debugger,
std::shared_ptr<AsyncStackTrace> stack);
......
Checks that console messages before Runtime.enable include a single stack frame
Running test: testEnable
{
args : [
[0] : {
type : string
value : Error on toplevel
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 8
functionName :
lineNumber : 10
scriptId : <scriptId>
url : test.js
}
]
}
timestamp : <timestamp>
type : error
}
{
args : [
[0] : {
type : string
value : Hello from foo!
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : foo
lineNumber : 2
scriptId : <scriptId>
url : test.js
}
]
}
timestamp : <timestamp>
type : log
}
{
args : [
[0] : {
type : string
value : Hello from bar!
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : bar
lineNumber : 6
scriptId : <scriptId>
url : test.js
}
]
}
timestamp : <timestamp>
type : trace
}
{
args : [
[0] : {
type : string
value : Hello from foo!
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : foo
lineNumber : 2
scriptId : <scriptId>
url : test.js
}
]
}
timestamp : <timestamp>
type : log
}
Running test: testEnableAfterDiscard
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const {session, contextGroup, Protocol} = InspectorTest.start(
'Checks that console messages before Runtime.enable include a single stack frame');
contextGroup.addScript(`
function foo() {
console.log("Hello from foo!");
}
function bar() {
console.trace("Hello from bar!");
foo();
}
console.error('Error on toplevel');
foo();
bar();
//# sourceURL=test.js`);
Protocol.Runtime.onConsoleAPICalled(
({params}) => InspectorTest.logMessage(params));
InspectorTest.runAsyncTestSuite([
async function testEnable() {
await Protocol.Runtime.enable();
await Protocol.Runtime.disable();
},
async function testEnableAfterDiscard() {
await Protocol.Runtime.discardConsoleEntries();
await Protocol.Runtime.enable();
await Protocol.Runtime.disable();
}
]);
Checks Runtime.setMaxCallStackSizeToCapture.
Running test: testBeforeEnable
{
code : -32000
message : Runtime agent is not enabled
}
Running test: testNegativeSize
{
code : -32000
message : maxCallStackSizeToCapture should be non-negative
}
Running test: testConsoleLogBeforeEnable
{
args : [
[0] : {
type : string
value : Log message.
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : testConsoleLog
lineNumber : 2
scriptId : <scriptId>
url : test.js
}
]
}
timestamp : <timestamp>
type : log
}
Running test: testConsoleTrace
Test with max size 0.
{
args : [
......@@ -23,9 +61,9 @@ Test with max size 1.
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
columnNumber : 12
functionName : bar
lineNumber : 2
lineNumber : 7
scriptId : <scriptId>
url : test.js
}
......@@ -33,9 +71,9 @@ Test with max size 1.
parent : {
callFrames : [
[0] : {
columnNumber : 2
functionName : test
lineNumber : 10
columnNumber : 4
functionName : executor
lineNumber : 16
scriptId : <scriptId>
url : test.js
}
......@@ -58,16 +96,16 @@ Test with max size 2.
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
columnNumber : 12
functionName : bar
lineNumber : 2
lineNumber : 7
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 2
columnNumber : 4
functionName : foo
lineNumber : 6
lineNumber : 12
scriptId : <scriptId>
url : test.js
}
......@@ -75,18 +113,18 @@ Test with max size 2.
parent : {
callFrames : [
[0] : {
columnNumber : 2
functionName : test
lineNumber : 10
columnNumber : 4
functionName : executor
lineNumber : 16
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 0
functionName :
lineNumber : 0
columnNumber : 9
functionName : testConsoleTrace
lineNumber : 15
scriptId : <scriptId>
url : expr.js
url : test.js
}
]
description : setTimeout
......@@ -95,3 +133,79 @@ Test with max size 2.
timestamp : <timestamp>
type : trace
}
Running test: testException
Test with max size 0.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:23:11) at foo (test.js:27:5) at testThrow (test.js:30:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 22
scriptId : <scriptId>
text : Uncaught
}
Test with max size 1.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:23:11) at foo (test.js:27:5) at testThrow (test.js:30:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 22
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : bar
lineNumber : 22
scriptId : <scriptId>
url : test.js
}
]
}
text : Uncaught
}
Test with max size 2.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:23:11) at foo (test.js:27:5) at testThrow (test.js:30:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 22
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : bar
lineNumber : 22
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 4
functionName : foo
lineNumber : 26
scriptId : <scriptId>
url : test.js
}
]
}
text : Uncaught
}
......@@ -4,34 +4,98 @@
let {session, contextGroup, Protocol} = InspectorTest.start('Checks Runtime.setMaxCallStackSizeToCapture.');
Protocol.Runtime.enable();
Protocol.Runtime.onConsoleAPICalled(
message => InspectorTest.logMessage(message.params));
({params}) => InspectorTest.logMessage(params));
contextGroup.addScript(`
function bar() {
console.trace("Nested call.");
function testConsoleLog() {
console.log("Log message.");
}
function foo() {
bar();
function testConsoleTrace() {
function bar(callback) {
console.trace("Nested call.");
callback();
}
function foo(callback) {
bar(callback);
}
return new Promise(function executor(resolve) {
setTimeout(foo.bind(undefined, resolve), 0);
});
}
async function test() {
setTimeout(foo, 0);
function testThrow() {
function bar() {
throw new Error();
}
function foo() {
bar();
}
foo();
}
//# sourceURL=test.js`);
Protocol.Runtime.setAsyncCallStackDepth({maxDepth: 10});
(async function test() {
await Protocol.Runtime.setMaxCallStackSizeToCapture({size: 0});
InspectorTest.log('Test with max size 0.');
await Protocol.Runtime.evaluate({ expression: 'test()//# sourceURL=expr.js'});
await Protocol.Runtime.setMaxCallStackSizeToCapture({size: 1});
InspectorTest.log('Test with max size 1.');
await Protocol.Runtime.evaluate({ expression: 'test()//# sourceURL=expr.js'});
await Protocol.Runtime.setMaxCallStackSizeToCapture({size: 2});
InspectorTest.log('Test with max size 2.');
await Protocol.Runtime.evaluate({ expression: 'test()//# sourceURL=expr.js'});
InspectorTest.completeTest();
})();
InspectorTest.runAsyncTestSuite([
async function testBeforeEnable() {
const {error} =
await Protocol.Runtime.setMaxCallStackSizeToCapture({size: 0});
InspectorTest.logMessage(error);
},
async function testNegativeSize() {
await Protocol.Runtime.enable();
const {error} =
await Protocol.Runtime.setMaxCallStackSizeToCapture({size: -42});
InspectorTest.logMessage(error);
await Protocol.Runtime.disable();
},
async function testConsoleLogBeforeEnable() {
await Protocol.Runtime.evaluate({expression: 'testConsoleLog()'});
await Protocol.Runtime.enable();
await Promise.all([
Protocol.Runtime.discardConsoleEntries(),
Protocol.Runtime.disable(),
]);
},
async function testConsoleTrace() {
await Promise.all([
Protocol.Runtime.enable(),
Protocol.Runtime.setAsyncCallStackDepth({maxDepth: 10}),
]);
for (let size = 0; size <= 2; ++size) {
await Protocol.Runtime.setMaxCallStackSizeToCapture({size});
InspectorTest.log(`Test with max size ${size}.`);
await Protocol.Runtime.evaluate(
{expression: 'testConsoleTrace()', awaitPromise: true});
}
await Promise.all([
Protocol.Runtime.discardConsoleEntries(),
Protocol.Runtime.disable(),
]);
},
async function testException() {
await Promise.all([
Protocol.Runtime.enable(),
Protocol.Runtime.setAsyncCallStackDepth({maxDepth: 0}),
]);
for (let size = 0; size <= 2; ++size) {
await Protocol.Runtime.setMaxCallStackSizeToCapture({size});
InspectorTest.log(`Test with max size ${size}.`);
const {result: {exceptionDetails}} =
await Protocol.Runtime.evaluate({expression: 'testThrow()'});
InspectorTest.logMessage(exceptionDetails);
}
await Promise.all([
Protocol.Runtime.discardConsoleEntries(),
Protocol.Runtime.disable(),
]);
}
])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment