Coverage Report

Created: 2023-02-22 06:51

/src/hermes/lib/VM/Profiler/CodeCoverageProfiler.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#include "hermes/VM/Profiler/CodeCoverageProfiler.h"
9
10
#include "hermes/VM/Callable.h"
11
12
#include <assert.h>
13
#include <unordered_map>
14
15
namespace hermes {
16
namespace vm {
17
18
// We intentionally leak these static members to avoid a case where they are
19
// accessed after they are destroyed during shutdown.
20
/* static */ std::unordered_set<CodeCoverageProfiler *>
21
198
    &CodeCoverageProfiler::allProfilers() {
22
198
  static auto *const allProfilers =
23
198
      new std::unordered_set<CodeCoverageProfiler *>();
24
198
  return *allProfilers;
25
198
}
26
198
/* static */ std::mutex &CodeCoverageProfiler::globalMutex() {
27
198
  static auto *const globalMutex = new std::mutex();
28
198
  return *globalMutex;
29
198
}
30
31
1.18k
void CodeCoverageProfiler::markRoots(RootAcceptor &acceptor) {
32
1.18k
  for (Domain *&domain : domains_) {
33
0
    acceptor.acceptPtr(domain);
34
0
  }
35
1.18k
}
36
37
0
void CodeCoverageProfiler::markExecutedSlowPath(CodeBlock *codeBlock) {
38
0
  std::lock_guard<std::mutex> lk(localMutex_);
39
0
  std::vector<bool> &moduleFuncMap =
40
0
      getModuleFuncMapRef(codeBlock->getRuntimeModule());
41
42
0
  const auto funcId = codeBlock->getFunctionID();
43
0
  assert(
44
0
      funcId < moduleFuncMap.size() &&
45
0
      "funcId is out of bound for moduleFuncMap.");
46
0
  moduleFuncMap[funcId] = true;
47
0
}
48
49
/* static */ std::
50
    unordered_map<std::string, std::vector<CodeCoverageProfiler::FuncInfo>>
51
0
    CodeCoverageProfiler::getExecutedFunctions() {
52
0
  std::lock_guard<std::mutex> lk(globalMutex());
53
0
  auto &profilers = allProfilers();
54
0
  std::unordered_map<std::string, std::vector<CodeCoverageProfiler::FuncInfo>>
55
0
      result;
56
0
  for (const auto &profiler : profilers) {
57
0
    std::vector<CodeCoverageProfiler::FuncInfo> profilerOutput =
58
0
        profiler->getExecutedFunctionsLocal();
59
0
    result.emplace(profiler->runtime_.getHeap().getName(), profilerOutput);
60
0
  }
61
0
  return result;
62
0
}
63
64
std::vector<CodeCoverageProfiler::FuncInfo>
65
0
CodeCoverageProfiler::getExecutedFunctionsLocal() {
66
0
  std::vector<CodeCoverageProfiler::FuncInfo> funcInfos;
67
0
  std::lock_guard<std::mutex> lk(localMutex_);
68
0
  for (auto &entry : executedFuncBitsArrayMap_) {
69
0
    auto *bcProvider = entry.first->getBytecode();
70
0
    const uint32_t segmentID = bcProvider->getSegmentID();
71
    // For Classic bundles, bcProvider->getSegmentID() is always 0.
72
    // For that situation we also provide the sourceURL, which
73
    // metro-symbolicate can use to parse the segmentID from the
74
    // sourceURL.
75
0
    llvh::StringRef sourceURL = entry.first->getSourceURL();
76
0
    const auto *debugInfo = bcProvider->getDebugInfo();
77
0
    const std::vector<bool> &moduleFuncBitsArray = entry.second;
78
0
    for (uint32_t i = 0; i < moduleFuncBitsArray.size(); ++i) {
79
0
      if (moduleFuncBitsArray[i]) {
80
0
        const auto *offsets = bcProvider->getDebugOffsets(i);
81
0
        if (debugInfo && offsets &&
82
0
            offsets->sourceLocations != hbc::DebugOffsets::NO_OFFSET) {
83
0
          if (auto pos = debugInfo->getLocationForAddress(
84
0
                  offsets->sourceLocations, 0 /* opcodeOffset */)) {
85
0
            const std::string file =
86
0
                debugInfo->getFilenameByID(pos->filenameId);
87
0
            const uint32_t line = pos->line - 1; // Normalising to zero-based
88
0
            const uint32_t column =
89
0
                pos->column - 1; // Normalising to zero-based
90
0
            funcInfos.emplace_back(line, column, file);
91
0
          }
92
0
        } else {
93
0
          const uint32_t funcVirtualOffset =
94
0
              bcProvider->getVirtualOffsetForFunction(i);
95
0
          funcInfos.emplace_back(segmentID, funcVirtualOffset, sourceURL);
96
0
        }
97
0
      }
98
0
    }
99
0
  }
100
0
  return funcInfos;
101
0
}
102
103
std::vector<bool> &CodeCoverageProfiler::getModuleFuncMapRef(
104
0
    RuntimeModule *module) {
105
0
  auto funcMapIter = executedFuncBitsArrayMap_.find(module);
106
0
  if (LLVM_LIKELY(funcMapIter != executedFuncBitsArrayMap_.end())) {
107
0
    return funcMapIter->second;
108
0
  }
109
110
  // For new module register its domain for marking.
111
0
  domains_.insert(module->getDomainUnsafe(runtime_));
112
113
0
  const uint32_t funcCount = module->getBytecode()->getFunctionCount();
114
0
  auto res = executedFuncBitsArrayMap_.insert(
115
0
      std::make_pair(module, std::vector<bool>(funcCount)));
116
0
  return res.first->second;
117
0
}
118
119
bool operator==(
120
    const CodeCoverageProfiler::FuncInfo &left,
121
0
    const CodeCoverageProfiler::FuncInfo &right) {
122
0
  return left.moduleId == right.moduleId &&
123
0
      left.funcVirtualOffset == right.funcVirtualOffset &&
124
0
      left.debugInfo == right.debugInfo;
125
0
}
126
127
} // namespace vm
128
} // namespace hermes