[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.

Bug: chromium:1283162, chromium:1278650, chromium:1258599
Bug: chromium:1280803, chromium:1280832, chromium:1280818
Fixed: chromium:1280831
Doc: https://bit.ly/v8-cheaper-inspector-stack-traces
Change-Id: I4ec951a858317fa49096cd4023deb0104d92c9c9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3361839
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78458}
This commit is contained in:
Benedikt Meurer 2021-12-31 14:55:20 +01:00 committed by V8 LUCI CQ
parent d6681cd4a3
commit 34f73cc759
11 changed files with 322 additions and 100 deletions

View File

@ -100,12 +100,15 @@ class ConsoleHelper {
void reportCall(ConsoleAPIType type,
const std::vector<v8::Local<v8::Value>>& arguments) {
if (!m_groupId) return;
auto stackTrace = V8StackTraceImpl::capture(
m_inspector->debugger(),
m_inspector->debugger()->maxCallStackSizeToCapture());
std::unique_ptr<V8ConsoleMessage> message =
V8ConsoleMessage::createForConsoleAPI(
m_context, m_contextId, m_groupId, m_inspector,
m_inspector->client()->currentTimeMS(), type, arguments,
consoleContextToString(m_isolate, m_consoleContext),
m_inspector->debugger()->captureStackTrace(false));
std::move(stackTrace));
consoleMessageStorage()->addMessage(std::move(message));
}

View File

@ -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() {
@ -817,8 +819,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 +845,45 @@ 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
// information
if (m_maxCallStackSizeToCaptureMap.empty()) {
m_maxAsyncCallStackDepth =
V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture;
m_isolate->SetCaptureStackTraceForUncaughtExceptions(false, 0);
} 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 +901,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 +978,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 +1083,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) {
if (session->runtimeAgent()->enabled())
stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
stackSize = V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture;
});
}
return V8StackTraceImpl::capture(this, stackSize);

View File

@ -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

View File

@ -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]++;
}

View File

@ -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;

View File

@ -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() {

View File

@ -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[] = "";
@ -499,7 +500,9 @@ Response V8RuntimeAgentImpl::setMaxCallStackSizeToCapture(int size) {
return Response::ServerError(
"maxCallStackSizeToCapture should be non-negative");
}
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();
}
@ -839,6 +842,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); });
@ -850,7 +858,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());
@ -865,7 +874,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(

View File

@ -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";
@ -221,13 +218,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,
@ -398,10 +388,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.stack_trace"),
"AsyncStackTrace::capture", "maxFrameCount", maxStackSize);

View File

@ -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);

View File

@ -1,4 +1,6 @@
Checks Runtime.setMaxCallStackSizeToCapture.
Running test: testConsoleTrace
Test with max size 0.
{
args : [
@ -23,9 +25,9 @@ Test with max size 1.
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
columnNumber : 12
functionName : bar
lineNumber : 2
lineNumber : 3
scriptId : <scriptId>
url : test.js
}
@ -33,9 +35,9 @@ Test with max size 1.
parent : {
callFrames : [
[0] : {
columnNumber : 2
functionName : test
lineNumber : 10
columnNumber : 4
functionName : executor
lineNumber : 12
scriptId : <scriptId>
url : test.js
}
@ -58,16 +60,16 @@ Test with max size 2.
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
columnNumber : 12
functionName : bar
lineNumber : 2
lineNumber : 3
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 2
columnNumber : 4
functionName : foo
lineNumber : 6
lineNumber : 8
scriptId : <scriptId>
url : test.js
}
@ -75,18 +77,18 @@ Test with max size 2.
parent : {
callFrames : [
[0] : {
columnNumber : 2
functionName : test
lineNumber : 10
columnNumber : 4
functionName : executor
lineNumber : 12
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 0
functionName :
lineNumber : 0
columnNumber : 9
functionName : testConsoleTrace
lineNumber : 11
scriptId : <scriptId>
url : expr.js
url : test.js
}
]
description : setTimeout
@ -95,3 +97,172 @@ Test with max size 2.
timestamp : <timestamp>
type : trace
}
Running test: testException
{
args : [
[0] : {
type : string
value : Nested call.
}
]
executionContextId : <executionContextId>
timestamp : <timestamp>
type : trace
}
{
args : [
[0] : {
type : string
value : Nested call.
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 12
functionName : bar
lineNumber : 3
scriptId : <scriptId>
url : test.js
}
]
parent : {
callFrames : [
[0] : {
columnNumber : 4
functionName : executor
lineNumber : 12
scriptId : <scriptId>
url : test.js
}
]
description : setTimeout
}
}
timestamp : <timestamp>
type : trace
}
{
args : [
[0] : {
type : string
value : Nested call.
}
]
executionContextId : <executionContextId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 12
functionName : bar
lineNumber : 3
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 4
functionName : foo
lineNumber : 8
scriptId : <scriptId>
url : test.js
}
]
parent : {
callFrames : [
[0] : {
columnNumber : 4
functionName : executor
lineNumber : 12
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 9
functionName : testConsoleTrace
lineNumber : 11
scriptId : <scriptId>
url : test.js
}
]
description : setTimeout
}
}
timestamp : <timestamp>
type : trace
}
Test with max size 0.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:19:11) at foo (test.js:23:5) at testThrow (test.js:26:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 18
scriptId : <scriptId>
text : Uncaught
}
Test with max size 1.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:19:11) at foo (test.js:23:5) at testThrow (test.js:26:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 18
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : bar
lineNumber : 18
scriptId : <scriptId>
url : test.js
}
]
}
text : Uncaught
}
Test with max size 2.
{
columnNumber : 4
exception : {
className : Error
description : Error at bar (test.js:19:11) at foo (test.js:23:5) at testThrow (test.js:26:3) at <anonymous>:1:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 18
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName : bar
lineNumber : 18
scriptId : <scriptId>
url : test.js
}
[1] : {
columnNumber : 4
functionName : foo
lineNumber : 22
scriptId : <scriptId>
url : test.js
}
]
}
text : Uncaught
}

View File

@ -4,34 +4,62 @@
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 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);
});
}
function foo() {
bar();
}
function testThrow() {
function bar() {
throw new Error();
}
async function test() {
setTimeout(foo, 0);
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 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 Protocol.Runtime.disable();
},
async function testException() {
await Protocol.Runtime.enable();
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 Protocol.Runtime.disable();
}
])