[coverage] Support conditional expressions

Bug: v8:6000
Change-Id: I8c068383300ba869a87f836504c84ea08fcff87e
Reviewed-on: https://chromium-review.googlesource.com/568307
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46675}
This commit is contained in:
jgruber 2017-07-14 13:01:00 +02:00 committed by Commit Bot
parent 705a50a3af
commit 8f6303fb6e
7 changed files with 89 additions and 1 deletions

View File

@ -31,6 +31,7 @@ struct SourceRange {
#define AST_SOURCE_RANGE_LIST(V) \
V(Block) \
V(CaseClause) \
V(Conditional) \
V(IfStatement) \
V(IterationStatement) \
V(JumpStatement) \
@ -88,6 +89,28 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges {
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 {
public:
explicit IfStatementSourceRanges(const SourceRange& then_range,

View File

@ -1851,12 +1851,19 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
}
void BytecodeGenerator::VisitConditional(Conditional* expr) {
int then_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kThen);
int else_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kElse);
if (expr->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
VisitForAccumulatorValue(expr->then_expression());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
} else if (expr->condition()->ToBooleanIsFalse()) {
// Generate else block unconditionally if it exists.
VisitForAccumulatorValue(expr->else_expression());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
} else {
BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone());
@ -1865,10 +1872,12 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
TestFallthrough::kThen);
then_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
else_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
}

View File

@ -2953,6 +2953,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// LogicalOrExpression
// LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
SourceRange then_range, else_range;
int pos = peek_position();
// We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
@ -2964,6 +2965,7 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
ExpressionT left;
{
SourceRangeScope range_scope(scanner(), &then_range);
ExpressionClassifier classifier(this);
// In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262,
@ -2975,12 +2977,15 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
Expect(Token::COLON, CHECK_OK);
ExpressionT right;
{
SourceRangeScope range_scope(scanner(), &else_range);
ExpressionClassifier classifier(this);
right = ParseAssignmentExpression(accept_IN, CHECK_OK);
AccumulateNonBindingPatternErrors();
}
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;
}

View File

@ -1157,6 +1157,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
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,
int32_t continuation_position) {
if (source_range_map_ == nullptr) return;

View File

@ -1748,6 +1748,9 @@ class PreParser : public ParserBase<PreParser> {
int32_t continuation_position) {}
V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node,
const SourceRange& body_range) {}
V8_INLINE void RecordConditionalSourceRange(PreParserExpression node,
const SourceRange& then_range,
const SourceRange& else_range) {}
V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node,
const SourceRange& then_range,
const SourceRange& else_range) {}

View File

@ -304,6 +304,11 @@ Running test: testPreciseCountCoverageIncremental
startOffset : 74
}
[1] : {
count : 0
endOffset : 156
startOffset : 145
}
[2] : {
count : 0
endOffset : 175
startOffset : 173

View File

@ -504,4 +504,38 @@ TestCoverage(
{"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);