Coverage Report

Created: 2025-08-28 06:48

/src/hermes/lib/VM/Metadata.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/Metadata.h"
9
10
#include "hermes/VM/SymbolID.h"
11
12
namespace hermes {
13
namespace vm {
14
15
using std::size_t;
16
using ArrayData = Metadata::ArrayData;
17
using ArrayType = ArrayData::ArrayType;
18
19
std::array<Metadata, kNumCellKinds> Metadata::metadataTable{};
20
21
79
Metadata::Metadata(Builder &&mb) : vtp(mb.vtp_) {
22
79
  offsets.array = mb.array_;
23
79
  size_t i = 0;
24
25
79
#define SLOT_TYPE(type)                   \
26
333
  for (const auto &p : mb.map##type##_) { \
27
333
    offsets.fields[i] = p.first;          \
28
333
    names[i] = p.second;                  \
29
333
    i++;                                  \
30
333
  }                                       \
31
316
  offsets.end##type = i;
32
79
#include "hermes/VM/SlotKinds.def"
33
79
#undef SLOT_TYPE
34
35
79
  assert(i <= kMaxNumFields && "Number of fields exceeds max.");
36
79
  assert(vtp->isValid() && "Must initialize VTable pointer for metadata.");
37
79
}
38
39
Metadata::Builder::Builder(const void *base)
40
79
    : base_(reinterpret_cast<const char *>(base)) {}
41
42
349
Metadata::offset_t Metadata::Builder::getOffset(const void *fieldLocation) {
43
349
  const size_t offset = reinterpret_cast<const char *>(fieldLocation) - base_;
44
349
  const offset_t ret = offset;
45
349
  assert(ret == offset && "Offset overflowed.");
46
349
  return ret;
47
349
}
48
49
#define SLOT_TYPE(type)                                         \
50
7
  void Metadata::Builder::addField(const type *fieldLocation) { \
51
7
    addField(nullptr, fieldLocation);                           \
52
7
  }
hermes::vm::Metadata::Builder::addField(hermes::vm::GCPointerBase const*)
Line
Count
Source
50
6
  void Metadata::Builder::addField(const type *fieldLocation) { \
51
6
    addField(nullptr, fieldLocation);                           \
52
6
  }
Unexecuted instantiation: hermes::vm::Metadata::Builder::addField(hermes::vm::GCHermesValueBase<hermes::vm::HermesValue> const*)
Unexecuted instantiation: hermes::vm::Metadata::Builder::addField(hermes::vm::GCHermesValueBase<hermes::vm::HermesValue32> const*)
hermes::vm::Metadata::Builder::addField(hermes::vm::GCSymbolID const*)
Line
Count
Source
50
1
  void Metadata::Builder::addField(const type *fieldLocation) { \
51
1
    addField(nullptr, fieldLocation);                           \
52
1
  }
53
#include "hermes/VM/SlotKinds.def"
54
#undef SLOT_TYPE
55
56
#define SLOT_TYPE(type)                                                        \
57
  void Metadata::Builder::addField(                                            \
58
333
      const char *name, const type *fieldLocation) {                           \
59
333
    offset_t offset = getOffset(fieldLocation);                                \
60
333
    assert(                                                                    \
61
333
        !fieldConflicts(offset, sizeof(type)) && "fields should not overlap"); \
62
333
    map##type##_[offset] = name;                                               \
63
333
  }
hermes::vm::Metadata::Builder::addField(char const*, hermes::vm::GCPointerBase const*)
Line
Count
Source
58
222
      const char *name, const type *fieldLocation) {                           \
59
222
    offset_t offset = getOffset(fieldLocation);                                \
60
222
    assert(                                                                    \
61
222
        !fieldConflicts(offset, sizeof(type)) && "fields should not overlap"); \
62
222
    map##type##_[offset] = name;                                               \
63
222
  }
hermes::vm::Metadata::Builder::addField(char const*, hermes::vm::GCHermesValueBase<hermes::vm::HermesValue> const*)
Line
Count
Source
58
10
      const char *name, const type *fieldLocation) {                           \
59
10
    offset_t offset = getOffset(fieldLocation);                                \
60
10
    assert(                                                                    \
61
10
        !fieldConflicts(offset, sizeof(type)) && "fields should not overlap"); \
62
10
    map##type##_[offset] = name;                                               \
63
10
  }
hermes::vm::Metadata::Builder::addField(char const*, hermes::vm::GCHermesValueBase<hermes::vm::HermesValue32> const*)
Line
Count
Source
58
99
      const char *name, const type *fieldLocation) {                           \
59
99
    offset_t offset = getOffset(fieldLocation);                                \
60
99
    assert(                                                                    \
61
99
        !fieldConflicts(offset, sizeof(type)) && "fields should not overlap"); \
62
99
    map##type##_[offset] = name;                                               \
63
99
  }
hermes::vm::Metadata::Builder::addField(char const*, hermes::vm::GCSymbolID const*)
Line
Count
Source
58
2
      const char *name, const type *fieldLocation) {                           \
59
2
    offset_t offset = getOffset(fieldLocation);                                \
60
2
    assert(                                                                    \
61
2
        !fieldConflicts(offset, sizeof(type)) && "fields should not overlap"); \
62
2
    map##type##_[offset] = name;                                               \
63
2
  }
64
#include "hermes/VM/SlotKinds.def"
65
#undef SLOT_TYPE
66
67
void Metadata::Builder::addArray(
68
    const char *name,
69
    ArrayData::ArrayType type,
70
    const void *startLocation,
71
    const AtomicIfConcurrentGC<uint32_t> *lengthLocation,
72
8
    std::size_t stride) {
73
8
  const uint8_t stride8 = stride;
74
8
  assert(stride8 == stride && "Stride overflowed");
75
8
  array_ = ArrayData(
76
8
      type, getOffset(startLocation), getOffset(lengthLocation), stride8);
77
8
}
78
79
79
Metadata Metadata::Builder::build() {
80
79
  return Metadata(std::move(*this));
81
79
}
82
83
#ifndef NDEBUG
84
333
bool Metadata::Builder::fieldConflicts(offset_t offset, size_t size) {
85
333
  size_t end = offset + size;
86
333
  coveredOffsets_.resize(std::max(coveredOffsets_.size(), end));
87
1.70k
  for (offset_t i = offset; i < end; ++i) {
88
1.37k
    if (coveredOffsets_[i])
89
0
      return true;
90
1.37k
    coveredOffsets_[i] = true;
91
1.37k
  }
92
333
  return false;
93
333
}
94
#endif
95
96
/// @name Formatters
97
/// @{
98
99
0
llvh::raw_ostream &operator<<(llvh::raw_ostream &os, const Metadata &meta) {
100
0
  os << "Metadata: {\n\tfieldsAndNames: [";
101
0
  bool first = true;
102
0
  size_t end;
103
0
#define SLOT_TYPE(type) end = meta.offsets.end##type;
104
0
#include "hermes/VM/SlotKinds.def"
105
0
#undef SLOT_TYPE
106
0
  for (size_t i = 0; i < end; ++i) {
107
0
    if (!first) {
108
0
      os << ",";
109
0
    } else {
110
0
      first = false;
111
0
    }
112
0
    os << "\n\t\t";
113
0
    os << "{ offset: " << meta.offsets.fields[i] << ", name: " << meta.names[i]
114
0
       << "}";
115
0
  }
116
0
  if (!first) {
117
0
    os << "\n\t";
118
0
  }
119
0
  os << "]";
120
0
  if (meta.offsets.array) {
121
0
    os << ",\n\tarray: " << *meta.offsets.array << ",\n";
122
0
  } else {
123
0
    os << "\n";
124
0
  }
125
0
  return os << "}";
126
0
}
127
128
0
llvh::raw_ostream &operator<<(llvh::raw_ostream &os, ArrayData array) {
129
0
  return os << "ArrayData: {type: {" << array.type
130
0
            << "}, lengthOffset: " << array.lengthOffset
131
0
            << ", stride: " << array.stride << "}";
132
0
}
133
134
0
llvh::raw_ostream &operator<<(llvh::raw_ostream &os, ArrayType arraytype) {
135
0
  os << "ArrayType: {";
136
0
  switch (arraytype) {
137
0
#define SLOT_TYPE(type) \
138
0
  case ArrayType::type: \
139
0
    os << #type;        \
140
0
    break;
141
0
#include "hermes/VM/SlotKinds.def"
142
0
#undef SLOT_TYPE
143
0
  }
144
0
  return os << "}";
145
0
}
146
147
/// @}
148
149
} // namespace vm
150
} // namespace hermes