Coverage Report

Created: 2025-12-11 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/include/hermes/VM/StackTracesTree-NoRuntime.h
Line
Count
Source
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
/// \file This header file defines features of StackTracesTree/allocation
9
/// location tracking without adding a dependency on other VM features. This is
10
/// primarily needed within the GC implementation. Concrete implementation for
11
/// features in this file appear in StackTracesTree.cpp.
12
13
#ifndef HERMES_STACK_TRACES_TREE_NO_RUNTIME_H
14
#define HERMES_STACK_TRACES_TREE_NO_RUNTIME_H
15
16
#include "hermes/Public/DebuggerTypes.h"
17
#include "hermes/Support/OptValue.h"
18
#include "hermes/Support/StringSetVector.h"
19
20
#include "llvh/ADT/DenseMap.h"
21
22
#include <cstdint>
23
#include <map>
24
#include <memory>
25
#pragma GCC diagnostic push
26
27
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
28
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
29
#endif
30
namespace hermes {
31
namespace vm {
32
33
struct StackTracesTree;
34
class CodeBlock;
35
36
struct StackTracesTreeNode {
37
  /// Each node represents a code location defined by this class. Note this is
38
  /// "less-specific" than IP + CodeBlock, but all that's needed to reconstruct
39
  /// a call-stack. As such, we have some utility functions here to de-dupe
40
  /// nodes that would appear at the same "location".
41
  struct SourceLoc {
42
    StringSetVector::size_type scriptName;
43
    ::facebook::hermes::debugger::ScriptID scriptID;
44
    int32_t lineNo;
45
    int32_t columnNo;
46
    SourceLoc(
47
        StringSetVector::size_type scriptName,
48
        ::facebook::hermes::debugger::ScriptID scriptID,
49
        int32_t lineNo,
50
        int32_t columnNo)
51
0
        : scriptName(scriptName),
52
0
          scriptID(scriptID),
53
0
          lineNo(lineNo),
54
0
          columnNo(columnNo) {}
55
56
0
    unsigned hash() const {
57
0
      return scriptName ^ scriptID ^ columnNo ^ lineNo;
58
0
    };
59
60
0
    bool operator==(const SourceLoc &r) const {
61
0
      return scriptName == r.scriptName && scriptID == r.scriptID &&
62
0
          lineNo == r.lineNo && columnNo == r.columnNo;
63
0
    }
64
  };
65
66
  /// Utility class for use with \c llvh::DenseMap .
67
  struct SourceLocMapInfo {
68
0
    static inline SourceLoc getEmptyKey() {
69
0
      return {SIZE_MAX, 0, -1, -1};
70
0
    }
71
0
    static inline SourceLoc getTombstoneKey() {
72
0
      return {SIZE_MAX - 1, 0, -1, -1};
73
0
    }
74
0
    static unsigned getHashValue(const SourceLoc &v) {
75
0
      return v.hash();
76
0
    }
77
0
    static bool isEqual(const SourceLoc &l, const SourceLoc &r) {
78
0
      return l == r;
79
0
    }
80
  };
81
82
  /// Map to index of child in children_.
83
  using ChildBytecodeMap = llvh::DenseMap<uint32_t, uint32_t>;
84
85
  // This is supposed to map a CodeBlock* to ChildBytecodeMap, but DenseMap
86
  // tries to do alignof() on CodeBlock* which isn't allowed on an incomplete
87
  // type. So I've worked around it by just using void* and casting as needed.
88
  using ChildCodeblockMap = llvh::DenseMap<const void *, ChildBytecodeMap>;
89
90
  /// Map to index of child in children_.
91
  using ChildSourceLocMap =
92
      llvh::DenseMap<SourceLoc, uint32_t, SourceLocMapInfo>;
93
94
  StackTracesTreeNode(
95
      size_t id,
96
      StackTracesTreeNode *parent,
97
      SourceLoc sourceLoc,
98
      const CodeBlock *codeBlock,
99
      const void *ip,
100
      StringSetVector::size_type name)
101
0
      : id(id),
102
0
        parent(parent),
103
0
        sourceLoc(sourceLoc),
104
0
        name(name),
105
0
        codeBlock_(codeBlock),
106
0
        ip_(ip) {};
107
108
  // Public data fields for the node.
109
  const size_t id;
110
  StackTracesTreeNode *const parent;
111
  const SourceLoc sourceLoc;
112
  const StringSetVector::size_type name;
113
114
0
  llvh::ArrayRef<StackTracesTreeNode *> getChildren() const {
115
0
    return children_;
116
0
  }
117
118
 private:
119
  friend StackTracesTree;
120
121
  StackTracesTreeNode *findChild(
122
      const CodeBlock *codeBlock,
123
      uint32_t bytecodeOffset) const;
124
125
  OptValue<uint32_t> findChildIndex(const SourceLoc &sourceLoc) const;
126
127
  StackTracesTreeNode *findChild(const SourceLoc &sourceLoc) const;
128
129
  void addChild(
130
      StackTracesTreeNode *child,
131
      const CodeBlock *codeBlock,
132
      uint32_t bytecodeOffset,
133
      SourceLoc sourceLoc);
134
135
  void addMapping(
136
      const CodeBlock *codeBlock,
137
      uint32_t bytecodeOffset,
138
      uint32_t childIndex);
139
140
  // These fields are used only to stop us adding the same stack frame multiple
141
  // times. This can happen, for example, with bound-functions and in some other
142
  // cases. It may be possible to do something smarter in the interpreter loop
143
  // to avoid the need for these.
144
  const CodeBlock *codeBlock_;
145
  /// Can't use Inst directly here, but doesn't matter as all we need is to
146
  /// compare pointer values.
147
  const void *ip_;
148
  /// Keep track of how many calls at this point in the stack sharing the
149
  /// codeBlock + IP. This value is only used at run-time, allowing us to skip
150
  /// the correct number of pops before we actually move the tree head above
151
  /// this stack location. It does not contribute to stack reconstruction.
152
  int duplicatePushDepth_{0};
153
154
  /// Maps SourceLoc to children.
155
  ChildSourceLocMap sourceLocToChildMap_;
156
157
  /// Cache of CodeBlock + IP to child to fast-path when the exact same bytecode
158
  /// location is used multiple times.
159
  ChildCodeblockMap codeBlockToChildMap_;
160
161
  /// List of children registered to this node, indexed from DenseMaps in this
162
  /// class.
163
  std::vector<StackTracesTreeNode *> children_{};
164
};
165
166
} // namespace vm
167
} // namespace hermes
168
#pragma GCC diagnostic pop
169
170
#endif // HERMES_STACK_TRACES_TREE_NO_RUNTIME_H