LLVM 22.0.0git
LazyRandomTypeCollection.cpp
Go to the documentation of this file.
1//===- LazyRandomTypeCollection.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/StringRef.h"
16#include "llvm/Support/Error.h"
17#include <algorithm>
18#include <cassert>
19#include <cstdint>
20#include <iterator>
21
22using namespace llvm;
23using namespace llvm::codeview;
24
25static void error(Error &&EC) {
26 assert(!static_cast<bool>(EC));
27 if (EC)
28 consumeError(std::move(EC));
29}
30
32 : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
33 PartialOffsetArray()) {}
34
36 const CVTypeArray &Types, uint32_t RecordCountHint,
37 PartialOffsetArray PartialOffsets)
38 : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) {
39 Records.resize(RecordCountHint);
40}
41
46
48 uint32_t RecordCountHint)
49 : LazyRandomTypeCollection(ArrayRef(Data.bytes_begin(), Data.bytes_end()),
50 RecordCountHint) {}
51
53 uint32_t NumRecords)
54 : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
55
57 uint32_t RecordCountHint) {
58 Count = 0;
59 PartialOffsets = PartialOffsetArray();
60
61 error(Reader.readArray(Types, Reader.bytesRemaining()));
62
63 // Clear and then resize, to make sure existing data gets destroyed.
64 Records.clear();
65 Records.resize(RecordCountHint);
66}
67
70 reset(Reader, RecordCountHint);
71}
72
74 uint32_t RecordCountHint) {
76 reset(Reader, RecordCountHint);
77}
78
80 error(ensureTypeExists(Index));
81 assert(contains(Index));
82
83 return Records[Index.toArrayIndex()].Offset;
84}
85
87 assert(!Index.isSimple());
88
89 auto EC = ensureTypeExists(Index);
90 error(std::move(EC));
91 assert(contains(Index));
92
93 return Records[Index.toArrayIndex()].Type;
94}
95
96std::optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) {
97 if (Index.isSimple())
98 return std::nullopt;
99
100 if (auto EC = ensureTypeExists(Index)) {
101 consumeError(std::move(EC));
102 return std::nullopt;
103 }
104
105 if (!contains(Index))
106 return std::nullopt;
107 return Records[Index.toArrayIndex()].Type;
108}
109
111 if (Index.isNoneType() || Index.isSimple())
112 return TypeIndex::simpleTypeName(Index);
113
114 // Try to make sure the type exists. Even if it doesn't though, it may be
115 // because we're dumping a symbol stream with no corresponding type stream
116 // present, in which case we still want to be able to print <unknown UDT>
117 // for the type names.
118 if (auto EC = ensureTypeExists(Index)) {
119 consumeError(std::move(EC));
120 return "<unknown UDT>";
121 }
122
123 uint32_t I = Index.toArrayIndex();
124 ensureCapacityFor(Index);
125 if (Records[I].Name.data() == nullptr) {
126 StringRef Result = NameStorage.save(computeTypeName(*this, Index));
127 Records[I].Name = Result;
128 }
129 return Records[I].Name;
130}
131
133 if (Index.isSimple() || Index.isNoneType())
134 return false;
135
136 if (Records.size() <= Index.toArrayIndex())
137 return false;
138 if (!Records[Index.toArrayIndex()].Type.valid())
139 return false;
140 return true;
141}
142
144
146
147Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
148 if (contains(TI))
149 return Error::success();
150
151 return visitRangeForType(TI);
152}
153
154void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) {
155 assert(!Index.isSimple());
156 uint32_t MinSize = Index.toArrayIndex() + 1;
157
158 if (MinSize <= capacity())
159 return;
160
161 uint32_t NewCapacity = MinSize * 3 / 2;
162
163 assert(NewCapacity > capacity());
164 Records.resize(NewCapacity);
165}
166
167Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
168 assert(!TI.isSimple());
169 if (PartialOffsets.empty())
170 return fullScanForType(TI);
171
172 auto Next = llvm::upper_bound(PartialOffsets, TI,
173 [](TypeIndex Value, const TypeIndexOffset &IO) {
174 return Value < IO.Type;
175 });
176
177 assert(Next != PartialOffsets.begin());
178 auto Prev = std::prev(Next);
179
180 TypeIndex TIB = Prev->Type;
181 if (contains(TIB)) {
182 // They've asked us to fetch a type index, but the entry we found in the
183 // partial offsets array has already been visited. Since we visit an entire
184 // block every time, that means this record should have been previously
185 // discovered. Ultimately, this means this is a request for a non-existent
186 // type index.
187 return make_error<CodeViewError>("Invalid type index");
188 }
189
190 TypeIndex TIE;
191 if (Next == PartialOffsets.end()) {
193 } else {
194 TIE = Next->Type;
195 }
196
197 visitRange(TIB, Prev->Offset, TIE);
198 return Error::success();
199}
200
201std::optional<TypeIndex> LazyRandomTypeCollection::getFirst() {
203 if (auto EC = ensureTypeExists(TI)) {
204 consumeError(std::move(EC));
205 return std::nullopt;
206 }
207 return TI;
208}
209
210std::optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) {
211 // We can't be sure how long this type stream is, given that the initial count
212 // given to the constructor is just a hint. So just try to make sure the next
213 // record exists, and if anything goes wrong, we must be at the end.
214 if (auto EC = ensureTypeExists(Prev + 1)) {
215 consumeError(std::move(EC));
216 return std::nullopt;
217 }
218
219 return Prev + 1;
220}
221
222Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
223 assert(!TI.isSimple());
224 assert(PartialOffsets.empty());
225
227 auto Begin = Types.begin();
228
229 if (Count > 0) {
230 // In the case of type streams which we don't know the number of records of,
231 // it's possible to search for a type index triggering a full scan, but then
232 // later additional records are added since we didn't know how many there
233 // would be until we did a full visitation, then you try to access the new
234 // type triggering another full scan. To avoid this, we assume that if the
235 // database has some records, this must be what's going on. We can also
236 // assume that this index must be larger than the largest type index we've
237 // visited, so we start from there and scan forward.
238 uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset;
239 CurrentTI = LargestTypeIndex + 1;
240 Begin = Types.at(Offset);
241 ++Begin;
242 }
243
244 auto End = Types.end();
245 while (Begin != End) {
246 ensureCapacityFor(CurrentTI);
247 LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI);
248 auto Idx = CurrentTI.toArrayIndex();
249 Records[Idx].Type = *Begin;
250 Records[Idx].Offset = Begin.offset();
251 ++Count;
252 ++Begin;
253 ++CurrentTI;
254 }
255 if (CurrentTI <= TI) {
256 return make_error<CodeViewError>("Type Index does not exist!");
257 }
258 return Error::success();
259}
260
261void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset,
262 TypeIndex End) {
263 auto RI = Types.at(BeginOffset);
264 assert(RI != Types.end());
265
266 ensureCapacityFor(End);
267 while (Begin != End) {
268 LargestTypeIndex = std::max(LargestTypeIndex, Begin);
269 auto Idx = Begin.toArrayIndex();
270 Records[Idx].Type = *RI;
271 Records[Idx].Offset = RI.offset();
272 ++Count;
273 ++Begin;
274 ++RI;
275 }
276}
277
279 bool Stabilize) {
280 llvm_unreachable("Method cannot be called");
281}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition MD5.cpp:58
This file contains some templates that are useful if you are working with the STL at all.
#define error(X)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
Provides read only access to a subclass of BinaryStream.
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
LLVM Value Representation.
Definition Value.h:75
std::optional< TypeIndex > getNext(TypeIndex Prev) override
std::optional< CVType > tryGetType(TypeIndex Index)
bool replaceType(TypeIndex &Index, CVType Data, bool Stabilize) override
StringRef getTypeName(TypeIndex Index) override
std::optional< TypeIndex > getFirst() override
void reset(ArrayRef< uint8_t > Data, uint32_t RecordCountHint)
A 32-bit type reference.
Definition TypeIndex.h:97
static TypeIndex fromArrayIndex(uint32_t Index)
Definition TypeIndex.h:124
uint32_t toArrayIndex() const
Definition TypeIndex.h:119
static LLVM_ABI StringRef simpleTypeName(TypeIndex TI)
Definition TypeIndex.cpp:71
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
CVRecord< TypeLeafKind > CVType
Definition CVRecord.h:64
VarStreamArray< CVType > CVTypeArray
Definition CVRecord.h:127
LLVM_ABI std::string computeTypeName(TypeCollection &Types, TypeIndex Index)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
auto upper_bound(R &&Range, T &&Value)
Provide wrappers to std::upper_bound which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2007
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
FunctionAddr VTableAddr Next
Definition InstrProf.h:141
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083