Commit 8f6303fb authored by jgruber's avatar jgruber Committed by Commit Bot

[coverage] Support conditional expressions

Bug: v8:6000
Change-Id: I8c068383300ba869a87f836504c84ea08fcff87e
Reviewed-on: https://chromium-review.googlesource.com/568307Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46675}
parent 705a50a3
...@@ -31,6 +31,7 @@ struct SourceRange { ...@@ -31,6 +31,7 @@ struct SourceRange {
#define AST_SOURCE_RANGE_LIST(V) \ #define AST_SOURCE_RANGE_LIST(V) \
V(Block) \ V(Block) \
V(CaseClause) \ V(CaseClause) \
V(Conditional) \
V(IfStatement) \ V(IfStatement) \
V(IterationStatement) \ V(IterationStatement) \
V(JumpStatement) \ V(JumpStatement) \
...@@ -88,6 +89,28 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges { ...@@ -88,6 +89,28 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges {
SourceRange body_range_; SourceRange body_range_;
}; };
class ConditionalSourceRanges final : public AstNodeSourceRanges {
public:
explicit ConditionalSourceRanges(const SourceRange& then_range,
const SourceRange& else_range)
: then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) {
switch (kind) {
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kElse:
return else_range_;
default:
UNREACHABLE();
}
}
private:
SourceRange then_range_;
SourceRange else_range_;
};
class IfStatementSourceRanges final : public AstNodeSourceRanges { class IfStatementSourceRanges final : public AstNodeSourceRanges {
public: public:
explicit IfStatementSourceRanges(const SourceRange& then_range, explicit IfStatementSourceRanges(const SourceRange& then_range,
......
...@@ -1851,12 +1851,19 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { ...@@ -1851,12 +1851,19 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
} }
void BytecodeGenerator::VisitConditional(Conditional* expr) { void BytecodeGenerator::VisitConditional(Conditional* expr) {
int then_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kThen);
int else_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kElse);
if (expr->condition()->ToBooleanIsTrue()) { if (expr->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true. // Generate then block unconditionally as always true.
VisitForAccumulatorValue(expr->then_expression()); VisitForAccumulatorValue(expr->then_expression());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
} else if (expr->condition()->ToBooleanIsFalse()) { } else if (expr->condition()->ToBooleanIsFalse()) {
// Generate else block unconditionally if it exists. // Generate else block unconditionally if it exists.
VisitForAccumulatorValue(expr->else_expression()); VisitForAccumulatorValue(expr->else_expression());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
} else { } else {
BytecodeLabel end_label; BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone()); BytecodeLabels then_labels(zone()), else_labels(zone());
...@@ -1865,10 +1872,12 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { ...@@ -1865,10 +1872,12 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
TestFallthrough::kThen); TestFallthrough::kThen);
then_labels.Bind(builder()); then_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
VisitForAccumulatorValue(expr->then_expression()); VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label); builder()->Jump(&end_label);
else_labels.Bind(builder()); else_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
VisitForAccumulatorValue(expr->else_expression()); VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label); builder()->Bind(&end_label);
} }
......
...@@ -2953,6 +2953,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -2953,6 +2953,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// LogicalOrExpression // LogicalOrExpression
// LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
SourceRange then_range, else_range;
int pos = peek_position(); int pos = peek_position();
// We start using the binary expression parser for prec >= 4 only! // We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
...@@ -2964,6 +2965,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -2964,6 +2965,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
ExpressionT left; ExpressionT left;
{ {
SourceRangeScope range_scope(scanner(), &then_range);
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
// In parsing the first assignment expression in conditional // In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262, // expressions we always accept the 'in' keyword; see ECMA-262,
...@@ -2975,12 +2977,15 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, ...@@ -2975,12 +2977,15 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
Expect(Token::COLON, CHECK_OK); Expect(Token::COLON, CHECK_OK);
ExpressionT right; ExpressionT right;
{ {
SourceRangeScope range_scope(scanner(), &else_range);
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
right = ParseAssignmentExpression(accept_IN, CHECK_OK); right = ParseAssignmentExpression(accept_IN, CHECK_OK);
AccumulateNonBindingPatternErrors(); AccumulateNonBindingPatternErrors();
} }
impl()->RewriteNonPattern(CHECK_OK); impl()->RewriteNonPattern(CHECK_OK);
return factory()->NewConditional(expression, left, right, pos); ExpressionT expr = factory()->NewConditional(expression, left, right, pos);
impl()->RecordConditionalSourceRange(expr, then_range, else_range);
return expr;
} }
......
...@@ -1157,6 +1157,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -1157,6 +1157,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
new (zone()) CaseClauseSourceRanges(body_range)); new (zone()) CaseClauseSourceRanges(body_range));
} }
V8_INLINE void RecordConditionalSourceRange(Expression* node,
const SourceRange& then_range,
const SourceRange& else_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node->AsConditional(),
new (zone()) ConditionalSourceRanges(then_range, else_range));
}
V8_INLINE void RecordJumpStatementSourceRange(Statement* node, V8_INLINE void RecordJumpStatementSourceRange(Statement* node,
int32_t continuation_position) { int32_t continuation_position) {
if (source_range_map_ == nullptr) return; if (source_range_map_ == nullptr) return;
......
...@@ -1748,6 +1748,9 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1748,6 +1748,9 @@ class PreParser : public ParserBase<PreParser> {
int32_t continuation_position) {} int32_t continuation_position) {}
V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node, V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node,
const SourceRange& body_range) {} const SourceRange& body_range) {}
V8_INLINE void RecordConditionalSourceRange(PreParserExpression node,
const SourceRange& then_range,
const SourceRange& else_range) {}
V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node, V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node,
const SourceRange& then_range, const SourceRange& then_range,
const SourceRange& else_range) {} const SourceRange& else_range) {}
......
...@@ -304,6 +304,11 @@ Running test: testPreciseCountCoverageIncremental ...@@ -304,6 +304,11 @@ Running test: testPreciseCountCoverageIncremental
startOffset : 74 startOffset : 74
} }
[1] : { [1] : {
count : 0
endOffset : 156
startOffset : 145
}
[2] : {
count : 0 count : 0
endOffset : 175 endOffset : 175
startOffset : 173 startOffset : 173
......
...@@ -504,4 +504,38 @@ TestCoverage( ...@@ -504,4 +504,38 @@ TestCoverage(
{"start":621,"end":653,"count":0}] {"start":621,"end":653,"count":0}]
); );
TestCoverage(
"conditional expressions",
`
var TRUE = true; // 0000
var FALSE = false; // 0050
!function() { // 0100
TRUE ? nop() : nop(); // 0150
true ? nop() : nop(); // 0200
false ? nop() : nop(); // 0250
FALSE ? TRUE ? nop() // 0300
: nop() // 0350
: nop(); // 0400
TRUE ? FALSE ? nop() // 0450
: nop() // 0500
: nop(); // 0550
TRUE ? nop() : FALSE ? nop() // 0600
: nop(); // 0650
FALSE ? nop() : TRUE ? nop() // 0700
: nop(); // 0750
}(); // 0800
`,
[{"start":0,"end":849,"count":1},
{"start":101,"end":801,"count":1},
{"start":167,"end":172,"count":0},
{"start":217,"end":222,"count":0},
{"start":260,"end":265,"count":0},
{"start":310,"end":372,"count":0},
{"start":467,"end":472,"count":0},
{"start":559,"end":564,"count":0},
{"start":617,"end":680,"count":0},
{"start":710,"end":715,"count":0},
{"start":775,"end":780,"count":0}]
);
%DebugToggleBlockCoverage(false); %DebugToggleBlockCoverage(false);
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