Skip to content

Commit

Permalink
deps: V8: cherry-pick fe191e8d05cc
Browse files Browse the repository at this point in the history
Original commit message:

    [coverage] optional chaining coverage

    Implement coverage tracking for optional chains.

    Bug: v8:10060
    Change-Id: I4f29eda64b6d859939f5f58f4fabead649905795
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2573013
    Reviewed-by: Leszek Swirski <[email protected]>
    Reviewed-by: Toon Verwaest <[email protected]>
    Reviewed-by: Gus Caplan <[email protected]>
    Reviewed-by: Sigurd Schneider <[email protected]>
    Commit-Queue: Benjamin Coe <[email protected]>
    Cr-Commit-Position: refs/heads/master@{#72075}

Refs: v8/v8@fe191e8

PR-URL: #36956
Reviewed-By: Rich Trott <[email protected]>
Reviewed-By: Michaël Zasso <[email protected]>
  • Loading branch information
bcoe authored and ruyadorno committed Jan 25, 2021
1 parent 48b6781 commit ca479b9
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 12 deletions.
19 changes: 19 additions & 0 deletions deps/v8/src/ast/ast-source-ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct SourceRange {
V(Block) \
V(CaseClause) \
V(Conditional) \
V(Expression) \
V(FunctionLiteral) \
V(IfStatement) \
V(IterationStatement) \
Expand Down Expand Up @@ -281,6 +282,24 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges {
ZoneVector<SourceRange> ranges_;
};

class ExpressionSourceRanges final : public AstNodeSourceRanges {
public:
explicit ExpressionSourceRanges(const SourceRange& right_range)
: right_range_(right_range) {}

SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return right_range_;
}

bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kRight;
}

private:
SourceRange right_range_;
};

class SuspendSourceRanges final : public ContinuationSourceRanges {
public:
explicit SuspendSourceRanges(int32_t continuation_position)
Expand Down
9 changes: 9 additions & 0 deletions deps/v8/src/interpreter/bytecode-generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4575,8 +4575,11 @@ void BytecodeGenerator::VisitThrow(Throw* expr) {
void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
if (property->is_optional_chain_link()) {
DCHECK_NOT_NULL(optional_chaining_null_labels_);
int right_range =
AllocateBlockCoverageSlotIfEnabled(property, SourceRangeKind::kRight);
builder()->LoadAccumulatorWithRegister(obj).JumpIfUndefinedOrNull(
optional_chaining_null_labels_->New());
BuildIncrementBlockCoverageCounterIfEnabled(right_range);
}

AssignType property_kind = Property::GetAssignType(property);
Expand Down Expand Up @@ -4902,8 +4905,11 @@ void BytecodeGenerator::VisitCall(Call* expr) {

if (expr->is_optional_chain_link()) {
DCHECK_NOT_NULL(optional_chaining_null_labels_);
int right_range =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kRight);
builder()->LoadAccumulatorWithRegister(callee).JumpIfUndefinedOrNull(
optional_chaining_null_labels_->New());
BuildIncrementBlockCoverageCounterIfEnabled(right_range);
}

// Evaluate all arguments to the function call and store in sequential args
Expand Down Expand Up @@ -5175,7 +5181,10 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) {
OptionalChainNullLabelScope label_scope(this);
VisitForAccumulatorValue(property->obj());
if (property->is_optional_chain_link()) {
int right_range = AllocateBlockCoverageSlotIfEnabled(
property, SourceRangeKind::kRight);
builder()->JumpIfUndefinedOrNull(label_scope.labels()->New());
BuildIncrementBlockCoverageCounterIfEnabled(right_range);
}
Register object = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(object);
Expand Down
26 changes: 15 additions & 11 deletions deps/v8/src/parsing/parser-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -3289,17 +3289,24 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {

bool optional_chaining = false;
bool is_optional = false;
int optional_link_begin;
do {
switch (peek()) {
case Token::QUESTION_PERIOD: {
if (is_optional) {
ReportUnexpectedToken(peek());
return impl()->FailureExpression();
}
// Include the ?. in the source range position.
optional_link_begin = scanner()->peek_location().beg_pos;
Consume(Token::QUESTION_PERIOD);
is_optional = true;
optional_chaining = true;
continue;
if (Token::IsPropertyOrCall(peek())) continue;
int pos = position();
ExpressionT key = ParsePropertyOrPrivatePropertyName();
result = factory()->NewProperty(result, key, pos, is_optional);
break;
}

/* Property */
Expand Down Expand Up @@ -3379,14 +3386,7 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
}

default:
/* Optional Property */
if (is_optional) {
DCHECK_EQ(scanner()->current_token(), Token::QUESTION_PERIOD);
int pos = position();
ExpressionT key = ParsePropertyOrPrivatePropertyName();
result = factory()->NewProperty(result, key, pos, is_optional);
break;
}
// Template literals in/after an Optional Chain not supported:
if (optional_chaining) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kOptionalChainingNoTemplate);
Expand All @@ -3397,8 +3397,12 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
result = ParseTemplateLiteral(result, position(), true);
break;
}
is_optional = false;
} while (is_optional || Token::IsPropertyOrCall(peek()));
if (is_optional) {
SourceRange chain_link_range(optional_link_begin, end_position());
impl()->RecordExpressionSourceRange(result, chain_link_range);
is_optional = false;
}
} while (Token::IsPropertyOrCall(peek()));
if (optional_chaining) return factory()->NewOptionalChain(result);
return result;
}
Expand Down
8 changes: 8 additions & 0 deletions deps/v8/src/parsing/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
node, zone()->New<IterationStatementSourceRanges>(body_range));
}

// Used to record source ranges of expressions associated with optional chain:
V8_INLINE void RecordExpressionSourceRange(Expression* node,
const SourceRange& right_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(node,
zone()->New<ExpressionSourceRanges>(right_range));
}

V8_INLINE void RecordSuspendSourceRange(Expression* node,
int32_t continuation_position) {
if (source_range_map_ == nullptr) return;
Expand Down
39 changes: 38 additions & 1 deletion deps/v8/test/mjsunit/code-coverage-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ a(true); // 0500
{"start":0,"end":401,"count":2},
{"start":154,"end":254,"count":0}]);

TestCoverage(
TestCoverage(
"https://crbug.com/v8/11231 - nullish coalescing",
`
const a = true // 0000
Expand All @@ -1195,4 +1195,41 @@ const i = c ?? b ?? 'hello' // 0400
{"start":262,"end":274,"count":0},
{"start":417,"end":427,"count":0}]);

TestCoverage(
"Optional Chaining",
`
const a = undefined || null // 0000
const b = a?.b // 0050
const c = a?.['b'] // 0100
const d = { // 0150
e: {f: 99, g: () => {return undefined}} // 0200
} // 0250
const e = d?.e?.f // 0300
const f = d?.e?.['f'] // 0350
const g = d?.e?.f?.g // 0400
const h = d?.e?.f?.g?.h // 0450
const i = d?.['d']?.['e']?.['h'] // 0500
const k = a?.('b') // 0550
const l = d?.e?.g?.() // 0600
const m = d?.e?.g?.()?.a?.b // 0650
delete a?.b // 0700
const n = d?.[d?.x?.f] // 0750
if (a?.[d?.x?.f]) { const p = 99 } else {}// 0800
const p = d?.[d?.x?.f]?.x // 0850
`,
[{"start":0,"end":899,"count":1},
{"start":61,"end":64,"count":0},
{"start":111,"end":118,"count":0},
{"start":470,"end":473,"count":0},
{"start":518,"end":532,"count":0},
{"start":561,"end":568,"count":0},
{"start":671,"end":677,"count":0},
{"start":708,"end":711,"count":0},
{"start":768,"end":771,"count":0},
{"start":805,"end":816,"count":0},
{"start":818,"end":834,"count":0},
{"start":868,"end":871,"count":0},
{"start":872,"end":875,"count":0},
{"start":216,"end":240,"count":2}]);

%DebugToggleBlockCoverage(false);

0 comments on commit ca479b9

Please sign in to comment.