Commit 379331b7 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[debugger] Don't attach source positions to implicit returns.

Previously we'd attach source positions to implicit returns that are
generated when leaving an async function with a promise rejection. This
was due to the use of `kNoSourcePosition` on the `end_position` in the
`ReturnStatement` nodes as indicator to pick the return position from
the function literal, instead of really not putting a source position on
that specific `Return` bytecode.

This CL adds a dedicated marker to `ReturnStatement` to express that the
`BytecodeGenerator` should put the return position from the function
literal there instead of overloading the meaning of `kNoSourcePosition`.

Bug: chromium:901819, chromium:782461
Fixed: chromium:1199919, chromium:1201706
Change-Id: I3647e0c3d711e9c3d6ae44606b70ec92ad82e1cf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2859945
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74301}
parent 78dbc143
...@@ -629,6 +629,11 @@ class ReturnStatement final : public JumpStatement { ...@@ -629,6 +629,11 @@ class ReturnStatement final : public JumpStatement {
return type() == kSyntheticAsyncReturn; return type() == kSyntheticAsyncReturn;
} }
// This constant is used to indicate that the return position
// from the FunctionLiteral should be used when emitting code.
static constexpr int kFunctionLiteralReturnPosition = -2;
STATIC_ASSERT(kFunctionLiteralReturnPosition == kNoSourcePosition - 1);
int end_position() const { return end_position_; } int end_position() const { return end_position_; }
private: private:
...@@ -2857,20 +2862,22 @@ class AstNodeFactory final { ...@@ -2857,20 +2862,22 @@ class AstNodeFactory final {
return zone_->New<BreakStatement>(target, pos); return zone_->New<BreakStatement>(target, pos);
} }
ReturnStatement* NewReturnStatement(Expression* expression, int pos, ReturnStatement* NewReturnStatement(
int end_position = kNoSourcePosition) { Expression* expression, int pos,
int end_position = ReturnStatement::kFunctionLiteralReturnPosition) {
return zone_->New<ReturnStatement>(expression, ReturnStatement::kNormal, return zone_->New<ReturnStatement>(expression, ReturnStatement::kNormal,
pos, end_position); pos, end_position);
} }
ReturnStatement* NewAsyncReturnStatement( ReturnStatement* NewAsyncReturnStatement(Expression* expression, int pos,
Expression* expression, int pos, int end_position = kNoSourcePosition) { int end_position) {
return zone_->New<ReturnStatement>( return zone_->New<ReturnStatement>(
expression, ReturnStatement::kAsyncReturn, pos, end_position); expression, ReturnStatement::kAsyncReturn, pos, end_position);
} }
ReturnStatement* NewSyntheticAsyncReturnStatement( ReturnStatement* NewSyntheticAsyncReturnStatement(
Expression* expression, int pos, int end_position = kNoSourcePosition) { Expression* expression, int pos,
int end_position = ReturnStatement::kFunctionLiteralReturnPosition) {
return zone_->New<ReturnStatement>( return zone_->New<ReturnStatement>(
expression, ReturnStatement::kSyntheticAsyncReturn, pos, end_position); expression, ReturnStatement::kSyntheticAsyncReturn, pos, end_position);
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/api/api-inl.h" #include "src/api/api-inl.h"
#include "src/ast/ast-source-ranges.h" #include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
#include "src/builtins/builtins-constructor.h" #include "src/builtins/builtins-constructor.h"
#include "src/codegen/compiler.h" #include "src/codegen/compiler.h"
...@@ -1774,7 +1775,7 @@ void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { ...@@ -1774,7 +1775,7 @@ void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
VisitForAccumulatorValue(stmt->expression()); VisitForAccumulatorValue(stmt->expression());
int return_position = stmt->end_position(); int return_position = stmt->end_position();
if (return_position == kNoSourcePosition) { if (return_position == ReturnStatement::kFunctionLiteralReturnPosition) {
return_position = info()->literal()->return_position(); return_position = info()->literal()->return_position();
} }
if (stmt->is_async_return()) { if (stmt->is_async_return()) {
......
...@@ -1452,8 +1452,9 @@ class ParserBase { ...@@ -1452,8 +1452,9 @@ class ParserBase {
// Convenience method which determines the type of return statement to emit // Convenience method which determines the type of return statement to emit
// depending on the current function type. // depending on the current function type.
inline StatementT BuildReturnStatement(ExpressionT expr, int pos, inline StatementT BuildReturnStatement(
int end_pos = kNoSourcePosition) { ExpressionT expr, int pos,
int end_pos = ReturnStatement::kFunctionLiteralReturnPosition) {
if (impl()->IsNull(expr)) { if (impl()->IsNull(expr)) {
expr = factory()->NewUndefinedLiteral(kNoSourcePosition); expr = factory()->NewUndefinedLiteral(kNoSourcePosition);
} else if (is_async_generator()) { } else if (is_async_generator()) {
......
...@@ -751,8 +751,8 @@ void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info, ...@@ -751,8 +751,8 @@ void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
kNoSourcePosition, FunctionSyntaxKind::kWrapped, LanguageMode::kSloppy, kNoSourcePosition, FunctionSyntaxKind::kWrapped, LanguageMode::kSloppy,
arguments_for_wrapped_function); arguments_for_wrapped_function);
Statement* return_statement = factory()->NewReturnStatement( Statement* return_statement =
function_literal, kNoSourcePosition, kNoSourcePosition); factory()->NewReturnStatement(function_literal, kNoSourcePosition);
body->Add(return_statement); body->Add(return_statement);
} }
...@@ -2011,8 +2011,8 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody( ...@@ -2011,8 +2011,8 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
Expression* reject_call = factory()->NewCallRuntime( Expression* reject_call = factory()->NewCallRuntime(
Runtime::kInlineAsyncGeneratorReject, reject_args, kNoSourcePosition); Runtime::kInlineAsyncGeneratorReject, reject_args, kNoSourcePosition);
catch_block = IgnoreCompletion( catch_block = IgnoreCompletion(factory()->NewReturnStatement(
factory()->NewReturnStatement(reject_call, kNoSourcePosition)); reject_call, kNoSourcePosition, kNoSourcePosition));
} }
{ {
...@@ -2878,8 +2878,8 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block, ...@@ -2878,8 +2878,8 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block,
reject_promise = factory()->NewCallRuntime( reject_promise = factory()->NewCallRuntime(
Runtime::kInlineAsyncFunctionReject, args, kNoSourcePosition); Runtime::kInlineAsyncFunctionReject, args, kNoSourcePosition);
} }
Block* catch_block = IgnoreCompletion( Block* catch_block = IgnoreCompletion(factory()->NewReturnStatement(
factory()->NewReturnStatement(reject_promise, kNoSourcePosition)); reject_promise, kNoSourcePosition, kNoSourcePosition));
// Treat the exception for REPL mode scripts as UNCAUGHT. This will // Treat the exception for REPL mode scripts as UNCAUGHT. This will
// keep the corresponding JSMessageObject alive on the Isolate. The // keep the corresponding JSMessageObject alive on the Isolate. The
......
...@@ -67,7 +67,7 @@ bytecodes: [ ...@@ -67,7 +67,7 @@ bytecodes: [
B(Star6), B(Star6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3),
/* 10 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [20], Smi [20],
...@@ -142,7 +142,7 @@ bytecodes: [ ...@@ -142,7 +142,7 @@ bytecodes: [
B(Star6), B(Star6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3),
/* 21 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [20], Smi [20],
...@@ -223,7 +223,7 @@ bytecodes: [ ...@@ -223,7 +223,7 @@ bytecodes: [
B(Star7), B(Star7),
B(Mov), R(0), R(5), B(Mov), R(0), R(5),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3),
/* 54 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [27], Smi [27],
...@@ -305,7 +305,7 @@ bytecodes: [ ...@@ -305,7 +305,7 @@ bytecodes: [
B(Star7), B(Star7),
B(Mov), R(0), R(5), B(Mov), R(0), R(5),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3),
/* 49 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [30], Smi [30],
......
...@@ -141,7 +141,7 @@ bytecodes: [ ...@@ -141,7 +141,7 @@ bytecodes: [
B(Star8), B(Star8),
B(Mov), R(0), R(6), B(Mov), R(0), R(6),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3),
/* 57 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [85], Smi [85],
...@@ -303,7 +303,7 @@ bytecodes: [ ...@@ -303,7 +303,7 @@ bytecodes: [
B(Star8), B(Star8),
B(Mov), R(0), R(6), B(Mov), R(0), R(6),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3),
/* 68 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [85], Smi [85],
...@@ -469,7 +469,7 @@ bytecodes: [ ...@@ -469,7 +469,7 @@ bytecodes: [
B(Star8), B(Star8),
B(Mov), R(0), R(6), B(Mov), R(0), R(6),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3),
/* 114 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [85], Smi [85],
...@@ -599,7 +599,7 @@ bytecodes: [ ...@@ -599,7 +599,7 @@ bytecodes: [
B(Star6), B(Star6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3),
/* 96 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
OBJECT_BOILERPLATE_DESCRIPTION_TYPE, OBJECT_BOILERPLATE_DESCRIPTION_TYPE,
......
...@@ -726,7 +726,7 @@ bytecodes: [ ...@@ -726,7 +726,7 @@ bytecodes: [
B(Star9), B(Star9),
B(Mov), R(0), R(7), B(Mov), R(0), R(7),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(7), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(7), U8(3),
/* 60 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
...@@ -850,7 +850,7 @@ bytecodes: [ ...@@ -850,7 +850,7 @@ bytecodes: [
B(Star8), B(Star8),
B(Mov), R(0), R(6), B(Mov), R(0), R(6),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(6), U8(3),
/* 54 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [88], Smi [88],
......
...@@ -394,7 +394,7 @@ bytecodes: [ ...@@ -394,7 +394,7 @@ bytecodes: [
B(Star7), B(Star7),
B(Mov), R(0), R(5), B(Mov), R(0), R(5),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(5), U8(3),
/* 67 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
...@@ -462,7 +462,7 @@ bytecodes: [ ...@@ -462,7 +462,7 @@ bytecodes: [
B(Star6), B(Star6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3), B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionReject), R(4), U8(3),
/* 61 S> */ B(Return), B(Return),
] ]
constant pool: [ constant pool: [
Smi [42], Smi [42],
......
...@@ -6,7 +6,7 @@ function testFunction() { ...@@ -6,7 +6,7 @@ function testFunction() {
async function f1() { async function f1() {
for (let x = |_|0; x |_|< 1; ++|_|x) |_|await x; for (let x = |_|0; x |_|< 1; ++|_|x) |_|await x;
|_|return |_|await Promise.|C|resolve(2);|R| |_|return |_|await Promise.|C|resolve(2);|R|
|R|} }
async function f2() { async function f2() {
let r = |_|await |C|f1() + |_|await |C|f1(); let r = |_|await |C|f1() + |_|await |C|f1();
...@@ -17,7 +17,7 @@ function testFunction() { ...@@ -17,7 +17,7 @@ function testFunction() {
let p = |_|Promise.|C|resolve(42); let p = |_|Promise.|C|resolve(42);
|_|await p; |_|await p;
|_|return r;|R| |_|return r;|R|
|R|} }
return |C|f2();|R| return |C|f2();|R|
} }
......
...@@ -21,7 +21,7 @@ function testFunction() { ...@@ -21,7 +21,7 @@ function testFunction() {
|_|(async function asyncF() { |_|(async function asyncF() {
let r = |_|await Promise.|C|resolve(42); let r = |_|await Promise.|C|resolve(42);
|_|return r;|R| |_|return r;|R|
|R|})|C|(); })|C|();
|_|return promise;|R| |_|return promise;|R|
} }
......
...@@ -236,7 +236,7 @@ async function testPromiseAsyncWithCode() { ...@@ -236,7 +236,7 @@ async function testPromiseAsyncWithCode() {
|R|} |R|}
|C|main(); |C|main();
|_|return testPromise;|R| |_|return testPromise;|R|
|R|} }
function returnFunction() { function returnFunction() {
|_|return returnObject;|R| |_|return returnObject;|R|
...@@ -249,7 +249,7 @@ async function testPromiseComplex() { ...@@ -249,7 +249,7 @@ async function testPromiseComplex() {
async function foo() { async function foo() {
|_|await Promise.|C|resolve(); |_|await Promise.|C|resolve();
|_|return 42;|R| |_|return 42;|R|
|R|} }
var x = |_|1; var x = |_|1;
var y = |_|2; var y = |_|2;
|C|returnFunction(|C|emptyFunction(), x++, --y, x => 2 |_|* x|R|, |C|returnCall())|C|().a = |_|await |C|foo((a => 2 |_|*a|R|)|C|(5)); |C|returnFunction(|C|emptyFunction(), x++, --y, x => 2 |_|* x|R|, |C|returnCall())|C|().a = |_|await |C|foo((a => 2 |_|*a|R|)|C|(5));
...@@ -257,7 +257,7 @@ async function testPromiseComplex() { ...@@ -257,7 +257,7 @@ async function testPromiseComplex() {
|R|} |R|}
|C|main(); |C|main();
|_|return testPromise;|R| |_|return testPromise;|R|
|R|} }
function twiceDefined() { function twiceDefined() {
|_|return a + b;|R| |_|return a + b;|R|
......
Regression test for crbug/1199919
Running test: testDefaultParameter
defaultParameter (v8://test.js:2:2)
(anonymous) (:0:0)
Running test: testDestructuringParameter
destructuringParameter (v8://test.js:6:2)
(anonymous) (:0:0)
// Copyright 2021 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('Regression test for crbug/1199919');
const source = `
async function defaultParameter(x = 1) {
return x;
}
async function destructuringParameter({x}) {
return x;
}
`;
const url = 'v8://test.js';
contextGroup.addScript(source, 0, 0, url);
session.setupScriptMap();
InspectorTest.runAsyncTestSuite([
async function testDefaultParameter() {
await Promise.all([Protocol.Runtime.enable(), Protocol.Debugger.enable()]);
const {result: {breakpointId}} = await Protocol.Debugger.setBreakpointByUrl({lineNumber: 2, url});
const evalPromise = Protocol.Runtime.evaluate({expression: 'defaultParameter()'});
const {params: {callFrames}} = await Protocol.Debugger.oncePaused();
session.logCallFrames(callFrames);
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Promise.all([Protocol.Debugger.resume(), evalPromise]);
await Promise.all([Protocol.Runtime.disable(), Protocol.Debugger.disable()]);
},
async function testDestructuringParameter() {
await Promise.all([Protocol.Runtime.enable(), Protocol.Debugger.enable()]);
const {result: {breakpointId}} = await Protocol.Debugger.setBreakpointByUrl({lineNumber: 6, url});
const evalPromise = Protocol.Runtime.evaluate({expression: 'destructuringParameter({x: 5})'});
const {params: {callFrames}} = await Protocol.Debugger.oncePaused();
session.logCallFrames(callFrames);
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Promise.all([Protocol.Debugger.resume(), evalPromise]);
await Promise.all([Protocol.Runtime.disable(), Protocol.Debugger.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