[inspector] Report exceptionMetaData for Runtime#getExceptionDetails

The ExceptionDetails structure allows the association of requests and
issues with JavaScript errors. These are currently only reported
when an exception goes through `Runtime#exceptionThrown`, but we
also want the metadata available when the ExceptionDetails are
requested explicitly for any Error object.

R=bmeurer@chromium.org

Bug: chromium:1280141
Change-Id: I1b1514207b9e146fda3452c3f7991cd7dc9a387b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3477098
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79199}
This commit is contained in:
Simon Zünd 2022-02-21 13:47:15 +01:00 committed by V8 LUCI CQ
parent 6892cdf8ae
commit 17536f94d6
6 changed files with 90 additions and 16 deletions

View File

@ -396,23 +396,11 @@ V8ConsoleMessage::getAssociatedExceptionData(
v8::Isolate* isolate = inspector->isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context;
if (!inspector->exceptionMetaDataContext().ToLocal(&context)) return nullptr;
v8::MaybeLocal<v8::Value> maybe_exception = m_arguments[0]->Get(isolate);
v8::Local<v8::Value> exception;
if (!maybe_exception.ToLocal(&exception)) return nullptr;
v8::MaybeLocal<v8::Object> maybe_data =
inspector->getAssociatedExceptionData(exception);
v8::Local<v8::Object> data;
if (!maybe_data.ToLocal(&data)) return nullptr;
v8::TryCatch tryCatch(isolate);
v8::MicrotasksScope microtasksScope(isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Context::Scope contextScope(context);
std::unique_ptr<protocol::DictionaryValue> jsonObject;
objectToProtocolValue(context, data, 2, &jsonObject);
return jsonObject;
return inspector->getAssociatedExceptionDataForProtocol(exception);
}
std::unique_ptr<protocol::Runtime::RemoteObject>

View File

@ -50,6 +50,7 @@
#include "src/inspector/v8-profiler-agent-impl.h"
#include "src/inspector/v8-runtime-agent-impl.h"
#include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/value-mirror.h"
namespace v8_inspector {
@ -518,4 +519,24 @@ v8::MaybeLocal<v8::Object> V8InspectorImpl::getAssociatedExceptionData(
return v8::MaybeLocal<v8::Object>();
return scope.Escape(object.As<v8::Object>());
}
std::unique_ptr<protocol::DictionaryValue>
V8InspectorImpl::getAssociatedExceptionDataForProtocol(
v8::Local<v8::Value> exception) {
v8::MaybeLocal<v8::Object> maybeData = getAssociatedExceptionData(exception);
v8::Local<v8::Object> data;
if (!maybeData.ToLocal(&data)) return nullptr;
v8::Local<v8::Context> context;
if (!exceptionMetaDataContext().ToLocal(&context)) return nullptr;
v8::TryCatch tryCatch(m_isolate);
v8::MicrotasksScope microtasksScope(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Context::Scope contextScope(context);
std::unique_ptr<protocol::DictionaryValue> jsonObject;
objectToProtocolValue(context, data, 2, &jsonObject);
return jsonObject;
}
} // namespace v8_inspector

View File

@ -134,6 +134,8 @@ class V8InspectorImpl : public V8Inspector {
int64_t generateUniqueId();
V8_EXPORT_PRIVATE v8::MaybeLocal<v8::Object> getAssociatedExceptionData(
v8::Local<v8::Value> exception);
std::unique_ptr<protocol::DictionaryValue>
getAssociatedExceptionDataForProtocol(v8::Local<v8::Value> exception);
class EvaluateScope {
public:

View File

@ -834,6 +834,13 @@ Response V8RuntimeAgentImpl::getExceptionDetails(
// Lets use the normal message text instead.
out_exceptionDetails->fromJust()->setText(
toProtocolString(m_inspector->isolate(), message->Get()));
// Check if the exception has any metadata on the inspector and also attach
// it.
std::unique_ptr<protocol::DictionaryValue> data =
m_inspector->getAssociatedExceptionDataForProtocol(error);
if (data)
out_exceptionDetails->fromJust()->setExceptionMetaData(std::move(data));
return Response::Success();
}

View File

@ -68,3 +68,45 @@ Running test: itShouldReportAnErrorForNonJSErrorObjects
}
id : <messageId>
}
Running test: itShouldIncludeMetaData
{
id : <messageId>
result : {
exceptionDetails : {
columnNumber : 9
exception : {
className : Error
description : Error: myerror at foo (<anonymous>:3:10) at <anonymous>:5:1
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
exceptionMetaData : {
foo : bar
}
lineNumber : 2
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 9
functionName : foo
lineNumber : 2
scriptId : <scriptId>
url :
}
[1] : {
columnNumber : 0
functionName :
lineNumber : 4
scriptId : <scriptId>
url :
}
]
}
text : Error: myerror
}
}
}

View File

@ -12,6 +12,13 @@ function foo() {
foo();
`;
const expressionWithMeta = `
function foo() {
return new inspector.newExceptionWithMetaData('myerror', 'foo', 'bar');
}
foo();
`;
InspectorTest.runAsyncTestSuite([
async function itShouldReturnExceptionDetailsForJSErrorObjects() {
await Protocol.Runtime.enable(); // Enable detailed stacktrace capturing.
@ -31,5 +38,12 @@ InspectorTest.runAsyncTestSuite([
const {result} = await Protocol.Runtime.evaluate({expression: '() =>({})'});
InspectorTest.logMessage(await Protocol.Runtime.getExceptionDetails(
{errorObjectId: result.result.objectId}));
},
async function itShouldIncludeMetaData() {
await Protocol.Runtime.enable(); // Enable detailed stacktrace capturing.
const {result} = await Protocol.Runtime.evaluate({expression: expressionWithMeta});
InspectorTest.logMessage(await Protocol.Runtime.getExceptionDetails(
{errorObjectId: result.result.objectId}));
}
]);