11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/debug/debug-coverage.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/ast/ast-source-ranges.h"
81cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
91cb0ef41Sopenharmony_ci#include "src/base/hashmap.h"
101cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
111cb0ef41Sopenharmony_ci#include "src/common/globals.h"
121cb0ef41Sopenharmony_ci#include "src/debug/debug.h"
131cb0ef41Sopenharmony_ci#include "src/deoptimizer/deoptimizer.h"
141cb0ef41Sopenharmony_ci#include "src/execution/frames-inl.h"
151cb0ef41Sopenharmony_ci#include "src/execution/isolate.h"
161cb0ef41Sopenharmony_ci#include "src/objects/debug-objects-inl.h"
171cb0ef41Sopenharmony_ci#include "src/objects/objects.h"
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cinamespace v8 {
201cb0ef41Sopenharmony_cinamespace internal {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciclass SharedToCounterMap
231cb0ef41Sopenharmony_ci    : public base::TemplateHashMapImpl<SharedFunctionInfo, uint32_t,
241cb0ef41Sopenharmony_ci                                       base::KeyEqualityMatcher<Object>,
251cb0ef41Sopenharmony_ci                                       base::DefaultAllocationPolicy> {
261cb0ef41Sopenharmony_ci public:
271cb0ef41Sopenharmony_ci  using Entry = base::TemplateHashMapEntry<SharedFunctionInfo, uint32_t>;
281cb0ef41Sopenharmony_ci  inline void Add(SharedFunctionInfo key, uint32_t count) {
291cb0ef41Sopenharmony_ci    Entry* entry = LookupOrInsert(key, Hash(key), []() { return 0; });
301cb0ef41Sopenharmony_ci    uint32_t old_count = entry->value;
311cb0ef41Sopenharmony_ci    if (UINT32_MAX - count < old_count) {
321cb0ef41Sopenharmony_ci      entry->value = UINT32_MAX;
331cb0ef41Sopenharmony_ci    } else {
341cb0ef41Sopenharmony_ci      entry->value = old_count + count;
351cb0ef41Sopenharmony_ci    }
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  inline uint32_t Get(SharedFunctionInfo key) {
391cb0ef41Sopenharmony_ci    Entry* entry = Lookup(key, Hash(key));
401cb0ef41Sopenharmony_ci    if (entry == nullptr) return 0;
411cb0ef41Sopenharmony_ci    return entry->value;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci private:
451cb0ef41Sopenharmony_ci  static uint32_t Hash(SharedFunctionInfo key) {
461cb0ef41Sopenharmony_ci    return static_cast<uint32_t>(key.ptr());
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  DISALLOW_GARBAGE_COLLECTION(no_gc)
501cb0ef41Sopenharmony_ci};
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cinamespace {
531cb0ef41Sopenharmony_ciint StartPosition(SharedFunctionInfo info) {
541cb0ef41Sopenharmony_ci  int start = info.function_token_position();
551cb0ef41Sopenharmony_ci  if (start == kNoSourcePosition) start = info.StartPosition();
561cb0ef41Sopenharmony_ci  return start;
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_cibool CompareCoverageBlock(const CoverageBlock& a, const CoverageBlock& b) {
601cb0ef41Sopenharmony_ci  DCHECK_NE(kNoSourcePosition, a.start);
611cb0ef41Sopenharmony_ci  DCHECK_NE(kNoSourcePosition, b.start);
621cb0ef41Sopenharmony_ci  if (a.start == b.start) return a.end > b.end;
631cb0ef41Sopenharmony_ci  return a.start < b.start;
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_civoid SortBlockData(std::vector<CoverageBlock>& v) {
671cb0ef41Sopenharmony_ci  // Sort according to the block nesting structure.
681cb0ef41Sopenharmony_ci  std::sort(v.begin(), v.end(), CompareCoverageBlock);
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_cistd::vector<CoverageBlock> GetSortedBlockData(SharedFunctionInfo shared) {
721cb0ef41Sopenharmony_ci  DCHECK(shared.HasCoverageInfo());
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  CoverageInfo coverage_info =
751cb0ef41Sopenharmony_ci      CoverageInfo::cast(shared.GetDebugInfo().coverage_info());
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  std::vector<CoverageBlock> result;
781cb0ef41Sopenharmony_ci  if (coverage_info.slot_count() == 0) return result;
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  for (int i = 0; i < coverage_info.slot_count(); i++) {
811cb0ef41Sopenharmony_ci    const int start_pos = coverage_info.slots_start_source_position(i);
821cb0ef41Sopenharmony_ci    const int until_pos = coverage_info.slots_end_source_position(i);
831cb0ef41Sopenharmony_ci    const int count = coverage_info.slots_block_count(i);
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    DCHECK_NE(kNoSourcePosition, start_pos);
861cb0ef41Sopenharmony_ci    result.emplace_back(start_pos, until_pos, count);
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  SortBlockData(result);
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  return result;
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci// A utility class to simplify logic for performing passes over block coverage
951cb0ef41Sopenharmony_ci// ranges. Provides access to the implicit tree structure of ranges (i.e. access
961cb0ef41Sopenharmony_ci// to parent and sibling blocks), and supports efficient in-place editing and
971cb0ef41Sopenharmony_ci// deletion. The underlying backing store is the array of CoverageBlocks stored
981cb0ef41Sopenharmony_ci// on the CoverageFunction.
991cb0ef41Sopenharmony_ciclass CoverageBlockIterator final {
1001cb0ef41Sopenharmony_ci public:
1011cb0ef41Sopenharmony_ci  explicit CoverageBlockIterator(CoverageFunction* function)
1021cb0ef41Sopenharmony_ci      : function_(function) {
1031cb0ef41Sopenharmony_ci    DCHECK(std::is_sorted(function_->blocks.begin(), function_->blocks.end(),
1041cb0ef41Sopenharmony_ci                          CompareCoverageBlock));
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  ~CoverageBlockIterator() {
1081cb0ef41Sopenharmony_ci    Finalize();
1091cb0ef41Sopenharmony_ci    DCHECK(std::is_sorted(function_->blocks.begin(), function_->blocks.end(),
1101cb0ef41Sopenharmony_ci                          CompareCoverageBlock));
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  bool HasNext() const {
1141cb0ef41Sopenharmony_ci    return read_index_ + 1 < static_cast<int>(function_->blocks.size());
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  bool Next() {
1181cb0ef41Sopenharmony_ci    if (!HasNext()) {
1191cb0ef41Sopenharmony_ci      if (!ended_) MaybeWriteCurrent();
1201cb0ef41Sopenharmony_ci      ended_ = true;
1211cb0ef41Sopenharmony_ci      return false;
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci    // If a block has been deleted, subsequent iteration moves trailing blocks
1251cb0ef41Sopenharmony_ci    // to their updated position within the array.
1261cb0ef41Sopenharmony_ci    MaybeWriteCurrent();
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci    if (read_index_ == -1) {
1291cb0ef41Sopenharmony_ci      // Initialize the nesting stack with the function range.
1301cb0ef41Sopenharmony_ci      nesting_stack_.emplace_back(function_->start, function_->end,
1311cb0ef41Sopenharmony_ci                                  function_->count);
1321cb0ef41Sopenharmony_ci    } else if (!delete_current_) {
1331cb0ef41Sopenharmony_ci      nesting_stack_.emplace_back(GetBlock());
1341cb0ef41Sopenharmony_ci    }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    delete_current_ = false;
1371cb0ef41Sopenharmony_ci    read_index_++;
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    CoverageBlock& block = GetBlock();
1421cb0ef41Sopenharmony_ci    while (nesting_stack_.size() > 1 &&
1431cb0ef41Sopenharmony_ci           nesting_stack_.back().end <= block.start) {
1441cb0ef41Sopenharmony_ci      nesting_stack_.pop_back();
1451cb0ef41Sopenharmony_ci    }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci    DCHECK_IMPLIES(block.start >= function_->end,
1481cb0ef41Sopenharmony_ci                   block.end == kNoSourcePosition);
1491cb0ef41Sopenharmony_ci    DCHECK_NE(block.start, kNoSourcePosition);
1501cb0ef41Sopenharmony_ci    DCHECK_LE(block.end, GetParent().end);
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci    return true;
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  CoverageBlock& GetBlock() {
1561cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1571cb0ef41Sopenharmony_ci    return function_->blocks[read_index_];
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  CoverageBlock& GetNextBlock() {
1611cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1621cb0ef41Sopenharmony_ci    DCHECK(HasNext());
1631cb0ef41Sopenharmony_ci    return function_->blocks[read_index_ + 1];
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  CoverageBlock& GetPreviousBlock() {
1671cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1681cb0ef41Sopenharmony_ci    DCHECK_GT(read_index_, 0);
1691cb0ef41Sopenharmony_ci    return function_->blocks[read_index_ - 1];
1701cb0ef41Sopenharmony_ci  }
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci  CoverageBlock& GetParent() {
1731cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1741cb0ef41Sopenharmony_ci    return nesting_stack_.back();
1751cb0ef41Sopenharmony_ci  }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  bool HasSiblingOrChild() {
1781cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1791cb0ef41Sopenharmony_ci    return HasNext() && GetNextBlock().start < GetParent().end;
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  CoverageBlock& GetSiblingOrChild() {
1831cb0ef41Sopenharmony_ci    DCHECK(HasSiblingOrChild());
1841cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1851cb0ef41Sopenharmony_ci    return GetNextBlock();
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  // A range is considered to be at top level if its parent range is the
1891cb0ef41Sopenharmony_ci  // function range.
1901cb0ef41Sopenharmony_ci  bool IsTopLevel() const { return nesting_stack_.size() == 1; }
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci  void DeleteBlock() {
1931cb0ef41Sopenharmony_ci    DCHECK(!delete_current_);
1941cb0ef41Sopenharmony_ci    DCHECK(IsActive());
1951cb0ef41Sopenharmony_ci    delete_current_ = true;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci private:
1991cb0ef41Sopenharmony_ci  void MaybeWriteCurrent() {
2001cb0ef41Sopenharmony_ci    if (delete_current_) return;
2011cb0ef41Sopenharmony_ci    if (read_index_ >= 0 && write_index_ != read_index_) {
2021cb0ef41Sopenharmony_ci      function_->blocks[write_index_] = function_->blocks[read_index_];
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci    write_index_++;
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  void Finalize() {
2081cb0ef41Sopenharmony_ci    while (Next()) {
2091cb0ef41Sopenharmony_ci      // Just iterate to the end.
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci    function_->blocks.resize(write_index_);
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  bool IsActive() const { return read_index_ >= 0 && !ended_; }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  CoverageFunction* function_;
2171cb0ef41Sopenharmony_ci  std::vector<CoverageBlock> nesting_stack_;
2181cb0ef41Sopenharmony_ci  bool ended_ = false;
2191cb0ef41Sopenharmony_ci  bool delete_current_ = false;
2201cb0ef41Sopenharmony_ci  int read_index_ = -1;
2211cb0ef41Sopenharmony_ci  int write_index_ = -1;
2221cb0ef41Sopenharmony_ci};
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_cibool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) {
2251cb0ef41Sopenharmony_ci  return lhs.start == rhs.start && lhs.end == rhs.end;
2261cb0ef41Sopenharmony_ci}
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_civoid MergeDuplicateRanges(CoverageFunction* function) {
2291cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  while (iter.Next() && iter.HasNext()) {
2321cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
2331cb0ef41Sopenharmony_ci    CoverageBlock& next_block = iter.GetNextBlock();
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci    if (!HaveSameSourceRange(block, next_block)) continue;
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci    DCHECK_NE(kNoSourcePosition, block.end);  // Non-singleton range.
2381cb0ef41Sopenharmony_ci    next_block.count = std::max(block.count, next_block.count);
2391cb0ef41Sopenharmony_ci    iter.DeleteBlock();
2401cb0ef41Sopenharmony_ci  }
2411cb0ef41Sopenharmony_ci}
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci// Rewrite position singletons (produced by unconditional control flow
2441cb0ef41Sopenharmony_ci// like return statements, and by continuation counters) into source
2451cb0ef41Sopenharmony_ci// ranges that end at the next sibling range or the end of the parent
2461cb0ef41Sopenharmony_ci// range, whichever comes first.
2471cb0ef41Sopenharmony_civoid RewritePositionSingletonsToRanges(CoverageFunction* function) {
2481cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  while (iter.Next()) {
2511cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
2521cb0ef41Sopenharmony_ci    CoverageBlock& parent = iter.GetParent();
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci    if (block.start >= function->end) {
2551cb0ef41Sopenharmony_ci      DCHECK_EQ(block.end, kNoSourcePosition);
2561cb0ef41Sopenharmony_ci      iter.DeleteBlock();
2571cb0ef41Sopenharmony_ci    } else if (block.end == kNoSourcePosition) {
2581cb0ef41Sopenharmony_ci      // The current block ends at the next sibling block (if it exists) or the
2591cb0ef41Sopenharmony_ci      // end of the parent block otherwise.
2601cb0ef41Sopenharmony_ci      if (iter.HasSiblingOrChild()) {
2611cb0ef41Sopenharmony_ci        block.end = iter.GetSiblingOrChild().start;
2621cb0ef41Sopenharmony_ci      } else if (iter.IsTopLevel()) {
2631cb0ef41Sopenharmony_ci        // See https://crbug.com/v8/6661. Functions are special-cased because
2641cb0ef41Sopenharmony_ci        // we never want the closing brace to be uncovered. This is mainly to
2651cb0ef41Sopenharmony_ci        // avoid a noisy UI.
2661cb0ef41Sopenharmony_ci        block.end = parent.end - 1;
2671cb0ef41Sopenharmony_ci      } else {
2681cb0ef41Sopenharmony_ci        block.end = parent.end;
2691cb0ef41Sopenharmony_ci      }
2701cb0ef41Sopenharmony_ci    }
2711cb0ef41Sopenharmony_ci  }
2721cb0ef41Sopenharmony_ci}
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_civoid MergeConsecutiveRanges(CoverageFunction* function) {
2751cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  while (iter.Next()) {
2781cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    if (iter.HasSiblingOrChild()) {
2811cb0ef41Sopenharmony_ci      CoverageBlock& sibling = iter.GetSiblingOrChild();
2821cb0ef41Sopenharmony_ci      if (sibling.start == block.end && sibling.count == block.count) {
2831cb0ef41Sopenharmony_ci        // Best-effort: this pass may miss mergeable siblings in the presence of
2841cb0ef41Sopenharmony_ci        // child blocks.
2851cb0ef41Sopenharmony_ci        sibling.start = block.start;
2861cb0ef41Sopenharmony_ci        iter.DeleteBlock();
2871cb0ef41Sopenharmony_ci      }
2881cb0ef41Sopenharmony_ci    }
2891cb0ef41Sopenharmony_ci  }
2901cb0ef41Sopenharmony_ci}
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_civoid MergeNestedRanges(CoverageFunction* function) {
2931cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  while (iter.Next()) {
2961cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
2971cb0ef41Sopenharmony_ci    CoverageBlock& parent = iter.GetParent();
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci    if (parent.count == block.count) {
3001cb0ef41Sopenharmony_ci      // Transformation may not be valid if sibling blocks exist with a
3011cb0ef41Sopenharmony_ci      // differing count.
3021cb0ef41Sopenharmony_ci      iter.DeleteBlock();
3031cb0ef41Sopenharmony_ci    }
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci}
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_civoid RewriteFunctionScopeCounter(CoverageFunction* function) {
3081cb0ef41Sopenharmony_ci  // Every function must have at least the top-level function counter.
3091cb0ef41Sopenharmony_ci  DCHECK(!function->blocks.empty());
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
3121cb0ef41Sopenharmony_ci  if (iter.Next()) {
3131cb0ef41Sopenharmony_ci    DCHECK(iter.IsTopLevel());
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
3161cb0ef41Sopenharmony_ci    if (block.start == SourceRange::kFunctionLiteralSourcePosition &&
3171cb0ef41Sopenharmony_ci        block.end == SourceRange::kFunctionLiteralSourcePosition) {
3181cb0ef41Sopenharmony_ci      // If a function-scope block exists, overwrite the function count. It has
3191cb0ef41Sopenharmony_ci      // a more reliable count than what we get from the FeedbackVector (which
3201cb0ef41Sopenharmony_ci      // is imprecise e.g. for generator functions and optimized code).
3211cb0ef41Sopenharmony_ci      function->count = block.count;
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci      // Then delete it; for compatibility with non-block coverage modes, the
3241cb0ef41Sopenharmony_ci      // function-scope block is expected in CoverageFunction, not as a
3251cb0ef41Sopenharmony_ci      // CoverageBlock.
3261cb0ef41Sopenharmony_ci      iter.DeleteBlock();
3271cb0ef41Sopenharmony_ci    }
3281cb0ef41Sopenharmony_ci  }
3291cb0ef41Sopenharmony_ci}
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_civoid FilterAliasedSingletons(CoverageFunction* function) {
3321cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  iter.Next();  // Advance once since we reference the previous block later.
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  while (iter.Next()) {
3371cb0ef41Sopenharmony_ci    CoverageBlock& previous_block = iter.GetPreviousBlock();
3381cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci    bool is_singleton = block.end == kNoSourcePosition;
3411cb0ef41Sopenharmony_ci    bool aliases_start = block.start == previous_block.start;
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci    if (is_singleton && aliases_start) {
3441cb0ef41Sopenharmony_ci      // The previous block must have a full range since duplicate singletons
3451cb0ef41Sopenharmony_ci      // have already been merged.
3461cb0ef41Sopenharmony_ci      DCHECK_NE(previous_block.end, kNoSourcePosition);
3471cb0ef41Sopenharmony_ci      // Likewise, the next block must have another start position since
3481cb0ef41Sopenharmony_ci      // singletons are sorted to the end.
3491cb0ef41Sopenharmony_ci      DCHECK_IMPLIES(iter.HasNext(), iter.GetNextBlock().start != block.start);
3501cb0ef41Sopenharmony_ci      iter.DeleteBlock();
3511cb0ef41Sopenharmony_ci    }
3521cb0ef41Sopenharmony_ci  }
3531cb0ef41Sopenharmony_ci}
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_civoid FilterUncoveredRanges(CoverageFunction* function) {
3561cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  while (iter.Next()) {
3591cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
3601cb0ef41Sopenharmony_ci    CoverageBlock& parent = iter.GetParent();
3611cb0ef41Sopenharmony_ci    if (block.count == 0 && parent.count == 0) iter.DeleteBlock();
3621cb0ef41Sopenharmony_ci  }
3631cb0ef41Sopenharmony_ci}
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_civoid FilterEmptyRanges(CoverageFunction* function) {
3661cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  while (iter.Next()) {
3691cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
3701cb0ef41Sopenharmony_ci    if (block.start == block.end) iter.DeleteBlock();
3711cb0ef41Sopenharmony_ci  }
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_civoid ClampToBinary(CoverageFunction* function) {
3751cb0ef41Sopenharmony_ci  CoverageBlockIterator iter(function);
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci  while (iter.Next()) {
3781cb0ef41Sopenharmony_ci    CoverageBlock& block = iter.GetBlock();
3791cb0ef41Sopenharmony_ci    if (block.count > 0) block.count = 1;
3801cb0ef41Sopenharmony_ci  }
3811cb0ef41Sopenharmony_ci}
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_civoid ResetAllBlockCounts(SharedFunctionInfo shared) {
3841cb0ef41Sopenharmony_ci  DCHECK(shared.HasCoverageInfo());
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  CoverageInfo coverage_info =
3871cb0ef41Sopenharmony_ci      CoverageInfo::cast(shared.GetDebugInfo().coverage_info());
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  for (int i = 0; i < coverage_info.slot_count(); i++) {
3901cb0ef41Sopenharmony_ci    coverage_info.ResetBlockCount(i);
3911cb0ef41Sopenharmony_ci  }
3921cb0ef41Sopenharmony_ci}
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_cibool IsBlockMode(debug::CoverageMode mode) {
3951cb0ef41Sopenharmony_ci  switch (mode) {
3961cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBlockBinary:
3971cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBlockCount:
3981cb0ef41Sopenharmony_ci      return true;
3991cb0ef41Sopenharmony_ci    default:
4001cb0ef41Sopenharmony_ci      return false;
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci}
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_cibool IsBinaryMode(debug::CoverageMode mode) {
4051cb0ef41Sopenharmony_ci  switch (mode) {
4061cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBlockBinary:
4071cb0ef41Sopenharmony_ci    case debug::CoverageMode::kPreciseBinary:
4081cb0ef41Sopenharmony_ci      return true;
4091cb0ef41Sopenharmony_ci    default:
4101cb0ef41Sopenharmony_ci      return false;
4111cb0ef41Sopenharmony_ci  }
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_civoid CollectBlockCoverageInternal(CoverageFunction* function,
4151cb0ef41Sopenharmony_ci                                  SharedFunctionInfo info,
4161cb0ef41Sopenharmony_ci                                  debug::CoverageMode mode) {
4171cb0ef41Sopenharmony_ci  DCHECK(IsBlockMode(mode));
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_ci  // Functions with empty source ranges are not interesting to report. This can
4201cb0ef41Sopenharmony_ci  // happen e.g. for internally-generated functions like class constructors.
4211cb0ef41Sopenharmony_ci  if (!function->HasNonEmptySourceRange()) return;
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  function->has_block_coverage = true;
4241cb0ef41Sopenharmony_ci  function->blocks = GetSortedBlockData(info);
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci  // If in binary mode, only report counts of 0/1.
4271cb0ef41Sopenharmony_ci  if (mode == debug::CoverageMode::kBlockBinary) ClampToBinary(function);
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci  // To stay compatible with non-block coverage modes, the function-scope count
4301cb0ef41Sopenharmony_ci  // is expected to be in the CoverageFunction, not as part of its blocks.
4311cb0ef41Sopenharmony_ci  // This finds the function-scope counter, overwrites CoverageFunction::count,
4321cb0ef41Sopenharmony_ci  // and removes it from the block list.
4331cb0ef41Sopenharmony_ci  //
4341cb0ef41Sopenharmony_ci  // Important: Must be called before other transformation passes.
4351cb0ef41Sopenharmony_ci  RewriteFunctionScopeCounter(function);
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci  // Functions without blocks don't need to be processed further.
4381cb0ef41Sopenharmony_ci  if (!function->HasBlocks()) return;
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  // Remove singleton ranges with the same start position as a full range and
4411cb0ef41Sopenharmony_ci  // throw away their counts.
4421cb0ef41Sopenharmony_ci  // Singleton ranges are only intended to split existing full ranges and should
4431cb0ef41Sopenharmony_ci  // never expand into a full range. Consider 'if (cond) { ... } else { ... }'
4441cb0ef41Sopenharmony_ci  // as a problematic example; if the then-block produces a continuation
4451cb0ef41Sopenharmony_ci  // singleton, it would incorrectly expand into the else range.
4461cb0ef41Sopenharmony_ci  // For more context, see https://crbug.com/v8/8237.
4471cb0ef41Sopenharmony_ci  FilterAliasedSingletons(function);
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  // Rewrite all singletons (created e.g. by continuations and unconditional
4501cb0ef41Sopenharmony_ci  // control flow) to ranges.
4511cb0ef41Sopenharmony_ci  RewritePositionSingletonsToRanges(function);
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci  // Merge nested and consecutive ranges with identical counts.
4541cb0ef41Sopenharmony_ci  // Note that it's necessary to merge duplicate ranges prior to merging nested
4551cb0ef41Sopenharmony_ci  // changes in order to avoid invalid transformations. See crbug.com/827530.
4561cb0ef41Sopenharmony_ci  MergeConsecutiveRanges(function);
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci  SortBlockData(function->blocks);
4591cb0ef41Sopenharmony_ci  MergeDuplicateRanges(function);
4601cb0ef41Sopenharmony_ci  MergeNestedRanges(function);
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci  MergeConsecutiveRanges(function);
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  // Filter out ranges with count == 0 unless the immediate parent range has
4651cb0ef41Sopenharmony_ci  // a count != 0.
4661cb0ef41Sopenharmony_ci  FilterUncoveredRanges(function);
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci  // Filter out ranges of zero length.
4691cb0ef41Sopenharmony_ci  FilterEmptyRanges(function);
4701cb0ef41Sopenharmony_ci}
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_civoid CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
4731cb0ef41Sopenharmony_ci                          debug::CoverageMode mode) {
4741cb0ef41Sopenharmony_ci  CollectBlockCoverageInternal(function, info, mode);
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  // Reset all counters on the DebugInfo to zero.
4771cb0ef41Sopenharmony_ci  ResetAllBlockCounts(info);
4781cb0ef41Sopenharmony_ci}
4791cb0ef41Sopenharmony_ci
4801cb0ef41Sopenharmony_civoid PrintBlockCoverage(const CoverageFunction* function,
4811cb0ef41Sopenharmony_ci                        SharedFunctionInfo info, bool has_nonempty_source_range,
4821cb0ef41Sopenharmony_ci                        bool function_is_relevant) {
4831cb0ef41Sopenharmony_ci  DCHECK(FLAG_trace_block_coverage);
4841cb0ef41Sopenharmony_ci  std::unique_ptr<char[]> function_name =
4851cb0ef41Sopenharmony_ci      function->name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
4861cb0ef41Sopenharmony_ci  i::PrintF(
4871cb0ef41Sopenharmony_ci      "Coverage for function='%s', SFI=%p, has_nonempty_source_range=%d, "
4881cb0ef41Sopenharmony_ci      "function_is_relevant=%d\n",
4891cb0ef41Sopenharmony_ci      function_name.get(), reinterpret_cast<void*>(info.ptr()),
4901cb0ef41Sopenharmony_ci      has_nonempty_source_range, function_is_relevant);
4911cb0ef41Sopenharmony_ci  i::PrintF("{start: %d, end: %d, count: %d}\n", function->start, function->end,
4921cb0ef41Sopenharmony_ci            function->count);
4931cb0ef41Sopenharmony_ci  for (const auto& block : function->blocks) {
4941cb0ef41Sopenharmony_ci    i::PrintF("{start: %d, end: %d, count: %d}\n", block.start, block.end,
4951cb0ef41Sopenharmony_ci              block.count);
4961cb0ef41Sopenharmony_ci  }
4971cb0ef41Sopenharmony_ci}
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_civoid CollectAndMaybeResetCounts(Isolate* isolate,
5001cb0ef41Sopenharmony_ci                                SharedToCounterMap* counter_map,
5011cb0ef41Sopenharmony_ci                                v8::debug::CoverageMode coverage_mode) {
5021cb0ef41Sopenharmony_ci  const bool reset_count =
5031cb0ef41Sopenharmony_ci      coverage_mode != v8::debug::CoverageMode::kBestEffort;
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ci  switch (isolate->code_coverage_mode()) {
5061cb0ef41Sopenharmony_ci    case v8::debug::CoverageMode::kBlockBinary:
5071cb0ef41Sopenharmony_ci    case v8::debug::CoverageMode::kBlockCount:
5081cb0ef41Sopenharmony_ci    case v8::debug::CoverageMode::kPreciseBinary:
5091cb0ef41Sopenharmony_ci    case v8::debug::CoverageMode::kPreciseCount: {
5101cb0ef41Sopenharmony_ci      // Feedback vectors are already listed to prevent losing them to GC.
5111cb0ef41Sopenharmony_ci      DCHECK(isolate->factory()
5121cb0ef41Sopenharmony_ci                 ->feedback_vectors_for_profiling_tools()
5131cb0ef41Sopenharmony_ci                 ->IsArrayList());
5141cb0ef41Sopenharmony_ci      Handle<ArrayList> list = Handle<ArrayList>::cast(
5151cb0ef41Sopenharmony_ci          isolate->factory()->feedback_vectors_for_profiling_tools());
5161cb0ef41Sopenharmony_ci      for (int i = 0; i < list->Length(); i++) {
5171cb0ef41Sopenharmony_ci        FeedbackVector vector = FeedbackVector::cast(list->Get(i));
5181cb0ef41Sopenharmony_ci        SharedFunctionInfo shared = vector.shared_function_info();
5191cb0ef41Sopenharmony_ci        DCHECK(shared.IsSubjectToDebugging());
5201cb0ef41Sopenharmony_ci        uint32_t count = static_cast<uint32_t>(vector.invocation_count());
5211cb0ef41Sopenharmony_ci        if (reset_count) vector.clear_invocation_count(kRelaxedStore);
5221cb0ef41Sopenharmony_ci        counter_map->Add(shared, count);
5231cb0ef41Sopenharmony_ci      }
5241cb0ef41Sopenharmony_ci      break;
5251cb0ef41Sopenharmony_ci    }
5261cb0ef41Sopenharmony_ci    case v8::debug::CoverageMode::kBestEffort: {
5271cb0ef41Sopenharmony_ci      DCHECK(!isolate->factory()
5281cb0ef41Sopenharmony_ci                  ->feedback_vectors_for_profiling_tools()
5291cb0ef41Sopenharmony_ci                  ->IsArrayList());
5301cb0ef41Sopenharmony_ci      DCHECK_EQ(v8::debug::CoverageMode::kBestEffort, coverage_mode);
5311cb0ef41Sopenharmony_ci      AllowGarbageCollection allow_gc;
5321cb0ef41Sopenharmony_ci      HeapObjectIterator heap_iterator(isolate->heap());
5331cb0ef41Sopenharmony_ci      for (HeapObject current_obj = heap_iterator.Next();
5341cb0ef41Sopenharmony_ci           !current_obj.is_null(); current_obj = heap_iterator.Next()) {
5351cb0ef41Sopenharmony_ci        if (!current_obj.IsJSFunction()) continue;
5361cb0ef41Sopenharmony_ci        JSFunction func = JSFunction::cast(current_obj);
5371cb0ef41Sopenharmony_ci        SharedFunctionInfo shared = func.shared();
5381cb0ef41Sopenharmony_ci        if (!shared.IsSubjectToDebugging()) continue;
5391cb0ef41Sopenharmony_ci        if (!(func.has_feedback_vector() ||
5401cb0ef41Sopenharmony_ci              func.has_closure_feedback_cell_array())) {
5411cb0ef41Sopenharmony_ci          continue;
5421cb0ef41Sopenharmony_ci        }
5431cb0ef41Sopenharmony_ci        uint32_t count = 0;
5441cb0ef41Sopenharmony_ci        if (func.has_feedback_vector()) {
5451cb0ef41Sopenharmony_ci          count =
5461cb0ef41Sopenharmony_ci              static_cast<uint32_t>(func.feedback_vector().invocation_count());
5471cb0ef41Sopenharmony_ci        } else if (func.raw_feedback_cell().interrupt_budget() <
5481cb0ef41Sopenharmony_ci                   FLAG_interrupt_budget_for_feedback_allocation) {
5491cb0ef41Sopenharmony_ci          // TODO(jgruber): The condition above is no longer precise since we
5501cb0ef41Sopenharmony_ci          // may use either the fixed interrupt_budget or
5511cb0ef41Sopenharmony_ci          // FLAG_interrupt_budget_factor_for_feedback_allocation. If the
5521cb0ef41Sopenharmony_ci          // latter, we may incorrectly set a count of 1.
5531cb0ef41Sopenharmony_ci          //
5541cb0ef41Sopenharmony_ci          // We haven't allocated feedback vector, but executed the function
5551cb0ef41Sopenharmony_ci          // atleast once. We don't have precise invocation count here.
5561cb0ef41Sopenharmony_ci          count = 1;
5571cb0ef41Sopenharmony_ci        }
5581cb0ef41Sopenharmony_ci        counter_map->Add(shared, count);
5591cb0ef41Sopenharmony_ci      }
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci      // Also check functions on the stack to collect the count map. With lazy
5621cb0ef41Sopenharmony_ci      // feedback allocation we may miss counting functions if the feedback
5631cb0ef41Sopenharmony_ci      // vector wasn't allocated yet and the function's interrupt budget wasn't
5641cb0ef41Sopenharmony_ci      // updated (i.e. it didn't execute return / jump).
5651cb0ef41Sopenharmony_ci      for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
5661cb0ef41Sopenharmony_ci        SharedFunctionInfo shared = it.frame()->function().shared();
5671cb0ef41Sopenharmony_ci        if (counter_map->Get(shared) != 0) continue;
5681cb0ef41Sopenharmony_ci        counter_map->Add(shared, 1);
5691cb0ef41Sopenharmony_ci      }
5701cb0ef41Sopenharmony_ci      break;
5711cb0ef41Sopenharmony_ci    }
5721cb0ef41Sopenharmony_ci  }
5731cb0ef41Sopenharmony_ci}
5741cb0ef41Sopenharmony_ci
5751cb0ef41Sopenharmony_ci// A {SFI, count} tuple is used to sort by source range (stored on
5761cb0ef41Sopenharmony_ci// the SFI) and call count (in the counter map).
5771cb0ef41Sopenharmony_cistruct SharedFunctionInfoAndCount {
5781cb0ef41Sopenharmony_ci  SharedFunctionInfoAndCount(Handle<SharedFunctionInfo> info, uint32_t count)
5791cb0ef41Sopenharmony_ci      : info(info),
5801cb0ef41Sopenharmony_ci        count(count),
5811cb0ef41Sopenharmony_ci        start(StartPosition(*info)),
5821cb0ef41Sopenharmony_ci        end(info->EndPosition()) {}
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  // Sort by:
5851cb0ef41Sopenharmony_ci  // - start, ascending.
5861cb0ef41Sopenharmony_ci  // - end, descending.
5871cb0ef41Sopenharmony_ci  // - info.is_toplevel() first
5881cb0ef41Sopenharmony_ci  // - count, descending.
5891cb0ef41Sopenharmony_ci  bool operator<(const SharedFunctionInfoAndCount& that) const {
5901cb0ef41Sopenharmony_ci    if (this->start != that.start) return this->start < that.start;
5911cb0ef41Sopenharmony_ci    if (this->end != that.end) return this->end > that.end;
5921cb0ef41Sopenharmony_ci    if (this->info->is_toplevel() != that.info->is_toplevel()) {
5931cb0ef41Sopenharmony_ci      return this->info->is_toplevel();
5941cb0ef41Sopenharmony_ci    }
5951cb0ef41Sopenharmony_ci    return this->count > that.count;
5961cb0ef41Sopenharmony_ci  }
5971cb0ef41Sopenharmony_ci
5981cb0ef41Sopenharmony_ci  Handle<SharedFunctionInfo> info;
5991cb0ef41Sopenharmony_ci  uint32_t count;
6001cb0ef41Sopenharmony_ci  int start;
6011cb0ef41Sopenharmony_ci  int end;
6021cb0ef41Sopenharmony_ci};
6031cb0ef41Sopenharmony_ci
6041cb0ef41Sopenharmony_ci}  // anonymous namespace
6051cb0ef41Sopenharmony_ci
6061cb0ef41Sopenharmony_cistd::unique_ptr<Coverage> Coverage::CollectPrecise(Isolate* isolate) {
6071cb0ef41Sopenharmony_ci  DCHECK(!isolate->is_best_effort_code_coverage());
6081cb0ef41Sopenharmony_ci  std::unique_ptr<Coverage> result =
6091cb0ef41Sopenharmony_ci      Collect(isolate, isolate->code_coverage_mode());
6101cb0ef41Sopenharmony_ci  if (!isolate->is_collecting_type_profile() &&
6111cb0ef41Sopenharmony_ci      (isolate->is_precise_binary_code_coverage() ||
6121cb0ef41Sopenharmony_ci       isolate->is_block_binary_code_coverage())) {
6131cb0ef41Sopenharmony_ci    // We do not have to hold onto feedback vectors for invocations we already
6141cb0ef41Sopenharmony_ci    // reported. So we can reset the list.
6151cb0ef41Sopenharmony_ci    isolate->SetFeedbackVectorsForProfilingTools(
6161cb0ef41Sopenharmony_ci        ReadOnlyRoots(isolate).empty_array_list());
6171cb0ef41Sopenharmony_ci  }
6181cb0ef41Sopenharmony_ci  return result;
6191cb0ef41Sopenharmony_ci}
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_cistd::unique_ptr<Coverage> Coverage::CollectBestEffort(Isolate* isolate) {
6221cb0ef41Sopenharmony_ci  return Collect(isolate, v8::debug::CoverageMode::kBestEffort);
6231cb0ef41Sopenharmony_ci}
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_cistd::unique_ptr<Coverage> Coverage::Collect(
6261cb0ef41Sopenharmony_ci    Isolate* isolate, v8::debug::CoverageMode collectionMode) {
6271cb0ef41Sopenharmony_ci  // Collect call counts for all functions.
6281cb0ef41Sopenharmony_ci  SharedToCounterMap counter_map;
6291cb0ef41Sopenharmony_ci  CollectAndMaybeResetCounts(isolate, &counter_map, collectionMode);
6301cb0ef41Sopenharmony_ci
6311cb0ef41Sopenharmony_ci  // Iterate shared function infos of every script and build a mapping
6321cb0ef41Sopenharmony_ci  // between source ranges and invocation counts.
6331cb0ef41Sopenharmony_ci  std::unique_ptr<Coverage> result(new Coverage());
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_ci  std::vector<Handle<Script>> scripts;
6361cb0ef41Sopenharmony_ci  Script::Iterator scriptIt(isolate);
6371cb0ef41Sopenharmony_ci  for (Script script = scriptIt.Next(); !script.is_null();
6381cb0ef41Sopenharmony_ci       script = scriptIt.Next()) {
6391cb0ef41Sopenharmony_ci    if (script.IsUserJavaScript()) scripts.push_back(handle(script, isolate));
6401cb0ef41Sopenharmony_ci  }
6411cb0ef41Sopenharmony_ci
6421cb0ef41Sopenharmony_ci  for (Handle<Script> script : scripts) {
6431cb0ef41Sopenharmony_ci    // Create and add new script data.
6441cb0ef41Sopenharmony_ci    result->emplace_back(script);
6451cb0ef41Sopenharmony_ci    std::vector<CoverageFunction>* functions = &result->back().functions;
6461cb0ef41Sopenharmony_ci
6471cb0ef41Sopenharmony_ci    std::vector<SharedFunctionInfoAndCount> sorted;
6481cb0ef41Sopenharmony_ci
6491cb0ef41Sopenharmony_ci    {
6501cb0ef41Sopenharmony_ci      // Sort functions by start position, from outer to inner functions.
6511cb0ef41Sopenharmony_ci      SharedFunctionInfo::ScriptIterator infos(isolate, *script);
6521cb0ef41Sopenharmony_ci      for (SharedFunctionInfo info = infos.Next(); !info.is_null();
6531cb0ef41Sopenharmony_ci           info = infos.Next()) {
6541cb0ef41Sopenharmony_ci        sorted.emplace_back(handle(info, isolate), counter_map.Get(info));
6551cb0ef41Sopenharmony_ci      }
6561cb0ef41Sopenharmony_ci      std::sort(sorted.begin(), sorted.end());
6571cb0ef41Sopenharmony_ci    }
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_ci    // Stack to track nested functions, referring function by index.
6601cb0ef41Sopenharmony_ci    std::vector<size_t> nesting;
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci    // Use sorted list to reconstruct function nesting.
6631cb0ef41Sopenharmony_ci    for (const SharedFunctionInfoAndCount& v : sorted) {
6641cb0ef41Sopenharmony_ci      Handle<SharedFunctionInfo> info = v.info;
6651cb0ef41Sopenharmony_ci      int start = v.start;
6661cb0ef41Sopenharmony_ci      int end = v.end;
6671cb0ef41Sopenharmony_ci      uint32_t count = v.count;
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_ci      // Find the correct outer function based on start position.
6701cb0ef41Sopenharmony_ci      //
6711cb0ef41Sopenharmony_ci      // This is, in general, not robust when considering two functions with
6721cb0ef41Sopenharmony_ci      // identical source ranges; then the notion of inner and outer is unclear.
6731cb0ef41Sopenharmony_ci      // Identical source ranges arise when the source range of top-most entity
6741cb0ef41Sopenharmony_ci      // (e.g. function) in the script is identical to the whole script, e.g.
6751cb0ef41Sopenharmony_ci      // <script>function foo() {}<script>. The script has its own shared
6761cb0ef41Sopenharmony_ci      // function info, which has the same source range as the SFI for `foo`.
6771cb0ef41Sopenharmony_ci      // Node.js creates an additional wrapper for scripts (again with identical
6781cb0ef41Sopenharmony_ci      // source range) and those wrappers will have a call count of zero even if
6791cb0ef41Sopenharmony_ci      // the wrapped script was executed (see v8:9212). We mitigate this issue
6801cb0ef41Sopenharmony_ci      // by sorting top-level SFIs first among SFIs with the same source range:
6811cb0ef41Sopenharmony_ci      // This ensures top-level SFIs are processed first. If a top-level SFI has
6821cb0ef41Sopenharmony_ci      // a non-zero call count, it gets recorded due to `function_is_relevant`
6831cb0ef41Sopenharmony_ci      // below (e.g. script wrappers), while top-level SFIs with zero call count
6841cb0ef41Sopenharmony_ci      // do not get reported (this ensures node's extra wrappers do not get
6851cb0ef41Sopenharmony_ci      // reported). If two SFIs with identical source ranges get reported, we
6861cb0ef41Sopenharmony_ci      // report them in decreasing order of call count, as in all known cases
6871cb0ef41Sopenharmony_ci      // this corresponds to the nesting order. In the case of the script tag
6881cb0ef41Sopenharmony_ci      // example above, we report the zero call count of `foo` last. As it turns
6891cb0ef41Sopenharmony_ci      // out, embedders started to rely on functions being reported in nesting
6901cb0ef41Sopenharmony_ci      // order.
6911cb0ef41Sopenharmony_ci      // TODO(jgruber):  Investigate whether it is possible to remove node's
6921cb0ef41Sopenharmony_ci      // extra  top-level wrapper script, or change its source range, or ensure
6931cb0ef41Sopenharmony_ci      // that it follows the invariant that nesting order is descending count
6941cb0ef41Sopenharmony_ci      // order for SFIs with identical source ranges.
6951cb0ef41Sopenharmony_ci      while (!nesting.empty() && functions->at(nesting.back()).end <= start) {
6961cb0ef41Sopenharmony_ci        nesting.pop_back();
6971cb0ef41Sopenharmony_ci      }
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci      if (count != 0) {
7001cb0ef41Sopenharmony_ci        switch (collectionMode) {
7011cb0ef41Sopenharmony_ci          case v8::debug::CoverageMode::kBlockCount:
7021cb0ef41Sopenharmony_ci          case v8::debug::CoverageMode::kPreciseCount:
7031cb0ef41Sopenharmony_ci            break;
7041cb0ef41Sopenharmony_ci          case v8::debug::CoverageMode::kBlockBinary:
7051cb0ef41Sopenharmony_ci          case v8::debug::CoverageMode::kPreciseBinary:
7061cb0ef41Sopenharmony_ci            count = info->has_reported_binary_coverage() ? 0 : 1;
7071cb0ef41Sopenharmony_ci            info->set_has_reported_binary_coverage(true);
7081cb0ef41Sopenharmony_ci            break;
7091cb0ef41Sopenharmony_ci          case v8::debug::CoverageMode::kBestEffort:
7101cb0ef41Sopenharmony_ci            count = 1;
7111cb0ef41Sopenharmony_ci            break;
7121cb0ef41Sopenharmony_ci        }
7131cb0ef41Sopenharmony_ci      }
7141cb0ef41Sopenharmony_ci
7151cb0ef41Sopenharmony_ci      Handle<String> name = SharedFunctionInfo::DebugName(info);
7161cb0ef41Sopenharmony_ci      CoverageFunction function(start, end, count, name);
7171cb0ef41Sopenharmony_ci
7181cb0ef41Sopenharmony_ci      if (IsBlockMode(collectionMode) && info->HasCoverageInfo()) {
7191cb0ef41Sopenharmony_ci        CollectBlockCoverage(&function, *info, collectionMode);
7201cb0ef41Sopenharmony_ci      }
7211cb0ef41Sopenharmony_ci
7221cb0ef41Sopenharmony_ci      // Only include a function range if itself or its parent function is
7231cb0ef41Sopenharmony_ci      // covered, or if it contains non-trivial block coverage.
7241cb0ef41Sopenharmony_ci      bool is_covered = (count != 0);
7251cb0ef41Sopenharmony_ci      bool parent_is_covered =
7261cb0ef41Sopenharmony_ci          (!nesting.empty() && functions->at(nesting.back()).count != 0);
7271cb0ef41Sopenharmony_ci      bool has_block_coverage = !function.blocks.empty();
7281cb0ef41Sopenharmony_ci      bool function_is_relevant =
7291cb0ef41Sopenharmony_ci          (is_covered || parent_is_covered || has_block_coverage);
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci      // It must also have a non-empty source range (otherwise it is not
7321cb0ef41Sopenharmony_ci      // interesting to report).
7331cb0ef41Sopenharmony_ci      bool has_nonempty_source_range = function.HasNonEmptySourceRange();
7341cb0ef41Sopenharmony_ci
7351cb0ef41Sopenharmony_ci      if (has_nonempty_source_range && function_is_relevant) {
7361cb0ef41Sopenharmony_ci        nesting.push_back(functions->size());
7371cb0ef41Sopenharmony_ci        functions->emplace_back(function);
7381cb0ef41Sopenharmony_ci      }
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ci      if (FLAG_trace_block_coverage) {
7411cb0ef41Sopenharmony_ci        PrintBlockCoverage(&function, *info, has_nonempty_source_range,
7421cb0ef41Sopenharmony_ci                           function_is_relevant);
7431cb0ef41Sopenharmony_ci      }
7441cb0ef41Sopenharmony_ci    }
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci    // Remove entries for scripts that have no coverage.
7471cb0ef41Sopenharmony_ci    if (functions->empty()) result->pop_back();
7481cb0ef41Sopenharmony_ci  }
7491cb0ef41Sopenharmony_ci  return result;
7501cb0ef41Sopenharmony_ci}
7511cb0ef41Sopenharmony_ci
7521cb0ef41Sopenharmony_civoid Coverage::SelectMode(Isolate* isolate, debug::CoverageMode mode) {
7531cb0ef41Sopenharmony_ci  if (mode != isolate->code_coverage_mode()) {
7541cb0ef41Sopenharmony_ci    // Changing the coverage mode can change the bytecode that would be
7551cb0ef41Sopenharmony_ci    // generated for a function, which can interfere with lazy source positions,
7561cb0ef41Sopenharmony_ci    // so just force source position collection whenever there's such a change.
7571cb0ef41Sopenharmony_ci    isolate->CollectSourcePositionsForAllBytecodeArrays();
7581cb0ef41Sopenharmony_ci    // Changing the coverage mode changes the generated bytecode and hence it is
7591cb0ef41Sopenharmony_ci    // not safe to flush bytecode. Set a flag here, so we can disable bytecode
7601cb0ef41Sopenharmony_ci    // flushing.
7611cb0ef41Sopenharmony_ci    isolate->set_disable_bytecode_flushing(true);
7621cb0ef41Sopenharmony_ci  }
7631cb0ef41Sopenharmony_ci
7641cb0ef41Sopenharmony_ci  switch (mode) {
7651cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBestEffort:
7661cb0ef41Sopenharmony_ci      // Note that DevTools switches back to best-effort coverage once the
7671cb0ef41Sopenharmony_ci      // recording is stopped. Since we delete coverage infos at that point, any
7681cb0ef41Sopenharmony_ci      // following coverage recording (without reloads) will be at function
7691cb0ef41Sopenharmony_ci      // granularity.
7701cb0ef41Sopenharmony_ci      isolate->debug()->RemoveAllCoverageInfos();
7711cb0ef41Sopenharmony_ci      if (!isolate->is_collecting_type_profile()) {
7721cb0ef41Sopenharmony_ci        isolate->SetFeedbackVectorsForProfilingTools(
7731cb0ef41Sopenharmony_ci            ReadOnlyRoots(isolate).undefined_value());
7741cb0ef41Sopenharmony_ci      }
7751cb0ef41Sopenharmony_ci      break;
7761cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBlockBinary:
7771cb0ef41Sopenharmony_ci    case debug::CoverageMode::kBlockCount:
7781cb0ef41Sopenharmony_ci    case debug::CoverageMode::kPreciseBinary:
7791cb0ef41Sopenharmony_ci    case debug::CoverageMode::kPreciseCount: {
7801cb0ef41Sopenharmony_ci      HandleScope scope(isolate);
7811cb0ef41Sopenharmony_ci
7821cb0ef41Sopenharmony_ci      // Remove all optimized function. Optimized and inlined functions do not
7831cb0ef41Sopenharmony_ci      // increment invocation count.
7841cb0ef41Sopenharmony_ci      Deoptimizer::DeoptimizeAll(isolate);
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_ci      std::vector<Handle<JSFunction>> funcs_needing_feedback_vector;
7871cb0ef41Sopenharmony_ci      {
7881cb0ef41Sopenharmony_ci        HeapObjectIterator heap_iterator(isolate->heap());
7891cb0ef41Sopenharmony_ci        for (HeapObject o = heap_iterator.Next(); !o.is_null();
7901cb0ef41Sopenharmony_ci             o = heap_iterator.Next()) {
7911cb0ef41Sopenharmony_ci          if (o.IsJSFunction()) {
7921cb0ef41Sopenharmony_ci            JSFunction func = JSFunction::cast(o);
7931cb0ef41Sopenharmony_ci            if (func.has_closure_feedback_cell_array()) {
7941cb0ef41Sopenharmony_ci              funcs_needing_feedback_vector.push_back(
7951cb0ef41Sopenharmony_ci                  Handle<JSFunction>(func, isolate));
7961cb0ef41Sopenharmony_ci            }
7971cb0ef41Sopenharmony_ci          } else if (IsBinaryMode(mode) && o.IsSharedFunctionInfo()) {
7981cb0ef41Sopenharmony_ci            // If collecting binary coverage, reset
7991cb0ef41Sopenharmony_ci            // SFI::has_reported_binary_coverage to avoid optimizing / inlining
8001cb0ef41Sopenharmony_ci            // functions before they have reported coverage.
8011cb0ef41Sopenharmony_ci            SharedFunctionInfo shared = SharedFunctionInfo::cast(o);
8021cb0ef41Sopenharmony_ci            shared.set_has_reported_binary_coverage(false);
8031cb0ef41Sopenharmony_ci          } else if (o.IsFeedbackVector()) {
8041cb0ef41Sopenharmony_ci            // In any case, clear any collected invocation counts.
8051cb0ef41Sopenharmony_ci            FeedbackVector::cast(o).clear_invocation_count(kRelaxedStore);
8061cb0ef41Sopenharmony_ci          }
8071cb0ef41Sopenharmony_ci        }
8081cb0ef41Sopenharmony_ci      }
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ci      for (Handle<JSFunction> func : funcs_needing_feedback_vector) {
8111cb0ef41Sopenharmony_ci        IsCompiledScope is_compiled_scope(
8121cb0ef41Sopenharmony_ci            func->shared().is_compiled_scope(isolate));
8131cb0ef41Sopenharmony_ci        CHECK(is_compiled_scope.is_compiled());
8141cb0ef41Sopenharmony_ci        JSFunction::EnsureFeedbackVector(isolate, func, &is_compiled_scope);
8151cb0ef41Sopenharmony_ci      }
8161cb0ef41Sopenharmony_ci
8171cb0ef41Sopenharmony_ci      // Root all feedback vectors to avoid early collection.
8181cb0ef41Sopenharmony_ci      isolate->MaybeInitializeVectorListFromHeap();
8191cb0ef41Sopenharmony_ci
8201cb0ef41Sopenharmony_ci      break;
8211cb0ef41Sopenharmony_ci    }
8221cb0ef41Sopenharmony_ci  }
8231cb0ef41Sopenharmony_ci  isolate->set_code_coverage_mode(mode);
8241cb0ef41Sopenharmony_ci}
8251cb0ef41Sopenharmony_ci
8261cb0ef41Sopenharmony_ci}  // namespace internal
8271cb0ef41Sopenharmony_ci}  // namespace v8
828