[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:
parent
705a50a3af
commit
8f6303fb6e
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {}
|
||||
|
@ -304,6 +304,11 @@ Running test: testPreciseCountCoverageIncremental
|
||||
startOffset : 74
|
||||
}
|
||||
[1] : {
|
||||
count : 0
|
||||
endOffset : 156
|
||||
startOffset : 145
|
||||
}
|
||||
[2] : {
|
||||
count : 0
|
||||
endOffset : 175
|
||||
startOffset : 173
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user