Commit 9365d090 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[coverage] Rework continuation counter handling

This changes a few bits about how continuation counters are handled.

It introduces a new mechanism that allows removal of a continuation
range after it has been created. If coverage is enabled, we run a first
post-processing pass on the AST immediately after parsing, which
removes problematic continuation ranges in two situations:

1. nested continuation counters - only the outermost stays alive.
2. trailing continuation counters within a block-like structure are
   removed if the containing structure itself has a continuation.

R=bmeurer@chromium.org, jgruber@chromium.org, yangguo@chromium.org

Bug: v8:8381, v8:8539
Change-Id: I6bcaea5060d8c481d7bae099f6db9f993cc30ee3
Reviewed-on: https://chromium-review.googlesource.com/c/1339119Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58443}
parent 491eff86
...@@ -1668,6 +1668,8 @@ v8_source_set("v8_base") { ...@@ -1668,6 +1668,8 @@ v8_source_set("v8_base") {
"src/ast/prettyprinter.h", "src/ast/prettyprinter.h",
"src/ast/scopes.cc", "src/ast/scopes.cc",
"src/ast/scopes.h", "src/ast/scopes.h",
"src/ast/source-range-ast-visitor.cc",
"src/ast/source-range-ast-visitor.h",
"src/ast/variables.cc", "src/ast/variables.cc",
"src/ast/variables.h", "src/ast/variables.h",
"src/bailout-reason.cc", "src/bailout-reason.cc",
......
...@@ -59,6 +59,8 @@ class AstNodeSourceRanges : public ZoneObject { ...@@ -59,6 +59,8 @@ class AstNodeSourceRanges : public ZoneObject {
public: public:
virtual ~AstNodeSourceRanges() = default; virtual ~AstNodeSourceRanges() = default;
virtual SourceRange GetRange(SourceRangeKind kind) = 0; virtual SourceRange GetRange(SourceRangeKind kind) = 0;
virtual bool HasRange(SourceRangeKind kind) = 0;
virtual void RemoveContinuationRange() { UNREACHABLE(); }
}; };
class BinaryOperationSourceRanges final : public AstNodeSourceRanges { class BinaryOperationSourceRanges final : public AstNodeSourceRanges {
...@@ -67,10 +69,14 @@ class BinaryOperationSourceRanges final : public AstNodeSourceRanges { ...@@ -67,10 +69,14 @@ class BinaryOperationSourceRanges final : public AstNodeSourceRanges {
: right_range_(right_range) {} : right_range_(right_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK_EQ(kind, SourceRangeKind::kRight); DCHECK(HasRange(kind));
return right_range_; return right_range_;
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kRight;
}
private: private:
SourceRange right_range_; SourceRange right_range_;
}; };
...@@ -81,10 +87,19 @@ class ContinuationSourceRanges : public AstNodeSourceRanges { ...@@ -81,10 +87,19 @@ class ContinuationSourceRanges : public AstNodeSourceRanges {
: continuation_position_(continuation_position) {} : continuation_position_(continuation_position) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK_EQ(kind, SourceRangeKind::kContinuation); DCHECK(HasRange(kind));
return SourceRange::OpenEnded(continuation_position_); return SourceRange::OpenEnded(continuation_position_);
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
continuation_position_ = kNoSourcePosition;
}
private: private:
int32_t continuation_position_; int32_t continuation_position_;
}; };
...@@ -101,10 +116,14 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges { ...@@ -101,10 +116,14 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges {
: body_range_(body_range) {} : body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK_EQ(kind, SourceRangeKind::kBody); DCHECK(HasRange(kind));
return body_range_; return body_range_;
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kBody;
}
private: private:
SourceRange body_range_; SourceRange body_range_;
}; };
...@@ -116,6 +135,7 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { ...@@ -116,6 +135,7 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges {
: then_range_(then_range), else_range_(else_range) {} : then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) { switch (kind) {
case SourceRangeKind::kThen: case SourceRangeKind::kThen:
return then_range_; return then_range_;
...@@ -126,6 +146,10 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { ...@@ -126,6 +146,10 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges {
} }
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse;
}
private: private:
SourceRange then_range_; SourceRange then_range_;
SourceRange else_range_; SourceRange else_range_;
...@@ -138,12 +162,14 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { ...@@ -138,12 +162,14 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges {
: then_range_(then_range), else_range_(else_range) {} : then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) { switch (kind) {
case SourceRangeKind::kElse: case SourceRangeKind::kElse:
return else_range_; return else_range_;
case SourceRangeKind::kThen: case SourceRangeKind::kThen:
return then_range_; return then_range_;
case SourceRangeKind::kContinuation: { case SourceRangeKind::kContinuation: {
if (!has_continuation_) return SourceRange::Empty();
const SourceRange& trailing_range = const SourceRange& trailing_range =
else_range_.IsEmpty() ? then_range_ : else_range_; else_range_.IsEmpty() ? then_range_ : else_range_;
return SourceRange::ContinuationOf(trailing_range); return SourceRange::ContinuationOf(trailing_range);
...@@ -153,9 +179,20 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { ...@@ -153,9 +179,20 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges {
} }
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private: private:
SourceRange then_range_; SourceRange then_range_;
SourceRange else_range_; SourceRange else_range_;
bool has_continuation_ = true;
}; };
class IterationStatementSourceRanges final : public AstNodeSourceRanges { class IterationStatementSourceRanges final : public AstNodeSourceRanges {
...@@ -164,18 +201,31 @@ class IterationStatementSourceRanges final : public AstNodeSourceRanges { ...@@ -164,18 +201,31 @@ class IterationStatementSourceRanges final : public AstNodeSourceRanges {
: body_range_(body_range) {} : body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) { switch (kind) {
case SourceRangeKind::kBody: case SourceRangeKind::kBody:
return body_range_; return body_range_;
case SourceRangeKind::kContinuation: case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(body_range_); return SourceRange::ContinuationOf(body_range_);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kBody ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private: private:
SourceRange body_range_; SourceRange body_range_;
bool has_continuation_ = true;
}; };
class JumpStatementSourceRanges final : public ContinuationSourceRanges { class JumpStatementSourceRanges final : public ContinuationSourceRanges {
...@@ -200,6 +250,7 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges { ...@@ -200,6 +250,7 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges {
size_t RangeCount() const { return ranges_.size(); } size_t RangeCount() const { return ranges_.size(); }
SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); } SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); }
bool HasRange(SourceRangeKind kind) override { return false; }
private: private:
ZoneVector<SourceRange> ranges_; ZoneVector<SourceRange> ranges_;
...@@ -229,18 +280,31 @@ class TryCatchStatementSourceRanges final : public AstNodeSourceRanges { ...@@ -229,18 +280,31 @@ class TryCatchStatementSourceRanges final : public AstNodeSourceRanges {
: catch_range_(catch_range) {} : catch_range_(catch_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) { switch (kind) {
case SourceRangeKind::kCatch: case SourceRangeKind::kCatch:
return catch_range_; return catch_range_;
case SourceRangeKind::kContinuation: case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(catch_range_); return SourceRange::ContinuationOf(catch_range_);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kCatch ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private: private:
SourceRange catch_range_; SourceRange catch_range_;
bool has_continuation_ = true;
}; };
class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
...@@ -249,18 +313,31 @@ class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { ...@@ -249,18 +313,31 @@ class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
: finally_range_(finally_range) {} : finally_range_(finally_range) {}
SourceRange GetRange(SourceRangeKind kind) override { SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) { switch (kind) {
case SourceRangeKind::kFinally: case SourceRangeKind::kFinally:
return finally_range_; return finally_range_;
case SourceRangeKind::kContinuation: case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(finally_range_); return SourceRange::ContinuationOf(finally_range_);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kFinally ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private: private:
SourceRange finally_range_; SourceRange finally_range_;
bool has_continuation_ = true;
}; };
// Maps ast node pointers to associated source ranges. The parser creates these // Maps ast node pointers to associated source ranges. The parser creates these
......
// Copyright 2018 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.
#include "src/ast/source-range-ast-visitor.h"
#include "src/ast/ast-source-ranges.h"
namespace v8 {
namespace internal {
SourceRangeAstVisitor::SourceRangeAstVisitor(uintptr_t stack_limit,
Expression* root,
SourceRangeMap* source_range_map)
: AstTraversalVisitor(stack_limit, root),
source_range_map_(source_range_map) {}
void SourceRangeAstVisitor::VisitBlock(Block* stmt) {
AstTraversalVisitor::VisitBlock(stmt);
ZonePtrList<Statement>* stmts = stmt->statements();
AstNodeSourceRanges* enclosingSourceRanges = source_range_map_->Find(stmt);
if (enclosingSourceRanges != nullptr) {
CHECK(enclosingSourceRanges->HasRange(SourceRangeKind::kContinuation));
MaybeRemoveLastContinuationRange(stmts);
}
}
void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
AstTraversalVisitor::VisitFunctionLiteral(expr);
ZonePtrList<Statement>* stmts = expr->body();
MaybeRemoveLastContinuationRange(stmts);
}
bool SourceRangeAstVisitor::VisitNode(AstNode* node) {
AstNodeSourceRanges* range = source_range_map_->Find(node);
if (range == nullptr) return true;
if (!range->HasRange(SourceRangeKind::kContinuation)) return true;
// Called in pre-order. In case of conflicting continuation ranges, only the
// outermost range may survive.
SourceRange continuation = range->GetRange(SourceRangeKind::kContinuation);
if (continuation_positions_.find(continuation.start) !=
continuation_positions_.end()) {
range->RemoveContinuationRange();
} else {
continuation_positions_.emplace(continuation.start);
}
return true;
}
void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange(
ZonePtrList<Statement>* statements) {
if (statements->is_empty()) return;
Statement* last_statement = statements->last();
AstNodeSourceRanges* last_range = source_range_map_->Find(last_statement);
if (last_range == nullptr) return;
if (last_range->HasRange(SourceRangeKind::kContinuation)) {
last_range->RemoveContinuationRange();
}
}
} // namespace internal
} // namespace v8
// Copyright 2018 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.
#ifndef V8_AST_SOURCE_RANGE_AST_VISITOR_H_
#define V8_AST_SOURCE_RANGE_AST_VISITOR_H_
#include <unordered_set>
#include "src/ast/ast-traversal-visitor.h"
namespace v8 {
namespace internal {
class SourceRangeMap;
// Post-processes generated source ranges while the AST structure still exists.
//
// In particular, SourceRangeAstVisitor
//
// 1. deduplicates continuation source ranges, only keeping the outermost one.
// See also: https://crbug.com/v8/8539.
//
// 2. removes the source range associated with the final statement in a block
// or function body if the parent itself has a source range associated with it.
// See also: https://crbug.com/v8/8381.
class SourceRangeAstVisitor final
: public AstTraversalVisitor<SourceRangeAstVisitor> {
public:
SourceRangeAstVisitor(uintptr_t stack_limit, Expression* root,
SourceRangeMap* source_range_map);
private:
friend class AstTraversalVisitor<SourceRangeAstVisitor>;
void VisitBlock(Block* stmt);
void VisitFunctionLiteral(FunctionLiteral* expr);
bool VisitNode(AstNode* node);
void MaybeRemoveLastContinuationRange(ZonePtrList<Statement>* stmts);
SourceRangeMap* source_range_map_ = nullptr;
std::unordered_set<int> continuation_positions_;
};
} // namespace internal
} // namespace v8
#endif // V8_AST_SOURCE_RANGE_AST_VISITOR_H_
...@@ -233,25 +233,6 @@ bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) { ...@@ -233,25 +233,6 @@ bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) {
return lhs.start == rhs.start && lhs.end == rhs.end; return lhs.start == rhs.start && lhs.end == rhs.end;
} }
void MergeDuplicateSingletons(CoverageFunction* function) {
CoverageBlockIterator iter(function);
while (iter.Next() && iter.HasNext()) {
CoverageBlock& block = iter.GetBlock();
CoverageBlock& next_block = iter.GetNextBlock();
// Identical ranges should only occur through singleton ranges. Consider the
// ranges for `for (.) break;`: continuation ranges for both the `break` and
// `for` statements begin after the trailing semicolon.
// Such ranges are merged and keep the maximal execution count.
if (!HaveSameSourceRange(block, next_block)) continue;
DCHECK_EQ(kNoSourcePosition, block.end); // Singleton range.
next_block.count = std::max(block.count, next_block.count);
iter.DeleteBlock();
}
}
void MergeDuplicateRanges(CoverageFunction* function) { void MergeDuplicateRanges(CoverageFunction* function) {
CoverageBlockIterator iter(function); CoverageBlockIterator iter(function);
...@@ -424,9 +405,6 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info, ...@@ -424,9 +405,6 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
// If in binary mode, only report counts of 0/1. // If in binary mode, only report counts of 0/1.
if (mode == debug::Coverage::kBlockBinary) ClampToBinary(function); if (mode == debug::Coverage::kBlockBinary) ClampToBinary(function);
// Remove duplicate singleton ranges, keeping the max count.
MergeDuplicateSingletons(function);
// Remove singleton ranges with the same start position as a full range and // Remove singleton ranges with the same start position as a full range and
// throw away their counts. // throw away their counts.
// Singleton ranges are only intended to split existing full ranges and should // Singleton ranges are only intended to split existing full ranges and should
......
...@@ -368,7 +368,6 @@ class BytecodeGenerator::ControlScopeForBreakable final ...@@ -368,7 +368,6 @@ class BytecodeGenerator::ControlScopeForBreakable final
protected: protected:
bool Execute(Command command, Statement* statement, bool Execute(Command command, Statement* statement,
int source_position) override { int source_position) override {
control_builder_->set_needs_continuation_counter();
if (statement != statement_) return false; if (statement != statement_) return false;
switch (command) { switch (command) {
case CMD_BREAK: case CMD_BREAK:
......
...@@ -13,7 +13,7 @@ namespace interpreter { ...@@ -13,7 +13,7 @@ namespace interpreter {
BreakableControlFlowBuilder::~BreakableControlFlowBuilder() { BreakableControlFlowBuilder::~BreakableControlFlowBuilder() {
BindBreakTarget(); BindBreakTarget();
DCHECK(break_labels_.empty() || break_labels_.is_bound()); DCHECK(break_labels_.empty() || break_labels_.is_bound());
if (block_coverage_builder_ != nullptr && needs_continuation_counter()) { if (block_coverage_builder_ != nullptr) {
block_coverage_builder_->IncrementBlockCounter( block_coverage_builder_->IncrementBlockCounter(
node_, SourceRangeKind::kContinuation); node_, SourceRangeKind::kContinuation);
} }
......
...@@ -58,11 +58,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder ...@@ -58,11 +58,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
BytecodeLabels* break_labels() { return &break_labels_; } BytecodeLabels* break_labels() { return &break_labels_; }
void set_needs_continuation_counter() { needs_continuation_counter_ = true; }
bool needs_continuation_counter() const {
return needs_continuation_counter_;
}
protected: protected:
void EmitJump(BytecodeLabels* labels); void EmitJump(BytecodeLabels* labels);
void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode, void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
...@@ -81,7 +76,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder ...@@ -81,7 +76,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
// A continuation counter (for block coverage) is needed e.g. when // A continuation counter (for block coverage) is needed e.g. when
// encountering a break statement. // encountering a break statement.
AstNode* node_; AstNode* node_;
bool needs_continuation_counter_ = false;
BlockCoverageBuilder* block_coverage_builder_; BlockCoverageBuilder* block_coverage_builder_;
}; };
...@@ -107,7 +101,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder { ...@@ -107,7 +101,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
: BreakableControlFlowBuilder(builder, block_coverage_builder, node), : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
continue_labels_(builder->zone()) { continue_labels_(builder->zone()) {
if (block_coverage_builder_ != nullptr) { if (block_coverage_builder_ != nullptr) {
set_needs_continuation_counter();
block_coverage_body_slot_ = block_coverage_body_slot_ =
block_coverage_builder_->AllocateBlockCoverageSlot( block_coverage_builder_->AllocateBlockCoverageSlot(
node, SourceRangeKind::kBody); node, SourceRangeKind::kBody);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-function-literal-id-reindexer.h"
#include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast-traversal-visitor.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/ast/source-range-ast-visitor.h"
#include "src/bailout-reason.h" #include "src/bailout-reason.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/char-predicates-inl.h" #include "src/char-predicates-inl.h"
...@@ -462,6 +463,15 @@ void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) { ...@@ -462,6 +463,15 @@ void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) {
info->ResetCharacterStream(); info->ResetCharacterStream();
} }
void MaybeProcessSourceRanges(ParseInfo* parse_info, Expression* root,
uintptr_t stack_limit_) {
if (root != nullptr && parse_info->source_range_map() != nullptr) {
SourceRangeAstVisitor visitor(stack_limit_, root,
parse_info->source_range_map());
visitor.Run();
}
}
} // namespace } // namespace
FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
...@@ -485,6 +495,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { ...@@ -485,6 +495,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
scanner_.Initialize(); scanner_.Initialize();
FunctionLiteral* result = DoParseProgram(isolate, info); FunctionLiteral* result = DoParseProgram(isolate, info);
MaybeResetCharacterStream(info, result); MaybeResetCharacterStream(info, result);
MaybeProcessSourceRanges(info, result, stack_limit_);
HandleSourceURLComments(isolate, info->script()); HandleSourceURLComments(isolate, info->script());
...@@ -673,6 +684,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, ...@@ -673,6 +684,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
FunctionLiteral* result = FunctionLiteral* result =
DoParseFunction(isolate, info, info->function_name()); DoParseFunction(isolate, info, info->function_name());
MaybeResetCharacterStream(info, result); MaybeResetCharacterStream(info, result);
MaybeProcessSourceRanges(info, result, stack_limit_);
if (result != nullptr) { if (result != nullptr) {
Handle<String> inferred_name(shared_info->inferred_name(), isolate); Handle<String> inferred_name(shared_info->inferred_name(), isolate);
result->set_inferred_name(inferred_name); result->set_inferred_name(inferred_name);
......
...@@ -23,7 +23,7 @@ f(); f(); f(); f(); f(); f(); // 0150 ...@@ -23,7 +23,7 @@ f(); f(); f(); f(); f(); f(); // 0150
`, `,
[{"start":0,"end":199,"count":1}, [{"start":0,"end":199,"count":1},
{"start":0,"end":33,"count":4}, // TODO(jgruber): Invocation count is off. {"start":0,"end":33,"count":4}, // TODO(jgruber): Invocation count is off.
{"start":25,"end":32,"count":16}, {"start":25,"end":31,"count":16},
{"start":50,"end":76,"count":2}] // TODO(jgruber): Invocation count is off. {"start":50,"end":76,"count":2}] // TODO(jgruber): Invocation count is off.
); );
...@@ -45,7 +45,7 @@ TestCoverage("Partial coverage collection", ...@@ -45,7 +45,7 @@ TestCoverage("Partial coverage collection",
}(); // 0400 }(); // 0400
`, `,
[{"start":52,"end":153,"count":0}, [{"start":52,"end":153,"count":0},
{"start":121,"end":152,"count":1}] {"start":121,"end":137,"count":1}]
); );
%DebugToggleBlockCoverage(false); %DebugToggleBlockCoverage(false);
...@@ -246,8 +246,7 @@ function g() {} // 0000 ...@@ -246,8 +246,7 @@ function g() {} // 0000
{"start":224,"end":237,"count":12}, {"start":224,"end":237,"count":12},
{"start":273,"end":277,"count":0}, {"start":273,"end":277,"count":0},
{"start":412,"end":416,"count":12}, {"start":412,"end":416,"count":12},
{"start":462,"end":475,"count":12}, {"start":462,"end":475,"count":12}]
{"start":620,"end":622,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -357,7 +356,7 @@ TestCoverage( ...@@ -357,7 +356,7 @@ TestCoverage(
{"start":219,"end":222,"count":0}, {"start":219,"end":222,"count":0},
{"start":254,"end":274,"count":0}, {"start":254,"end":274,"count":0},
{"start":369,"end":372,"count":0}, {"start":369,"end":372,"count":0},
{"start":390,"end":404,"count":0}, {"start":403,"end":404,"count":0},
{"start":513,"end":554,"count":0}] {"start":513,"end":554,"count":0}]
); );
...@@ -376,10 +375,10 @@ TestCoverage("try/catch/finally statements with early return", ...@@ -376,10 +375,10 @@ TestCoverage("try/catch/finally statements with early return",
[{"start":0,"end":449,"count":1}, [{"start":0,"end":449,"count":1},
{"start":1,"end":151,"count":1}, {"start":1,"end":151,"count":1},
{"start":67,"end":70,"count":0}, {"start":67,"end":70,"count":0},
{"start":89,"end":150,"count":0}, {"start":91,"end":150,"count":0},
{"start":201,"end":401,"count":1}, {"start":201,"end":401,"count":1},
{"start":267,"end":270,"count":0}, {"start":267,"end":270,"count":0},
{"start":319,"end":400,"count":0}] {"start":321,"end":400,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -411,11 +410,11 @@ TestCoverage( ...@@ -411,11 +410,11 @@ TestCoverage(
[{"start":0,"end":1099,"count":1}, [{"start":0,"end":1099,"count":1},
{"start":1,"end":151,"count":1}, {"start":1,"end":151,"count":1},
{"start":67,"end":70,"count":0}, {"start":67,"end":70,"count":0},
{"start":89,"end":150,"count":0}, {"start":91,"end":150,"count":0},
{"start":201,"end":351,"count":1}, {"start":201,"end":351,"count":1},
{"start":284,"end":350,"count":0}, {"start":286,"end":350,"count":0},
{"start":401,"end":701,"count":1}, {"start":401,"end":701,"count":1},
{"start":569,"end":700,"count":0}, {"start":603,"end":700,"count":0},
{"start":561,"end":568,"count":0}, // TODO(jgruber): Sorting. {"start":561,"end":568,"count":0}, // TODO(jgruber): Sorting.
{"start":751,"end":1051,"count":1}, {"start":751,"end":1051,"count":1},
{"start":817,"end":820,"count":0}, {"start":817,"end":820,"count":0},
...@@ -437,7 +436,7 @@ TestCoverage( ...@@ -437,7 +436,7 @@ TestCoverage(
[{"start":0,"end":399,"count":1}, [{"start":0,"end":399,"count":1},
{"start":1,"end":351,"count":1}, {"start":1,"end":351,"count":1},
{"start":154,"end":204,"count":0}, {"start":154,"end":204,"count":0},
{"start":226,"end":303,"count":0}] {"start":226,"end":350,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -467,11 +466,7 @@ TestCoverage( ...@@ -467,11 +466,7 @@ TestCoverage(
[{"start":0,"end":999,"count":1}, [{"start":0,"end":999,"count":1},
{"start":1,"end":951,"count":1}, {"start":1,"end":951,"count":1},
{"start":152,"end":202,"count":0}, {"start":152,"end":202,"count":0},
{"start":285,"end":353,"count":0}, {"start":285,"end":353,"count":0}]
{"start":472,"end":503,"count":0},
{"start":626,"end":653,"count":0},
{"start":768,"end":803,"count":0},
{"start":867,"end":869,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -496,11 +491,8 @@ TestCoverage( ...@@ -496,11 +491,8 @@ TestCoverage(
[{"start":0,"end":749,"count":1}, [{"start":0,"end":749,"count":1},
{"start":1,"end":701,"count":1}, {"start":1,"end":701,"count":1},
{"start":87,"end":153,"count":2}, {"start":87,"end":153,"count":2},
{"start":125,"end":153,"count":0},
{"start":271,"end":403,"count":2}, {"start":271,"end":403,"count":2},
{"start":379,"end":403,"count":0}, {"start":509,"end":653,"count":2}]
{"start":509,"end":653,"count":2},
{"start":621,"end":653,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -570,6 +562,7 @@ try { // 0200 ...@@ -570,6 +562,7 @@ try { // 0200
} catch (e) {} // 0450 } catch (e) {} // 0450
`, `,
[{"start":0,"end":499,"count":1}, [{"start":0,"end":499,"count":1},
{"start":451,"end":452,"count":0},
{"start":12,"end":101,"count":3}, {"start":12,"end":101,"count":3},
{"start":60,"end":100,"count":0}, {"start":60,"end":100,"count":0},
{"start":264,"end":353,"count":3}, {"start":264,"end":353,"count":3},
...@@ -648,6 +641,7 @@ try { // 0200 ...@@ -648,6 +641,7 @@ try { // 0200
} catch (e) {} // 0450 } catch (e) {} // 0450
`, `,
[{"start":0,"end":499,"count":1}, [{"start":0,"end":499,"count":1},
{"start":451,"end":452,"count":0},
{"start":12,"end":101,"count":3}, {"start":12,"end":101,"count":3},
{"start":65,"end":100,"count":0}, {"start":65,"end":100,"count":0},
{"start":264,"end":353,"count":3}, {"start":264,"end":353,"count":3},
...@@ -846,8 +840,7 @@ Util.escape("foo.bar"); // 0400 ...@@ -846,8 +840,7 @@ Util.escape("foo.bar"); // 0400
`, `,
[{"start":0,"end":449,"count":1}, [{"start":0,"end":449,"count":1},
{"start":64,"end":351,"count":1}, {"start":64,"end":351,"count":1},
{"start":112,"end":203,"count":0}, {"start":112,"end":203,"count":0}]
{"start":268,"end":350,"count":0}]
); );
TestCoverage( TestCoverage(
...@@ -879,17 +872,136 @@ TestCoverage( ...@@ -879,17 +872,136 @@ TestCoverage(
{"start":1,"end":151,"count":1}, {"start":1,"end":151,"count":1},
{"start":118,"end":137,"count":0}, {"start":118,"end":137,"count":0},
{"start":201,"end":351,"count":1}, {"start":201,"end":351,"count":1},
{"start":277,"end":318,"count":0}, {"start":279,"end":318,"count":0},
{"start":401,"end":525,"count":1}, {"start":401,"end":525,"count":1},
{"start":475,"end":486,"count":0}, {"start":475,"end":486,"count":0},
{"start":503,"end":523,"count":0}, {"start":503,"end":523,"count":0},
{"start":551,"end":651,"count":1}, {"start":551,"end":651,"count":1},
{"start":622,"end":639,"count":0}, {"start":622,"end":639,"count":0},
{"start":701,"end":801,"count":1}, {"start":701,"end":801,"count":1},
{"start":773,"end":791,"count":0}, {"start":774,"end":791,"count":0},
{"start":851,"end":1001,"count":1}, {"start":851,"end":1001,"count":1},
{"start":920,"end":928,"count":0}, {"start":920,"end":928,"count":0},
{"start":929,"end":965,"count":0}] {"start":929,"end":965,"count":0}]
); );
TestCoverage(
"terminal break statement",
`
while (true) { // 0000
const b = false // 0050
break // 0100
} // 0150
let stop = false // 0200
while (true) { // 0250
if (stop) { // 0300
break // 0350
} // 0400
stop = true // 0450
} // 0500
`,
[{"start":0,"end":549,"count":1},
{"start":263,"end":501,"count":2},
{"start":312,"end":501,"count":1}]
);
TestCoverage(
"terminal return statement",
`
function a () { // 0000
const b = false // 0050
return 1 // 0100
} // 0150
const b = (early) => { // 0200
if (early) { // 0250
return 2 // 0300
} // 0350
return 3 // 0400
} // 0450
const c = () => { // 0500
if (true) { // 0550
return // 0600
} // 0650
} // 0700
a(); b(false); b(true); c() // 0750
`,
[{"start":0,"end":799,"count":1},
{"start":0,"end":151,"count":1},
{"start":210,"end":451,"count":2},
{"start":263,"end":450,"count":1},
{"start":510,"end":701,"count":1}]
);
TestCoverage(
"terminal blocks",
`
function a () { // 0000
{ // 0050
return 'a' // 0100
} // 0150
} // 0200
function b () { // 0250
{ // 0300
{ // 0350
return 'b' // 0400
} // 0450
} // 0500
} // 0550
a(); b() // 0600
`,
[{"start":0,"end":649,"count":1},
{"start":0,"end":201,"count":1},
{"start":250,"end":551,"count":1}]
);
TestCoverage(
"terminal if statements",
`
function a (branch) { // 0000
if (branch) { // 0050
return 'a' // 0100
} else { // 0150
return 'b' // 0200
} // 0250
} // 0300
function b (branch) { // 0350
if (branch) { // 0400
if (branch) { // 0450
return 'c' // 0500
} // 0550
} // 0600
} // 0650
function c (branch) { // 0700
if (branch) { // 0750
return 'c' // 0800
} else { // 0850
return 'd' // 0900
} // 0950
} // 1000
function d (branch) { // 1050
if (branch) { // 1100
if (!branch) { // 1150
return 'e' // 1200
} else { // 1250
return 'f' // 1300
} // 1350
} else { // 1400
// noop // 1450
} // 1500
} // 1550
a(true); a(false); b(true); b(false) // 1600
c(true); d(true); // 1650
`,
[{"start":0,"end":1699,"count":1},
{"start":0,"end":301,"count":2},
{"start":64,"end":253,"count":1},
{"start":350,"end":651,"count":2},
{"start":414,"end":603,"count":1},
{"start":700,"end":1001,"count":1},
{"start":853,"end":953,"count":0},
{"start":1050,"end":1551,"count":1},
{"start":1167,"end":1255,"count":0},
{"start":1403,"end":1503,"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