llvm.org GIT mirror llvm / f061f6c
[CV Type Merging] Find nested type indices faster. Merging two type streams is one of the most time consuming parts of generating a PDB, and as such it needs to be as fast as possible. The visitor abstractions used for interoperating nicely with many different types of inputs and outputs have been used widely and help greatly for testability and implementing tools, but the abstractions build up and get in the way of performance. This patch removes all of the visitation stuff from the type stream merger, essentially re-inventing the leaf / member switch and loop, but at a very low level. This allows us many other optimizations, such as not actually deserializing *any* records (even member records which don't describe their own length), as the operation of "figure out how long this record is" is somewhat faster than "figure out how long this record *and* get all its fields out". Furthermore, whereas before we had to deserialize, re-write type indices, then re-serialize, now we don't have to do any of those 3 steps. We just find out where the type indices are and pull them directly out of the byte stream and re-write them. This is worth a 50-60% performance increase. On top of all other optimizations that have been applied this week, I now get the following numbers when linking lld.exe and lld.pdb MSVC: 25.67s Before This Patch: 18.59s After This Patch: 8.92s So this is a huge performance win. Differential Revision: https://reviews.llvm.org/D33564 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303935 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
8 changed file(s) with 954 addition(s) and 355 deletion(s). Raw diff Collapse all Expand all
0 //===- TypeIndexDiscovery.h -------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEXDISCOVERY_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEXDISCOVERY_H
11
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 #include "llvm/Support/Error.h"
15
16 namespace llvm {
17 namespace codeview {
18 enum class TiRefKind { TypeRef, IndexRef };
19 struct TiReference {
20 TiRefKind Kind;
21 uint32_t Offset;
22 uint32_t Count;
23 };
24
25 void discoverTypeIndices(ArrayRef RecordData,
26 SmallVectorImpl &Refs);
27 void discoverTypeIndices(const CVType &Type,
28 SmallVectorImpl &Refs);
29 }
30 }
31
32 #endif
278278 Attrs(calcAttrs(PK, PM, PO, Size)) {}
279279
280280 PointerRecord(TypeIndex ReferentType, PointerKind PK, PointerMode PM,
281 PointerOptions PO, uint8_t Size,
282 const MemberPointerInfo &Member)
281 PointerOptions PO, uint8_t Size, const MemberPointerInfo &MPI)
283282 : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType),
284 Attrs(calcAttrs(PK, PM, PO, Size)), MemberInfo(Member) {}
285
286 PointerRecord(TypeIndex ReferentType, uint32_t Attrs,
287 const MemberPointerInfo &Member)
288 : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType),
289 Attrs(Attrs), MemberInfo(Member) {}
283 Attrs(calcAttrs(PK, PM, PO, Size)), MemberInfo(MPI) {}
290284
291285 TypeIndex getReferentType() const { return ReferentType; }
292286
2121 TypeDatabaseVisitor.cpp
2222 TypeDumpVisitor.cpp
2323 TypeIndex.cpp
24 TypeIndexDiscovery.cpp
2425 TypeRecordMapping.cpp
2526 TypeSerializer.cpp
2627 TypeStreamMerger.cpp
0 //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
9
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/Support/Endian.h"
12
13 using namespace llvm;
14 using namespace llvm::codeview;
15
16 static inline MethodKind getMethodKind(uint16_t Attrs) {
17 Attrs &= uint16_t(MethodOptions::MethodKindMask);
18 Attrs >>= 2;
19 return MethodKind(Attrs);
20 }
21
22 static inline bool isIntroVirtual(uint16_t Attrs) {
23 MethodKind MK = getMethodKind(Attrs);
24 return MK == MethodKind::IntroducingVirtual ||
25 MK == MethodKind::PureIntroducingVirtual;
26 }
27
28 static inline PointerMode getPointerMode(uint32_t Attrs) {
29 return static_cast((Attrs >> PointerRecord::PointerModeShift) &
30 PointerRecord::PointerModeMask);
31 }
32
33 static inline bool isMemberPointer(uint32_t Attrs) {
34 PointerMode Mode = getPointerMode(Attrs);
35 return Mode == PointerMode::PointerToDataMember ||
36 Mode == PointerMode::PointerToDataMember;
37 }
38
39 static inline uint32_t getEncodedIntegerLength(ArrayRef Data) {
40 uint16_t N = support::endian::read16le(Data.data());
41 if (N < LF_NUMERIC)
42 return 2;
43
44 assert(N <= LF_UQUADWORD);
45
46 constexpr uint32_t Sizes[] = {
47 1, // LF_CHAR
48 2, // LF_SHORT
49 2, // LF_USHORT
50 4, // LF_LONG
51 4, // LF_ULONG
52 4, // LF_REAL32
53 8, // LF_REAL64
54 10, // LF_REAL80
55 16, // LF_REAL128
56 8, // LF_QUADWORD
57 8, // LF_UQUADWORD
58 };
59
60 return Sizes[N - LF_NUMERIC];
61 }
62
63 static inline uint32_t getCStringLength(ArrayRef Data) {
64 const char *S = reinterpret_cast(Data.data());
65 return strlen(S) + 1;
66 }
67
68 static void handleMethodOverloadList(ArrayRef Content,
69 SmallVectorImpl &Refs) {
70 uint32_t Offset = 0;
71
72 while (!Content.empty()) {
73 // Array of:
74 // 0: Attrs
75 // 2: Padding
76 // 4: TypeIndex
77 // if (isIntroVirtual())
78 // 8: VFTableOffset
79
80 // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
81 // intro virtual.
82 uint32_t Len = 8;
83
84 uint16_t Attrs = support::endian::read16le(Content.data());
85 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
86
87 if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
88 Len += 4;
89 Offset += Len;
90 Content = Content.drop_front(Len);
91 }
92 }
93
94 static uint32_t handleBaseClass(ArrayRef Data, uint32_t Offset,
95 SmallVectorImpl &Refs) {
96 // 0: Kind
97 // 2: Padding
98 // 4: TypeIndex
99 // 8: Encoded Integer
100 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
101 return 8 + getEncodedIntegerLength(Data.drop_front(8));
102 }
103
104 static uint32_t handleEnumerator(ArrayRef Data, uint32_t Offset,
105 SmallVectorImpl &Refs) {
106 // 0: Kind
107 // 2: Padding
108 // 4: Encoded Integer
109 // : Name
110 uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
111 return Size + getCStringLength(Data.drop_front(Size));
112 }
113
114 static uint32_t handleDataMember(ArrayRef Data, uint32_t Offset,
115 SmallVectorImpl &Refs) {
116 // 0: Kind
117 // 2: Padding
118 // 4: TypeIndex
119 // 8: Encoded Integer
120 // : Name
121 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
122 uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
123 return Size + getCStringLength(Data.drop_front(Size));
124 }
125
126 static uint32_t handleOverloadedMethod(ArrayRef Data, uint32_t Offset,
127 SmallVectorImpl &Refs) {
128 // 0: Kind
129 // 2: Padding
130 // 4: TypeIndex
131 // 8: Name
132 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
133 return 8 + getCStringLength(Data.drop_front(8));
134 }
135
136 static uint32_t handleOneMethod(ArrayRef Data, uint32_t Offset,
137 SmallVectorImpl &Refs) {
138 // 0: Kind
139 // 2: Attributes
140 // 4: Type
141 // if (isIntroVirtual)
142 // 8: VFTableOffset
143 // : Name
144 uint32_t Size = 8;
145 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
146
147 uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
148 if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
149 Size += 4;
150
151 return Size + getCStringLength(Data.drop_front(Size));
152 }
153
154 static uint32_t handleNestedType(ArrayRef Data, uint32_t Offset,
155 SmallVectorImpl &Refs) {
156 // 0: Kind
157 // 2: Padding
158 // 4: TypeIndex
159 // 8: Name
160 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
161 return 8 + getCStringLength(Data.drop_front(8));
162 }
163
164 static uint32_t handleStaticDataMember(ArrayRef Data, uint32_t Offset,
165 SmallVectorImpl &Refs) {
166 // 0: Kind
167 // 2: Padding
168 // 4: TypeIndex
169 // 8: Name
170 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
171 return 8 + getCStringLength(Data.drop_front(8));
172 }
173
174 static uint32_t handleVirtualBaseClass(ArrayRef Data, uint32_t Offset,
175 bool IsIndirect,
176 SmallVectorImpl &Refs) {
177 // 0: Kind
178 // 2: Attrs
179 // 4: TypeIndex
180 // 8: TypeIndex
181 // 12: Encoded Integer
182 // : Encoded Integer
183 uint32_t Size = 12;
184 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
185 Size += getEncodedIntegerLength(Data.drop_front(Size));
186 Size += getEncodedIntegerLength(Data.drop_front(Size));
187 return Size;
188 }
189
190 static uint32_t handleVFPtr(ArrayRef Data, uint32_t Offset,
191 SmallVectorImpl &Refs) {
192 // 0: Kind
193 // 2: Padding
194 // 4: TypeIndex
195 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
196 return 8;
197 }
198
199 static uint32_t handleListContinuation(ArrayRef Data, uint32_t Offset,
200 SmallVectorImpl &Refs) {
201 // 0: Kind
202 // 2: Padding
203 // 4: TypeIndex
204 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
205 return 8;
206 }
207
208 static void handleFieldList(ArrayRef Content,
209 SmallVectorImpl &Refs) {
210 uint32_t Offset = 0;
211 uint32_t ThisLen = 0;
212 while (!Content.empty()) {
213 TypeLeafKind Kind =
214 static_cast(support::endian::read16le(Content.data()));
215 switch (Kind) {
216 case LF_BCLASS:
217 ThisLen = handleBaseClass(Content, Offset, Refs);
218 break;
219 case LF_ENUMERATE:
220 ThisLen = handleEnumerator(Content, Offset, Refs);
221 break;
222 case LF_MEMBER:
223 ThisLen = handleDataMember(Content, Offset, Refs);
224 break;
225 case LF_METHOD:
226 ThisLen = handleOverloadedMethod(Content, Offset, Refs);
227 break;
228 case LF_ONEMETHOD:
229 ThisLen = handleOneMethod(Content, Offset, Refs);
230 break;
231 case LF_NESTTYPE:
232 ThisLen = handleNestedType(Content, Offset, Refs);
233 break;
234 case LF_STMEMBER:
235 ThisLen = handleStaticDataMember(Content, Offset, Refs);
236 break;
237 case LF_VBCLASS:
238 case LF_IVBCLASS:
239 ThisLen =
240 handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
241 break;
242 case LF_VFUNCTAB:
243 ThisLen = handleVFPtr(Content, Offset, Refs);
244 break;
245 case LF_INDEX:
246 ThisLen = handleListContinuation(Content, Offset, Refs);
247 break;
248 default:
249 return;
250 }
251 Content = Content.drop_front(ThisLen);
252 Offset += ThisLen;
253 if (!Content.empty()) {
254 uint8_t Pad = Content.front();
255 if (Pad >= LF_PAD0) {
256 uint32_t Skip = Pad & 0x0F;
257 Content = Content.drop_front(Skip);
258 Offset += Skip;
259 }
260 }
261 }
262 }
263
264 static void handlePointer(ArrayRef Content,
265 SmallVectorImpl &Refs) {
266 Refs.push_back({TiRefKind::TypeRef, 0, 1});
267
268 uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
269 if (isMemberPointer(Attrs))
270 Refs.push_back({TiRefKind::TypeRef, 8, 1});
271 }
272
273 static void discoverTypeIndices(ArrayRef Content, TypeLeafKind Kind,
274 SmallVectorImpl &Refs) {
275 uint32_t Count;
276 // FIXME: In the future it would be nice if we could avoid hardcoding these
277 // values. One idea is to define some structures representing these types
278 // that would allow the use of offsetof().
279 switch (Kind) {
280 case TypeLeafKind::LF_FUNC_ID:
281 Refs.push_back({TiRefKind::IndexRef, 0, 1});
282 Refs.push_back({TiRefKind::TypeRef, 4, 1});
283 break;
284 case TypeLeafKind::LF_MFUNC_ID:
285 Refs.push_back({TiRefKind::TypeRef, 0, 2});
286 break;
287 case TypeLeafKind::LF_STRING_ID:
288 Refs.push_back({TiRefKind::IndexRef, 0, 1});
289 break;
290 case TypeLeafKind::LF_SUBSTR_LIST:
291 Count = support::endian::read32le(Content.data());
292 if (Count > 0)
293 Refs.push_back({TiRefKind::IndexRef, 4, Count});
294 break;
295 case TypeLeafKind::LF_BUILDINFO:
296 Count = support::endian::read16le(Content.data());
297 if (Count > 0)
298 Refs.push_back({TiRefKind::IndexRef, 2, Count});
299 break;
300 case TypeLeafKind::LF_UDT_SRC_LINE:
301 Refs.push_back({TiRefKind::TypeRef, 0, 1});
302 Refs.push_back({TiRefKind::IndexRef, 4, 1});
303 break;
304 case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
305 Refs.push_back({TiRefKind::TypeRef, 0, 1});
306 break;
307 case TypeLeafKind::LF_MODIFIER:
308 Refs.push_back({TiRefKind::TypeRef, 0, 1});
309 break;
310 case TypeLeafKind::LF_PROCEDURE:
311 Refs.push_back({TiRefKind::TypeRef, 0, 1});
312 Refs.push_back({TiRefKind::TypeRef, 8, 1});
313 break;
314 case TypeLeafKind::LF_MFUNCTION:
315 Refs.push_back({TiRefKind::TypeRef, 0, 3});
316 Refs.push_back({TiRefKind::TypeRef, 16, 1});
317 break;
318 case TypeLeafKind::LF_ARGLIST:
319 Count = support::endian::read32le(Content.data());
320 if (Count > 0)
321 Refs.push_back({TiRefKind::TypeRef, 4, Count});
322 break;
323 case TypeLeafKind::LF_ARRAY:
324 Refs.push_back({TiRefKind::TypeRef, 0, 2});
325 break;
326 case TypeLeafKind::LF_CLASS:
327 case TypeLeafKind::LF_STRUCTURE:
328 case TypeLeafKind::LF_INTERFACE:
329 Refs.push_back({TiRefKind::TypeRef, 4, 3});
330 break;
331 case TypeLeafKind::LF_UNION:
332 Refs.push_back({TiRefKind::TypeRef, 4, 1});
333 break;
334 case TypeLeafKind::LF_ENUM:
335 Refs.push_back({TiRefKind::TypeRef, 4, 2});
336 break;
337 case TypeLeafKind::LF_BITFIELD:
338 Refs.push_back({TiRefKind::TypeRef, 0, 1});
339 break;
340 case TypeLeafKind::LF_VFTABLE:
341 Refs.push_back({TiRefKind::TypeRef, 0, 2});
342 break;
343 case TypeLeafKind::LF_VTSHAPE:
344 break;
345 case TypeLeafKind::LF_METHODLIST:
346 handleMethodOverloadList(Content, Refs);
347 break;
348 case TypeLeafKind::LF_FIELDLIST:
349 handleFieldList(Content, Refs);
350 break;
351 case TypeLeafKind::LF_POINTER:
352 handlePointer(Content, Refs);
353 break;
354 default:
355 break;
356 }
357 }
358
359 void llvm::codeview::discoverTypeIndices(const CVType &Type,
360 SmallVectorImpl &Refs) {
361 ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
362 }
363
364 void llvm::codeview::discoverTypeIndices(ArrayRef RecordData,
365 SmallVectorImpl &Refs) {
366 const RecordPrefix *P =
367 reinterpret_cast(RecordData.data());
368 TypeLeafKind K = static_cast(uint16_t(P->RecordKind));
369 ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
370 }
1212 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1313 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1414 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
1516 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1617 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
1718 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
6566
6667 static const TypeIndex Untranslated;
6768
68 /// TypeVisitorCallbacks overrides.
69 #define TYPE_RECORD(EnumName, EnumVal, Name) \
70 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
71 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
72 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
73 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
74 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
75 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
76
77 Error visitUnknownType(CVType &Record) override;
78
7969 Error visitTypeBegin(CVType &Record) override;
8070 Error visitTypeEnd(CVType &Record) override;
81 Error visitMemberEnd(CVMemberRecord &Record) override;
8271
8372 Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
8473 const CVTypeArray &IdsAndTypes);
9584 bool remapTypeIndex(TypeIndex &Idx);
9685 bool remapItemIndex(TypeIndex &Idx);
9786
98 bool remapIndices(RemappedType &Record, ArrayRef TidOffs,
99 ArrayRef IidOffs) {
87 bool remapIndices(RemappedType &Record, ArrayRef Refs) {
10088 auto OriginalData = Record.OriginalRecord.content();
10189 bool Success = true;
102 for (auto Off : TidOffs) {
103 ArrayRef Bytes = OriginalData.slice(Off, sizeof(TypeIndex));
104 TypeIndex OldTI(
105 *reinterpret_cast(Bytes.data()));
106 TypeIndex NewTI = OldTI;
107 bool ThisSuccess = remapTypeIndex(NewTI);
108 if (ThisSuccess && NewTI != OldTI)
109 Record.Mappings.emplace_back(Off, NewTI);
110 Success &= ThisSuccess;
111 }
112 for (auto Off : IidOffs) {
113 ArrayRef Bytes = OriginalData.slice(Off, sizeof(TypeIndex));
114 TypeIndex OldTI(
115 *reinterpret_cast(Bytes.data()));
116 TypeIndex NewTI = OldTI;
117 bool ThisSuccess = remapItemIndex(NewTI);
118 if (ThisSuccess && NewTI != OldTI)
119 Record.Mappings.emplace_back(Off, NewTI);
120 Success &= ThisSuccess;
90 for (auto &Ref : Refs) {
91 uint32_t Offset = Ref.Offset;
92 ArrayRef Bytes =
93 OriginalData.slice(Ref.Offset, sizeof(TypeIndex));
94 ArrayRef TIs(reinterpret_cast(Bytes.data()),
95 Ref.Count);
96 for (auto TI : TIs) {
97 TypeIndex NewTI = TI;
98 bool ThisSuccess = (Ref.Kind == TiRefKind::IndexRef)
99 ? remapItemIndex(NewTI)
100 : remapTypeIndex(NewTI);
101 if (ThisSuccess && NewTI != TI)
102 Record.Mappings.emplace_back(Offset, NewTI);
103 Offset += sizeof(TypeIndex);
104 Success &= ThisSuccess;
105 }
121106 }
122107 return Success;
123108 }
131116
132117 Error errorCorruptRecord() const {
133118 return llvm::make_error(cv_error_code::corrupt_record);
134 }
135
136 template
137 Error writeKnownRecord(TypeTableBuilder &Dest, RecordType &R,
138 bool RemapSuccess) {
139 TypeIndex DestIdx = Untranslated;
140 if (RemapSuccess)
141 DestIdx = Dest.writeKnownType(R);
142 addMapping(DestIdx);
143 return Error::success();
144 }
145
146 template
147 Error writeKnownTypeRecord(RecordType &R, bool RemapSuccess) {
148 return writeKnownRecord(*DestTypeStream, R, RemapSuccess);
149 }
150
151 template
152 Error writeKnownIdRecord(RecordType &R, bool RemapSuccess) {
153 return writeKnownRecord(*DestIdStream, R, RemapSuccess);
154119 }
155120
156121 Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record,
177142 return writeRecord(*DestIdStream, Record, RemapSuccess);
178143 }
179144
180 template
181 Error writeMember(RecordType &R, bool RemapSuccess) {
182 if (RemapSuccess)
183 FieldListBuilder->writeMemberType(R);
184 else
185 HadUntranslatedMember = true;
186 return Error::success();
187 }
188
189145 Optional LastError;
190146
191147 bool IsSecondPass = false;
193149 bool HadUntranslatedMember = false;
194150
195151 unsigned NumBadIndices = 0;
196
197 BumpPtrAllocator Allocator;
198152
199153 TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
200154
201155 TypeTableBuilder *DestIdStream = nullptr;
202156 TypeTableBuilder *DestTypeStream = nullptr;
203 std::unique_ptr FieldListBuilder;
204157 TypeServerHandler *Handler = nullptr;
205158
206159 // If we're only mapping id records, this array contains the mapping for
216169
217170 const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
218171
219 Error TypeStreamMerger::visitTypeBegin(CVType &Rec) { return Error::success(); }
172 Error TypeStreamMerger::visitTypeBegin(CVType &Rec) {
173 RemappedType R(Rec);
174 SmallVector Refs;
175 discoverTypeIndices(Rec.RecordData, Refs);
176 bool Success = remapIndices(R, Refs);
177 switch (Rec.kind()) {
178 case TypeLeafKind::LF_FUNC_ID:
179 case TypeLeafKind::LF_MFUNC_ID:
180 case TypeLeafKind::LF_STRING_ID:
181 case TypeLeafKind::LF_SUBSTR_LIST:
182 case TypeLeafKind::LF_BUILDINFO:
183 case TypeLeafKind::LF_UDT_SRC_LINE:
184 case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
185 return writeIdRecord(R, Success);
186 default:
187 return writeTypeRecord(R, Success);
188 }
189 return Error::success();
190 }
220191
221192 Error TypeStreamMerger::visitTypeEnd(CVType &Rec) {
222193 ++CurIndex;
223194 if (!IsSecondPass)
224195 assert(IndexMap.size() == slotForIndex(CurIndex) &&
225196 "visitKnownRecord should add one index map entry");
226 return Error::success();
227 }
228
229 Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) {
230197 return Error::success();
231198 }
232199
289256 return remapIndex(Idx, IndexMap);
290257 }
291258
292 //----------------------------------------------------------------------------//
293 // Item records
294 //----------------------------------------------------------------------------//
295
296 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FuncIdRecord &R) {
297 assert(DestIdStream);
298
299 RemappedType RR(CVR);
300 return writeIdRecord(RR, remapIndices(RR, {4}, {0}));
301 }
302
303 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &R) {
304 assert(DestIdStream);
305
306 RemappedType RR(CVR);
307 return writeIdRecord(RR, remapIndices(RR, {0, 4}, {}));
308 }
309
310 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringIdRecord &R) {
311 assert(DestIdStream);
312
313 RemappedType RR(CVR);
314 return writeIdRecord(RR, remapIndices(RR, {}, {0}));
315 }
316
317 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringListRecord &R) {
318 assert(DestIdStream);
319
320 if (auto EC = TypeDeserializer::deserializeAs(CVR, R))
321 return EC;
322 bool Success = true;
323
324 for (TypeIndex &Id : R.StringIndices)
325 Success &= remapItemIndex(Id);
326 return writeKnownIdRecord(R, Success);
327 }
328
329 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BuildInfoRecord &R) {
330 assert(DestIdStream);
331
332 if (auto EC = TypeDeserializer::deserializeAs(CVR, R))
333 return EC;
334
335 bool Success = true;
336 for (TypeIndex &Str : R.ArgIndices)
337 Success &= remapItemIndex(Str);
338 return writeKnownIdRecord(R, Success);
339 }
340
341 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &R) {
342 assert(DestIdStream);
343
344 RemappedType RR(CVR);
345
346 // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the
347 // IPI stream.
348 return writeIdRecord(RR, remapIndices(RR, {0}, {4}));
349 }
350
351 Error TypeStreamMerger::visitKnownRecord(CVType &CVR,
352 UdtModSourceLineRecord &R) {
353 assert(DestIdStream);
354
355 RemappedType RR(CVR);
356
357 // UdtModSourceLine Source File Ids are offsets into the global string table,
358 // not type indices.
359 // FIXME: We need to merge string table records for this to be valid.
360 return writeIdRecord(RR, remapIndices(RR, {0}, {}));
361 }
362
363 //----------------------------------------------------------------------------//
364 // Type records
365 //----------------------------------------------------------------------------//
366
367 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ModifierRecord &R) {
368 assert(DestTypeStream);
369
370 RemappedType RR(CVR);
371 return writeTypeRecord(RR, remapIndices(RR, {0}, {}));
372 }
373
374 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ProcedureRecord &R) {
375 assert(DestTypeStream);
376
377 RemappedType RR(CVR);
378 return writeTypeRecord(RR, remapIndices(RR, {0, 8}, {}));
379 }
380
381 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFunctionRecord &R) {
382 assert(DestTypeStream);
383
384 RemappedType RR(CVR);
385 return writeTypeRecord(RR, remapIndices(RR, {0, 4, 8, 16}, {}));
386 }
387
388 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArgListRecord &R) {
389 assert(DestTypeStream);
390
391 if (auto EC = TypeDeserializer::deserializeAs(CVR, R))
392 return EC;
393
394 bool Success = true;
395 for (TypeIndex &Arg : R.ArgIndices)
396 Success &= remapTypeIndex(Arg);
397
398 return writeKnownTypeRecord(R, Success);
399 }
400
401 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, PointerRecord &R) {
402 assert(DestTypeStream);
403
404 // Pointer records have a different number of TypeIndex mappings depending
405 // on whether or not it is a pointer to member.
406 if (auto EC = TypeDeserializer::deserializeAs(CVR, R))
407 return EC;
408
409 bool Success = remapTypeIndex(R.ReferentType);
410 if (R.isPointerToMember())
411 Success &= remapTypeIndex(R.MemberInfo->ContainingType);
412 return writeKnownTypeRecord(R, Success);
413 }
414
415 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArrayRecord &R) {
416 assert(DestTypeStream);
417
418 RemappedType RR(CVR);
419 return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {}));
420 }
421
422 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ClassRecord &R) {
423 assert(DestTypeStream);
424
425 RemappedType RR(CVR);
426 return writeTypeRecord(RR, remapIndices(RR, {4, 8, 12}, {}));
427 }
428
429 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UnionRecord &R) {
430 assert(DestTypeStream);
431
432 RemappedType RR(CVR);
433 return writeTypeRecord(RR, remapIndices(RR, {4}, {}));
434 }
435
436 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, EnumRecord &R) {
437 assert(DestTypeStream);
438
439 RemappedType RR(CVR);
440 return writeTypeRecord(RR, remapIndices(RR, {4, 8}, {}));
441 }
442
443 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BitFieldRecord &R) {
444 assert(DestTypeStream);
445
446 RemappedType RR(CVR);
447 return writeTypeRecord(RR, remapIndices(RR, {0}, {}));
448 }
449
450 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableShapeRecord &R) {
451 assert(DestTypeStream);
452
453 return writeTypeRecord(CVR);
454 }
455
456 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, TypeServer2Record &R) {
457 assert(DestTypeStream);
458
459 return writeTypeRecord(CVR);
460 }
461
462 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, LabelRecord &R) {
463 assert(DestTypeStream);
464
465 return writeTypeRecord(CVR);
466 }
467
468 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableRecord &R) {
469 assert(DestTypeStream);
470
471 RemappedType RR(CVR);
472 return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {}));
473 }
474
475 Error TypeStreamMerger::visitKnownRecord(CVType &CVR,
476 MethodOverloadListRecord &R) {
477 assert(DestTypeStream);
478
479 if (auto EC = TypeDeserializer::deserializeAs(CVR, R))
480 return EC;
481
482 bool Success = true;
483 for (OneMethodRecord &Meth : R.Methods)
484 Success &= remapTypeIndex(Meth.Type);
485 return writeKnownTypeRecord(R, Success);
486 }
487
488 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FieldListRecord &R) {
489 assert(DestTypeStream);
490 // Visit the members inside the field list.
491 HadUntranslatedMember = false;
492 if (!FieldListBuilder)
493 FieldListBuilder =
494 llvm::make_unique(*DestTypeStream);
495
496 FieldListBuilder->begin();
497 if (auto EC = codeview::visitMemberRecordStream(CVR.content(), *this))
498 return EC;
499
500 // Write the record if we translated all field list members.
501 TypeIndex DestIdx = FieldListBuilder->end(!HadUntranslatedMember);
502 addMapping(HadUntranslatedMember ? Untranslated : DestIdx);
503
504 return Error::success();
505 }
506
507 //----------------------------------------------------------------------------//
508 // Member records
509 //----------------------------------------------------------------------------//
510
511 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
512 NestedTypeRecord &R) {
513 return writeMember(R, remapTypeIndex(R.Type));
514 }
515
516 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) {
517 bool Success = true;
518 Success &= remapTypeIndex(R.Type);
519 return writeMember(R, Success);
520 }
521
522 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
523 OverloadedMethodRecord &R) {
524 return writeMember(R, remapTypeIndex(R.MethodList));
525 }
526
527 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
528 DataMemberRecord &R) {
529 return writeMember(R, remapTypeIndex(R.Type));
530 }
531
532 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
533 StaticDataMemberRecord &R) {
534 return writeMember(R, remapTypeIndex(R.Type));
535 }
536
537 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
538 EnumeratorRecord &R) {
539 return writeMember(R, true);
540 }
541
542 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) {
543 return writeMember(R, remapTypeIndex(R.Type));
544 }
545
546 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) {
547 return writeMember(R, remapTypeIndex(R.Type));
548 }
549
550 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
551 VirtualBaseClassRecord &R) {
552 bool Success = true;
553 Success &= remapTypeIndex(R.BaseType);
554 Success &= remapTypeIndex(R.VBPtrType);
555 return writeMember(R, Success);
556 }
557
558 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
559 ListContinuationRecord &R) {
560 return writeMember(R, remapTypeIndex(R.ContinuationIndex));
561 }
562
563 Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
564 // We failed to translate a type. Translate this index as "not translated".
565 addMapping(TypeIndex(SimpleTypeKind::NotTranslated));
566 return errorCorruptRecord();
567 }
568
569259 Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest,
570260 const CVTypeArray &Types) {
571261 DestTypeStream = &Dest;
597287 // We don't want to deserialize records. I guess this flag is poorly named,
598288 // but it really means "Don't deserialize records before switching on the
599289 // concrete type.
290 // FIXME: We can probably get even more speed here if we don't use the visitor
291 // pipeline here, but instead write the switch ourselves. I don't think it
292 // would buy us much since it's already pretty fast, but it's probably worth
293 // a few cycles.
600294 if (auto EC =
601295 codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler))
602296 return EC;
33
44 set(DebugInfoCodeViewSources
55 RandomAccessVisitorTest.cpp
6 TypeIndexDiscoveryTest.cpp
67 )
78
89 add_llvm_unittest(DebugInfoCodeViewTests
2323 EXPECT_TRUE(static_cast(E)); \
2424 if (E) \
2525 consumeError(std::move(E)); \
26 }
27
28 #define ASSERT_EXPECTED(Exp) \
29 { \
30 auto E = Exp.takeError(); \
31 bool Success = static_cast(E); \
32 if (!Success) \
33 consumeError(std::move(E)); \
34 ASSERT_FALSE(Success); \
2635 }
2736
2837 #define EXPECT_EXPECTED(Exp) \
0 //===- llvm/unittest/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
10
11 #include "ErrorChecking.h"
12 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
13 #include "llvm/Support/Allocator.h"
14
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17
18 using namespace llvm;
19 using namespace llvm::codeview;
20
21 class TypeIndexIteratorTest : public testing::Test {
22 public:
23 TypeIndexIteratorTest() {}
24
25 void SetUp() override {
26 Refs.clear();
27 TTB = make_unique(Storage);
28 FLRB = make_unique(*TTB);
29 }
30
31 void TearDown() override {
32 FLRB.reset();
33 TTB.reset();
34 }
35
36 protected:
37 template
38 bool checkTypeReferences(uint32_t RecordIndex, Indices &&... TIs) const {
39 EXPECT_EQ(sizeof...(Indices), countRefs(RecordIndex));
40 return checkTypeReferencesImpl(RecordIndex, std::forward(TIs)...);
41 }
42
43 template void writeFieldList(T &&... MemberRecords) {
44 FLRB->begin();
45 writeFieldListImpl(std::forward(MemberRecords)...);
46 FLRB->end(true);
47 ASSERT_EQ(1u, TTB->records().size());
48 discoverAllTypeIndices();
49 }
50
51 template void writeTypeRecords(T &&... Records) {
52 writeTypeRecordsImpl(std::forward(Records)...);
53 ASSERT_EQ(sizeof...(T), TTB->records().size());
54 discoverAllTypeIndices();
55 }
56
57 std::unique_ptr TTB;
58
59 private:
60 uint32_t countRefs(uint32_t RecordIndex) const {
61 auto &R = Refs[RecordIndex];
62 uint32_t Count = 0;
63 for (auto &Ref : R) {
64 Count += Ref.Count;
65 }
66 return Count;
67 }
68
69 bool checkOneTypeReference(uint32_t RecordIndex, ArrayRef RecordData,
70 TypeIndex TI) const {
71 RecordData = RecordData.drop_front(sizeof(RecordPrefix));
72 auto &RefList = Refs[RecordIndex];
73 for (auto &Ref : RefList) {
74 uint32_t Offset = Ref.Offset;
75 ArrayRef Loc = RecordData.drop_front(Offset);
76 ArrayRef Indices(
77 reinterpret_cast(Loc.data()), Ref.Count);
78 if (llvm::any_of(Indices,
79 [TI](const TypeIndex &Other) { return Other == TI; }))
80 return true;
81 }
82 return false;
83 }
84
85 template
86 bool checkTypeReferencesImpl(uint32_t RecordIndex) const {
87 return true;
88 }
89
90 template
91 bool checkTypeReferencesImpl(uint32_t RecordIndex, TypeIndex TI,
92 Indices &&... Rest) const {
93 ArrayRef Record = TTB->records()[RecordIndex];
94 bool Success = checkOneTypeReference(RecordIndex, Record, TI);
95 EXPECT_TRUE(Success);
96 return Success &
97 checkTypeReferencesImpl(RecordIndex, std::forward(Rest)...);
98 }
99
100 void discoverAllTypeIndices() {
101 Refs.resize(TTB->records().size());
102 for (uint32_t I = 0; I < TTB->records().size(); ++I) {
103 ArrayRef Data = TTB->records()[I];
104 discoverTypeIndices(Data, Refs[I]);
105 }
106 }
107
108 // Helper function to write out a field list record with the given list
109 // of member records.
110 void writeFieldListImpl() {}
111
112 template
113 void writeFieldListImpl(RecType &&Record, Rest &&... Records) {
114 FLRB->writeMemberType(Record);
115 writeFieldListImpl(std::forward(Records)...);
116 }
117
118 // Helper function to write out a list of type records.
119 void writeTypeRecordsImpl() {}
120
121 template
122 void writeTypeRecordsImpl(RecType &&Record, Rest &&... Records) {
123 TTB->writeKnownType(Record);
124 writeTypeRecordsImpl(std::forward(Records)...);
125 }
126
127 std::vector> Refs;
128 std::unique_ptr FLRB;
129 BumpPtrAllocator Storage;
130 };
131
132 namespace leafs {
133 static FuncIdRecord FuncId(TypeIndex(1), TypeIndex(2), "FuncId");
134 static MemberFuncIdRecord MemFuncId(TypeIndex(3), TypeIndex(4), "FuncId");
135 static StringIdRecord StringId(TypeIndex(5), "TheString");
136 static struct {
137 std::vector Ids = {TypeIndex(6), TypeIndex(7), TypeIndex(8)};
138 StringListRecord Record{TypeRecordKind::StringList, Ids};
139 } StringList;
140 static struct {
141 std::vector Ids = {TypeIndex(9), TypeIndex(10), TypeIndex(11)};
142 BuildInfoRecord Record{Ids};
143 } BuildInfo;
144 static UdtSourceLineRecord UdtSourceLine(TypeIndex(12), TypeIndex(13), 0);
145 static UdtModSourceLineRecord UdtModSourceLine(TypeIndex(14), TypeIndex(15), 0,
146 0);
147 static ModifierRecord Modifier(TypeIndex(16), ModifierOptions::None);
148 static ProcedureRecord Procedure(TypeIndex(17), CallingConvention::PpcCall,
149 FunctionOptions::None, 0, TypeIndex(18));
150 static MemberFunctionRecord MemberFunction(TypeIndex(19), TypeIndex(20),
151 TypeIndex(21),
152 CallingConvention::ThisCall,
153 FunctionOptions::None, 2,
154 TypeIndex(22), 0);
155 static struct {
156 std::vector Ids = {TypeIndex(23), TypeIndex(24), TypeIndex(25)};
157 ArgListRecord Record{TypeRecordKind::ArgList, Ids};
158 } ArgList;
159 static ArrayRecord Array(TypeIndex(26), TypeIndex(27), 10, "MyArray");
160 static ClassRecord Class(TypeRecordKind::Class, 3, ClassOptions::None,
161 TypeIndex(28), TypeIndex(29), TypeIndex(30), 10,
162 "MyClass", "MyClassUniqueName");
163 static ClassRecord Struct(TypeRecordKind::Struct, 3, ClassOptions::None,
164 TypeIndex(31), TypeIndex(32), TypeIndex(33), 10,
165 "MyClass", "MyClassUniqueName");
166 static UnionRecord Union(1, ClassOptions::None, TypeIndex(34), 10, "MyUnion",
167 "MyUnionUniqueName");
168 static EnumRecord Enum(1, ClassOptions::None, TypeIndex(35), "MyEnum",
169 "EnumUniqueName", TypeIndex(36));
170 static BitFieldRecord BitField(TypeIndex(37), 1, 0);
171 static VFTableRecord VFTable(TypeIndex(38), TypeIndex(39), 1, "VFT", {});
172 static VFTableShapeRecord VTableShape({});
173 static struct {
174 const TypeIndex T1{40};
175 const TypeIndex T2{41};
176 const TypeIndex T3{42};
177 const TypeIndex T4{43};
178
179 std::vector Methods{
180 {T1, MemberAccess::Public, MethodKind::IntroducingVirtual,
181 MethodOptions::None, 0, "Method1"},
182 {T2, MemberAccess::Public, MethodKind::PureVirtual, MethodOptions::None,
183 0, "Method1"},
184 {T3, MemberAccess::Public, MethodKind::PureIntroducingVirtual,
185 MethodOptions::None, 0, "Method1"},
186 {T4, MemberAccess::Public, MethodKind::Static, MethodOptions::None, 0,
187 "Method1"}};
188
189 MethodOverloadListRecord Record{Methods};
190 } MethodOverloadList;
191 static PointerRecord Pointer(TypeIndex(44), PointerKind::Near32,
192 PointerMode::Pointer, PointerOptions::Const, 3);
193 static PointerRecord MemberPointer(
194 TypeIndex(45), PointerKind::Near32, PointerMode::PointerToDataMember,
195 PointerOptions::Const, 3,
196 MemberPointerInfo(TypeIndex(46),
197 PointerToMemberRepresentation::GeneralData));
198 }
199
200 namespace members {
201 static BaseClassRecord BaseClass(MemberAccess::Public, TypeIndex(47), 0);
202 static EnumeratorRecord Enumerator(MemberAccess::Public,
203 APSInt(APInt(8, 3, false)), "Test");
204 DataMemberRecord DataMember(MemberAccess::Public, TypeIndex(48), 0, "Test");
205 OverloadedMethodRecord OverloadedMethod(3, TypeIndex(49), "MethodList");
206 static struct {
207 const TypeIndex T1{50};
208 const TypeIndex T2{51};
209 const TypeIndex T3{52};
210 const TypeIndex T4{53};
211 OneMethodRecord R1{T1,
212 MemberAccess::Public,
213 MethodKind::IntroducingVirtual,
214 MethodOptions::None,
215 0,
216 "M1"};
217 OneMethodRecord R2{T2,
218 MemberAccess::Public,
219 MethodKind::PureVirtual,
220 MethodOptions::None,
221 0,
222 "M2"};
223 OneMethodRecord R3{T3,
224 MemberAccess::Public,
225 MethodKind::PureIntroducingVirtual,
226 MethodOptions::None,
227 0,
228 "M3"};
229 OneMethodRecord R4{T4,
230 MemberAccess::Protected,
231 MethodKind::Vanilla,
232 MethodOptions::CompilerGenerated,
233 0,
234 "M4"};
235 } OneMethod;
236 static NestedTypeRecord NestedType(TypeIndex(54), "MyClass");
237 static StaticDataMemberRecord StaticDataMember(MemberAccess::Public,
238 TypeIndex(55), "Foo");
239 static VirtualBaseClassRecord VirtualBaseClass(TypeRecordKind::VirtualBaseClass,
240 MemberAccess::Public,
241 TypeIndex(56), TypeIndex(57), 0,
242 0);
243 static VFPtrRecord VFPtr(TypeIndex(58));
244 static ListContinuationRecord Continuation(TypeIndex(59));
245 }
246
247 TEST_F(TypeIndexIteratorTest, FuncId) {
248 using namespace leafs;
249 writeTypeRecords(FuncId);
250 checkTypeReferences(0, FuncId.FunctionType, FuncId.ParentScope);
251 }
252
253 TEST_F(TypeIndexIteratorTest, MemFuncId) {
254 using namespace leafs;
255 writeTypeRecords(MemFuncId);
256 checkTypeReferences(0, MemFuncId.ClassType, MemFuncId.FunctionType);
257 }
258
259 TEST_F(TypeIndexIteratorTest, StringId) {
260 using namespace leafs;
261 writeTypeRecords(StringId);
262 checkTypeReferences(0, StringId.Id);
263 }
264
265 TEST_F(TypeIndexIteratorTest, SubstrList) {
266 using namespace leafs;
267 writeTypeRecords(StringList.Record);
268 checkTypeReferences(0, StringList.Ids[0], StringList.Ids[1],
269 StringList.Ids[2]);
270 }
271
272 TEST_F(TypeIndexIteratorTest, BuildInfo) {
273 using namespace leafs;
274 writeTypeRecords(BuildInfo.Record);
275 checkTypeReferences(0, BuildInfo.Ids[0], BuildInfo.Ids[1], BuildInfo.Ids[2]);
276 }
277
278 TEST_F(TypeIndexIteratorTest, UdtSrcLine) {
279 using namespace leafs;
280 writeTypeRecords(UdtSourceLine);
281 checkTypeReferences(0, UdtSourceLine.UDT, UdtSourceLine.SourceFile);
282 }
283
284 TEST_F(TypeIndexIteratorTest, UdtModSrcLine) {
285 using namespace leafs;
286 writeTypeRecords(UdtModSourceLine);
287 checkTypeReferences(0, UdtModSourceLine.UDT, UdtModSourceLine.SourceFile);
288 }
289
290 TEST_F(TypeIndexIteratorTest, Modifier) {
291 using namespace leafs;
292 writeTypeRecords(Modifier);
293 checkTypeReferences(0, Modifier.ModifiedType);
294 }
295
296 TEST_F(TypeIndexIteratorTest, Procedure) {
297 using namespace leafs;
298 writeTypeRecords(Procedure);
299 checkTypeReferences(0, Procedure.ReturnType, Procedure.ArgumentList);
300 }
301
302 TEST_F(TypeIndexIteratorTest, MemFunc) {
303 using namespace leafs;
304 writeTypeRecords(MemberFunction);
305 checkTypeReferences(0, MemberFunction.ReturnType, MemberFunction.ClassType,
306 MemberFunction.ThisType, MemberFunction.ArgumentList);
307 }
308
309 TEST_F(TypeIndexIteratorTest, ArgList) {
310 using namespace leafs;
311 writeTypeRecords(ArgList.Record);
312 checkTypeReferences(0, ArgList.Ids[0], ArgList.Ids[1], ArgList.Ids[2]);
313 }
314
315 TEST_F(TypeIndexIteratorTest, Array) {
316 using namespace leafs;
317 writeTypeRecords(Array);
318 checkTypeReferences(0, Array.ElementType, Array.IndexType);
319 }
320
321 TEST_F(TypeIndexIteratorTest, Class) {
322 using namespace leafs;
323 writeTypeRecords(Class);
324 checkTypeReferences(0, Class.FieldList, Class.DerivationList,
325 Class.VTableShape);
326 }
327
328 TEST_F(TypeIndexIteratorTest, Struct) {
329 using namespace leafs;
330 writeTypeRecords(Struct);
331 checkTypeReferences(0, Struct.FieldList, Struct.DerivationList,
332 Struct.VTableShape);
333 }
334
335 TEST_F(TypeIndexIteratorTest, Union) {
336 using namespace leafs;
337 writeTypeRecords(Union);
338 checkTypeReferences(0, Union.FieldList);
339 }
340
341 TEST_F(TypeIndexIteratorTest, Enum) {
342 using namespace leafs;
343 writeTypeRecords(Enum);
344 checkTypeReferences(0, Enum.FieldList, Enum.UnderlyingType);
345 }
346
347 TEST_F(TypeIndexIteratorTest, Bitfield) {
348 using namespace leafs;
349 writeTypeRecords(BitField);
350 checkTypeReferences(0, BitField.Type);
351 }
352
353 TEST_F(TypeIndexIteratorTest, VTable) {
354 using namespace leafs;
355 writeTypeRecords(VFTable);
356 checkTypeReferences(0, VFTable.CompleteClass, VFTable.OverriddenVFTable);
357 }
358
359 TEST_F(TypeIndexIteratorTest, VTShape) {
360 using namespace leafs;
361 writeTypeRecords(VTableShape);
362 checkTypeReferences(0);
363 }
364
365 TEST_F(TypeIndexIteratorTest, OverloadList) {
366 using namespace leafs;
367 writeTypeRecords(MethodOverloadList.Record);
368 checkTypeReferences(0, MethodOverloadList.T1, MethodOverloadList.T2,
369 MethodOverloadList.T3, MethodOverloadList.T4);
370 }
371
372 TEST_F(TypeIndexIteratorTest, Pointer) {
373 using namespace leafs;
374 writeTypeRecords(Pointer);
375 checkTypeReferences(0, Pointer.ReferentType);
376 }
377
378 TEST_F(TypeIndexIteratorTest, MemberPointer) {
379 using namespace leafs;
380 writeTypeRecords(MemberPointer);
381 checkTypeReferences(0, MemberPointer.ReferentType,
382 MemberPointer.MemberInfo->ContainingType);
383 }
384
385 TEST_F(TypeIndexIteratorTest, ManyTypes) {
386
387 using namespace leafs;
388 writeTypeRecords(FuncId, MemFuncId, StringId, StringList.Record,
389 BuildInfo.Record, UdtSourceLine, UdtModSourceLine, Modifier,
390 Procedure, MemberFunction, ArgList.Record, Array, Class,
391 Union, Enum, BitField, VFTable, VTableShape,
392 MethodOverloadList.Record, Pointer, MemberPointer);
393
394 checkTypeReferences(0, FuncId.FunctionType, FuncId.ParentScope);
395 checkTypeReferences(1, MemFuncId.ClassType, MemFuncId.FunctionType);
396 checkTypeReferences(2, StringId.Id);
397 checkTypeReferences(3, StringList.Ids[0], StringList.Ids[1],
398 StringList.Ids[2]);
399 checkTypeReferences(4, BuildInfo.Ids[0], BuildInfo.Ids[1], BuildInfo.Ids[2]);
400 checkTypeReferences(5, UdtSourceLine.UDT, UdtSourceLine.SourceFile);
401 checkTypeReferences(6, UdtModSourceLine.UDT, UdtModSourceLine.SourceFile);
402 checkTypeReferences(7, Modifier.ModifiedType);
403 checkTypeReferences(8, Procedure.ReturnType, Procedure.ArgumentList);
404 checkTypeReferences(9, MemberFunction.ReturnType, MemberFunction.ClassType,
405 MemberFunction.ThisType, MemberFunction.ArgumentList);
406 checkTypeReferences(10, ArgList.Ids[0], ArgList.Ids[1], ArgList.Ids[2]);
407 checkTypeReferences(11, Array.ElementType, Array.IndexType);
408 checkTypeReferences(12, Class.FieldList, Class.DerivationList,
409 Class.VTableShape);
410 checkTypeReferences(13, Union.FieldList);
411 checkTypeReferences(14, Enum.FieldList, Enum.UnderlyingType);
412 checkTypeReferences(15, BitField.Type);
413 checkTypeReferences(16, VFTable.CompleteClass, VFTable.OverriddenVFTable);
414 checkTypeReferences(17);
415 checkTypeReferences(18, MethodOverloadList.T1, MethodOverloadList.T2,
416 MethodOverloadList.T3, MethodOverloadList.T4);
417 checkTypeReferences(19, Pointer.ReferentType);
418 checkTypeReferences(20, MemberPointer.ReferentType,
419 MemberPointer.MemberInfo->ContainingType);
420 }
421
422 TEST_F(TypeIndexIteratorTest, FieldListBaseClass) {
423 using namespace members;
424 writeFieldList(BaseClass);
425 checkTypeReferences(0, BaseClass.Type);
426 }
427
428 TEST_F(TypeIndexIteratorTest, FieldListEnumerator) {
429 using namespace members;
430 writeFieldList(Enumerator);
431 checkTypeReferences(0);
432 }
433
434 TEST_F(TypeIndexIteratorTest, FieldListMember) {
435 using namespace members;
436 writeFieldList(DataMember);
437 checkTypeReferences(0, DataMember.Type);
438 }
439
440 TEST_F(TypeIndexIteratorTest, FieldListMethod) {
441 using namespace members;
442 writeFieldList(OverloadedMethod);
443 checkTypeReferences(0, OverloadedMethod.MethodList);
444 }
445
446 TEST_F(TypeIndexIteratorTest, FieldListOneMethod) {
447 using namespace members;
448 writeFieldList(OneMethod.R1, OneMethod.R2, OneMethod.R3, OneMethod.R4);
449 checkTypeReferences(0, OneMethod.T1, OneMethod.T2, OneMethod.T3,
450 OneMethod.T4);
451 }
452
453 TEST_F(TypeIndexIteratorTest, FieldListNestedType) {
454 using namespace members;
455 writeFieldList(NestedType);
456 checkTypeReferences(0, NestedType.Type);
457 }
458
459 TEST_F(TypeIndexIteratorTest, FieldListStaticMember) {
460 using namespace members;
461 writeFieldList(StaticDataMember);
462 checkTypeReferences(0, StaticDataMember.Type);
463 }
464
465 TEST_F(TypeIndexIteratorTest, FieldListVirtualBase) {
466 using namespace members;
467 writeFieldList(VirtualBaseClass);
468 checkTypeReferences(0, VirtualBaseClass.BaseType, VirtualBaseClass.VBPtrType);
469 }
470
471 TEST_F(TypeIndexIteratorTest, FieldListVFTable) {
472 using namespace members;
473 writeFieldList(VFPtr);
474 checkTypeReferences(0, VFPtr.Type);
475 }
476
477 TEST_F(TypeIndexIteratorTest, FieldListContinuation) {
478 using namespace members;
479 writeFieldList(Continuation);
480 checkTypeReferences(0, Continuation.ContinuationIndex);
481 }
482
483 TEST_F(TypeIndexIteratorTest, ManyMembers) {
484 using namespace members;
485 writeFieldList(BaseClass, Enumerator, DataMember, OverloadedMethod,
486 OneMethod.R1, OneMethod.R2, OneMethod.R3, OneMethod.R4,
487 NestedType, StaticDataMember, VirtualBaseClass, VFPtr,
488 Continuation);
489
490 checkTypeReferences(
491 0, BaseClass.Type, DataMember.Type, OverloadedMethod.MethodList,
492 OneMethod.T1, OneMethod.T2, OneMethod.T3, OneMethod.T4, NestedType.Type,
493 StaticDataMember.Type, VirtualBaseClass.BaseType,
494 VirtualBaseClass.VBPtrType, VFPtr.Type, Continuation.ContinuationIndex);
495 }