Commit 0206ad77 authored by Yury Semikhatsky's avatar Yury Semikhatsky Committed by Commit Bot

Ignore returnByValue when serializing caught value in promise rejections.

Since the same value is also returned in 'result' field it is still populated in accord with 'returnByValue' parameter. This behavior is consistent with 'evaluate'.

R=dgozman@chromium.org, lushnikov@chromium.org

Bug: v8:9509
Change-Id: I9f72682f87492ce5cd0759dce75ab3d75a5fe31c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1707331Reviewed-by: 's avatarDmitry Gozman <dgozman@chromium.org>
Commit-Queue: Yury Semikhatsky <yurys@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63134}
parent 37648d73
...@@ -50,8 +50,8 @@ ...@@ -50,8 +50,8 @@
namespace v8_inspector { namespace v8_inspector {
namespace { namespace {
static const char kGlobalHandleLabel[] = "DevTools console"; const char kGlobalHandleLabel[] = "DevTools console";
static bool isResolvableNumberLike(String16 query) { bool isResolvableNumberLike(String16 query) {
return query == "Infinity" || query == "-Infinity" || query == "NaN"; return query == "Infinity" || query == "-Infinity" || query == "NaN";
} }
} // namespace } // namespace
...@@ -220,8 +220,13 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -220,8 +220,13 @@ class InjectedScript::ProtocolPromiseHandler {
: 0) : 0)
.setColumnNumber( .setColumnNumber(
stack && !stack->isEmpty() ? stack->topColumnNumber() : 0) stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
.setException(wrappedValue->clone())
.build(); .build();
response = scope.injectedScript()->addExceptionToDetails(
result, exceptionDetails.get(), m_objectGroup);
if (!response.isSuccess()) {
callback->sendFailure(response);
return;
}
if (stack) if (stack)
exceptionDetails->setStackTrace( exceptionDetails->setStackTrace(
stack->buildInspectorObjectImpl(m_inspector->debugger())); stack->buildInspectorObjectImpl(m_inspector->debugger()));
...@@ -289,8 +294,7 @@ Response InjectedScript::getProperties( ...@@ -289,8 +294,7 @@ Response InjectedScript::getProperties(
PropertyAccumulator accumulator(&mirrors); PropertyAccumulator accumulator(&mirrors);
if (!ValueMirror::getProperties(context, object, ownProperties, if (!ValueMirror::getProperties(context, object, ownProperties,
accessorPropertiesOnly, &accumulator)) { accessorPropertiesOnly, &accumulator)) {
return createExceptionDetails(tryCatch, groupName, wrapMode, return createExceptionDetails(tryCatch, groupName, exceptionDetails);
exceptionDetails);
} }
for (const PropertyMirror& mirror : mirrors) { for (const PropertyMirror& mirror : mirrors) {
std::unique_ptr<PropertyDescriptor> descriptor = std::unique_ptr<PropertyDescriptor> descriptor =
...@@ -632,9 +636,25 @@ Response InjectedScript::resolveCallArgument( ...@@ -632,9 +636,25 @@ Response InjectedScript::resolveCallArgument(
return Response::OK(); return Response::OK();
} }
Response InjectedScript::addExceptionToDetails(
v8::Local<v8::Value> exception,
protocol::Runtime::ExceptionDetails* exceptionDetails,
const String16& objectGroup) {
if (exception.IsEmpty()) return Response::OK();
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
Response response =
wrapObject(exception, objectGroup,
exception->IsNativeError() ? WrapMode::kNoPreview
: WrapMode::kWithPreview,
&wrapped);
if (!response.isSuccess()) return response;
exceptionDetails->setException(std::move(wrapped));
return Response::OK();
}
Response InjectedScript::createExceptionDetails( Response InjectedScript::createExceptionDetails(
const v8::TryCatch& tryCatch, const String16& objectGroup, const v8::TryCatch& tryCatch, const String16& objectGroup,
WrapMode wrapMode, Maybe<protocol::Runtime::ExceptionDetails>* result) { Maybe<protocol::Runtime::ExceptionDetails>* result) {
if (!tryCatch.HasCaught()) return Response::InternalError(); if (!tryCatch.HasCaught()) return Response::InternalError();
v8::Local<v8::Message> message = tryCatch.Message(); v8::Local<v8::Message> message = tryCatch.Message();
v8::Local<v8::Value> exception = tryCatch.Exception(); v8::Local<v8::Value> exception = tryCatch.Exception();
...@@ -667,16 +687,9 @@ Response InjectedScript::createExceptionDetails( ...@@ -667,16 +687,9 @@ Response InjectedScript::createExceptionDetails(
->createStackTrace(stackTrace) ->createStackTrace(stackTrace)
->buildInspectorObjectImpl(m_context->inspector()->debugger())); ->buildInspectorObjectImpl(m_context->inspector()->debugger()));
} }
if (!exception.IsEmpty()) { Response response =
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped; addExceptionToDetails(exception, exceptionDetails.get(), objectGroup);
Response response = if (!response.isSuccess()) return response;
wrapObject(exception, objectGroup,
exception->IsNativeError() ? WrapMode::kNoPreview
: WrapMode::kWithPreview,
&wrapped);
if (!response.isSuccess()) return response;
exceptionDetails->setException(std::move(wrapped));
}
*result = std::move(exceptionDetails); *result = std::move(exceptionDetails);
return Response::OK(); return Response::OK();
} }
...@@ -709,8 +722,7 @@ Response InjectedScript::wrapEvaluateResult( ...@@ -709,8 +722,7 @@ Response InjectedScript::wrapEvaluateResult(
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
// We send exception in result for compatibility reasons, even though it's // We send exception in result for compatibility reasons, even though it's
// accessible through exceptionDetails.exception. // accessible through exceptionDetails.exception.
response = createExceptionDetails(tryCatch, objectGroup, wrapMode, response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails);
exceptionDetails);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
} }
return Response::OK(); return Response::OK();
......
...@@ -117,7 +117,7 @@ class InjectedScript final { ...@@ -117,7 +117,7 @@ class InjectedScript final {
v8::Local<v8::Value>* result); v8::Local<v8::Value>* result);
Response createExceptionDetails( Response createExceptionDetails(
const v8::TryCatch&, const String16& groupName, WrapMode wrapMode, const v8::TryCatch&, const String16& groupName,
Maybe<protocol::Runtime::ExceptionDetails>* result); Maybe<protocol::Runtime::ExceptionDetails>* result);
Response wrapEvaluateResult( Response wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&, v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&,
...@@ -219,6 +219,10 @@ class InjectedScript final { ...@@ -219,6 +219,10 @@ class InjectedScript final {
void discardEvaluateCallbacks(); void discardEvaluateCallbacks();
std::unique_ptr<EvaluateCallback> takeEvaluateCallback( std::unique_ptr<EvaluateCallback> takeEvaluateCallback(
EvaluateCallback* callback); EvaluateCallback* callback);
Response addExceptionToDetails(
v8::Local<v8::Value> exception,
protocol::Runtime::ExceptionDetails* exceptionDetails,
const String16& objectGroup);
InspectedContext* m_context; InspectedContext* m_context;
int m_sessionId; int m_sessionId;
......
...@@ -490,7 +490,7 @@ Response V8RuntimeAgentImpl::compileScript( ...@@ -490,7 +490,7 @@ Response V8RuntimeAgentImpl::compileScript(
if (!isOk) { if (!isOk) {
if (scope.tryCatch().HasCaught()) { if (scope.tryCatch().HasCaught()) {
response = scope.injectedScript()->createExceptionDetails( response = scope.injectedScript()->createExceptionDetails(
scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails); scope.tryCatch(), String16(), exceptionDetails);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
return Response::OK(); return Response::OK();
} else { } else {
......
...@@ -19,10 +19,22 @@ Running test: testRejectedPromise ...@@ -19,10 +19,22 @@ Running test: testRejectedPromise
exceptionDetails : { exceptionDetails : {
columnNumber : 0 columnNumber : 0
exception : { exception : {
type : object className : Object
value : { description : Object
a : 1 objectId : <objectId>
preview : {
description : Object
overflow : false
properties : [
[0] : {
name : a
type : number
value : 1
}
]
type : object
} }
type : object
} }
exceptionId : <exceptionId> exceptionId : <exceptionId>
lineNumber : 0 lineNumber : 0
......
...@@ -166,10 +166,22 @@ Running test: testFunctionReturnRejectedPromise ...@@ -166,10 +166,22 @@ Running test: testFunctionReturnRejectedPromise
exceptionDetails : { exceptionDetails : {
columnNumber : 0 columnNumber : 0
exception : { exception : {
type : object className : Object
value : { description : Object
a : 3 objectId : <objectId>
preview : {
description : Object
overflow : false
properties : [
[0] : {
name : a
type : number
value : 3
}
]
type : object
} }
type : object
} }
exceptionId : <exceptionId> exceptionId : <exceptionId>
lineNumber : 0 lineNumber : 0
...@@ -204,3 +216,75 @@ Running test: testPassingBothObjectIdAndExecutionContextId ...@@ -204,3 +216,75 @@ Running test: testPassingBothObjectIdAndExecutionContextId
} }
id : <messageId> id : <messageId>
} }
Running test: testThrowNumber
{
id : <messageId>
result : {
exceptionDetails : {
columnNumber : 10
exception : {
description : 100500
type : number
value : 100500
}
exceptionId : <exceptionId>
lineNumber : 0
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 10
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
}
text : Uncaught
}
result : {
description : 100500
type : number
value : 100500
}
}
}
Running test: testAsyncFunctionWithUnknownReferenceReturnByValue
{
id : <messageId>
result : {
exceptionDetails : {
columnNumber : 30
exception : {
className : ReferenceError
description : ReferenceError: does_not_exist is not defined at <anonymous>:1:30
objectId : <objectId>
subtype : error
type : object
}
exceptionId : <exceptionId>
lineNumber : 1
scriptId : <scriptId>
stackTrace : {
callFrames : [
[0] : {
columnNumber : 29
functionName :
lineNumber : 0
scriptId : <scriptId>
url :
}
]
}
text : Uncaught (in promise) ReferenceError: does_not_exist is not defined
}
result : {
type : object
value : {
}
}
}
}
...@@ -146,6 +146,28 @@ let testSuite = [ ...@@ -146,6 +146,28 @@ let testSuite = [
awaitPromise: false awaitPromise: false
})); }));
}, },
async function testThrowNumber() {
InspectorTest.logMessage(await callFunctionOn({
executionContextId,
functionDeclaration: '(() => { throw 100500; } )',
arguments: prepareArguments([]),
returnByValue: true,
generatePreview: false,
awaitPromise: true
}));
},
async function testAsyncFunctionWithUnknownReferenceReturnByValue() {
InspectorTest.logMessage(await callFunctionOn({
executionContextId,
functionDeclaration: '(async () => does_not_exist.click())',
arguments: prepareArguments([]),
returnByValue: true,
generatePreview: false,
awaitPromise: true
}));
},
]; ];
function prepareArguments(args) { function prepareArguments(args) {
......
...@@ -172,10 +172,22 @@ Running test: testAwaitRejectedPromise ...@@ -172,10 +172,22 @@ Running test: testAwaitRejectedPromise
exceptionDetails : { exceptionDetails : {
columnNumber : 0 columnNumber : 0
exception : { exception : {
type : object className : Object
value : { description : Object
a : 1 objectId : <objectId>
preview : {
description : Object
overflow : false
properties : [
[0] : {
name : a
type : number
value : 1
}
]
type : object
} }
type : object
} }
exceptionId : <exceptionId> exceptionId : <exceptionId>
lineNumber : 0 lineNumber : 0
......
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