/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 |