diff options
Diffstat (limited to 'deps/v8/src')
-rw-r--r-- | deps/v8/src/ast/ast-source-ranges.h | 83 | ||||
-rw-r--r-- | deps/v8/src/ast/source-range-ast-visitor.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ast/source-range-ast-visitor.h | 49 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-coverage.cc | 64 | ||||
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 1 | ||||
-rw-r--r-- | deps/v8/src/interpreter/control-flow-builders.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/interpreter/control-flow-builders.h | 7 | ||||
-rw-r--r-- | deps/v8/src/objects/debug-objects.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/parsing/parser-base.h | 8 | ||||
-rw-r--r-- | deps/v8/src/parsing/parser.cc | 12 |
10 files changed, 252 insertions, 44 deletions
diff --git a/deps/v8/src/ast/ast-source-ranges.h b/deps/v8/src/ast/ast-source-ranges.h index 60222a4035..a04e68fa2f 100644 --- a/deps/v8/src/ast/ast-source-ranges.h +++ b/deps/v8/src/ast/ast-source-ranges.h @@ -59,6 +59,8 @@ class AstNodeSourceRanges : public ZoneObject { public: virtual ~AstNodeSourceRanges() = default; virtual SourceRange GetRange(SourceRangeKind kind) = 0; + virtual bool HasRange(SourceRangeKind kind) = 0; + virtual void RemoveContinuationRange() { UNREACHABLE(); } }; class BinaryOperationSourceRanges final : public AstNodeSourceRanges { @@ -67,10 +69,14 @@ class BinaryOperationSourceRanges final : public AstNodeSourceRanges { : right_range_(right_range) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kRight); + DCHECK(HasRange(kind)); return right_range_; } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kRight; + } + private: SourceRange right_range_; }; @@ -81,10 +87,19 @@ class ContinuationSourceRanges : public AstNodeSourceRanges { : continuation_position_(continuation_position) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kContinuation); + DCHECK(HasRange(kind)); 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: int32_t continuation_position_; }; @@ -101,10 +116,14 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges { : body_range_(body_range) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kBody); + DCHECK(HasRange(kind)); return body_range_; } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kBody; + } + private: SourceRange body_range_; }; @@ -116,6 +135,7 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { : then_range_(then_range), else_range_(else_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kThen: return then_range_; @@ -126,6 +146,10 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse; + } + private: SourceRange then_range_; SourceRange else_range_; @@ -138,12 +162,14 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { : then_range_(then_range), else_range_(else_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kElse: return else_range_; case SourceRangeKind::kThen: return then_range_; case SourceRangeKind::kContinuation: { + if (!has_continuation_) return SourceRange::Empty(); const SourceRange& trailing_range = else_range_.IsEmpty() ? then_range_ : else_range_; return SourceRange::ContinuationOf(trailing_range); @@ -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: SourceRange then_range_; SourceRange else_range_; + bool has_continuation_ = true; }; class IterationStatementSourceRanges final : public AstNodeSourceRanges { @@ -164,18 +201,31 @@ class IterationStatementSourceRanges final : public AstNodeSourceRanges { : body_range_(body_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kBody: return body_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(body_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kBody || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange body_range_; + bool has_continuation_ = true; }; class JumpStatementSourceRanges final : public ContinuationSourceRanges { @@ -200,6 +250,7 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges { size_t RangeCount() const { return ranges_.size(); } SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); } + bool HasRange(SourceRangeKind kind) override { return false; } private: ZoneVector<SourceRange> ranges_; @@ -229,18 +280,31 @@ class TryCatchStatementSourceRanges final : public AstNodeSourceRanges { : catch_range_(catch_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kCatch: return catch_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(catch_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kCatch || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange catch_range_; + bool has_continuation_ = true; }; class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { @@ -249,18 +313,31 @@ class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { : finally_range_(finally_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kFinally: return finally_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(finally_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kFinally || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange finally_range_; + bool has_continuation_ = true; }; // Maps ast node pointers to associated source ranges. The parser creates these diff --git a/deps/v8/src/ast/source-range-ast-visitor.cc b/deps/v8/src/ast/source-range-ast-visitor.cc new file mode 100644 index 0000000000..b6acbddf0a --- /dev/null +++ b/deps/v8/src/ast/source-range-ast-visitor.cc @@ -0,0 +1,68 @@ +// 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 == nullptr || 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 diff --git a/deps/v8/src/ast/source-range-ast-visitor.h b/deps/v8/src/ast/source-range-ast-visitor.h new file mode 100644 index 0000000000..4ea36a947f --- /dev/null +++ b/deps/v8/src/ast/source-range-ast-visitor.h @@ -0,0 +1,49 @@ +// 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_ diff --git a/deps/v8/src/debug/debug-coverage.cc b/deps/v8/src/debug/debug-coverage.cc index 57c5f31079..9e0791babc 100644 --- a/deps/v8/src/debug/debug-coverage.cc +++ b/deps/v8/src/debug/debug-coverage.cc @@ -81,11 +81,6 @@ std::vector<CoverageBlock> GetSortedBlockData(SharedFunctionInfo* shared) { std::vector<CoverageBlock> result; if (coverage_info->SlotCount() == 0) return result; - if (FLAG_trace_block_coverage) { - PrintF("Collecting coverage data\n"); - coverage_info->Print(shared->DebugName()->ToCString()); - } - for (int i = 0; i < coverage_info->SlotCount(); i++) { const int start_pos = coverage_info->StartSourcePosition(i); const int until_pos = coverage_info->EndSourcePosition(i); @@ -176,6 +171,12 @@ class CoverageBlockIterator final { return function_->blocks[read_index_ + 1]; } + CoverageBlock& GetPreviousBlock() { + DCHECK(IsActive()); + DCHECK_GT(read_index_, 0); + return function_->blocks[read_index_ - 1]; + } + CoverageBlock& GetParent() { DCHECK(IsActive()); return nesting_stack_.back(); @@ -232,25 +233,6 @@ bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) { 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) { CoverageBlockIterator iter(function); @@ -330,6 +312,30 @@ void MergeNestedRanges(CoverageFunction* function) { } } +void FilterAliasedSingletons(CoverageFunction* function) { + CoverageBlockIterator iter(function); + + iter.Next(); // Advance once since we reference the previous block later. + + while (iter.Next()) { + CoverageBlock& previous_block = iter.GetPreviousBlock(); + CoverageBlock& block = iter.GetBlock(); + + bool is_singleton = block.end == kNoSourcePosition; + bool aliases_start = block.start == previous_block.start; + + if (is_singleton && aliases_start) { + // The previous block must have a full range since duplicate singletons + // have already been merged. + DCHECK_NE(previous_block.end, kNoSourcePosition); + // Likewise, the next block must have another start position since + // singletons are sorted to the end. + DCHECK_IMPLIES(iter.HasNext(), iter.GetNextBlock().start != block.start); + iter.DeleteBlock(); + } + } +} + void FilterUncoveredRanges(CoverageFunction* function) { CoverageBlockIterator iter(function); @@ -399,8 +405,14 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo* info, // If in binary mode, only report counts of 0/1. 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 + // throw away their counts. + // Singleton ranges are only intended to split existing full ranges and should + // never expand into a full range. Consider 'if (cond) { ... } else { ... }' + // as a problematic example; if the then-block produces a continuation + // singleton, it would incorrectly expand into the else range. + // For more context, see https://crbug.com/v8/8237. + FilterAliasedSingletons(function); // Rewrite all singletons (created e.g. by continuations and unconditional // control flow) to ranges. diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index b00d3773cd..48682439fb 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -368,7 +368,6 @@ class BytecodeGenerator::ControlScopeForBreakable final protected: bool Execute(Command command, Statement* statement, int source_position) override { - control_builder_->set_needs_continuation_counter(); if (statement != statement_) return false; switch (command) { case CMD_BREAK: diff --git a/deps/v8/src/interpreter/control-flow-builders.cc b/deps/v8/src/interpreter/control-flow-builders.cc index bada935e4a..6b1bdc3424 100644 --- a/deps/v8/src/interpreter/control-flow-builders.cc +++ b/deps/v8/src/interpreter/control-flow-builders.cc @@ -13,7 +13,7 @@ namespace interpreter { BreakableControlFlowBuilder::~BreakableControlFlowBuilder() { BindBreakTarget(); 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( node_, SourceRangeKind::kContinuation); } diff --git a/deps/v8/src/interpreter/control-flow-builders.h b/deps/v8/src/interpreter/control-flow-builders.h index fdc57776a8..8359f0d1ee 100644 --- a/deps/v8/src/interpreter/control-flow-builders.h +++ b/deps/v8/src/interpreter/control-flow-builders.h @@ -58,11 +58,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder 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: void EmitJump(BytecodeLabels* labels); void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode, @@ -81,7 +76,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder // A continuation counter (for block coverage) is needed e.g. when // encountering a break statement. AstNode* node_; - bool needs_continuation_counter_ = false; BlockCoverageBuilder* block_coverage_builder_; }; @@ -107,7 +101,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder { : BreakableControlFlowBuilder(builder, block_coverage_builder, node), continue_labels_(builder->zone()) { if (block_coverage_builder_ != nullptr) { - set_needs_continuation_counter(); block_coverage_body_slot_ = block_coverage_builder_->AllocateBlockCoverageSlot( node, SourceRangeKind::kBody); diff --git a/deps/v8/src/objects/debug-objects.cc b/deps/v8/src/objects/debug-objects.cc index 43fcdb5aee..b77b6e136e 100644 --- a/deps/v8/src/objects/debug-objects.cc +++ b/deps/v8/src/objects/debug-objects.cc @@ -375,7 +375,7 @@ void CoverageInfo::Print(std::unique_ptr<char[]> function_name) { for (int i = 0; i < SlotCount(); i++) { os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}" - << ": " << BlockCount(i) << std::endl; + << std::endl; } } diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index d1ad0e9d13..bfb056e0c8 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -5116,7 +5116,6 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement)); { BlockState block_state(zone(), &scope_); - // Scope starts before opening brace. scope()->set_start_position(scanner()->location().beg_pos); typename Types::Target target(this, body); @@ -5128,10 +5127,9 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( } Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullStatement)); - // Scope ends after closing brace. - scope()->set_end_position(scanner()->location().end_pos); - // Coverage range uses position before closing brace. - impl()->RecordBlockSourceRange(body, scanner()->location().beg_pos); + int end_pos = end_position(); + scope()->set_end_position(end_pos); + impl()->RecordBlockSourceRange(body, end_pos); body->set_scope(scope()->FinalizeBlockScope()); } return body; diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 6d0d9fff21..5687633f2f 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -10,6 +10,7 @@ #include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" +#include "src/ast/source-range-ast-visitor.h" #include "src/bailout-reason.h" #include "src/base/platform/platform.h" #include "src/char-predicates-inl.h" @@ -441,6 +442,15 @@ void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) { } } +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 FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { @@ -464,6 +474,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { scanner_.Initialize(); FunctionLiteral* result = DoParseProgram(isolate, info); MaybeResetCharacterStream(info, result); + MaybeProcessSourceRanges(info, result, stack_limit_); HandleSourceURLComments(isolate, info->script()); @@ -660,6 +671,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, FunctionLiteral* result = DoParseFunction(isolate, info, info->function_name()); MaybeResetCharacterStream(info, result); + MaybeProcessSourceRanges(info, result, stack_limit_); if (result != nullptr) { Handle<String> inferred_name(shared_info->inferred_name(), isolate); result->set_inferred_name(inferred_name); |