Commit 645a1ea5 authored by jgruber's avatar jgruber Committed by Commit Bot

[coverage] Move source ranges out of AST

This CL moves collected source range information out of AST nodes
and into a side table stored on ParseInfo. The side table is only 
created if block coverage is enabled, so there's almost no memory
overhead in the standard case.

Change-Id: I41871b8425ebbc6217d82d3ad26b5fc9e5d68ecb
Reviewed-on: https://chromium-review.googlesource.com/566808
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46590}
parent f720d024
......@@ -1152,6 +1152,7 @@ v8_source_set("v8_base") {
"src/ast/ast-function-literal-id-reindexer.h",
"src/ast/ast-numbering.cc",
"src/ast/ast-numbering.h",
"src/ast/ast-source-ranges.h",
"src/ast/ast-traversal-visitor.h",
"src/ast/ast-value-factory.cc",
"src/ast/ast-value-factory.h",
......
// Copyright 2017 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_AST_SOURCE_RANGES_H_
#define V8_AST_AST_SOURCE_RANGES_H_
#include "src/ast/ast.h"
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
// Specifies a range within the source code. {start} is 0-based and inclusive,
// {end} is 0-based and exclusive.
struct SourceRange {
SourceRange() : SourceRange(kNoSourcePosition, kNoSourcePosition) {}
SourceRange(int start, int end) : start(start), end(end) {}
bool IsEmpty() const { return start == kNoSourcePosition; }
static SourceRange Empty() { return SourceRange(); }
static SourceRange OpenEnded(int32_t start) {
return SourceRange(start, kNoSourcePosition);
}
static SourceRange ContinuationOf(const SourceRange& that) {
return that.IsEmpty() ? Empty() : OpenEnded(that.end);
}
int32_t start, end;
};
// The list of ast node kinds that have associated source ranges.
#define AST_SOURCE_RANGE_LIST(V) \
V(CaseClause) \
V(IfStatement) \
V(IterationStatement) \
V(JumpStatement) \
V(SwitchStatement) \
V(Throw) \
V(TryCatchStatement) \
V(TryFinallyStatement)
enum class SourceRangeKind {
kBody,
kCatch,
kContinuation,
kElse,
kFinally,
kThen,
};
class AstNodeSourceRanges : public ZoneObject {
public:
virtual ~AstNodeSourceRanges() {}
virtual SourceRange GetRange(SourceRangeKind kind) = 0;
};
class ContinuationSourceRanges : public AstNodeSourceRanges {
public:
explicit ContinuationSourceRanges(int32_t continuation_position)
: continuation_position_(continuation_position) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK(kind == SourceRangeKind::kContinuation);
return SourceRange::OpenEnded(continuation_position_);
}
private:
int32_t continuation_position_;
};
class CaseClauseSourceRanges final : public AstNodeSourceRanges {
public:
explicit CaseClauseSourceRanges(const SourceRange& body_range)
: body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK(kind == SourceRangeKind::kBody);
return body_range_;
}
private:
SourceRange body_range_;
};
class IfStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit IfStatementSourceRanges(const SourceRange& then_range,
const SourceRange& else_range)
: then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) {
switch (kind) {
case SourceRangeKind::kElse:
return else_range_;
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kContinuation: {
const SourceRange& trailing_range =
else_range_.IsEmpty() ? then_range_ : else_range_;
return SourceRange::ContinuationOf(trailing_range);
}
default:
UNREACHABLE();
}
}
private:
SourceRange then_range_;
SourceRange else_range_;
};
class IterationStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit IterationStatementSourceRanges(const SourceRange& body_range)
: body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) {
switch (kind) {
case SourceRangeKind::kBody:
return body_range_;
case SourceRangeKind::kContinuation:
return SourceRange::ContinuationOf(body_range_);
default:
UNREACHABLE();
}
}
private:
SourceRange body_range_;
};
class JumpStatementSourceRanges final : public ContinuationSourceRanges {
public:
explicit JumpStatementSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class SwitchStatementSourceRanges final : public ContinuationSourceRanges {
public:
explicit SwitchStatementSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class ThrowSourceRanges final : public ContinuationSourceRanges {
public:
explicit ThrowSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class TryCatchStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit TryCatchStatementSourceRanges(const SourceRange& catch_range)
: catch_range_(catch_range) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK(kind == SourceRangeKind::kCatch);
return catch_range_;
}
private:
SourceRange catch_range_;
};
class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit TryFinallyStatementSourceRanges(const SourceRange& finally_range)
: finally_range_(finally_range) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK(kind == SourceRangeKind::kFinally);
return finally_range_;
}
private:
SourceRange finally_range_;
};
// Maps ast node pointers to associated source ranges. The parser creates these
// mappings and the bytecode generator consumes them.
class SourceRangeMap final : public ZoneObject {
public:
explicit SourceRangeMap(Zone* zone) : map_(zone) {}
AstNodeSourceRanges* Find(AstNode* node) {
auto it = map_.find(node);
if (it == map_.end()) return nullptr;
return it->second;
}
// Type-checked insertion.
#define DEFINE_MAP_INSERT(type) \
void Insert(type* node, type##SourceRanges* ranges) { \
map_.emplace(node, ranges); \
}
AST_SOURCE_RANGE_LIST(DEFINE_MAP_INSERT)
#undef DEFINE_MAP_INSERT
private:
ZoneMap<AstNode*, AstNodeSourceRanges*> map_;
};
#undef AST_SOURCE_RANGE_LIST
} // namespace internal
} // namespace v8
#endif // V8_AST_AST_SOURCE_RANGES_H_
......@@ -1068,11 +1068,8 @@ Call::CallType Call::GetCallType() const {
}
CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements,
int pos, const SourceRange& clause_range)
: Expression(pos, kCaseClause),
label_(label),
statements_(statements),
clause_range_(clause_range) {}
int pos)
: Expression(pos, kCaseClause), label_(label), statements_(statements) {}
void CaseClause::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
......
This diff is collapsed.
......@@ -516,6 +516,8 @@ bool CompileUnoptimizedInnerFunctions(
parse_info.set_ast_value_factory(
outer_info->parse_info()->ast_value_factory());
parse_info.set_ast_value_factory_owned(false);
parse_info.set_source_range_map(
outer_info->parse_info()->source_range_map());
if (will_serialize) info.PrepareForSerializing();
if (is_debug) info.MarkAsDebug();
......
......@@ -6,6 +6,7 @@
#include "src/accessors.h"
#include "src/allocation-site-scopes.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h"
#include "src/base/bits.h"
#include "src/bootstrapper.h"
......
......@@ -5,7 +5,7 @@
#ifndef V8_INTERPRETER_BLOCK_COVERAGE_BUILDER_H_
#define V8_INTERPRETER_BLOCK_COVERAGE_BUILDER_H_
#include "src/ast/ast.h"
#include "src/ast/ast-source-ranges.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/zone/zone-containers.h"
......@@ -18,13 +18,24 @@ namespace interpreter {
// mapping for block coverage.
class BlockCoverageBuilder final : public ZoneObject {
public:
BlockCoverageBuilder(Zone* zone, BytecodeArrayBuilder* builder)
: slots_(0, zone), builder_(builder) {}
BlockCoverageBuilder(Zone* zone, BytecodeArrayBuilder* builder,
SourceRangeMap* source_range_map)
: slots_(0, zone),
builder_(builder),
source_range_map_(source_range_map) {
DCHECK_NOT_NULL(builder);
DCHECK_NOT_NULL(source_range_map);
}
static constexpr int kNoCoverageArraySlot = -1;
static const int kNoCoverageArraySlot = -1;
int AllocateBlockCoverageSlot(AstNode* node, SourceRangeKind kind) {
AstNodeSourceRanges* ranges = source_range_map_->Find(node);
if (ranges == nullptr) return kNoCoverageArraySlot;
int AllocateBlockCoverageSlot(SourceRange range) {
SourceRange range = ranges->GetRange(kind);
if (range.IsEmpty()) return kNoCoverageArraySlot;
const int slot = static_cast<int>(slots_.size());
slots_.emplace_back(range);
return slot;
......@@ -42,6 +53,7 @@ class BlockCoverageBuilder final : public ZoneObject {
// slots. Slot i covers range slots_[i].
ZoneVector<SourceRange> slots_;
BytecodeArrayBuilder* builder_;
SourceRangeMap* source_range_map_;
};
} // namespace interpreter
......
......@@ -4,6 +4,7 @@
#include "src/interpreter/bytecode-generator.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/compile-time-value.h"
#include "src/ast/scopes.h"
#include "src/builtins/builtins-constructor.h"
......@@ -802,8 +803,8 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
if (info->is_block_coverage_enabled()) {
DCHECK(FLAG_block_coverage);
block_coverage_builder_ =
new (zone()) BlockCoverageBuilder(zone(), builder());
block_coverage_builder_ = new (zone()) BlockCoverageBuilder(
zone(), builder(), info->parse_info()->source_range_map());
}
}
......@@ -1230,8 +1231,10 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
builder()->SetStatementPosition(stmt);
int then_slot = AllocateBlockCoverageSlotIfEnabled(stmt->then_range());
int else_slot = AllocateBlockCoverageSlotIfEnabled(stmt->else_range());
int then_slot =
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kThen);
int else_slot =
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kElse);
if (stmt->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
......@@ -1266,7 +1269,8 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
}
builder()->Bind(&end_label);
}
BuildIncrementBlockCoverageCounterIfEnabled(stmt->continuation_range());
BuildIncrementBlockCoverageCounterIfEnabled(stmt,
SourceRangeKind::kContinuation);
}
void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
......@@ -1275,19 +1279,19 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
}
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
AllocateBlockCoverageSlotIfEnabled(stmt->continuation_range());
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
builder()->SetStatementPosition(stmt);
execution_control()->Continue(stmt->target());
}
void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
AllocateBlockCoverageSlotIfEnabled(stmt->continuation_range());
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
builder()->SetStatementPosition(stmt);
execution_control()->Break(stmt->target());
}
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
AllocateBlockCoverageSlotIfEnabled(stmt->continuation_range());
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
builder()->SetStatementPosition(stmt);
VisitForAccumulatorValue(stmt->expression());
if (stmt->is_async_return()) {
......@@ -1348,11 +1352,12 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
for (int i = 0; i < clauses->length(); i++) {
CaseClause* clause = clauses->at(i);
switch_builder.SetCaseTarget(i);
BuildIncrementBlockCoverageCounterIfEnabled(clause->clause_range());
BuildIncrementBlockCoverageCounterIfEnabled(clause, SourceRangeKind::kBody);
VisitStatements(clause->statements());
}
switch_builder.BindBreakTarget();
BuildIncrementBlockCoverageCounterIfEnabled(stmt->continuation_range());
BuildIncrementBlockCoverageCounterIfEnabled(stmt,
SourceRangeKind::kContinuation);
}
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
......@@ -1370,8 +1375,7 @@ void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
}
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
LoopBuilder loop_builder(builder(), block_coverage_builder_,
stmt->body_range(), stmt->continuation_range());
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
if (stmt->cond()->ToBooleanIsFalse()) {
VisitIterationBody(stmt, &loop_builder);
} else if (stmt->cond()->ToBooleanIsTrue()) {
......@@ -1391,8 +1395,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
}
void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
LoopBuilder loop_builder(builder(), block_coverage_builder_,
stmt->body_range(), stmt->continuation_range());
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
if (stmt->cond()->ToBooleanIsFalse()) {
// If the condition is false there is no need to generate the loop.
......@@ -1412,8 +1415,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
}
void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
LoopBuilder loop_builder(builder(), block_coverage_builder_,
stmt->body_range(), stmt->continuation_range());
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
if (stmt->init() != nullptr) {
Visit(stmt->init());
......@@ -1536,7 +1538,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// The loop
{
LoopBuilder loop_builder(builder());
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
VisitIterationHeader(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->each());
builder()->ForInContinue(index, cache_length);
......@@ -1556,7 +1558,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
LoopBuilder loop_builder(builder());
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
builder()->SetExpressionAsStatementPosition(stmt->assign_iterator());
VisitForEffect(stmt->assign_iterator());
......@@ -1610,7 +1612,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
builder()->LoadAccumulatorWithRegister(context);
// Evaluate the catch-block.
BuildIncrementBlockCoverageCounterIfEnabled(stmt->catch_range());
BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kCatch);
VisitInScope(stmt->catch_block(), stmt->scope());
try_control_builder.EndCatch();
}
......@@ -1669,7 +1671,7 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
message);
// Evaluate the finally-block.
BuildIncrementBlockCoverageCounterIfEnabled(stmt->finally_range());
BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kFinally);
Visit(stmt->finally_block());
try_control_builder.EndFinally();
......@@ -2793,7 +2795,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
.StoreAccumulatorInRegister(resume_mode);
{
LoopBuilder loop(builder());
LoopBuilder loop(builder(), block_coverage_builder_, expr);
VisitIterationHeader(expr->suspend_id(), 1, &loop);
{
......@@ -2951,7 +2953,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
}
void BytecodeGenerator::VisitThrow(Throw* expr) {
AllocateBlockCoverageSlotIfEnabled(expr->continuation_range());
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation);
VisitForAccumulatorValue(expr->exception());
builder()->SetExpressionPosition(expr);
builder()->Throw();
......@@ -4154,24 +4156,24 @@ void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property,
}
int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(
const SourceRange& range) {
AstNode* node, SourceRangeKind kind) {
return (block_coverage_builder_ == nullptr)
? BlockCoverageBuilder::kNoCoverageArraySlot
: block_coverage_builder_->AllocateBlockCoverageSlot(range);
: block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
}
void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
int coverage_array_slot) {
if (block_coverage_builder_ != nullptr) {
block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
}
AstNode* node, SourceRangeKind kind) {
if (block_coverage_builder_ == nullptr) return;
int slot = block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
block_coverage_builder_->IncrementBlockCounter(slot);
}
void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
const SourceRange& range) {
int coverage_array_slot) {
if (block_coverage_builder_ != nullptr) {
int slot = block_coverage_builder_->AllocateBlockCoverageSlot(range);
block_coverage_builder_->IncrementBlockCounter(slot);
block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
}
}
......
......@@ -14,8 +14,10 @@
namespace v8 {
namespace internal {
class AstNodeSourceRanges;
class AstStringConstants;
class CompilationInfo;
enum class SourceRangeKind;
namespace interpreter {
......@@ -192,9 +194,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);
int AllocateBlockCoverageSlotIfEnabled(const SourceRange& range);
int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
SourceRangeKind kind);
void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);
void BuildIncrementBlockCoverageCounterIfEnabled(const SourceRange& range);
void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
......
......@@ -7,6 +7,7 @@
#include "src/interpreter/bytecode-array-builder.h"
#include "src/ast/ast-source-ranges.h"
#include "src/interpreter/block-coverage-builder.h"
#include "src/interpreter/bytecode-label.h"
#include "src/zone/zone-containers.h"
......@@ -89,9 +90,7 @@ class V8_EXPORT_PRIVATE BlockBuilder final
class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
public:
LoopBuilder(BytecodeArrayBuilder* builder,
BlockCoverageBuilder* block_coverage_builder = nullptr,
const SourceRange& body_range = {},
const SourceRange& continuation_range = {})
BlockCoverageBuilder* block_coverage_builder, AstNode* node)
: BreakableControlFlowBuilder(builder),
continue_labels_(builder->zone()),
generator_jump_table_location_(nullptr),
......@@ -99,10 +98,11 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
block_coverage_builder_(block_coverage_builder) {
if (block_coverage_builder_ != nullptr) {
block_coverage_body_slot_ =
block_coverage_builder_->AllocateBlockCoverageSlot(body_range);
block_coverage_builder_->AllocateBlockCoverageSlot(
node, SourceRangeKind::kBody);
block_coverage_continuation_slot_ =
block_coverage_builder_->AllocateBlockCoverageSlot(
continuation_range);
node, SourceRangeKind::kContinuation);
}
}
~LoopBuilder();
......
......@@ -5,6 +5,7 @@
#include "src/parsing/parse-info.h"
#include "src/api.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/heap/heap-inl.h"
......@@ -39,6 +40,7 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
ast_string_constants_(nullptr),
function_name_(nullptr),
runtime_call_stats_(nullptr),
source_range_map_(nullptr),
literal_(nullptr),
deferred_handles_(nullptr) {}
......@@ -162,6 +164,9 @@ void ParseInfo::InitFromIsolate(Isolate* isolate) {
isolate->is_tail_call_elimination_enabled());
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_ast_string_constants(isolate->ast_string_constants());
if (FLAG_block_coverage && isolate->is_block_code_coverage()) {
set_source_range_map(new (zone()) SourceRangeMap(zone()));
}
}
void ParseInfo::UpdateStatisticsAfterBackgroundParse(Isolate* isolate) {
......
......@@ -31,6 +31,7 @@ class FunctionLiteral;
class RuntimeCallStats;
class ScriptData;
class SharedFunctionInfo;
class SourceRangeMap;
class UnicodeCache;
class Utf16CharacterStream;
class Zone;
......@@ -207,6 +208,11 @@ class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
runtime_call_stats_ = runtime_call_stats;
}
SourceRangeMap* source_range_map() const { return source_range_map_; }
void set_source_range_map(SourceRangeMap* source_range_map) {
source_range_map_ = source_range_map;
}
// Getters for individual compiler hints.
bool is_declaration() const;
FunctionKind function_kind() const;
......@@ -310,6 +316,7 @@ class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
const class AstStringConstants* ast_string_constants_;
const AstRawString* function_name_;
RuntimeCallStats* runtime_call_stats_;
SourceRangeMap* source_range_map_; // Used when block coverage is enabled.
//----------- Output of parsing and scope analysis ------------------------
FunctionLiteral* literal_;
......
......@@ -5,6 +5,7 @@
#ifndef V8_PARSING_PARSER_BASE_H
#define V8_PARSING_PARSER_BASE_H
#include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
......@@ -101,11 +102,12 @@ class SourceRangeScope final {
~SourceRangeScope() { Finalize(); }
void Finalize() {
if (is_finalized_) return;
const SourceRange& Finalize() {
if (is_finalized_) return *range_;
is_finalized_ = true;
range_->end = GetPosition(post_kind_);
DCHECK_NE(range_->end, kNoSourcePosition);
return *range_;
}
private:
......@@ -1428,12 +1430,9 @@ class ParserBase {
// Convenience method which determines the type of return statement to emit
// depending on the current function type.
inline StatementT BuildReturnStatement(
ExpressionT expr, int pos, int continuation_pos = kNoSourcePosition) {
if (is_async_function()) {
return factory()->NewAsyncReturnStatement(expr, pos, continuation_pos);
}
return factory()->NewReturnStatement(expr, pos, continuation_pos);
inline StatementT BuildReturnStatement(ExpressionT expr, int pos) {
return is_async_function() ? factory()->NewAsyncReturnStatement(expr, pos)
: factory()->NewReturnStatement(expr, pos);
}
inline SuspendExpressionT BuildSuspend(
......@@ -5200,8 +5199,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
} else {
else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
return factory()->NewIfStatement(condition, then_statement, else_statement,
pos, then_range, else_range);
StatementT stmt =
factory()->NewIfStatement(condition, then_statement, else_statement, pos);
impl()->RecordIfStatementSourceRange(stmt, then_range, else_range);
return stmt;
}
template <typename Impl>
......@@ -5236,8 +5237,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
return impl()->NullStatement();
}
ExpectSemicolon(CHECK_OK);
int continuation_pos = scanner_->location().end_pos;
return factory()->NewContinueStatement(target, pos, continuation_pos);
StatementT stmt = factory()->NewContinueStatement(target, pos);
impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
return stmt;
}
template <typename Impl>
......@@ -5275,8 +5277,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
return impl()->NullStatement();
}
ExpectSemicolon(CHECK_OK);
int continuation_pos = scanner_->location().end_pos;
return factory()->NewBreakStatement(target, pos, continuation_pos);
StatementT stmt = factory()->NewBreakStatement(target, pos);
impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
return stmt;
}
template <typename Impl>
......@@ -5330,8 +5333,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
}
ExpectSemicolon(CHECK_OK);
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
int continuation_pos = scanner_->location().end_pos;
return BuildReturnStatement(return_value, loc.beg_pos, continuation_pos);
StatementT stmt = BuildReturnStatement(return_value, loc.beg_pos);
impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
return stmt;
}
template <typename Impl>
......@@ -5393,7 +5397,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
// ExpectSemicolon() functionality here.
Check(Token::SEMICOLON);
loop->Initialize(cond, body, body_range);
loop->Initialize(cond, body);
impl()->RecordIterationStatementSourceRange(loop, body_range);
return loop;
}
......@@ -5418,7 +5424,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
body = ParseStatement(nullptr, CHECK_OK);
}
loop->Initialize(cond, body, body_range);
loop->Initialize(cond, body);
impl()->RecordIterationStatementSourceRange(loop, body_range);
return loop;
}
......@@ -5437,9 +5445,11 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
}
ExpressionT exception = ParseExpression(true, CHECK_OK);
ExpectSemicolon(CHECK_OK);
int continuation_pos = scanner_->location().end_pos;
return impl()->NewThrowStatement(exception, pos, continuation_pos);
StatementT stmt = impl()->NewThrowStatement(exception, pos);
impl()->RecordThrowSourceRange(stmt, scanner_->location().end_pos);
return stmt;
}
template <typename Impl>
......@@ -5493,19 +5503,17 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
StatementT stat = ParseStatementListItem(CHECK_OK);
statements->Add(stat, zone());
}
range_scope.Finalize();
auto clause =
factory()->NewCaseClause(label, statements, clause_pos, clause_range);
auto clause = factory()->NewCaseClause(label, statements, clause_pos);
impl()->RecordCaseClauseSourceRange(clause, range_scope.Finalize());
cases->Add(clause, zone());
}
Expect(Token::RBRACE, CHECK_OK);
int end_position = scanner()->location().end_pos;
scope()->set_end_position(end_position);
int continuation_pos = end_position;
impl()->RecordSwitchStatementSourceRange(switch_statement, end_position);
return impl()->RewriteSwitchStatement(tag, switch_statement, cases,
scope()->FinalizeBlockScope(),
continuation_pos);
scope()->FinalizeBlockScope());
}
}
......@@ -5879,11 +5887,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
}
block->statements()->Add(loop, zone());
block->set_scope(for_scope);
loop->Initialize(init, cond, next, body, body_range);
loop->Initialize(init, cond, next, body);
impl()->RecordIterationStatementSourceRange(loop, body_range);
return block;
}
loop->Initialize(init, cond, next, body, body_range);
loop->Initialize(init, cond, next, body);
impl()->RecordIterationStatementSourceRange(loop, body_range);
return loop;
}
......
......@@ -487,6 +487,7 @@ Parser::Parser(ParseInfo* info)
scanner_(info->unicode_cache()),
reusable_preparser_(nullptr),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
source_range_map_(info->source_range_map()),
target_stack_(nullptr),
compile_options_(info->compile_options()),
cached_parse_data_(nullptr),
......@@ -1641,8 +1642,7 @@ Expression* Parser::RewriteDoExpression(Block* body, int pos, bool* ok) {
Statement* Parser::RewriteSwitchStatement(Expression* tag,
SwitchStatement* switch_statement,
ZoneList<CaseClause*>* cases,
Scope* scope,
int32_t continuation_pos) {
Scope* scope) {
// In order to get the CaseClauses to execute in their own lexical scope,
// but without requiring downstream code to have special scope handling
// code for switch statements, desugar into blocks as follows:
......@@ -1673,7 +1673,7 @@ Statement* Parser::RewriteSwitchStatement(Expression* tag,
zone());
Expression* tag_read = factory()->NewVariableProxy(tag_variable);
switch_statement->Initialize(tag_read, cases, continuation_pos);
switch_statement->Initialize(tag_read, cases);
Block* cases_block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
cases_block->statements()->Add(switch_statement, zone());
cases_block->set_scope(scope);
......@@ -1751,8 +1751,8 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
DCHECK_NOT_NULL(catch_info.scope);
TryCatchStatement* statement;
statement = factory()->NewTryCatchStatement(try_block, catch_info.scope,
catch_block, kNoSourcePosition,
catch_range);
catch_block, kNoSourcePosition);
RecordTryCatchStatementSourceRange(statement, catch_range);
try_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
try_block->statements()->Add(statement, zone());
......@@ -1767,12 +1767,16 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
DCHECK_NULL(finally_block);
DCHECK_NOT_NULL(catch_info.scope);
return factory()->NewTryCatchStatement(try_block, catch_info.scope,
catch_block, pos, catch_range);
TryCatchStatement* stmt = factory()->NewTryCatchStatement(
try_block, catch_info.scope, catch_block, pos);
RecordTryCatchStatementSourceRange(stmt, catch_range);
return stmt;
} else {
DCHECK_NOT_NULL(finally_block);
return factory()->NewTryFinallyStatement(try_block, finally_block, pos,
finally_range);
TryFinallyStatement* stmt =
factory()->NewTryFinallyStatement(try_block, finally_block, pos);
RecordTryFinallyStatementSourceRange(stmt, finally_range);
return stmt;
}
}
......@@ -2448,7 +2452,9 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
inner_block->set_scope(inner_scope);
}
outer_loop->Initialize(NULL, NULL, NULL, inner_block, body_range);
outer_loop->Initialize(NULL, NULL, NULL, inner_block);
RecordIterationStatementSourceRange(outer_loop, body_range);
return outer_block;
}
......@@ -4616,8 +4622,7 @@ Expression* Parser::RewriteYieldStar(Expression* iterable, int pos) {
cases->Add(factory()->NewCaseClause(kreturn, case_return, nopos), zone());
cases->Add(factory()->NewCaseClause(kthrow, case_throw, nopos), zone());
switch_mode->Initialize(factory()->NewVariableProxy(var_mode), cases,
kNoSourcePosition);
switch_mode->Initialize(factory()->NewVariableProxy(var_mode), cases);
}
// while (true) { ... }
......
......@@ -5,6 +5,7 @@
#ifndef V8_PARSING_PARSER_H_
#define V8_PARSING_PARSER_H_
#include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/base/compiler-specific.h"
......@@ -340,8 +341,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(Expression* tag,
SwitchStatement* switch_statement,
ZoneList<CaseClause*>* cases, Scope* scope,
int32_t continuation_pos);
ZoneList<CaseClause*>* cases, Scope* scope);
void RewriteCatchPattern(CatchInfo* catch_info, bool* ok);
void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok);
Statement* RewriteTryStatement(Block* try_block, Block* catch_block,
......@@ -1051,10 +1051,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ZoneList<Expression*>* args, int pos,
bool* ok);
V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos,
int32_t continuation_pos) {
V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) {
return factory()->NewExpressionStatement(
factory()->NewThrow(exception, pos, continuation_pos), pos);
factory()->NewThrow(exception, pos), pos);
}
V8_INLINE void AddParameterInitializationBlock(
......@@ -1147,6 +1146,68 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return parameters_end_pos_ != kNoSourcePosition;
}
V8_INLINE void RecordCaseClauseSourceRange(CaseClause* node,
const SourceRange& body_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(node,
new (zone()) CaseClauseSourceRanges(body_range));
}
V8_INLINE void RecordJumpStatementSourceRange(Statement* node,
int32_t continuation_position) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
static_cast<JumpStatement*>(node),
new (zone()) JumpStatementSourceRanges(continuation_position));
}
V8_INLINE void RecordIfStatementSourceRange(Statement* node,
const SourceRange& then_range,
const SourceRange& else_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node->AsIfStatement(),
new (zone()) IfStatementSourceRanges(then_range, else_range));
}
V8_INLINE void RecordIterationStatementSourceRange(
IterationStatement* node, const SourceRange& body_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node, new (zone()) IterationStatementSourceRanges(body_range));
}
V8_INLINE void RecordSwitchStatementSourceRange(
Statement* node, int32_t continuation_position) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node->AsSwitchStatement(),
new (zone()) SwitchStatementSourceRanges(continuation_position));
}
V8_INLINE void RecordThrowSourceRange(Statement* node,
int32_t continuation_position) {
if (source_range_map_ == nullptr) return;
ExpressionStatement* expr_stmt = static_cast<ExpressionStatement*>(node);
Throw* throw_expr = expr_stmt->expression()->AsThrow();
source_range_map_->Insert(
throw_expr, new (zone()) ThrowSourceRanges(continuation_position));
}
V8_INLINE void RecordTryCatchStatementSourceRange(
TryCatchStatement* node, const SourceRange& body_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node, new (zone()) TryCatchStatementSourceRanges(body_range));
}
V8_INLINE void RecordTryFinallyStatementSourceRange(
TryFinallyStatement* node, const SourceRange& body_range) {
if (source_range_map_ == nullptr) return;
source_range_map_->Insert(
node, new (zone()) TryFinallyStatementSourceRanges(body_range));
}
// Parser's private field members.
friend class DiscardableZoneScope; // Uses reusable_preparser_.
// FIXME(marja): Make reusable_preparser_ always use its own temp Zone (call
......@@ -1161,6 +1222,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
CompilerDispatcher* compiler_dispatcher_ = nullptr;
ParseInfo* main_parse_info_ = nullptr;
SourceRangeMap* source_range_map_ = nullptr;
friend class ParserTarget;
friend class ParserTargetScope;
ParserTarget* target_stack_; // for break, continue statements
......
......@@ -769,8 +769,7 @@ class PreParserFactory {
}
PreParserStatement NewCaseClause(PreParserExpression label,
PreParserStatementList statements, int pos,
const SourceRange& clause_range) {
PreParserStatementList statements, int pos) {
return PreParserStatement::Default();
}
......@@ -1068,7 +1067,7 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserStatement RewriteSwitchStatement(
PreParserExpression tag, PreParserStatement switch_statement,
PreParserStatementList cases, Scope* scope, int32_t continuation_pos) {
PreParserStatementList cases, Scope* scope) {
return PreParserStatement::Default();
}
......@@ -1638,8 +1637,7 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserStatement NewThrowStatement(PreParserExpression exception,
int pos,
int32_t continuation_pos) {
int pos) {
return PreParserStatement::Jump();
}
......@@ -1745,6 +1743,25 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return false; }
V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node,
const SourceRange& body_range) {}
V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node,
const SourceRange& then_range,
const SourceRange& else_range) {}
V8_INLINE void RecordJumpStatementSourceRange(PreParserStatement node,
int32_t continuation_position) {
}
V8_INLINE void RecordIterationStatementSourceRange(
PreParserStatement node, const SourceRange& body_range) {}
V8_INLINE void RecordSwitchStatementSourceRange(
PreParserStatement node, int32_t continuation_position) {}
V8_INLINE void RecordThrowSourceRange(PreParserStatement node,
int32_t continuation_position) {}
V8_INLINE void RecordTryCatchStatementSourceRange(
PreParserStatement node, const SourceRange& body_range) {}
V8_INLINE void RecordTryFinallyStatementSourceRange(
PreParserStatement node, const SourceRange& body_range) {}
// Preparser's private field members.
int* use_counts_;
......
......@@ -593,6 +593,7 @@
'ast/ast-function-literal-id-reindexer.h',
'ast/ast-numbering.cc',
'ast/ast-numbering.h',
'ast/ast-source-ranges.h',
'ast/ast-traversal-visitor.h',
'ast/ast-value-factory.cc',
'ast/ast-value-factory.h',
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --no-always-opt --block-coverage
// Flags: --allow-natives-syntax --no-always-opt --ignition --block-coverage
// Test precise code coverage.
......@@ -342,6 +342,36 @@ TestCoverage(
{"start":513,"end":564,"count":0}]
);
TestCoverage(
"early return in blocks",
`
!function() { // 0000
try { throw 42; } catch (e) { return; } // 0050
nop(); // 0100
}(); // 0150
!function() { // 0200
try { nop(); } finally { return; } // 0250
nop(); // 0300
}(); // 0350
!function() { // 0400
{ // 0450
let x = 42; // 0500
return () => x; // 0550
} // 0600
nop(); // 0650
}(); // 0700
`,
[{"start":0,"end":749,"count":1},
{"start":1,"end":151,"count":1},
{"start":67,"end":80,"count":0},
{"start":89,"end":91,"count":0}, // TODO(jgruber): Missing continuation.
{"start":201,"end":351,"count":1},
{"start":284,"end":286,"count":0}, // TODO(jgruber): Missing continuation.
{"start":401,"end":701,"count":1},
{"start":569,"end":701,"count":0},
{"start":561,"end":568,"count":0}] // TODO(jgruber): Sorting.
);
TestCoverage(
"switch statements",
`
......
......@@ -236,7 +236,7 @@ TEST_F(BytecodeAnalysisTest, SimpleLoop) {
expected_liveness.emplace_back("..LL", "L.LL");
{
interpreter::LoopBuilder loop_builder(&builder);
interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
loop_builder.LoopHeader();
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
......@@ -322,7 +322,7 @@ TEST_F(BytecodeAnalysisTest, DiamondInLoop) {
expected_liveness.emplace_back("...L", "L..L");
{
interpreter::LoopBuilder loop_builder(&builder);
interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
loop_builder.LoopHeader();
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
......@@ -371,7 +371,7 @@ TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) {
expected_liveness.emplace_back(".L.L", "LL..");
{
interpreter::LoopBuilder loop_builder(&builder);
interpreter::LoopBuilder loop_builder(&builder, nullptr, nullptr);
loop_builder.LoopHeader();
builder.LoadAccumulatorWithRegister(reg_0);
......@@ -385,7 +385,7 @@ TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) {
expected_liveness.emplace_back(".L.L", ".L.L");
{
interpreter::LoopBuilder inner_loop_builder(&builder);
interpreter::LoopBuilder inner_loop_builder(&builder, nullptr, nullptr);
inner_loop_builder.LoopHeader();
builder.StoreAccumulatorInRegister(reg_0);
......
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