/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/VTableBuilder.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===// |
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 | | // |
9 | | // This contains code dealing with generation of the layout of virtual tables. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "clang/AST/VTableBuilder.h" |
14 | | #include "clang/AST/ASTContext.h" |
15 | | #include "clang/AST/ASTDiagnostic.h" |
16 | | #include "clang/AST/CXXInheritance.h" |
17 | | #include "clang/AST/RecordLayout.h" |
18 | | #include "clang/Basic/TargetInfo.h" |
19 | | #include "llvm/ADT/SetOperations.h" |
20 | | #include "llvm/ADT/SetVector.h" |
21 | | #include "llvm/ADT/SmallPtrSet.h" |
22 | | #include "llvm/Support/Format.h" |
23 | | #include "llvm/Support/raw_ostream.h" |
24 | | #include <algorithm> |
25 | | #include <cstdio> |
26 | | |
27 | | using namespace clang; |
28 | | |
29 | | #define DUMP_OVERRIDERS 0 |
30 | | |
31 | | namespace { |
32 | | |
33 | | /// BaseOffset - Represents an offset from a derived class to a direct or |
34 | | /// indirect base class. |
35 | | struct BaseOffset { |
36 | | /// DerivedClass - The derived class. |
37 | | const CXXRecordDecl *DerivedClass; |
38 | | |
39 | | /// VirtualBase - If the path from the derived class to the base class |
40 | | /// involves virtual base classes, this holds the declaration of the last |
41 | | /// virtual base in this path (i.e. closest to the base class). |
42 | | const CXXRecordDecl *VirtualBase; |
43 | | |
44 | | /// NonVirtualOffset - The offset from the derived class to the base class. |
45 | | /// (Or the offset from the virtual base class to the base class, if the |
46 | | /// path from the derived class to the base class involves a virtual base |
47 | | /// class. |
48 | | CharUnits NonVirtualOffset; |
49 | | |
50 | | BaseOffset() : DerivedClass(nullptr), VirtualBase(nullptr), |
51 | 25.3k | NonVirtualOffset(CharUnits::Zero()) { } |
52 | | BaseOffset(const CXXRecordDecl *DerivedClass, |
53 | | const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset) |
54 | | : DerivedClass(DerivedClass), VirtualBase(VirtualBase), |
55 | 4.11k | NonVirtualOffset(NonVirtualOffset) { } |
56 | | |
57 | 19.0k | bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase18.7k ; } |
58 | | }; |
59 | | |
60 | | /// FinalOverriders - Contains the final overrider member functions for all |
61 | | /// member functions in the base subobjects of a class. |
62 | | class FinalOverriders { |
63 | | public: |
64 | | /// OverriderInfo - Information about a final overrider. |
65 | | struct OverriderInfo { |
66 | | /// Method - The method decl of the overrider. |
67 | | const CXXMethodDecl *Method; |
68 | | |
69 | | /// VirtualBase - The virtual base class subobject of this overrider. |
70 | | /// Note that this records the closest derived virtual base class subobject. |
71 | | const CXXRecordDecl *VirtualBase; |
72 | | |
73 | | /// Offset - the base offset of the overrider's parent in the layout class. |
74 | | CharUnits Offset; |
75 | | |
76 | | OverriderInfo() : Method(nullptr), VirtualBase(nullptr), |
77 | 16.1k | Offset(CharUnits::Zero()) { } |
78 | | }; |
79 | | |
80 | | private: |
81 | | /// MostDerivedClass - The most derived class for which the final overriders |
82 | | /// are stored. |
83 | | const CXXRecordDecl *MostDerivedClass; |
84 | | |
85 | | /// MostDerivedClassOffset - If we're building final overriders for a |
86 | | /// construction vtable, this holds the offset from the layout class to the |
87 | | /// most derived class. |
88 | | const CharUnits MostDerivedClassOffset; |
89 | | |
90 | | /// LayoutClass - The class we're using for layout information. Will be |
91 | | /// different than the most derived class if the final overriders are for a |
92 | | /// construction vtable. |
93 | | const CXXRecordDecl *LayoutClass; |
94 | | |
95 | | ASTContext &Context; |
96 | | |
97 | | /// MostDerivedClassLayout - the AST record layout of the most derived class. |
98 | | const ASTRecordLayout &MostDerivedClassLayout; |
99 | | |
100 | | /// MethodBaseOffsetPairTy - Uniquely identifies a member function |
101 | | /// in a base subobject. |
102 | | typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy; |
103 | | |
104 | | typedef llvm::DenseMap<MethodBaseOffsetPairTy, |
105 | | OverriderInfo> OverridersMapTy; |
106 | | |
107 | | /// OverridersMap - The final overriders for all virtual member functions of |
108 | | /// all the base subobjects of the most derived class. |
109 | | OverridersMapTy OverridersMap; |
110 | | |
111 | | /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented |
112 | | /// as a record decl and a subobject number) and its offsets in the most |
113 | | /// derived class as well as the layout class. |
114 | | typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>, |
115 | | CharUnits> SubobjectOffsetMapTy; |
116 | | |
117 | | typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy; |
118 | | |
119 | | /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the |
120 | | /// given base. |
121 | | void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, |
122 | | CharUnits OffsetInLayoutClass, |
123 | | SubobjectOffsetMapTy &SubobjectOffsets, |
124 | | SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, |
125 | | SubobjectCountMapTy &SubobjectCounts); |
126 | | |
127 | | typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; |
128 | | |
129 | | /// dump - dump the final overriders for a base subobject, and all its direct |
130 | | /// and indirect base subobjects. |
131 | | void dump(raw_ostream &Out, BaseSubobject Base, |
132 | | VisitedVirtualBasesSetTy& VisitedVirtualBases); |
133 | | |
134 | | public: |
135 | | FinalOverriders(const CXXRecordDecl *MostDerivedClass, |
136 | | CharUnits MostDerivedClassOffset, |
137 | | const CXXRecordDecl *LayoutClass); |
138 | | |
139 | | /// getOverrider - Get the final overrider for the given method declaration in |
140 | | /// the subobject with the given base offset. |
141 | | OverriderInfo getOverrider(const CXXMethodDecl *MD, |
142 | 34.1k | CharUnits BaseOffset) const { |
143 | 34.1k | assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) && |
144 | 34.1k | "Did not find overrider!"); |
145 | | |
146 | 34.1k | return OverridersMap.lookup(std::make_pair(MD, BaseOffset)); |
147 | 34.1k | } |
148 | | |
149 | | /// dump - dump the final overriders. |
150 | 0 | void dump() { |
151 | 0 | VisitedVirtualBasesSetTy VisitedVirtualBases; |
152 | 0 | dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()), |
153 | 0 | VisitedVirtualBases); |
154 | 0 | } |
155 | | |
156 | | }; |
157 | | |
158 | | FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, |
159 | | CharUnits MostDerivedClassOffset, |
160 | | const CXXRecordDecl *LayoutClass) |
161 | | : MostDerivedClass(MostDerivedClass), |
162 | | MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), |
163 | | Context(MostDerivedClass->getASTContext()), |
164 | 5.15k | MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { |
165 | | |
166 | | // Compute base offsets. |
167 | 5.15k | SubobjectOffsetMapTy SubobjectOffsets; |
168 | 5.15k | SubobjectOffsetMapTy SubobjectLayoutClassOffsets; |
169 | 5.15k | SubobjectCountMapTy SubobjectCounts; |
170 | 5.15k | ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()), |
171 | 5.15k | /*IsVirtual=*/false, |
172 | 5.15k | MostDerivedClassOffset, |
173 | 5.15k | SubobjectOffsets, SubobjectLayoutClassOffsets, |
174 | 5.15k | SubobjectCounts); |
175 | | |
176 | | // Get the final overriders. |
177 | 5.15k | CXXFinalOverriderMap FinalOverriders; |
178 | 5.15k | MostDerivedClass->getFinalOverriders(FinalOverriders); |
179 | | |
180 | 15.9k | for (const auto &Overrider : FinalOverriders) { |
181 | 15.9k | const CXXMethodDecl *MD = Overrider.first; |
182 | 15.9k | const OverridingMethods &Methods = Overrider.second; |
183 | | |
184 | 16.1k | for (const auto &M : Methods) { |
185 | 16.1k | unsigned SubobjectNumber = M.first; |
186 | 16.1k | assert(SubobjectOffsets.count(std::make_pair(MD->getParent(), |
187 | 16.1k | SubobjectNumber)) && |
188 | 16.1k | "Did not find subobject offset!"); |
189 | | |
190 | 16.1k | CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), |
191 | 16.1k | SubobjectNumber)]; |
192 | | |
193 | 16.1k | assert(M.second.size() == 1 && "Final overrider is not unique!"); |
194 | 16.1k | const UniqueVirtualMethod &Method = M.second.front(); |
195 | | |
196 | 16.1k | const CXXRecordDecl *OverriderRD = Method.Method->getParent(); |
197 | 16.1k | assert(SubobjectLayoutClassOffsets.count( |
198 | 16.1k | std::make_pair(OverriderRD, Method.Subobject)) |
199 | 16.1k | && "Did not find subobject offset!"); |
200 | 16.1k | CharUnits OverriderOffset = |
201 | 16.1k | SubobjectLayoutClassOffsets[std::make_pair(OverriderRD, |
202 | 16.1k | Method.Subobject)]; |
203 | | |
204 | 16.1k | OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)]; |
205 | 16.1k | assert(!Overrider.Method && "Overrider should not exist yet!"); |
206 | | |
207 | 16.1k | Overrider.Offset = OverriderOffset; |
208 | 16.1k | Overrider.Method = Method.Method; |
209 | 16.1k | Overrider.VirtualBase = Method.InVirtualSubobject; |
210 | 16.1k | } |
211 | 15.9k | } |
212 | | |
213 | | #if DUMP_OVERRIDERS |
214 | | // And dump them (for now). |
215 | | dump(); |
216 | | #endif |
217 | 5.15k | } |
218 | | |
219 | | static BaseOffset ComputeBaseOffset(const ASTContext &Context, |
220 | | const CXXRecordDecl *DerivedRD, |
221 | 4.11k | const CXXBasePath &Path) { |
222 | 4.11k | CharUnits NonVirtualOffset = CharUnits::Zero(); |
223 | | |
224 | 4.11k | unsigned NonVirtualStart = 0; |
225 | 4.11k | const CXXRecordDecl *VirtualBase = nullptr; |
226 | | |
227 | | // First, look for the virtual base class. |
228 | 8.52k | for (int I = Path.size(), E = 0; I != E; --I4.40k ) { |
229 | 4.84k | const CXXBasePathElement &Element = Path[I - 1]; |
230 | | |
231 | 4.84k | if (Element.Base->isVirtual()) { |
232 | 447 | NonVirtualStart = I; |
233 | 447 | QualType VBaseType = Element.Base->getType(); |
234 | 447 | VirtualBase = VBaseType->getAsCXXRecordDecl(); |
235 | 447 | break; |
236 | 447 | } |
237 | 4.84k | } |
238 | | |
239 | | // Now compute the non-virtual offset. |
240 | 8.52k | for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I4.40k ) { |
241 | 4.40k | const CXXBasePathElement &Element = Path[I]; |
242 | | |
243 | | // Check the base class offset. |
244 | 4.40k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); |
245 | | |
246 | 4.40k | const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl(); |
247 | | |
248 | 4.40k | NonVirtualOffset += Layout.getBaseClassOffset(Base); |
249 | 4.40k | } |
250 | | |
251 | | // FIXME: This should probably use CharUnits or something. Maybe we should |
252 | | // even change the base offsets in ASTRecordLayout to be specified in |
253 | | // CharUnits. |
254 | 4.11k | return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset); |
255 | | |
256 | 4.11k | } |
257 | | |
258 | | static BaseOffset ComputeBaseOffset(const ASTContext &Context, |
259 | | const CXXRecordDecl *BaseRD, |
260 | 305 | const CXXRecordDecl *DerivedRD) { |
261 | 305 | CXXBasePaths Paths(/*FindAmbiguities=*/false, |
262 | 305 | /*RecordPaths=*/true, /*DetectVirtual=*/false); |
263 | | |
264 | 305 | if (!DerivedRD->isDerivedFrom(BaseRD, Paths)) |
265 | 0 | llvm_unreachable("Class must be derived from the passed in base class!"); |
266 | | |
267 | 305 | return ComputeBaseOffset(Context, DerivedRD, Paths.front()); |
268 | 305 | } |
269 | | |
270 | | static BaseOffset |
271 | | ComputeReturnAdjustmentBaseOffset(ASTContext &Context, |
272 | | const CXXMethodDecl *DerivedMD, |
273 | 14.7k | const CXXMethodDecl *BaseMD) { |
274 | 14.7k | const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>(); |
275 | 14.7k | const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>(); |
276 | | |
277 | | // Canonicalize the return types. |
278 | 14.7k | CanQualType CanDerivedReturnType = |
279 | 14.7k | Context.getCanonicalType(DerivedFT->getReturnType()); |
280 | 14.7k | CanQualType CanBaseReturnType = |
281 | 14.7k | Context.getCanonicalType(BaseFT->getReturnType()); |
282 | | |
283 | 14.7k | assert(CanDerivedReturnType->getTypeClass() == |
284 | 14.7k | CanBaseReturnType->getTypeClass() && |
285 | 14.7k | "Types must have same type class!"); |
286 | | |
287 | 14.7k | if (CanDerivedReturnType == CanBaseReturnType) { |
288 | | // No adjustment needed. |
289 | 14.4k | return BaseOffset(); |
290 | 14.4k | } |
291 | | |
292 | 307 | if (isa<ReferenceType>(CanDerivedReturnType)) { |
293 | 37 | CanDerivedReturnType = |
294 | 37 | CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType(); |
295 | 37 | CanBaseReturnType = |
296 | 37 | CanBaseReturnType->getAs<ReferenceType>()->getPointeeType(); |
297 | 270 | } else if (isa<PointerType>(CanDerivedReturnType)) { |
298 | 270 | CanDerivedReturnType = |
299 | 270 | CanDerivedReturnType->getAs<PointerType>()->getPointeeType(); |
300 | 270 | CanBaseReturnType = |
301 | 270 | CanBaseReturnType->getAs<PointerType>()->getPointeeType(); |
302 | 270 | } else { |
303 | 0 | llvm_unreachable("Unexpected return type!"); |
304 | 0 | } |
305 | | |
306 | | // We need to compare unqualified types here; consider |
307 | | // const T *Base::foo(); |
308 | | // T *Derived::foo(); |
309 | 307 | if (CanDerivedReturnType.getUnqualifiedType() == |
310 | 307 | CanBaseReturnType.getUnqualifiedType()) { |
311 | | // No adjustment needed. |
312 | 2 | return BaseOffset(); |
313 | 2 | } |
314 | | |
315 | 305 | const CXXRecordDecl *DerivedRD = |
316 | 305 | cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); |
317 | | |
318 | 305 | const CXXRecordDecl *BaseRD = |
319 | 305 | cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); |
320 | | |
321 | 305 | return ComputeBaseOffset(Context, BaseRD, DerivedRD); |
322 | 307 | } |
323 | | |
324 | | void |
325 | | FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, |
326 | | CharUnits OffsetInLayoutClass, |
327 | | SubobjectOffsetMapTy &SubobjectOffsets, |
328 | | SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, |
329 | 10.9k | SubobjectCountMapTy &SubobjectCounts) { |
330 | 10.9k | const CXXRecordDecl *RD = Base.getBase(); |
331 | | |
332 | 10.9k | unsigned SubobjectNumber = 0; |
333 | 10.9k | if (!IsVirtual) |
334 | 9.50k | SubobjectNumber = ++SubobjectCounts[RD]; |
335 | | |
336 | | // Set up the subobject to offset mapping. |
337 | 10.9k | assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber)) |
338 | 10.9k | && "Subobject offset already exists!"); |
339 | 10.9k | assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber)) |
340 | 10.9k | && "Subobject offset already exists!"); |
341 | | |
342 | 10.9k | SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset(); |
343 | 10.9k | SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] = |
344 | 10.9k | OffsetInLayoutClass; |
345 | | |
346 | | // Traverse our bases. |
347 | 10.9k | for (const auto &B : RD->bases()) { |
348 | 6.11k | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
349 | | |
350 | 6.11k | CharUnits BaseOffset; |
351 | 6.11k | CharUnits BaseOffsetInLayoutClass; |
352 | 6.11k | if (B.isVirtual()) { |
353 | | // Check if we've visited this virtual base before. |
354 | 1.76k | if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0))) |
355 | 351 | continue; |
356 | | |
357 | 1.41k | const ASTRecordLayout &LayoutClassLayout = |
358 | 1.41k | Context.getASTRecordLayout(LayoutClass); |
359 | | |
360 | 1.41k | BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); |
361 | 1.41k | BaseOffsetInLayoutClass = |
362 | 1.41k | LayoutClassLayout.getVBaseClassOffset(BaseDecl); |
363 | 4.35k | } else { |
364 | 4.35k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
365 | 4.35k | CharUnits Offset = Layout.getBaseClassOffset(BaseDecl); |
366 | | |
367 | 4.35k | BaseOffset = Base.getBaseOffset() + Offset; |
368 | 4.35k | BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset; |
369 | 4.35k | } |
370 | | |
371 | 5.76k | ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), |
372 | 5.76k | B.isVirtual(), BaseOffsetInLayoutClass, |
373 | 5.76k | SubobjectOffsets, SubobjectLayoutClassOffsets, |
374 | 5.76k | SubobjectCounts); |
375 | 5.76k | } |
376 | 10.9k | } |
377 | | |
378 | | void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, |
379 | 0 | VisitedVirtualBasesSetTy &VisitedVirtualBases) { |
380 | 0 | const CXXRecordDecl *RD = Base.getBase(); |
381 | 0 | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
382 | 0 |
|
383 | 0 | for (const auto &B : RD->bases()) { |
384 | 0 | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
385 | 0 |
|
386 | 0 | // Ignore bases that don't have any virtual member functions. |
387 | 0 | if (!BaseDecl->isPolymorphic()) |
388 | 0 | continue; |
389 | 0 |
|
390 | 0 | CharUnits BaseOffset; |
391 | 0 | if (B.isVirtual()) { |
392 | 0 | if (!VisitedVirtualBases.insert(BaseDecl).second) { |
393 | 0 | // We've visited this base before. |
394 | 0 | continue; |
395 | 0 | } |
396 | 0 |
|
397 | 0 | BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); |
398 | 0 | } else { |
399 | 0 | BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); |
400 | 0 | } |
401 | 0 |
|
402 | 0 | dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases); |
403 | 0 | } |
404 | 0 |
|
405 | 0 | Out << "Final overriders for ("; |
406 | 0 | RD->printQualifiedName(Out); |
407 | 0 | Out << ", "; |
408 | 0 | Out << Base.getBaseOffset().getQuantity() << ")\n"; |
409 | 0 |
|
410 | 0 | // Now dump the overriders for this base subobject. |
411 | 0 | for (const auto *MD : RD->methods()) { |
412 | 0 | if (!VTableContextBase::hasVtableSlot(MD)) |
413 | 0 | continue; |
414 | 0 | MD = MD->getCanonicalDecl(); |
415 | 0 |
|
416 | 0 | OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset()); |
417 | 0 |
|
418 | 0 | Out << " "; |
419 | 0 | MD->printQualifiedName(Out); |
420 | 0 | Out << " - ("; |
421 | 0 | Overrider.Method->printQualifiedName(Out); |
422 | 0 | Out << ", " << Overrider.Offset.getQuantity() << ')'; |
423 | 0 |
|
424 | 0 | BaseOffset Offset; |
425 | 0 | if (!Overrider.Method->isPure()) |
426 | 0 | Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); |
427 | 0 |
|
428 | 0 | if (!Offset.isEmpty()) { |
429 | 0 | Out << " [ret-adj: "; |
430 | 0 | if (Offset.VirtualBase) { |
431 | 0 | Offset.VirtualBase->printQualifiedName(Out); |
432 | 0 | Out << " vbase, "; |
433 | 0 | } |
434 | 0 |
|
435 | 0 | Out << Offset.NonVirtualOffset.getQuantity() << " nv]"; |
436 | 0 | } |
437 | 0 |
|
438 | 0 | Out << "\n"; |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | /// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. |
443 | | struct VCallOffsetMap { |
444 | | |
445 | | typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy; |
446 | | |
447 | | /// Offsets - Keeps track of methods and their offsets. |
448 | | // FIXME: This should be a real map and not a vector. |
449 | | SmallVector<MethodAndOffsetPairTy, 16> Offsets; |
450 | | |
451 | | /// MethodsCanShareVCallOffset - Returns whether two virtual member functions |
452 | | /// can share the same vcall offset. |
453 | | static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, |
454 | | const CXXMethodDecl *RHS); |
455 | | |
456 | | public: |
457 | | /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the |
458 | | /// add was successful, or false if there was already a member function with |
459 | | /// the same signature in the map. |
460 | | bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset); |
461 | | |
462 | | /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the |
463 | | /// vtable address point) for the given virtual member function. |
464 | | CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD); |
465 | | |
466 | | // empty - Return whether the offset map is empty or not. |
467 | 1.02k | bool empty() const { return Offsets.empty(); } |
468 | | }; |
469 | | |
470 | | static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, |
471 | 224 | const CXXMethodDecl *RHS) { |
472 | 224 | const FunctionProtoType *LT = |
473 | 224 | cast<FunctionProtoType>(LHS->getType().getCanonicalType()); |
474 | 224 | const FunctionProtoType *RT = |
475 | 224 | cast<FunctionProtoType>(RHS->getType().getCanonicalType()); |
476 | | |
477 | | // Fast-path matches in the canonical types. |
478 | 224 | if (LT == RT) return true221 ; |
479 | | |
480 | | // Force the signatures to match. We can't rely on the overrides |
481 | | // list here because there isn't necessarily an inheritance |
482 | | // relationship between the two methods. |
483 | 3 | if (LT->getMethodQuals() != RT->getMethodQuals()) |
484 | 3 | return false; |
485 | 0 | return LT->getParamTypes() == RT->getParamTypes(); |
486 | 3 | } |
487 | | |
488 | | bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, |
489 | 588 | const CXXMethodDecl *RHS) { |
490 | 588 | assert(VTableContextBase::hasVtableSlot(LHS) && "LHS must be virtual!"); |
491 | 588 | assert(VTableContextBase::hasVtableSlot(RHS) && "RHS must be virtual!"); |
492 | | |
493 | | // A destructor can share a vcall offset with another destructor. |
494 | 588 | if (isa<CXXDestructorDecl>(LHS)) |
495 | 191 | return isa<CXXDestructorDecl>(RHS); |
496 | | |
497 | | // FIXME: We need to check more things here. |
498 | | |
499 | | // The methods must have the same name. |
500 | 397 | DeclarationName LHSName = LHS->getDeclName(); |
501 | 397 | DeclarationName RHSName = RHS->getDeclName(); |
502 | 397 | if (LHSName != RHSName) |
503 | 173 | return false; |
504 | | |
505 | | // And the same signatures. |
506 | 224 | return HasSameVirtualSignature(LHS, RHS); |
507 | 397 | } |
508 | | |
509 | | bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, |
510 | 952 | CharUnits OffsetOffset) { |
511 | | // Check if we can reuse an offset. |
512 | 952 | for (const auto &OffsetPair : Offsets) { |
513 | 232 | if (MethodsCanShareVCallOffset(OffsetPair.first, MD)) |
514 | 93 | return false; |
515 | 232 | } |
516 | | |
517 | | // Add the offset. |
518 | 859 | Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); |
519 | 859 | return true; |
520 | 952 | } |
521 | | |
522 | 303 | CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { |
523 | | // Look for an offset. |
524 | 356 | for (const auto &OffsetPair : Offsets) { |
525 | 356 | if (MethodsCanShareVCallOffset(OffsetPair.first, MD)) |
526 | 303 | return OffsetPair.second; |
527 | 356 | } |
528 | | |
529 | 0 | llvm_unreachable("Should always find a vcall offset offset!"); |
530 | 0 | } |
531 | | |
532 | | /// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. |
533 | | class VCallAndVBaseOffsetBuilder { |
534 | | public: |
535 | | typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> |
536 | | VBaseOffsetOffsetsMapTy; |
537 | | |
538 | | private: |
539 | | const ItaniumVTableContext &VTables; |
540 | | |
541 | | /// MostDerivedClass - The most derived class for which we're building vcall |
542 | | /// and vbase offsets. |
543 | | const CXXRecordDecl *MostDerivedClass; |
544 | | |
545 | | /// LayoutClass - The class we're using for layout information. Will be |
546 | | /// different than the most derived class if we're building a construction |
547 | | /// vtable. |
548 | | const CXXRecordDecl *LayoutClass; |
549 | | |
550 | | /// Context - The ASTContext which we will use for layout information. |
551 | | ASTContext &Context; |
552 | | |
553 | | /// Components - vcall and vbase offset components |
554 | | typedef SmallVector<VTableComponent, 64> VTableComponentVectorTy; |
555 | | VTableComponentVectorTy Components; |
556 | | |
557 | | /// VisitedVirtualBases - Visited virtual bases. |
558 | | llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; |
559 | | |
560 | | /// VCallOffsets - Keeps track of vcall offsets. |
561 | | VCallOffsetMap VCallOffsets; |
562 | | |
563 | | |
564 | | /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, |
565 | | /// relative to the address point. |
566 | | VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; |
567 | | |
568 | | /// FinalOverriders - The final overriders of the most derived class. |
569 | | /// (Can be null when we're not building a vtable of the most derived class). |
570 | | const FinalOverriders *Overriders; |
571 | | |
572 | | /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the |
573 | | /// given base subobject. |
574 | | void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, |
575 | | CharUnits RealBaseOffset); |
576 | | |
577 | | /// AddVCallOffsets - Add vcall offsets for the given base subobject. |
578 | | void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset); |
579 | | |
580 | | /// AddVBaseOffsets - Add vbase offsets for the given class. |
581 | | void AddVBaseOffsets(const CXXRecordDecl *Base, |
582 | | CharUnits OffsetInLayoutClass); |
583 | | |
584 | | /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in |
585 | | /// chars, relative to the vtable address point. |
586 | | CharUnits getCurrentOffsetOffset() const; |
587 | | |
588 | | public: |
589 | | VCallAndVBaseOffsetBuilder(const ItaniumVTableContext &VTables, |
590 | | const CXXRecordDecl *MostDerivedClass, |
591 | | const CXXRecordDecl *LayoutClass, |
592 | | const FinalOverriders *Overriders, |
593 | | BaseSubobject Base, bool BaseIsVirtual, |
594 | | CharUnits OffsetInLayoutClass) |
595 | | : VTables(VTables), MostDerivedClass(MostDerivedClass), |
596 | | LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), |
597 | 4.86k | Overriders(Overriders) { |
598 | | |
599 | | // Add vcall and vbase offsets. |
600 | 4.86k | AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); |
601 | 4.86k | } |
602 | | |
603 | | /// Methods for iterating over the components. |
604 | | typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; |
605 | 4.47k | const_iterator components_begin() const { return Components.rbegin(); } |
606 | 4.47k | const_iterator components_end() const { return Components.rend(); } |
607 | | |
608 | 823 | const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } |
609 | 4.12k | const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { |
610 | 4.12k | return VBaseOffsetOffsets; |
611 | 4.12k | } |
612 | | }; |
613 | | |
614 | | void |
615 | | VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, |
616 | | bool BaseIsVirtual, |
617 | 7.64k | CharUnits RealBaseOffset) { |
618 | 7.64k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); |
619 | | |
620 | | // Itanium C++ ABI 2.5.2: |
621 | | // ..in classes sharing a virtual table with a primary base class, the vcall |
622 | | // and vbase offsets added by the derived class all come before the vcall |
623 | | // and vbase offsets required by the base class, so that the latter may be |
624 | | // laid out as required by the base class without regard to additions from |
625 | | // the derived class(es). |
626 | | |
627 | | // (Since we're emitting the vcall and vbase offsets in reverse order, we'll |
628 | | // emit them for the primary base first). |
629 | 7.64k | if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { |
630 | 2.78k | bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); |
631 | | |
632 | 2.78k | CharUnits PrimaryBaseOffset; |
633 | | |
634 | | // Get the base offset of the primary base. |
635 | 2.78k | if (PrimaryBaseIsVirtual) { |
636 | 455 | assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && |
637 | 455 | "Primary vbase should have a zero offset!"); |
638 | | |
639 | 455 | const ASTRecordLayout &MostDerivedClassLayout = |
640 | 455 | Context.getASTRecordLayout(MostDerivedClass); |
641 | | |
642 | 455 | PrimaryBaseOffset = |
643 | 455 | MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); |
644 | 2.32k | } else { |
645 | 2.32k | assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && |
646 | 2.32k | "Primary base should have a zero offset!"); |
647 | | |
648 | 2.32k | PrimaryBaseOffset = Base.getBaseOffset(); |
649 | 2.32k | } |
650 | | |
651 | 2.78k | AddVCallAndVBaseOffsets( |
652 | 2.78k | BaseSubobject(PrimaryBase,PrimaryBaseOffset), |
653 | 2.78k | PrimaryBaseIsVirtual, RealBaseOffset); |
654 | 2.78k | } |
655 | | |
656 | 7.64k | AddVBaseOffsets(Base.getBase(), RealBaseOffset); |
657 | | |
658 | | // We only want to add vcall offsets for virtual bases. |
659 | 7.64k | if (BaseIsVirtual) |
660 | 988 | AddVCallOffsets(Base, RealBaseOffset); |
661 | 7.64k | } |
662 | | |
663 | 2.59k | CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { |
664 | | // OffsetIndex is the index of this vcall or vbase offset, relative to the |
665 | | // vtable address point. (We subtract 3 to account for the information just |
666 | | // above the address point, the RTTI info, the offset to top, and the |
667 | | // vcall offset itself). |
668 | 2.59k | int64_t OffsetIndex = -(int64_t)(3 + Components.size()); |
669 | | |
670 | | // Under the relative ABI, the offset widths are 32-bit ints instead of |
671 | | // pointer widths. |
672 | 2.59k | CharUnits OffsetWidth = Context.toCharUnitsFromBits( |
673 | 2.59k | VTables.isRelativeLayout() |
674 | 2.59k | ? 32151 |
675 | 2.59k | : Context.getTargetInfo().getPointerWidth(LangAS::Default)2.44k ); |
676 | 2.59k | CharUnits OffsetOffset = OffsetWidth * OffsetIndex; |
677 | | |
678 | 2.59k | return OffsetOffset; |
679 | 2.59k | } |
680 | | |
681 | | void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, |
682 | 1.40k | CharUnits VBaseOffset) { |
683 | 1.40k | const CXXRecordDecl *RD = Base.getBase(); |
684 | 1.40k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
685 | | |
686 | 1.40k | const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); |
687 | | |
688 | | // Handle the primary base first. |
689 | | // We only want to add vcall offsets if the base is non-virtual; a virtual |
690 | | // primary base will have its vcall and vbase offsets emitted already. |
691 | 1.40k | if (PrimaryBase && !Layout.isPrimaryBaseVirtual()284 ) { |
692 | | // Get the base offset of the primary base. |
693 | 176 | assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && |
694 | 176 | "Primary base should have a zero offset!"); |
695 | | |
696 | 176 | AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), |
697 | 176 | VBaseOffset); |
698 | 176 | } |
699 | | |
700 | | // Add the vcall offsets. |
701 | 8.13k | for (const auto *MD : RD->methods())1.40k { |
702 | 8.13k | if (!VTableContextBase::hasVtableSlot(MD)) |
703 | 7.18k | continue; |
704 | 952 | MD = MD->getCanonicalDecl(); |
705 | | |
706 | 952 | CharUnits OffsetOffset = getCurrentOffsetOffset(); |
707 | | |
708 | | // Don't add a vcall offset if we already have one for this member function |
709 | | // signature. |
710 | 952 | if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) |
711 | 93 | continue; |
712 | | |
713 | 859 | CharUnits Offset = CharUnits::Zero(); |
714 | | |
715 | 859 | if (Overriders) { |
716 | | // Get the final overrider. |
717 | 652 | FinalOverriders::OverriderInfo Overrider = |
718 | 652 | Overriders->getOverrider(MD, Base.getBaseOffset()); |
719 | | |
720 | | /// The vcall offset is the offset from the virtual base to the object |
721 | | /// where the function was overridden. |
722 | 652 | Offset = Overrider.Offset - VBaseOffset; |
723 | 652 | } |
724 | | |
725 | 859 | Components.push_back( |
726 | 859 | VTableComponent::MakeVCallOffset(Offset)); |
727 | 859 | } |
728 | | |
729 | | // And iterate over all non-virtual bases (ignoring the primary base). |
730 | 1.40k | for (const auto &B : RD->bases()) { |
731 | 895 | if (B.isVirtual()) |
732 | 477 | continue; |
733 | | |
734 | 418 | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
735 | 418 | if (BaseDecl == PrimaryBase) |
736 | 176 | continue; |
737 | | |
738 | | // Get the base offset of this base. |
739 | 242 | CharUnits BaseOffset = Base.getBaseOffset() + |
740 | 242 | Layout.getBaseClassOffset(BaseDecl); |
741 | | |
742 | 242 | AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), |
743 | 242 | VBaseOffset); |
744 | 242 | } |
745 | 1.40k | } |
746 | | |
747 | | void |
748 | | VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, |
749 | 16.9k | CharUnits OffsetInLayoutClass) { |
750 | 16.9k | const ASTRecordLayout &LayoutClassLayout = |
751 | 16.9k | Context.getASTRecordLayout(LayoutClass); |
752 | | |
753 | | // Add vbase offsets. |
754 | 16.9k | for (const auto &B : RD->bases()) { |
755 | 9.27k | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
756 | | |
757 | | // Check if this is a virtual base that we haven't visited before. |
758 | 9.27k | if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second4.03k ) { |
759 | 1.64k | CharUnits Offset = |
760 | 1.64k | LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; |
761 | | |
762 | | // Add the vbase offset offset. |
763 | 1.64k | assert(!VBaseOffsetOffsets.count(BaseDecl) && |
764 | 1.64k | "vbase offset offset already exists!"); |
765 | | |
766 | 1.64k | CharUnits VBaseOffsetOffset = getCurrentOffsetOffset(); |
767 | 1.64k | VBaseOffsetOffsets.insert( |
768 | 1.64k | std::make_pair(BaseDecl, VBaseOffsetOffset)); |
769 | | |
770 | 1.64k | Components.push_back( |
771 | 1.64k | VTableComponent::MakeVBaseOffset(Offset)); |
772 | 1.64k | } |
773 | | |
774 | | // Check the base class looking for more vbase offsets. |
775 | 9.27k | AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); |
776 | 9.27k | } |
777 | 16.9k | } |
778 | | |
779 | | /// ItaniumVTableBuilder - Class for building vtable layout information. |
780 | | class ItaniumVTableBuilder { |
781 | | public: |
782 | | /// PrimaryBasesSetVectorTy - A set vector of direct and indirect |
783 | | /// primary bases. |
784 | | typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> |
785 | | PrimaryBasesSetVectorTy; |
786 | | |
787 | | typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> |
788 | | VBaseOffsetOffsetsMapTy; |
789 | | |
790 | | typedef VTableLayout::AddressPointsMapTy AddressPointsMapTy; |
791 | | |
792 | | typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; |
793 | | |
794 | | private: |
795 | | /// VTables - Global vtable information. |
796 | | ItaniumVTableContext &VTables; |
797 | | |
798 | | /// MostDerivedClass - The most derived class for which we're building this |
799 | | /// vtable. |
800 | | const CXXRecordDecl *MostDerivedClass; |
801 | | |
802 | | /// MostDerivedClassOffset - If we're building a construction vtable, this |
803 | | /// holds the offset from the layout class to the most derived class. |
804 | | const CharUnits MostDerivedClassOffset; |
805 | | |
806 | | /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual |
807 | | /// base. (This only makes sense when building a construction vtable). |
808 | | bool MostDerivedClassIsVirtual; |
809 | | |
810 | | /// LayoutClass - The class we're using for layout information. Will be |
811 | | /// different than the most derived class if we're building a construction |
812 | | /// vtable. |
813 | | const CXXRecordDecl *LayoutClass; |
814 | | |
815 | | /// Context - The ASTContext which we will use for layout information. |
816 | | ASTContext &Context; |
817 | | |
818 | | /// FinalOverriders - The final overriders of the most derived class. |
819 | | const FinalOverriders Overriders; |
820 | | |
821 | | /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual |
822 | | /// bases in this vtable. |
823 | | llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; |
824 | | |
825 | | /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for |
826 | | /// the most derived class. |
827 | | VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; |
828 | | |
829 | | /// Components - The components of the vtable being built. |
830 | | SmallVector<VTableComponent, 64> Components; |
831 | | |
832 | | /// AddressPoints - Address points for the vtable being built. |
833 | | AddressPointsMapTy AddressPoints; |
834 | | |
835 | | /// MethodInfo - Contains information about a method in a vtable. |
836 | | /// (Used for computing 'this' pointer adjustment thunks. |
837 | | struct MethodInfo { |
838 | | /// BaseOffset - The base offset of this method. |
839 | | const CharUnits BaseOffset; |
840 | | |
841 | | /// BaseOffsetInLayoutClass - The base offset in the layout class of this |
842 | | /// method. |
843 | | const CharUnits BaseOffsetInLayoutClass; |
844 | | |
845 | | /// VTableIndex - The index in the vtable that this method has. |
846 | | /// (For destructors, this is the index of the complete destructor). |
847 | | const uint64_t VTableIndex; |
848 | | |
849 | | MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass, |
850 | | uint64_t VTableIndex) |
851 | | : BaseOffset(BaseOffset), |
852 | | BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), |
853 | 12.5k | VTableIndex(VTableIndex) { } |
854 | | |
855 | | MethodInfo() |
856 | | : BaseOffset(CharUnits::Zero()), |
857 | | BaseOffsetInLayoutClass(CharUnits::Zero()), |
858 | 0 | VTableIndex(0) { } |
859 | | |
860 | | MethodInfo(MethodInfo const&) = default; |
861 | | }; |
862 | | |
863 | | typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; |
864 | | |
865 | | /// MethodInfoMap - The information for all methods in the vtable we're |
866 | | /// currently building. |
867 | | MethodInfoMapTy MethodInfoMap; |
868 | | |
869 | | /// MethodVTableIndices - Contains the index (relative to the vtable address |
870 | | /// point) where the function pointer for a virtual function is stored. |
871 | | MethodVTableIndicesTy MethodVTableIndices; |
872 | | |
873 | | typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; |
874 | | |
875 | | /// VTableThunks - The thunks by vtable index in the vtable currently being |
876 | | /// built. |
877 | | VTableThunksMapTy VTableThunks; |
878 | | |
879 | | typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; |
880 | | typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; |
881 | | |
882 | | /// Thunks - A map that contains all the thunks needed for all methods in the |
883 | | /// most derived class for which the vtable is currently being built. |
884 | | ThunksMapTy Thunks; |
885 | | |
886 | | /// AddThunk - Add a thunk for the given method. |
887 | | void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); |
888 | | |
889 | | /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the |
890 | | /// part of the vtable we're currently building. |
891 | | void ComputeThisAdjustments(); |
892 | | |
893 | | typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; |
894 | | |
895 | | /// PrimaryVirtualBases - All known virtual bases who are a primary base of |
896 | | /// some other base. |
897 | | VisitedVirtualBasesSetTy PrimaryVirtualBases; |
898 | | |
899 | | /// ComputeReturnAdjustment - Compute the return adjustment given a return |
900 | | /// adjustment base offset. |
901 | | ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); |
902 | | |
903 | | /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting |
904 | | /// the 'this' pointer from the base subobject to the derived subobject. |
905 | | BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, |
906 | | BaseSubobject Derived) const; |
907 | | |
908 | | /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the |
909 | | /// given virtual member function, its offset in the layout class and its |
910 | | /// final overrider. |
911 | | ThisAdjustment |
912 | | ComputeThisAdjustment(const CXXMethodDecl *MD, |
913 | | CharUnits BaseOffsetInLayoutClass, |
914 | | FinalOverriders::OverriderInfo Overrider); |
915 | | |
916 | | /// AddMethod - Add a single virtual member function to the vtable |
917 | | /// components vector. |
918 | | void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); |
919 | | |
920 | | /// IsOverriderUsed - Returns whether the overrider will ever be used in this |
921 | | /// part of the vtable. |
922 | | /// |
923 | | /// Itanium C++ ABI 2.5.2: |
924 | | /// |
925 | | /// struct A { virtual void f(); }; |
926 | | /// struct B : virtual public A { int i; }; |
927 | | /// struct C : virtual public A { int j; }; |
928 | | /// struct D : public B, public C {}; |
929 | | /// |
930 | | /// When B and C are declared, A is a primary base in each case, so although |
931 | | /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this |
932 | | /// adjustment is required and no thunk is generated. However, inside D |
933 | | /// objects, A is no longer a primary base of C, so if we allowed calls to |
934 | | /// C::f() to use the copy of A's vtable in the C subobject, we would need |
935 | | /// to adjust this from C* to B::A*, which would require a third-party |
936 | | /// thunk. Since we require that a call to C::f() first convert to A*, |
937 | | /// C-in-D's copy of A's vtable is never referenced, so this is not |
938 | | /// necessary. |
939 | | bool IsOverriderUsed(const CXXMethodDecl *Overrider, |
940 | | CharUnits BaseOffsetInLayoutClass, |
941 | | const CXXRecordDecl *FirstBaseInPrimaryBaseChain, |
942 | | CharUnits FirstBaseOffsetInLayoutClass) const; |
943 | | |
944 | | |
945 | | /// AddMethods - Add the methods of this base subobject and all its |
946 | | /// primary bases to the vtable components vector. |
947 | | void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, |
948 | | const CXXRecordDecl *FirstBaseInPrimaryBaseChain, |
949 | | CharUnits FirstBaseOffsetInLayoutClass, |
950 | | PrimaryBasesSetVectorTy &PrimaryBases); |
951 | | |
952 | | // LayoutVTable - Layout the vtable for the given base class, including its |
953 | | // secondary vtables and any vtables for virtual bases. |
954 | | void LayoutVTable(); |
955 | | |
956 | | /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the |
957 | | /// given base subobject, as well as all its secondary vtables. |
958 | | /// |
959 | | /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base |
960 | | /// or a direct or indirect base of a virtual base. |
961 | | /// |
962 | | /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual |
963 | | /// in the layout class. |
964 | | void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, |
965 | | bool BaseIsMorallyVirtual, |
966 | | bool BaseIsVirtualInLayoutClass, |
967 | | CharUnits OffsetInLayoutClass); |
968 | | |
969 | | /// LayoutSecondaryVTables - Layout the secondary vtables for the given base |
970 | | /// subobject. |
971 | | /// |
972 | | /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base |
973 | | /// or a direct or indirect base of a virtual base. |
974 | | void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, |
975 | | CharUnits OffsetInLayoutClass); |
976 | | |
977 | | /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this |
978 | | /// class hierarchy. |
979 | | void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, |
980 | | CharUnits OffsetInLayoutClass, |
981 | | VisitedVirtualBasesSetTy &VBases); |
982 | | |
983 | | /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the |
984 | | /// given base (excluding any primary bases). |
985 | | void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, |
986 | | VisitedVirtualBasesSetTy &VBases); |
987 | | |
988 | | /// isBuildingConstructionVTable - Return whether this vtable builder is |
989 | | /// building a construction vtable. |
990 | 11.7k | bool isBuildingConstructorVTable() const { |
991 | 11.7k | return MostDerivedClass != LayoutClass; |
992 | 11.7k | } |
993 | | |
994 | | public: |
995 | | /// Component indices of the first component of each of the vtables in the |
996 | | /// vtable group. |
997 | | SmallVector<size_t, 4> VTableIndices; |
998 | | |
999 | | ItaniumVTableBuilder(ItaniumVTableContext &VTables, |
1000 | | const CXXRecordDecl *MostDerivedClass, |
1001 | | CharUnits MostDerivedClassOffset, |
1002 | | bool MostDerivedClassIsVirtual, |
1003 | | const CXXRecordDecl *LayoutClass) |
1004 | | : VTables(VTables), MostDerivedClass(MostDerivedClass), |
1005 | | MostDerivedClassOffset(MostDerivedClassOffset), |
1006 | | MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), |
1007 | | LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), |
1008 | 3.82k | Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { |
1009 | 3.82k | assert(!Context.getTargetInfo().getCXXABI().isMicrosoft()); |
1010 | | |
1011 | 3.82k | LayoutVTable(); |
1012 | | |
1013 | 3.82k | if (Context.getLangOpts().DumpVTableLayouts) |
1014 | 230 | dumpLayout(llvm::outs()); |
1015 | 3.82k | } |
1016 | | |
1017 | 0 | uint64_t getNumThunks() const { |
1018 | 0 | return Thunks.size(); |
1019 | 0 | } |
1020 | | |
1021 | 3.50k | ThunksMapTy::const_iterator thunks_begin() const { |
1022 | 3.50k | return Thunks.begin(); |
1023 | 3.50k | } |
1024 | | |
1025 | 3.50k | ThunksMapTy::const_iterator thunks_end() const { |
1026 | 3.50k | return Thunks.end(); |
1027 | 3.50k | } |
1028 | | |
1029 | 248 | const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { |
1030 | 248 | return VBaseOffsetOffsets; |
1031 | 248 | } |
1032 | | |
1033 | 3.82k | const AddressPointsMapTy &getAddressPoints() const { |
1034 | 3.82k | return AddressPoints; |
1035 | 3.82k | } |
1036 | | |
1037 | 3.50k | MethodVTableIndicesTy::const_iterator vtable_indices_begin() const { |
1038 | 3.50k | return MethodVTableIndices.begin(); |
1039 | 3.50k | } |
1040 | | |
1041 | 3.50k | MethodVTableIndicesTy::const_iterator vtable_indices_end() const { |
1042 | 3.50k | return MethodVTableIndices.end(); |
1043 | 3.50k | } |
1044 | | |
1045 | 3.82k | ArrayRef<VTableComponent> vtable_components() const { return Components; } |
1046 | | |
1047 | 0 | AddressPointsMapTy::const_iterator address_points_begin() const { |
1048 | 0 | return AddressPoints.begin(); |
1049 | 0 | } |
1050 | | |
1051 | 0 | AddressPointsMapTy::const_iterator address_points_end() const { |
1052 | 0 | return AddressPoints.end(); |
1053 | 0 | } |
1054 | | |
1055 | 3.82k | VTableThunksMapTy::const_iterator vtable_thunks_begin() const { |
1056 | 3.82k | return VTableThunks.begin(); |
1057 | 3.82k | } |
1058 | | |
1059 | 3.82k | VTableThunksMapTy::const_iterator vtable_thunks_end() const { |
1060 | 3.82k | return VTableThunks.end(); |
1061 | 3.82k | } |
1062 | | |
1063 | | /// dumpLayout - Dump the vtable layout. |
1064 | | void dumpLayout(raw_ostream&); |
1065 | | }; |
1066 | | |
1067 | | void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD, |
1068 | 440 | const ThunkInfo &Thunk) { |
1069 | 440 | assert(!isBuildingConstructorVTable() && |
1070 | 440 | "Can't add thunks for construction vtable"); |
1071 | | |
1072 | 440 | SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD]; |
1073 | | |
1074 | | // Check if we have this thunk already. |
1075 | 440 | if (llvm::is_contained(ThunksVector, Thunk)) |
1076 | 65 | return; |
1077 | | |
1078 | 375 | ThunksVector.push_back(Thunk); |
1079 | 375 | } |
1080 | | |
1081 | | typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; |
1082 | | |
1083 | | /// Visit all the methods overridden by the given method recursively, |
1084 | | /// in a depth-first pre-order. The Visitor's visitor method returns a bool |
1085 | | /// indicating whether to continue the recursion for the given overridden |
1086 | | /// method (i.e. returning false stops the iteration). |
1087 | | template <class VisitorTy> |
1088 | | static void |
1089 | 26.5k | visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { |
1090 | 26.5k | assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!"); |
1091 | | |
1092 | 26.5k | for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { |
1093 | 8.62k | if (!Visitor(OverriddenMD)) |
1094 | 147 | continue; |
1095 | 8.47k | visitAllOverriddenMethods(OverriddenMD, Visitor); |
1096 | 8.47k | } |
1097 | 26.5k | } VTableBuilder.cpp:void (anonymous namespace)::visitAllOverriddenMethods<(anonymous namespace)::ComputeAllOverriddenMethods(clang::CXXMethodDecl const*, llvm::SmallPtrSet<clang::CXXMethodDecl const*, 8u>&)::$_0>(clang::CXXMethodDecl const*, (anonymous namespace)::ComputeAllOverriddenMethods(clang::CXXMethodDecl const*, llvm::SmallPtrSet<clang::CXXMethodDecl const*, 8u>&)::$_0&) Line | Count | Source | 1089 | 21.1k | visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { | 1090 | 21.1k | assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!"); | 1091 | | | 1092 | 21.1k | for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { | 1093 | 5.94k | if (!Visitor(OverriddenMD)) | 1094 | 73 | continue; | 1095 | 5.87k | visitAllOverriddenMethods(OverriddenMD, Visitor); | 1096 | 5.87k | } | 1097 | 21.1k | } |
VTableBuilder.cpp:void (anonymous namespace)::visitAllOverriddenMethods<(anonymous namespace)::VFTableBuilder::ComputeThisOffset((anonymous namespace)::FinalOverriders::OverriderInfo)::$_0>(clang::CXXMethodDecl const*, (anonymous namespace)::VFTableBuilder::ComputeThisOffset((anonymous namespace)::FinalOverriders::OverriderInfo)::$_0&) Line | Count | Source | 1089 | 5.38k | visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { | 1090 | 5.38k | assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!"); | 1091 | | | 1092 | 5.38k | for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { | 1093 | 2.68k | if (!Visitor(OverriddenMD)) | 1094 | 74 | continue; | 1095 | 2.60k | visitAllOverriddenMethods(OverriddenMD, Visitor); | 1096 | 2.60k | } | 1097 | 5.38k | } |
|
1098 | | |
1099 | | /// ComputeAllOverriddenMethods - Given a method decl, will return a set of all |
1100 | | /// the overridden methods that the function decl overrides. |
1101 | | static void |
1102 | | ComputeAllOverriddenMethods(const CXXMethodDecl *MD, |
1103 | 15.3k | OverriddenMethodsSetTy& OverriddenMethods) { |
1104 | 15.3k | auto OverriddenMethodsCollector = [&](const CXXMethodDecl *MD) { |
1105 | | // Don't recurse on this method if we've already collected it. |
1106 | 5.94k | return OverriddenMethods.insert(MD).second; |
1107 | 5.94k | }; |
1108 | 15.3k | visitAllOverriddenMethods(MD, OverriddenMethodsCollector); |
1109 | 15.3k | } |
1110 | | |
1111 | 4.47k | void ItaniumVTableBuilder::ComputeThisAdjustments() { |
1112 | | // Now go through the method info map and see if any of the methods need |
1113 | | // 'this' pointer adjustments. |
1114 | 9.08k | for (const auto &MI : MethodInfoMap) { |
1115 | 9.08k | const CXXMethodDecl *MD = MI.first; |
1116 | 9.08k | const MethodInfo &MethodInfo = MI.second; |
1117 | | |
1118 | | // Ignore adjustments for unused function pointers. |
1119 | 9.08k | uint64_t VTableIndex = MethodInfo.VTableIndex; |
1120 | 9.08k | if (Components[VTableIndex].getKind() == |
1121 | 9.08k | VTableComponent::CK_UnusedFunctionPointer) |
1122 | 59 | continue; |
1123 | | |
1124 | | // Get the final overrider for this method. |
1125 | 9.02k | FinalOverriders::OverriderInfo Overrider = |
1126 | 9.02k | Overriders.getOverrider(MD, MethodInfo.BaseOffset); |
1127 | | |
1128 | | // Check if we need an adjustment at all. |
1129 | 9.02k | if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { |
1130 | | // When a return thunk is needed by a derived class that overrides a |
1131 | | // virtual base, gcc uses a virtual 'this' adjustment as well. |
1132 | | // While the thunk itself might be needed by vtables in subclasses or |
1133 | | // in construction vtables, there doesn't seem to be a reason for using |
1134 | | // the thunk in this vtable. Still, we do so to match gcc. |
1135 | 8.65k | if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) |
1136 | 8.63k | continue; |
1137 | 8.65k | } |
1138 | | |
1139 | 389 | ThisAdjustment ThisAdjustment = |
1140 | 389 | ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); |
1141 | | |
1142 | 389 | if (ThisAdjustment.isEmpty()) |
1143 | 14 | continue; |
1144 | | |
1145 | | // Add it. |
1146 | 375 | VTableThunks[VTableIndex].This = ThisAdjustment; |
1147 | | |
1148 | 375 | if (isa<CXXDestructorDecl>(MD)) { |
1149 | | // Add an adjustment for the deleting destructor as well. |
1150 | 109 | VTableThunks[VTableIndex + 1].This = ThisAdjustment; |
1151 | 109 | } |
1152 | 375 | } |
1153 | | |
1154 | | /// Clear the method info map. |
1155 | 4.47k | MethodInfoMap.clear(); |
1156 | | |
1157 | 4.47k | if (isBuildingConstructorVTable()) { |
1158 | | // We don't need to store thunk information for construction vtables. |
1159 | 624 | return; |
1160 | 624 | } |
1161 | | |
1162 | 3.84k | for (const auto &TI : VTableThunks) { |
1163 | 426 | const VTableComponent &Component = Components[TI.first]; |
1164 | 426 | const ThunkInfo &Thunk = TI.second; |
1165 | 426 | const CXXMethodDecl *MD; |
1166 | | |
1167 | 426 | switch (Component.getKind()) { |
1168 | 0 | default: |
1169 | 0 | llvm_unreachable("Unexpected vtable component kind!"); |
1170 | 234 | case VTableComponent::CK_FunctionPointer: |
1171 | 234 | MD = Component.getFunctionDecl(); |
1172 | 234 | break; |
1173 | 96 | case VTableComponent::CK_CompleteDtorPointer: |
1174 | 96 | MD = Component.getDestructorDecl(); |
1175 | 96 | break; |
1176 | 96 | case VTableComponent::CK_DeletingDtorPointer: |
1177 | | // We've already added the thunk when we saw the complete dtor pointer. |
1178 | 96 | continue; |
1179 | 426 | } |
1180 | | |
1181 | 330 | if (MD->getParent() == MostDerivedClass) |
1182 | 310 | AddThunk(MD, Thunk); |
1183 | 330 | } |
1184 | 3.84k | } |
1185 | | |
1186 | | ReturnAdjustment |
1187 | 9.15k | ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { |
1188 | 9.15k | ReturnAdjustment Adjustment; |
1189 | | |
1190 | 9.15k | if (!Offset.isEmpty()) { |
1191 | 31 | if (Offset.VirtualBase) { |
1192 | | // Get the virtual base offset offset. |
1193 | 26 | if (Offset.DerivedClass == MostDerivedClass) { |
1194 | | // We can get the offset offset directly from our map. |
1195 | 18 | Adjustment.Virtual.Itanium.VBaseOffsetOffset = |
1196 | 18 | VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); |
1197 | 18 | } else { |
1198 | 8 | Adjustment.Virtual.Itanium.VBaseOffsetOffset = |
1199 | 8 | VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, |
1200 | 8 | Offset.VirtualBase).getQuantity(); |
1201 | 8 | } |
1202 | 26 | } |
1203 | | |
1204 | 31 | Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); |
1205 | 31 | } |
1206 | | |
1207 | 9.15k | return Adjustment; |
1208 | 9.15k | } |
1209 | | |
1210 | | BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset( |
1211 | 3.77k | BaseSubobject Base, BaseSubobject Derived) const { |
1212 | 3.77k | const CXXRecordDecl *BaseRD = Base.getBase(); |
1213 | 3.77k | const CXXRecordDecl *DerivedRD = Derived.getBase(); |
1214 | | |
1215 | 3.77k | CXXBasePaths Paths(/*FindAmbiguities=*/true, |
1216 | 3.77k | /*RecordPaths=*/true, /*DetectVirtual=*/true); |
1217 | | |
1218 | 3.77k | if (!DerivedRD->isDerivedFrom(BaseRD, Paths)) |
1219 | 0 | llvm_unreachable("Class must be derived from the passed in base class!"); |
1220 | | |
1221 | | // We have to go through all the paths, and see which one leads us to the |
1222 | | // right base subobject. |
1223 | 3.81k | for (const CXXBasePath &Path : Paths) { |
1224 | 3.81k | BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path); |
1225 | | |
1226 | 3.81k | CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset; |
1227 | | |
1228 | 3.81k | if (Offset.VirtualBase) { |
1229 | | // If we have a virtual base class, the non-virtual offset is relative |
1230 | | // to the virtual base class offset. |
1231 | 325 | const ASTRecordLayout &LayoutClassLayout = |
1232 | 325 | Context.getASTRecordLayout(LayoutClass); |
1233 | | |
1234 | | /// Get the virtual base offset, relative to the most derived class |
1235 | | /// layout. |
1236 | 325 | OffsetToBaseSubobject += |
1237 | 325 | LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); |
1238 | 3.48k | } else { |
1239 | | // Otherwise, the non-virtual offset is relative to the derived class |
1240 | | // offset. |
1241 | 3.48k | OffsetToBaseSubobject += Derived.getBaseOffset(); |
1242 | 3.48k | } |
1243 | | |
1244 | | // Check if this path gives us the right base subobject. |
1245 | 3.81k | if (OffsetToBaseSubobject == Base.getBaseOffset()) { |
1246 | | // Since we're going from the base class _to_ the derived class, we'll |
1247 | | // invert the non-virtual offset here. |
1248 | 3.76k | Offset.NonVirtualOffset = -Offset.NonVirtualOffset; |
1249 | 3.76k | return Offset; |
1250 | 3.76k | } |
1251 | 3.81k | } |
1252 | | |
1253 | 7 | return BaseOffset(); |
1254 | 3.77k | } |
1255 | | |
1256 | | ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment( |
1257 | | const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass, |
1258 | 3.77k | FinalOverriders::OverriderInfo Overrider) { |
1259 | | // Ignore adjustments for pure virtual member functions. |
1260 | 3.77k | if (Overrider.Method->isPure()) |
1261 | 2 | return ThisAdjustment(); |
1262 | | |
1263 | 3.77k | BaseSubobject OverriddenBaseSubobject(MD->getParent(), |
1264 | 3.77k | BaseOffsetInLayoutClass); |
1265 | | |
1266 | 3.77k | BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), |
1267 | 3.77k | Overrider.Offset); |
1268 | | |
1269 | | // Compute the adjustment offset. |
1270 | 3.77k | BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, |
1271 | 3.77k | OverriderBaseSubobject); |
1272 | 3.77k | if (Offset.isEmpty()) |
1273 | 3.25k | return ThisAdjustment(); |
1274 | | |
1275 | 517 | ThisAdjustment Adjustment; |
1276 | | |
1277 | 517 | if (Offset.VirtualBase) { |
1278 | | // Get the vcall offset map for this virtual base. |
1279 | 303 | VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; |
1280 | | |
1281 | 303 | if (VCallOffsets.empty()) { |
1282 | | // We don't have vcall offsets for this virtual base, go ahead and |
1283 | | // build them. |
1284 | 100 | VCallAndVBaseOffsetBuilder Builder( |
1285 | 100 | VTables, MostDerivedClass, MostDerivedClass, |
1286 | 100 | /*Overriders=*/nullptr, |
1287 | 100 | BaseSubobject(Offset.VirtualBase, CharUnits::Zero()), |
1288 | 100 | /*BaseIsVirtual=*/true, |
1289 | | /*OffsetInLayoutClass=*/ |
1290 | 100 | CharUnits::Zero()); |
1291 | | |
1292 | 100 | VCallOffsets = Builder.getVCallOffsets(); |
1293 | 100 | } |
1294 | | |
1295 | 303 | Adjustment.Virtual.Itanium.VCallOffsetOffset = |
1296 | 303 | VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); |
1297 | 303 | } |
1298 | | |
1299 | | // Set the non-virtual part of the adjustment. |
1300 | 517 | Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); |
1301 | | |
1302 | 517 | return Adjustment; |
1303 | 3.77k | } |
1304 | | |
1305 | | void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD, |
1306 | 9.02k | ReturnAdjustment ReturnAdjustment) { |
1307 | 9.02k | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { |
1308 | 2.18k | assert(ReturnAdjustment.isEmpty() && |
1309 | 2.18k | "Destructor can't have return adjustment!"); |
1310 | | |
1311 | | // Add both the complete destructor and the deleting destructor. |
1312 | 2.18k | Components.push_back(VTableComponent::MakeCompleteDtor(DD)); |
1313 | 2.18k | Components.push_back(VTableComponent::MakeDeletingDtor(DD)); |
1314 | 6.84k | } else { |
1315 | | // Add the return adjustment if necessary. |
1316 | 6.84k | if (!ReturnAdjustment.isEmpty()) |
1317 | 26 | VTableThunks[Components.size()].Return = ReturnAdjustment; |
1318 | | |
1319 | | // Add the function. |
1320 | 6.84k | Components.push_back(VTableComponent::MakeFunction(MD)); |
1321 | 6.84k | } |
1322 | 9.02k | } |
1323 | | |
1324 | | /// OverridesIndirectMethodInBase - Return whether the given member function |
1325 | | /// overrides any methods in the set of given bases. |
1326 | | /// Unlike OverridesMethodInBase, this checks "overriders of overriders". |
1327 | | /// For example, if we have: |
1328 | | /// |
1329 | | /// struct A { virtual void f(); } |
1330 | | /// struct B : A { virtual void f(); } |
1331 | | /// struct C : B { virtual void f(); } |
1332 | | /// |
1333 | | /// OverridesIndirectMethodInBase will return true if given C::f as the method |
1334 | | /// and { A } as the set of bases. |
1335 | | static bool OverridesIndirectMethodInBases( |
1336 | | const CXXMethodDecl *MD, |
1337 | 112 | ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) { |
1338 | 112 | if (Bases.count(MD->getParent())) |
1339 | 9 | return true; |
1340 | | |
1341 | 103 | for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { |
1342 | | // Check "indirect overriders". |
1343 | 44 | if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) |
1344 | 10 | return true; |
1345 | 44 | } |
1346 | | |
1347 | 93 | return false; |
1348 | 103 | } |
1349 | | |
1350 | | bool ItaniumVTableBuilder::IsOverriderUsed( |
1351 | | const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass, |
1352 | | const CXXRecordDecl *FirstBaseInPrimaryBaseChain, |
1353 | 9.08k | CharUnits FirstBaseOffsetInLayoutClass) const { |
1354 | | // If the base and the first base in the primary base chain have the same |
1355 | | // offsets, then this overrider will be used. |
1356 | 9.08k | if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) |
1357 | 9.00k | return true; |
1358 | | |
1359 | | // We know now that Base (or a direct or indirect base of it) is a primary |
1360 | | // base in part of the class hierarchy, but not a primary base in the most |
1361 | | // derived class. |
1362 | | |
1363 | | // If the overrider is the first base in the primary base chain, we know |
1364 | | // that the overrider will be used. |
1365 | 79 | if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) |
1366 | 11 | return true; |
1367 | | |
1368 | 68 | ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; |
1369 | | |
1370 | 68 | const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; |
1371 | 68 | PrimaryBases.insert(RD); |
1372 | | |
1373 | | // Now traverse the base chain, starting with the first base, until we find |
1374 | | // the base that is no longer a primary base. |
1375 | 76 | while (true) { |
1376 | 76 | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
1377 | 76 | const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); |
1378 | | |
1379 | 76 | if (!PrimaryBase) |
1380 | 0 | break; |
1381 | | |
1382 | 76 | if (Layout.isPrimaryBaseVirtual()) { |
1383 | 68 | assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && |
1384 | 68 | "Primary base should always be at offset 0!"); |
1385 | | |
1386 | 68 | const ASTRecordLayout &LayoutClassLayout = |
1387 | 68 | Context.getASTRecordLayout(LayoutClass); |
1388 | | |
1389 | | // Now check if this is the primary base that is not a primary base in the |
1390 | | // most derived class. |
1391 | 68 | if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != |
1392 | 68 | FirstBaseOffsetInLayoutClass) { |
1393 | | // We found it, stop walking the chain. |
1394 | 68 | break; |
1395 | 68 | } |
1396 | 68 | } else { |
1397 | 8 | assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && |
1398 | 8 | "Primary base should always be at offset 0!"); |
1399 | 8 | } |
1400 | | |
1401 | 8 | if (!PrimaryBases.insert(PrimaryBase)) |
1402 | 0 | llvm_unreachable("Found a duplicate primary base!"); |
1403 | | |
1404 | 8 | RD = PrimaryBase; |
1405 | 8 | } |
1406 | | |
1407 | | // If the final overrider is an override of one of the primary bases, |
1408 | | // then we know that it will be used. |
1409 | 68 | return OverridesIndirectMethodInBases(Overrider, PrimaryBases); |
1410 | 68 | } |
1411 | | |
1412 | | typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy; |
1413 | | |
1414 | | /// FindNearestOverriddenMethod - Given a method, returns the overridden method |
1415 | | /// from the nearest base. Returns null if no method was found. |
1416 | | /// The Bases are expected to be sorted in a base-to-derived order. |
1417 | | static const CXXMethodDecl * |
1418 | | FindNearestOverriddenMethod(const CXXMethodDecl *MD, |
1419 | 15.3k | BasesSetVectorTy &Bases) { |
1420 | 15.3k | OverriddenMethodsSetTy OverriddenMethods; |
1421 | 15.3k | ComputeAllOverriddenMethods(MD, OverriddenMethods); |
1422 | | |
1423 | 15.3k | for (const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) { |
1424 | | // Now check the overridden methods. |
1425 | 7.72k | for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) { |
1426 | | // We found our overridden method. |
1427 | 4.92k | if (OverriddenMD->getParent() == PrimaryBase) |
1428 | 4.23k | return OverriddenMD; |
1429 | 4.92k | } |
1430 | 7.72k | } |
1431 | | |
1432 | 11.0k | return nullptr; |
1433 | 15.3k | } |
1434 | | |
1435 | | void ItaniumVTableBuilder::AddMethods( |
1436 | | BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, |
1437 | | const CXXRecordDecl *FirstBaseInPrimaryBaseChain, |
1438 | | CharUnits FirstBaseOffsetInLayoutClass, |
1439 | 7.11k | PrimaryBasesSetVectorTy &PrimaryBases) { |
1440 | | // Itanium C++ ABI 2.5.2: |
1441 | | // The order of the virtual function pointers in a virtual table is the |
1442 | | // order of declaration of the corresponding member functions in the class. |
1443 | | // |
1444 | | // There is an entry for any virtual function declared in a class, |
1445 | | // whether it is a new function or overrides a base class function, |
1446 | | // unless it overrides a function from the primary base, and conversion |
1447 | | // between their return types does not require an adjustment. |
1448 | | |
1449 | 7.11k | const CXXRecordDecl *RD = Base.getBase(); |
1450 | 7.11k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
1451 | | |
1452 | 7.11k | if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { |
1453 | 2.64k | CharUnits PrimaryBaseOffset; |
1454 | 2.64k | CharUnits PrimaryBaseOffsetInLayoutClass; |
1455 | 2.64k | if (Layout.isPrimaryBaseVirtual()) { |
1456 | 346 | assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && |
1457 | 346 | "Primary vbase should have a zero offset!"); |
1458 | | |
1459 | 346 | const ASTRecordLayout &MostDerivedClassLayout = |
1460 | 346 | Context.getASTRecordLayout(MostDerivedClass); |
1461 | | |
1462 | 346 | PrimaryBaseOffset = |
1463 | 346 | MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); |
1464 | | |
1465 | 346 | const ASTRecordLayout &LayoutClassLayout = |
1466 | 346 | Context.getASTRecordLayout(LayoutClass); |
1467 | | |
1468 | 346 | PrimaryBaseOffsetInLayoutClass = |
1469 | 346 | LayoutClassLayout.getVBaseClassOffset(PrimaryBase); |
1470 | 2.29k | } else { |
1471 | 2.29k | assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && |
1472 | 2.29k | "Primary base should have a zero offset!"); |
1473 | | |
1474 | 2.29k | PrimaryBaseOffset = Base.getBaseOffset(); |
1475 | 2.29k | PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; |
1476 | 2.29k | } |
1477 | | |
1478 | 2.64k | AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), |
1479 | 2.64k | PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, |
1480 | 2.64k | FirstBaseOffsetInLayoutClass, PrimaryBases); |
1481 | | |
1482 | 2.64k | if (!PrimaryBases.insert(PrimaryBase)) |
1483 | 0 | llvm_unreachable("Found a duplicate primary base!"); |
1484 | 2.64k | } |
1485 | | |
1486 | 7.11k | typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy; |
1487 | 7.11k | NewVirtualFunctionsTy NewVirtualFunctions; |
1488 | | |
1489 | 7.11k | llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions; |
1490 | | |
1491 | | // Now go through all virtual member functions and add them. |
1492 | 50.3k | for (const auto *MD : RD->methods()) { |
1493 | 50.3k | if (!ItaniumVTableContext::hasVtableSlot(MD)) |
1494 | 37.7k | continue; |
1495 | 12.5k | MD = MD->getCanonicalDecl(); |
1496 | | |
1497 | | // Get the final overrider. |
1498 | 12.5k | FinalOverriders::OverriderInfo Overrider = |
1499 | 12.5k | Overriders.getOverrider(MD, Base.getBaseOffset()); |
1500 | | |
1501 | | // Check if this virtual member function overrides a method in a primary |
1502 | | // base. If this is the case, and the return type doesn't require adjustment |
1503 | | // then we can just use the member function from the primary base. |
1504 | 12.5k | if (const CXXMethodDecl *OverriddenMD = |
1505 | 12.5k | FindNearestOverriddenMethod(MD, PrimaryBases)) { |
1506 | 3.46k | if (ComputeReturnAdjustmentBaseOffset(Context, MD, |
1507 | 3.46k | OverriddenMD).isEmpty()) { |
1508 | | // Replace the method info of the overridden method with our own |
1509 | | // method. |
1510 | 3.44k | assert(MethodInfoMap.count(OverriddenMD) && |
1511 | 3.44k | "Did not find the overridden method!"); |
1512 | 3.44k | MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; |
1513 | | |
1514 | 3.44k | MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, |
1515 | 3.44k | OverriddenMethodInfo.VTableIndex); |
1516 | | |
1517 | 3.44k | assert(!MethodInfoMap.count(MD) && |
1518 | 3.44k | "Should not have method info for this method yet!"); |
1519 | | |
1520 | 3.44k | MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); |
1521 | 3.44k | MethodInfoMap.erase(OverriddenMD); |
1522 | | |
1523 | | // If the overridden method exists in a virtual base class or a direct |
1524 | | // or indirect base class of a virtual base class, we need to emit a |
1525 | | // thunk if we ever have a class hierarchy where the base class is not |
1526 | | // a primary base in the complete object. |
1527 | 3.44k | if (!isBuildingConstructorVTable() && OverriddenMD != MD3.38k ) { |
1528 | | // Compute the this adjustment. |
1529 | 3.38k | ThisAdjustment ThisAdjustment = |
1530 | 3.38k | ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, |
1531 | 3.38k | Overrider); |
1532 | | |
1533 | 3.38k | if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset && |
1534 | 3.38k | Overrider.Method->getParent() == MostDerivedClass130 ) { |
1535 | | |
1536 | | // There's no return adjustment from OverriddenMD and MD, |
1537 | | // but that doesn't mean there isn't one between MD and |
1538 | | // the final overrider. |
1539 | 130 | BaseOffset ReturnAdjustmentOffset = |
1540 | 130 | ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); |
1541 | 130 | ReturnAdjustment ReturnAdjustment = |
1542 | 130 | ComputeReturnAdjustment(ReturnAdjustmentOffset); |
1543 | | |
1544 | | // This is a virtual thunk for the most derived class, add it. |
1545 | 130 | AddThunk(Overrider.Method, |
1546 | 130 | ThunkInfo(ThisAdjustment, ReturnAdjustment)); |
1547 | 130 | } |
1548 | 3.38k | } |
1549 | | |
1550 | 3.44k | continue; |
1551 | 3.44k | } |
1552 | 3.46k | } |
1553 | | |
1554 | 9.08k | if (MD->isImplicit()) |
1555 | 30 | NewImplicitVirtualFunctions.push_back(MD); |
1556 | 9.05k | else |
1557 | 9.05k | NewVirtualFunctions.push_back(MD); |
1558 | 9.08k | } |
1559 | | |
1560 | 7.11k | std::stable_sort( |
1561 | 7.11k | NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(), |
1562 | 7.11k | [](const CXXMethodDecl *A, const CXXMethodDecl *B) { |
1563 | 5 | if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator()) |
1564 | 2 | return A->isCopyAssignmentOperator(); |
1565 | 3 | if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator()) |
1566 | 1 | return A->isMoveAssignmentOperator(); |
1567 | 2 | if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B)) |
1568 | 1 | return isa<CXXDestructorDecl>(A); |
1569 | 1 | assert(A->getOverloadedOperator() == OO_EqualEqual && |
1570 | 1 | B->getOverloadedOperator() == OO_EqualEqual && |
1571 | 1 | "unexpected or duplicate implicit virtual function"); |
1572 | | // We rely on Sema to have declared the operator== members in the |
1573 | | // same order as the corresponding operator<=> members. |
1574 | 1 | return false; |
1575 | 1 | }); |
1576 | 7.11k | NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(), |
1577 | 7.11k | NewImplicitVirtualFunctions.end()); |
1578 | | |
1579 | 9.08k | for (const CXXMethodDecl *MD : NewVirtualFunctions) { |
1580 | | // Get the final overrider. |
1581 | 9.08k | FinalOverriders::OverriderInfo Overrider = |
1582 | 9.08k | Overriders.getOverrider(MD, Base.getBaseOffset()); |
1583 | | |
1584 | | // Insert the method info for this method. |
1585 | 9.08k | MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, |
1586 | 9.08k | Components.size()); |
1587 | | |
1588 | 9.08k | assert(!MethodInfoMap.count(MD) && |
1589 | 9.08k | "Should not have method info for this method yet!"); |
1590 | 9.08k | MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); |
1591 | | |
1592 | | // Check if this overrider is going to be used. |
1593 | 9.08k | const CXXMethodDecl *OverriderMD = Overrider.Method; |
1594 | 9.08k | if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, |
1595 | 9.08k | FirstBaseInPrimaryBaseChain, |
1596 | 9.08k | FirstBaseOffsetInLayoutClass)) { |
1597 | 59 | Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); |
1598 | 59 | continue; |
1599 | 59 | } |
1600 | | |
1601 | | // Check if this overrider needs a return adjustment. |
1602 | | // We don't want to do this for pure virtual member functions. |
1603 | 9.02k | BaseOffset ReturnAdjustmentOffset; |
1604 | 9.02k | if (!OverriderMD->isPure()) { |
1605 | 8.58k | ReturnAdjustmentOffset = |
1606 | 8.58k | ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); |
1607 | 8.58k | } |
1608 | | |
1609 | 9.02k | ReturnAdjustment ReturnAdjustment = |
1610 | 9.02k | ComputeReturnAdjustment(ReturnAdjustmentOffset); |
1611 | | |
1612 | 9.02k | AddMethod(Overrider.Method, ReturnAdjustment); |
1613 | 9.02k | } |
1614 | 7.11k | } |
1615 | | |
1616 | 3.82k | void ItaniumVTableBuilder::LayoutVTable() { |
1617 | 3.82k | LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, |
1618 | 3.82k | CharUnits::Zero()), |
1619 | 3.82k | /*BaseIsMorallyVirtual=*/false, |
1620 | 3.82k | MostDerivedClassIsVirtual, |
1621 | 3.82k | MostDerivedClassOffset); |
1622 | | |
1623 | 3.82k | VisitedVirtualBasesSetTy VBases; |
1624 | | |
1625 | | // Determine the primary virtual bases. |
1626 | 3.82k | DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, |
1627 | 3.82k | VBases); |
1628 | 3.82k | VBases.clear(); |
1629 | | |
1630 | 3.82k | LayoutVTablesForVirtualBases(MostDerivedClass, VBases); |
1631 | | |
1632 | | // -fapple-kext adds an extra entry at end of vtbl. |
1633 | 3.82k | bool IsAppleKext = Context.getLangOpts().AppleKext; |
1634 | 3.82k | if (IsAppleKext) |
1635 | 14 | Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero())); |
1636 | 3.82k | } |
1637 | | |
1638 | | void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables( |
1639 | | BaseSubobject Base, bool BaseIsMorallyVirtual, |
1640 | 4.47k | bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) { |
1641 | 4.47k | assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); |
1642 | | |
1643 | 4.47k | unsigned VTableIndex = Components.size(); |
1644 | 4.47k | VTableIndices.push_back(VTableIndex); |
1645 | | |
1646 | | // Add vcall and vbase offsets for this vtable. |
1647 | 4.47k | VCallAndVBaseOffsetBuilder Builder( |
1648 | 4.47k | VTables, MostDerivedClass, LayoutClass, &Overriders, Base, |
1649 | 4.47k | BaseIsVirtualInLayoutClass, OffsetInLayoutClass); |
1650 | 4.47k | Components.append(Builder.components_begin(), Builder.components_end()); |
1651 | | |
1652 | | // Check if we need to add these vcall offsets. |
1653 | 4.47k | if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()433 ) { |
1654 | 290 | VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; |
1655 | | |
1656 | 290 | if (VCallOffsets.empty()) |
1657 | 290 | VCallOffsets = Builder.getVCallOffsets(); |
1658 | 290 | } |
1659 | | |
1660 | | // If we're laying out the most derived class we want to keep track of the |
1661 | | // virtual base class offset offsets. |
1662 | 4.47k | if (Base.getBase() == MostDerivedClass) |
1663 | 3.82k | VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); |
1664 | | |
1665 | | // Add the offset to top. |
1666 | 4.47k | CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; |
1667 | 4.47k | Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); |
1668 | | |
1669 | | // Next, add the RTTI. |
1670 | 4.47k | Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); |
1671 | | |
1672 | 4.47k | uint64_t AddressPoint = Components.size(); |
1673 | | |
1674 | | // Now go through all virtual member functions and add them. |
1675 | 4.47k | PrimaryBasesSetVectorTy PrimaryBases; |
1676 | 4.47k | AddMethods(Base, OffsetInLayoutClass, |
1677 | 4.47k | Base.getBase(), OffsetInLayoutClass, |
1678 | 4.47k | PrimaryBases); |
1679 | | |
1680 | 4.47k | const CXXRecordDecl *RD = Base.getBase(); |
1681 | 4.47k | if (RD == MostDerivedClass) { |
1682 | 3.82k | assert(MethodVTableIndices.empty()); |
1683 | 8.47k | for (const auto &I : MethodInfoMap)3.82k { |
1684 | 8.47k | const CXXMethodDecl *MD = I.first; |
1685 | 8.47k | const MethodInfo &MI = I.second; |
1686 | 8.47k | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { |
1687 | 2.07k | MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] |
1688 | 2.07k | = MI.VTableIndex - AddressPoint; |
1689 | 2.07k | MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] |
1690 | 2.07k | = MI.VTableIndex + 1 - AddressPoint; |
1691 | 6.39k | } else { |
1692 | 6.39k | MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint; |
1693 | 6.39k | } |
1694 | 8.47k | } |
1695 | 3.82k | } |
1696 | | |
1697 | | // Compute 'this' pointer adjustments. |
1698 | 4.47k | ComputeThisAdjustments(); |
1699 | | |
1700 | | // Add all address points. |
1701 | 7.03k | while (true) { |
1702 | 7.03k | AddressPoints.insert( |
1703 | 7.03k | std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), |
1704 | 7.03k | VTableLayout::AddressPointLocation{ |
1705 | 7.03k | unsigned(VTableIndices.size() - 1), |
1706 | 7.03k | unsigned(AddressPoint - VTableIndex)})); |
1707 | | |
1708 | 7.03k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
1709 | 7.03k | const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); |
1710 | | |
1711 | 7.03k | if (!PrimaryBase) |
1712 | 4.39k | break; |
1713 | | |
1714 | 2.63k | if (Layout.isPrimaryBaseVirtual()) { |
1715 | | // Check if this virtual primary base is a primary base in the layout |
1716 | | // class. If it's not, we don't want to add it. |
1717 | 340 | const ASTRecordLayout &LayoutClassLayout = |
1718 | 340 | Context.getASTRecordLayout(LayoutClass); |
1719 | | |
1720 | 340 | if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != |
1721 | 340 | OffsetInLayoutClass) { |
1722 | | // We don't want to add this class (or any of its primary bases). |
1723 | 74 | break; |
1724 | 74 | } |
1725 | 340 | } |
1726 | | |
1727 | 2.56k | RD = PrimaryBase; |
1728 | 2.56k | } |
1729 | | |
1730 | | // Layout secondary vtables. |
1731 | 4.47k | LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); |
1732 | 4.47k | } |
1733 | | |
1734 | | void |
1735 | | ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, |
1736 | | bool BaseIsMorallyVirtual, |
1737 | 6.74k | CharUnits OffsetInLayoutClass) { |
1738 | | // Itanium C++ ABI 2.5.2: |
1739 | | // Following the primary virtual table of a derived class are secondary |
1740 | | // virtual tables for each of its proper base classes, except any primary |
1741 | | // base(s) with which it shares its primary virtual table. |
1742 | | |
1743 | 6.74k | const CXXRecordDecl *RD = Base.getBase(); |
1744 | 6.74k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
1745 | 6.74k | const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); |
1746 | | |
1747 | 6.74k | for (const auto &B : RD->bases()) { |
1748 | | // Ignore virtual bases, we'll emit them later. |
1749 | 4.17k | if (B.isVirtual()) |
1750 | 1.12k | continue; |
1751 | | |
1752 | 3.05k | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
1753 | | |
1754 | | // Ignore bases that don't have a vtable. |
1755 | 3.05k | if (!BaseDecl->isDynamicClass()) |
1756 | 464 | continue; |
1757 | | |
1758 | 2.58k | if (isBuildingConstructorVTable()) { |
1759 | | // Itanium C++ ABI 2.6.4: |
1760 | | // Some of the base class subobjects may not need construction virtual |
1761 | | // tables, which will therefore not be present in the construction |
1762 | | // virtual table group, even though the subobject virtual tables are |
1763 | | // present in the main virtual table group for the complete object. |
1764 | 201 | if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()100 ) |
1765 | 22 | continue; |
1766 | 201 | } |
1767 | | |
1768 | | // Get the base offset of this base. |
1769 | 2.56k | CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); |
1770 | 2.56k | CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; |
1771 | | |
1772 | 2.56k | CharUnits BaseOffsetInLayoutClass = |
1773 | 2.56k | OffsetInLayoutClass + RelativeBaseOffset; |
1774 | | |
1775 | | // Don't emit a secondary vtable for a primary base. We might however want |
1776 | | // to emit secondary vtables for other bases of this base. |
1777 | 2.56k | if (BaseDecl == PrimaryBase) { |
1778 | 2.27k | LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), |
1779 | 2.27k | BaseIsMorallyVirtual, BaseOffsetInLayoutClass); |
1780 | 2.27k | continue; |
1781 | 2.27k | } |
1782 | | |
1783 | | // Layout the primary vtable (and any secondary vtables) for this base. |
1784 | 289 | LayoutPrimaryAndSecondaryVTables( |
1785 | 289 | BaseSubobject(BaseDecl, BaseOffset), |
1786 | 289 | BaseIsMorallyVirtual, |
1787 | 289 | /*BaseIsVirtualInLayoutClass=*/false, |
1788 | 289 | BaseOffsetInLayoutClass); |
1789 | 289 | } |
1790 | 6.74k | } |
1791 | | |
1792 | | void ItaniumVTableBuilder::DeterminePrimaryVirtualBases( |
1793 | | const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass, |
1794 | 7.79k | VisitedVirtualBasesSetTy &VBases) { |
1795 | 7.79k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
1796 | | |
1797 | | // Check if this base has a primary base. |
1798 | 7.79k | if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { |
1799 | | |
1800 | | // Check if it's virtual. |
1801 | 2.63k | if (Layout.isPrimaryBaseVirtual()) { |
1802 | 340 | bool IsPrimaryVirtualBase = true; |
1803 | | |
1804 | 340 | if (isBuildingConstructorVTable()) { |
1805 | | // Check if the base is actually a primary base in the class we use for |
1806 | | // layout. |
1807 | 149 | const ASTRecordLayout &LayoutClassLayout = |
1808 | 149 | Context.getASTRecordLayout(LayoutClass); |
1809 | | |
1810 | 149 | CharUnits PrimaryBaseOffsetInLayoutClass = |
1811 | 149 | LayoutClassLayout.getVBaseClassOffset(PrimaryBase); |
1812 | | |
1813 | | // We know that the base is not a primary base in the layout class if |
1814 | | // the base offsets are different. |
1815 | 149 | if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) |
1816 | 45 | IsPrimaryVirtualBase = false; |
1817 | 149 | } |
1818 | | |
1819 | 340 | if (IsPrimaryVirtualBase) |
1820 | 295 | PrimaryVirtualBases.insert(PrimaryBase); |
1821 | 340 | } |
1822 | 2.63k | } |
1823 | | |
1824 | | // Traverse bases, looking for more primary virtual bases. |
1825 | 7.79k | for (const auto &B : RD->bases()) { |
1826 | 4.24k | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
1827 | | |
1828 | 4.24k | CharUnits BaseOffsetInLayoutClass; |
1829 | | |
1830 | 4.24k | if (B.isVirtual()) { |
1831 | 1.16k | if (!VBases.insert(BaseDecl).second) |
1832 | 281 | continue; |
1833 | | |
1834 | 883 | const ASTRecordLayout &LayoutClassLayout = |
1835 | 883 | Context.getASTRecordLayout(LayoutClass); |
1836 | | |
1837 | 883 | BaseOffsetInLayoutClass = |
1838 | 883 | LayoutClassLayout.getVBaseClassOffset(BaseDecl); |
1839 | 3.08k | } else { |
1840 | 3.08k | BaseOffsetInLayoutClass = |
1841 | 3.08k | OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); |
1842 | 3.08k | } |
1843 | | |
1844 | 3.96k | DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); |
1845 | 3.96k | } |
1846 | 7.79k | } |
1847 | | |
1848 | | void ItaniumVTableBuilder::LayoutVTablesForVirtualBases( |
1849 | 4.74k | const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { |
1850 | | // Itanium C++ ABI 2.5.2: |
1851 | | // Then come the virtual base virtual tables, also in inheritance graph |
1852 | | // order, and again excluding primary bases (which share virtual tables with |
1853 | | // the classes for which they are primary). |
1854 | 4.74k | for (const auto &B : RD->bases()) { |
1855 | 4.14k | const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
1856 | | |
1857 | | // Check if this base needs a vtable. (If it's virtual, not a primary base |
1858 | | // of some other class, and we haven't visited it before). |
1859 | 4.14k | if (B.isVirtual() && BaseDecl->isDynamicClass()1.61k && |
1860 | 4.14k | !PrimaryVirtualBases.count(BaseDecl)983 && |
1861 | 4.14k | VBases.insert(BaseDecl).second675 ) { |
1862 | 354 | const ASTRecordLayout &MostDerivedClassLayout = |
1863 | 354 | Context.getASTRecordLayout(MostDerivedClass); |
1864 | 354 | CharUnits BaseOffset = |
1865 | 354 | MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); |
1866 | | |
1867 | 354 | const ASTRecordLayout &LayoutClassLayout = |
1868 | 354 | Context.getASTRecordLayout(LayoutClass); |
1869 | 354 | CharUnits BaseOffsetInLayoutClass = |
1870 | 354 | LayoutClassLayout.getVBaseClassOffset(BaseDecl); |
1871 | | |
1872 | 354 | LayoutPrimaryAndSecondaryVTables( |
1873 | 354 | BaseSubobject(BaseDecl, BaseOffset), |
1874 | 354 | /*BaseIsMorallyVirtual=*/true, |
1875 | 354 | /*BaseIsVirtualInLayoutClass=*/true, |
1876 | 354 | BaseOffsetInLayoutClass); |
1877 | 354 | } |
1878 | | |
1879 | | // We only need to check the base for virtual base vtables if it actually |
1880 | | // has virtual bases. |
1881 | 4.14k | if (BaseDecl->getNumVBases()) |
1882 | 920 | LayoutVTablesForVirtualBases(BaseDecl, VBases); |
1883 | 4.14k | } |
1884 | 4.74k | } |
1885 | | |
1886 | | /// dumpLayout - Dump the vtable layout. |
1887 | 230 | void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { |
1888 | | // FIXME: write more tests that actually use the dumpLayout output to prevent |
1889 | | // ItaniumVTableBuilder regressions. |
1890 | | |
1891 | 230 | if (isBuildingConstructorVTable()) { |
1892 | 172 | Out << "Construction vtable for ('"; |
1893 | 172 | MostDerivedClass->printQualifiedName(Out); |
1894 | 172 | Out << "', "; |
1895 | 172 | Out << MostDerivedClassOffset.getQuantity() << ") in '"; |
1896 | 172 | LayoutClass->printQualifiedName(Out); |
1897 | 172 | } else { |
1898 | 58 | Out << "Vtable for '"; |
1899 | 58 | MostDerivedClass->printQualifiedName(Out); |
1900 | 58 | } |
1901 | 230 | Out << "' (" << Components.size() << " entries).\n"; |
1902 | | |
1903 | | // Iterate through the address points and insert them into a new map where |
1904 | | // they are keyed by the index and not the base object. |
1905 | | // Since an address point can be shared by multiple subobjects, we use an |
1906 | | // STL multimap. |
1907 | 230 | std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex; |
1908 | 830 | for (const auto &AP : AddressPoints) { |
1909 | 830 | const BaseSubobject &Base = AP.first; |
1910 | 830 | uint64_t Index = |
1911 | 830 | VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex; |
1912 | | |
1913 | 830 | AddressPointsByIndex.insert(std::make_pair(Index, Base)); |
1914 | 830 | } |
1915 | | |
1916 | 2.81k | for (unsigned I = 0, E = Components.size(); I != E; ++I2.58k ) { |
1917 | 2.58k | uint64_t Index = I; |
1918 | | |
1919 | 2.58k | Out << llvm::format("%4d | ", I); |
1920 | | |
1921 | 2.58k | const VTableComponent &Component = Components[I]; |
1922 | | |
1923 | | // Dump the component. |
1924 | 2.58k | switch (Component.getKind()) { |
1925 | | |
1926 | 308 | case VTableComponent::CK_VCallOffset: |
1927 | 308 | Out << "vcall_offset (" |
1928 | 308 | << Component.getVCallOffset().getQuantity() |
1929 | 308 | << ")"; |
1930 | 308 | break; |
1931 | | |
1932 | 739 | case VTableComponent::CK_VBaseOffset: |
1933 | 739 | Out << "vbase_offset (" |
1934 | 739 | << Component.getVBaseOffset().getQuantity() |
1935 | 739 | << ")"; |
1936 | 739 | break; |
1937 | | |
1938 | 529 | case VTableComponent::CK_OffsetToTop: |
1939 | 529 | Out << "offset_to_top (" |
1940 | 529 | << Component.getOffsetToTop().getQuantity() |
1941 | 529 | << ")"; |
1942 | 529 | break; |
1943 | | |
1944 | 529 | case VTableComponent::CK_RTTI: |
1945 | 529 | Component.getRTTIDecl()->printQualifiedName(Out); |
1946 | 529 | Out << " RTTI"; |
1947 | 529 | break; |
1948 | | |
1949 | 445 | case VTableComponent::CK_FunctionPointer: { |
1950 | 445 | const CXXMethodDecl *MD = Component.getFunctionDecl(); |
1951 | | |
1952 | 445 | std::string Str = |
1953 | 445 | PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, |
1954 | 445 | MD); |
1955 | 445 | Out << Str; |
1956 | 445 | if (MD->isPure()) |
1957 | 5 | Out << " [pure]"; |
1958 | | |
1959 | 445 | if (MD->isDeleted()) |
1960 | 1 | Out << " [deleted]"; |
1961 | | |
1962 | 445 | ThunkInfo Thunk = VTableThunks.lookup(I); |
1963 | 445 | if (!Thunk.isEmpty()) { |
1964 | | // If this function pointer has a return adjustment, dump it. |
1965 | 84 | if (!Thunk.Return.isEmpty()) { |
1966 | 7 | Out << "\n [return adjustment: "; |
1967 | 7 | Out << Thunk.Return.NonVirtual << " non-virtual"; |
1968 | | |
1969 | 7 | if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { |
1970 | 6 | Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; |
1971 | 6 | Out << " vbase offset offset"; |
1972 | 6 | } |
1973 | | |
1974 | 7 | Out << ']'; |
1975 | 7 | } |
1976 | | |
1977 | | // If this function pointer has a 'this' pointer adjustment, dump it. |
1978 | 84 | if (!Thunk.This.isEmpty()) { |
1979 | 81 | Out << "\n [this adjustment: "; |
1980 | 81 | Out << Thunk.This.NonVirtual << " non-virtual"; |
1981 | | |
1982 | 81 | if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { |
1983 | 71 | Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; |
1984 | 71 | Out << " vcall offset offset"; |
1985 | 71 | } |
1986 | | |
1987 | 81 | Out << ']'; |
1988 | 81 | } |
1989 | 84 | } |
1990 | | |
1991 | 445 | break; |
1992 | 0 | } |
1993 | | |
1994 | 5 | case VTableComponent::CK_CompleteDtorPointer: |
1995 | 10 | case VTableComponent::CK_DeletingDtorPointer: { |
1996 | 10 | bool IsComplete = |
1997 | 10 | Component.getKind() == VTableComponent::CK_CompleteDtorPointer; |
1998 | | |
1999 | 10 | const CXXDestructorDecl *DD = Component.getDestructorDecl(); |
2000 | | |
2001 | 10 | DD->printQualifiedName(Out); |
2002 | 10 | if (IsComplete) |
2003 | 5 | Out << "() [complete]"; |
2004 | 5 | else |
2005 | 5 | Out << "() [deleting]"; |
2006 | | |
2007 | 10 | if (DD->isPure()) |
2008 | 2 | Out << " [pure]"; |
2009 | | |
2010 | 10 | ThunkInfo Thunk = VTableThunks.lookup(I); |
2011 | 10 | if (!Thunk.isEmpty()) { |
2012 | | // If this destructor has a 'this' pointer adjustment, dump it. |
2013 | 4 | if (!Thunk.This.isEmpty()) { |
2014 | 4 | Out << "\n [this adjustment: "; |
2015 | 4 | Out << Thunk.This.NonVirtual << " non-virtual"; |
2016 | | |
2017 | 4 | if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { |
2018 | 4 | Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; |
2019 | 4 | Out << " vcall offset offset"; |
2020 | 4 | } |
2021 | | |
2022 | 4 | Out << ']'; |
2023 | 4 | } |
2024 | 4 | } |
2025 | | |
2026 | 10 | break; |
2027 | 5 | } |
2028 | | |
2029 | 26 | case VTableComponent::CK_UnusedFunctionPointer: { |
2030 | 26 | const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); |
2031 | | |
2032 | 26 | std::string Str = |
2033 | 26 | PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, |
2034 | 26 | MD); |
2035 | 26 | Out << "[unused] " << Str; |
2036 | 26 | if (MD->isPure()) |
2037 | 0 | Out << " [pure]"; |
2038 | 26 | } |
2039 | | |
2040 | 2.58k | } |
2041 | | |
2042 | 2.58k | Out << '\n'; |
2043 | | |
2044 | | // Dump the next address point. |
2045 | 2.58k | uint64_t NextIndex = Index + 1; |
2046 | 2.58k | if (AddressPointsByIndex.count(NextIndex)) { |
2047 | 529 | if (AddressPointsByIndex.count(NextIndex) == 1) { |
2048 | 295 | const BaseSubobject &Base = |
2049 | 295 | AddressPointsByIndex.find(NextIndex)->second; |
2050 | | |
2051 | 295 | Out << " -- ("; |
2052 | 295 | Base.getBase()->printQualifiedName(Out); |
2053 | 295 | Out << ", " << Base.getBaseOffset().getQuantity(); |
2054 | 295 | Out << ") vtable address --\n"; |
2055 | 295 | } else { |
2056 | 234 | CharUnits BaseOffset = |
2057 | 234 | AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); |
2058 | | |
2059 | | // We store the class names in a set to get a stable order. |
2060 | 234 | std::set<std::string> ClassNames; |
2061 | 234 | for (const auto &I : |
2062 | 535 | llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) { |
2063 | 535 | assert(I.second.getBaseOffset() == BaseOffset && |
2064 | 535 | "Invalid base offset!"); |
2065 | 535 | const CXXRecordDecl *RD = I.second.getBase(); |
2066 | 535 | ClassNames.insert(RD->getQualifiedNameAsString()); |
2067 | 535 | } |
2068 | | |
2069 | 535 | for (const std::string &Name : ClassNames)234 { |
2070 | 535 | Out << " -- (" << Name; |
2071 | 535 | Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n"; |
2072 | 535 | } |
2073 | 234 | } |
2074 | 529 | } |
2075 | 2.58k | } |
2076 | | |
2077 | 230 | Out << '\n'; |
2078 | | |
2079 | 230 | if (isBuildingConstructorVTable()) |
2080 | 172 | return; |
2081 | | |
2082 | 58 | if (MostDerivedClass->getNumVBases()) { |
2083 | | // We store the virtual base class names and their offsets in a map to get |
2084 | | // a stable order. |
2085 | | |
2086 | 36 | std::map<std::string, CharUnits> ClassNamesAndOffsets; |
2087 | 75 | for (const auto &I : VBaseOffsetOffsets) { |
2088 | 75 | std::string ClassName = I.first->getQualifiedNameAsString(); |
2089 | 75 | CharUnits OffsetOffset = I.second; |
2090 | 75 | ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); |
2091 | 75 | } |
2092 | | |
2093 | 36 | Out << "Virtual base offset offsets for '"; |
2094 | 36 | MostDerivedClass->printQualifiedName(Out); |
2095 | 36 | Out << "' ("; |
2096 | 36 | Out << ClassNamesAndOffsets.size(); |
2097 | 36 | Out << (ClassNamesAndOffsets.size() == 1 ? " entry"16 : " entries"20 ) << ").\n"; |
2098 | | |
2099 | 36 | for (const auto &I : ClassNamesAndOffsets) |
2100 | 75 | Out << " " << I.first << " | " << I.second.getQuantity() << '\n'; |
2101 | | |
2102 | 36 | Out << "\n"; |
2103 | 36 | } |
2104 | | |
2105 | 58 | if (!Thunks.empty()) { |
2106 | | // We store the method names in a map to get a stable order. |
2107 | 25 | std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; |
2108 | | |
2109 | 29 | for (const auto &I : Thunks) { |
2110 | 29 | const CXXMethodDecl *MD = I.first; |
2111 | 29 | std::string MethodName = |
2112 | 29 | PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, |
2113 | 29 | MD); |
2114 | | |
2115 | 29 | MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); |
2116 | 29 | } |
2117 | | |
2118 | 29 | for (const auto &I : MethodNamesAndDecls) { |
2119 | 29 | const std::string &MethodName = I.first; |
2120 | 29 | const CXXMethodDecl *MD = I.second; |
2121 | | |
2122 | 29 | ThunkInfoVectorTy ThunksVector = Thunks[MD]; |
2123 | 29 | llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) { |
2124 | 11 | assert(LHS.Method == nullptr && RHS.Method == nullptr); |
2125 | 11 | return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); |
2126 | 11 | }); |
2127 | | |
2128 | 29 | Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); |
2129 | 29 | Out << (ThunksVector.size() == 1 ? " entry"21 : " entries"8 ) << ").\n"; |
2130 | | |
2131 | 68 | for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I39 ) { |
2132 | 39 | const ThunkInfo &Thunk = ThunksVector[I]; |
2133 | | |
2134 | 39 | Out << llvm::format("%4d | ", I); |
2135 | | |
2136 | | // If this function pointer has a return pointer adjustment, dump it. |
2137 | 39 | if (!Thunk.Return.isEmpty()) { |
2138 | 5 | Out << "return adjustment: " << Thunk.Return.NonVirtual; |
2139 | 5 | Out << " non-virtual"; |
2140 | 5 | if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { |
2141 | 4 | Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; |
2142 | 4 | Out << " vbase offset offset"; |
2143 | 4 | } |
2144 | | |
2145 | 5 | if (!Thunk.This.isEmpty()) |
2146 | 2 | Out << "\n "; |
2147 | 5 | } |
2148 | | |
2149 | | // If this function pointer has a 'this' pointer adjustment, dump it. |
2150 | 39 | if (!Thunk.This.isEmpty()) { |
2151 | 36 | Out << "this adjustment: "; |
2152 | 36 | Out << Thunk.This.NonVirtual << " non-virtual"; |
2153 | | |
2154 | 36 | if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { |
2155 | 28 | Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; |
2156 | 28 | Out << " vcall offset offset"; |
2157 | 28 | } |
2158 | 36 | } |
2159 | | |
2160 | 39 | Out << '\n'; |
2161 | 39 | } |
2162 | | |
2163 | 29 | Out << '\n'; |
2164 | 29 | } |
2165 | 25 | } |
2166 | | |
2167 | | // Compute the vtable indices for all the member functions. |
2168 | | // Store them in a map keyed by the index so we'll get a sorted table. |
2169 | 58 | std::map<uint64_t, std::string> IndicesMap; |
2170 | | |
2171 | 265 | for (const auto *MD : MostDerivedClass->methods()) { |
2172 | | // We only want virtual member functions. |
2173 | 265 | if (!ItaniumVTableContext::hasVtableSlot(MD)) |
2174 | 180 | continue; |
2175 | 85 | MD = MD->getCanonicalDecl(); |
2176 | | |
2177 | 85 | std::string MethodName = |
2178 | 85 | PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, |
2179 | 85 | MD); |
2180 | | |
2181 | 85 | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { |
2182 | 3 | GlobalDecl GD(DD, Dtor_Complete); |
2183 | 3 | assert(MethodVTableIndices.count(GD)); |
2184 | 3 | uint64_t VTableIndex = MethodVTableIndices[GD]; |
2185 | 3 | IndicesMap[VTableIndex] = MethodName + " [complete]"; |
2186 | 3 | IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; |
2187 | 82 | } else { |
2188 | 82 | assert(MethodVTableIndices.count(MD)); |
2189 | 82 | IndicesMap[MethodVTableIndices[MD]] = MethodName; |
2190 | 82 | } |
2191 | 85 | } |
2192 | | |
2193 | | // Print the vtable indices for all the member functions. |
2194 | 58 | if (!IndicesMap.empty()) { |
2195 | 56 | Out << "VTable indices for '"; |
2196 | 56 | MostDerivedClass->printQualifiedName(Out); |
2197 | 56 | Out << "' (" << IndicesMap.size() << " entries).\n"; |
2198 | | |
2199 | 88 | for (const auto &I : IndicesMap) { |
2200 | 88 | uint64_t VTableIndex = I.first; |
2201 | 88 | const std::string &MethodName = I.second; |
2202 | | |
2203 | 88 | Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName |
2204 | 88 | << '\n'; |
2205 | 88 | } |
2206 | 56 | } |
2207 | | |
2208 | 58 | Out << '\n'; |
2209 | 58 | } |
2210 | | } |
2211 | | |
2212 | | static VTableLayout::AddressPointsIndexMapTy |
2213 | | MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints, |
2214 | 5.11k | unsigned numVTables) { |
2215 | 5.11k | VTableLayout::AddressPointsIndexMapTy indexMap(numVTables); |
2216 | | |
2217 | 12.1k | for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it7.03k ) { |
2218 | 7.03k | const auto &addressPointLoc = it->second; |
2219 | 7.03k | unsigned vtableIndex = addressPointLoc.VTableIndex; |
2220 | 7.03k | unsigned addressPoint = addressPointLoc.AddressPointIndex; |
2221 | 7.03k | if (indexMap[vtableIndex]) { |
2222 | | // Multiple BaseSubobjects can map to the same AddressPointLocation, but |
2223 | | // every vtable index should have a unique address point. |
2224 | 2.56k | assert(indexMap[vtableIndex] == addressPoint && |
2225 | 2.56k | "Every vtable index should have a unique address point. Found a " |
2226 | 2.56k | "vtable that has two different address points."); |
2227 | 4.47k | } else { |
2228 | 4.47k | indexMap[vtableIndex] = addressPoint; |
2229 | 4.47k | } |
2230 | 7.03k | } |
2231 | | |
2232 | | // Note that by this point, not all the address may be initialized if the |
2233 | | // AddressPoints map is empty. This is ok if the map isn't needed. See |
2234 | | // MicrosoftVTableContext::computeVTableRelatedInformation() which uses an |
2235 | | // emprt map. |
2236 | 5.11k | return indexMap; |
2237 | 5.11k | } |
2238 | | |
2239 | | VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices, |
2240 | | ArrayRef<VTableComponent> VTableComponents, |
2241 | | ArrayRef<VTableThunkTy> VTableThunks, |
2242 | | const AddressPointsMapTy &AddressPoints) |
2243 | | : VTableComponents(VTableComponents), VTableThunks(VTableThunks), |
2244 | | AddressPoints(AddressPoints), AddressPointIndices(MakeAddressPointIndices( |
2245 | 5.11k | AddressPoints, VTableIndices.size())) { |
2246 | 5.11k | if (VTableIndices.size() <= 1) |
2247 | 4.63k | assert(VTableIndices.size() == 1 && VTableIndices[0] == 0); |
2248 | 478 | else |
2249 | 478 | this->VTableIndices = OwningArrayRef<size_t>(VTableIndices); |
2250 | | |
2251 | 5.11k | llvm::sort(this->VTableThunks, [](const VTableLayout::VTableThunkTy &LHS, |
2252 | 5.11k | const VTableLayout::VTableThunkTy &RHS) { |
2253 | 376 | assert((LHS.first != RHS.first || LHS.second == RHS.second) && |
2254 | 376 | "Different thunks should have unique indices!"); |
2255 | 376 | return LHS.first < RHS.first; |
2256 | 376 | }); |
2257 | 5.11k | } |
2258 | | |
2259 | 3.71k | VTableLayout::~VTableLayout() { } |
2260 | | |
2261 | 448k | bool VTableContextBase::hasVtableSlot(const CXXMethodDecl *MD) { |
2262 | 448k | return MD->isVirtual() && !MD->isConsteval()58.1k ; |
2263 | 448k | } |
2264 | | |
2265 | | ItaniumVTableContext::ItaniumVTableContext( |
2266 | | ASTContext &Context, VTableComponentLayout ComponentLayout) |
2267 | 31.9k | : VTableContextBase(/*MS=*/false), ComponentLayout(ComponentLayout) {} |
2268 | | |
2269 | 28.0k | ItaniumVTableContext::~ItaniumVTableContext() {} |
2270 | | |
2271 | 4.49k | uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) { |
2272 | 4.49k | GD = GD.getCanonicalDecl(); |
2273 | 4.49k | MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); |
2274 | 4.49k | if (I != MethodVTableIndices.end()) |
2275 | 2.94k | return I->second; |
2276 | | |
2277 | 1.55k | const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); |
2278 | | |
2279 | 1.55k | computeVTableRelatedInformation(RD); |
2280 | | |
2281 | 1.55k | I = MethodVTableIndices.find(GD); |
2282 | 1.55k | assert(I != MethodVTableIndices.end() && "Did not find index!"); |
2283 | 1.55k | return I->second; |
2284 | 1.55k | } |
2285 | | |
2286 | | CharUnits |
2287 | | ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, |
2288 | 975 | const CXXRecordDecl *VBase) { |
2289 | 975 | ClassPairTy ClassPair(RD, VBase); |
2290 | | |
2291 | 975 | VirtualBaseClassOffsetOffsetsMapTy::iterator I = |
2292 | 975 | VirtualBaseClassOffsetOffsets.find(ClassPair); |
2293 | 975 | if (I != VirtualBaseClassOffsetOffsets.end()) |
2294 | 683 | return I->second; |
2295 | | |
2296 | 292 | VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, /*Overriders=*/nullptr, |
2297 | 292 | BaseSubobject(RD, CharUnits::Zero()), |
2298 | 292 | /*BaseIsVirtual=*/false, |
2299 | 292 | /*OffsetInLayoutClass=*/CharUnits::Zero()); |
2300 | | |
2301 | 345 | for (const auto &I : Builder.getVBaseOffsetOffsets()) { |
2302 | | // Insert all types. |
2303 | 345 | ClassPairTy ClassPair(RD, I.first); |
2304 | | |
2305 | 345 | VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second)); |
2306 | 345 | } |
2307 | | |
2308 | 292 | I = VirtualBaseClassOffsetOffsets.find(ClassPair); |
2309 | 292 | assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); |
2310 | | |
2311 | 292 | return I->second; |
2312 | 292 | } |
2313 | | |
2314 | | static std::unique_ptr<VTableLayout> |
2315 | 3.82k | CreateVTableLayout(const ItaniumVTableBuilder &Builder) { |
2316 | 3.82k | SmallVector<VTableLayout::VTableThunkTy, 1> |
2317 | 3.82k | VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); |
2318 | | |
2319 | 3.82k | return std::make_unique<VTableLayout>( |
2320 | 3.82k | Builder.VTableIndices, Builder.vtable_components(), VTableThunks, |
2321 | 3.82k | Builder.getAddressPoints()); |
2322 | 3.82k | } |
2323 | | |
2324 | | void |
2325 | 12.2k | ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) { |
2326 | 12.2k | std::unique_ptr<const VTableLayout> &Entry = VTableLayouts[RD]; |
2327 | | |
2328 | | // Check if we've computed this information before. |
2329 | 12.2k | if (Entry) |
2330 | 8.78k | return; |
2331 | | |
2332 | 3.50k | ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(), |
2333 | 3.50k | /*MostDerivedClassIsVirtual=*/false, RD); |
2334 | 3.50k | Entry = CreateVTableLayout(Builder); |
2335 | | |
2336 | 3.50k | MethodVTableIndices.insert(Builder.vtable_indices_begin(), |
2337 | 3.50k | Builder.vtable_indices_end()); |
2338 | | |
2339 | | // Add the known thunks. |
2340 | 3.50k | Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); |
2341 | | |
2342 | | // If we don't have the vbase information for this class, insert it. |
2343 | | // getVirtualBaseOffsetOffset will compute it separately without computing |
2344 | | // the rest of the vtable related information. |
2345 | 3.50k | if (!RD->getNumVBases()) |
2346 | 3.15k | return; |
2347 | | |
2348 | 347 | const CXXRecordDecl *VBase = |
2349 | 347 | RD->vbases_begin()->getType()->getAsCXXRecordDecl(); |
2350 | | |
2351 | 347 | if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) |
2352 | 99 | return; |
2353 | | |
2354 | 304 | for (const auto &I : Builder.getVBaseOffsetOffsets())248 { |
2355 | | // Insert all types. |
2356 | 304 | ClassPairTy ClassPair(RD, I.first); |
2357 | | |
2358 | 304 | VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second)); |
2359 | 304 | } |
2360 | 248 | } |
2361 | | |
2362 | | std::unique_ptr<VTableLayout> |
2363 | | ItaniumVTableContext::createConstructionVTableLayout( |
2364 | | const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, |
2365 | 327 | bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) { |
2366 | 327 | ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset, |
2367 | 327 | MostDerivedClassIsVirtual, LayoutClass); |
2368 | 327 | return CreateVTableLayout(Builder); |
2369 | 327 | } |
2370 | | |
2371 | | namespace { |
2372 | | |
2373 | | // Vtables in the Microsoft ABI are different from the Itanium ABI. |
2374 | | // |
2375 | | // The main differences are: |
2376 | | // 1. Separate vftable and vbtable. |
2377 | | // |
2378 | | // 2. Each subobject with a vfptr gets its own vftable rather than an address |
2379 | | // point in a single vtable shared between all the subobjects. |
2380 | | // Each vftable is represented by a separate section and virtual calls |
2381 | | // must be done using the vftable which has a slot for the function to be |
2382 | | // called. |
2383 | | // |
2384 | | // 3. Virtual method definitions expect their 'this' parameter to point to the |
2385 | | // first vfptr whose table provides a compatible overridden method. In many |
2386 | | // cases, this permits the original vf-table entry to directly call |
2387 | | // the method instead of passing through a thunk. |
2388 | | // See example before VFTableBuilder::ComputeThisOffset below. |
2389 | | // |
2390 | | // A compatible overridden method is one which does not have a non-trivial |
2391 | | // covariant-return adjustment. |
2392 | | // |
2393 | | // The first vfptr is the one with the lowest offset in the complete-object |
2394 | | // layout of the defining class, and the method definition will subtract |
2395 | | // that constant offset from the parameter value to get the real 'this' |
2396 | | // value. Therefore, if the offset isn't really constant (e.g. if a virtual |
2397 | | // function defined in a virtual base is overridden in a more derived |
2398 | | // virtual base and these bases have a reverse order in the complete |
2399 | | // object), the vf-table may require a this-adjustment thunk. |
2400 | | // |
2401 | | // 4. vftables do not contain new entries for overrides that merely require |
2402 | | // this-adjustment. Together with #3, this keeps vf-tables smaller and |
2403 | | // eliminates the need for this-adjustment thunks in many cases, at the cost |
2404 | | // of often requiring redundant work to adjust the "this" pointer. |
2405 | | // |
2406 | | // 5. Instead of VTT and constructor vtables, vbtables and vtordisps are used. |
2407 | | // Vtordisps are emitted into the class layout if a class has |
2408 | | // a) a user-defined ctor/dtor |
2409 | | // and |
2410 | | // b) a method overriding a method in a virtual base. |
2411 | | // |
2412 | | // To get a better understanding of this code, |
2413 | | // you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp |
2414 | | |
2415 | | class VFTableBuilder { |
2416 | | public: |
2417 | | typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> |
2418 | | MethodVFTableLocationsTy; |
2419 | | |
2420 | | typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator> |
2421 | | method_locations_range; |
2422 | | |
2423 | | private: |
2424 | | /// VTables - Global vtable information. |
2425 | | MicrosoftVTableContext &VTables; |
2426 | | |
2427 | | /// Context - The ASTContext which we will use for layout information. |
2428 | | ASTContext &Context; |
2429 | | |
2430 | | /// MostDerivedClass - The most derived class for which we're building this |
2431 | | /// vtable. |
2432 | | const CXXRecordDecl *MostDerivedClass; |
2433 | | |
2434 | | const ASTRecordLayout &MostDerivedClassLayout; |
2435 | | |
2436 | | const VPtrInfo &WhichVFPtr; |
2437 | | |
2438 | | /// FinalOverriders - The final overriders of the most derived class. |
2439 | | const FinalOverriders Overriders; |
2440 | | |
2441 | | /// Components - The components of the vftable being built. |
2442 | | SmallVector<VTableComponent, 64> Components; |
2443 | | |
2444 | | MethodVFTableLocationsTy MethodVFTableLocations; |
2445 | | |
2446 | | /// Does this class have an RTTI component? |
2447 | | bool HasRTTIComponent = false; |
2448 | | |
2449 | | /// MethodInfo - Contains information about a method in a vtable. |
2450 | | /// (Used for computing 'this' pointer adjustment thunks. |
2451 | | struct MethodInfo { |
2452 | | /// VBTableIndex - The nonzero index in the vbtable that |
2453 | | /// this method's base has, or zero. |
2454 | | const uint64_t VBTableIndex; |
2455 | | |
2456 | | /// VFTableIndex - The index in the vftable that this method has. |
2457 | | const uint64_t VFTableIndex; |
2458 | | |
2459 | | /// Shadowed - Indicates if this vftable slot is shadowed by |
2460 | | /// a slot for a covariant-return override. If so, it shouldn't be printed |
2461 | | /// or used for vcalls in the most derived class. |
2462 | | bool Shadowed; |
2463 | | |
2464 | | /// UsesExtraSlot - Indicates if this vftable slot was created because |
2465 | | /// any of the overridden slots required a return adjusting thunk. |
2466 | | bool UsesExtraSlot; |
2467 | | |
2468 | | MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex, |
2469 | | bool UsesExtraSlot = false) |
2470 | | : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), |
2471 | 2.50k | Shadowed(false), UsesExtraSlot(UsesExtraSlot) {} |
2472 | | |
2473 | | MethodInfo() |
2474 | | : VBTableIndex(0), VFTableIndex(0), Shadowed(false), |
2475 | 0 | UsesExtraSlot(false) {} |
2476 | | }; |
2477 | | |
2478 | | typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; |
2479 | | |
2480 | | /// MethodInfoMap - The information for all methods in the vftable we're |
2481 | | /// currently building. |
2482 | | MethodInfoMapTy MethodInfoMap; |
2483 | | |
2484 | | typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; |
2485 | | |
2486 | | /// VTableThunks - The thunks by vftable index in the vftable currently being |
2487 | | /// built. |
2488 | | VTableThunksMapTy VTableThunks; |
2489 | | |
2490 | | typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; |
2491 | | typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; |
2492 | | |
2493 | | /// Thunks - A map that contains all the thunks needed for all methods in the |
2494 | | /// most derived class for which the vftable is currently being built. |
2495 | | ThunksMapTy Thunks; |
2496 | | |
2497 | | /// AddThunk - Add a thunk for the given method. |
2498 | 340 | void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { |
2499 | 340 | SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; |
2500 | | |
2501 | | // Check if we have this thunk already. |
2502 | 340 | if (llvm::is_contained(ThunksVector, Thunk)) |
2503 | 0 | return; |
2504 | | |
2505 | 340 | ThunksVector.push_back(Thunk); |
2506 | 340 | } |
2507 | | |
2508 | | /// ComputeThisOffset - Returns the 'this' argument offset for the given |
2509 | | /// method, relative to the beginning of the MostDerivedClass. |
2510 | | CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider); |
2511 | | |
2512 | | void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider, |
2513 | | CharUnits ThisOffset, ThisAdjustment &TA); |
2514 | | |
2515 | | /// AddMethod - Add a single virtual member function to the vftable |
2516 | | /// components vector. |
2517 | 1.84k | void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) { |
2518 | 1.84k | if (!TI.isEmpty()) { |
2519 | 340 | VTableThunks[Components.size()] = TI; |
2520 | 340 | AddThunk(MD, TI); |
2521 | 340 | } |
2522 | 1.84k | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { |
2523 | 359 | assert(TI.Return.isEmpty() && |
2524 | 359 | "Destructor can't have return adjustment!"); |
2525 | 359 | Components.push_back(VTableComponent::MakeDeletingDtor(DD)); |
2526 | 1.48k | } else { |
2527 | 1.48k | Components.push_back(VTableComponent::MakeFunction(MD)); |
2528 | 1.48k | } |
2529 | 1.84k | } |
2530 | | |
2531 | | /// AddMethods - Add the methods of this base subobject and the relevant |
2532 | | /// subbases to the vftable we're currently laying out. |
2533 | | void AddMethods(BaseSubobject Base, unsigned BaseDepth, |
2534 | | const CXXRecordDecl *LastVBase, |
2535 | | BasesSetVectorTy &VisitedBases); |
2536 | | |
2537 | 1.28k | void LayoutVFTable() { |
2538 | | // RTTI data goes before all other entries. |
2539 | 1.28k | if (HasRTTIComponent) |
2540 | 486 | Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); |
2541 | | |
2542 | 1.28k | BasesSetVectorTy VisitedBases; |
2543 | 1.28k | AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr, |
2544 | 1.28k | VisitedBases); |
2545 | | // Note that it is possible for the vftable to contain only an RTTI |
2546 | | // pointer, if all virtual functions are constewval. |
2547 | 1.28k | assert(!Components.empty() && "vftable can't be empty"); |
2548 | | |
2549 | 1.28k | assert(MethodVFTableLocations.empty()); |
2550 | 1.84k | for (const auto &I : MethodInfoMap)1.28k { |
2551 | 1.84k | const CXXMethodDecl *MD = I.first; |
2552 | 1.84k | const MethodInfo &MI = I.second; |
2553 | 1.84k | assert(MD == MD->getCanonicalDecl()); |
2554 | | |
2555 | | // Skip the methods that the MostDerivedClass didn't override |
2556 | | // and the entries shadowed by return adjusting thunks. |
2557 | 1.84k | if (MD->getParent() != MostDerivedClass || MI.Shadowed1.31k ) |
2558 | 528 | continue; |
2559 | 1.31k | MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(), |
2560 | 1.31k | WhichVFPtr.NonVirtualOffset, MI.VFTableIndex); |
2561 | 1.31k | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { |
2562 | 359 | MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc; |
2563 | 954 | } else { |
2564 | 954 | MethodVFTableLocations[MD] = Loc; |
2565 | 954 | } |
2566 | 1.31k | } |
2567 | 1.28k | } |
2568 | | |
2569 | | public: |
2570 | | VFTableBuilder(MicrosoftVTableContext &VTables, |
2571 | | const CXXRecordDecl *MostDerivedClass, const VPtrInfo &Which) |
2572 | | : VTables(VTables), |
2573 | | Context(MostDerivedClass->getASTContext()), |
2574 | | MostDerivedClass(MostDerivedClass), |
2575 | | MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)), |
2576 | | WhichVFPtr(Which), |
2577 | 1.28k | Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) { |
2578 | | // Provide the RTTI component if RTTIData is enabled. If the vftable would |
2579 | | // be available externally, we should not provide the RTTI componenent. It |
2580 | | // is currently impossible to get available externally vftables with either |
2581 | | // dllimport or extern template instantiations, but eventually we may add a |
2582 | | // flag to support additional devirtualization that needs this. |
2583 | 1.28k | if (Context.getLangOpts().RTTIData) |
2584 | 486 | HasRTTIComponent = true; |
2585 | | |
2586 | 1.28k | LayoutVFTable(); |
2587 | | |
2588 | 1.28k | if (Context.getLangOpts().DumpVTableLayouts) |
2589 | 394 | dumpLayout(llvm::outs()); |
2590 | 1.28k | } |
2591 | | |
2592 | 0 | uint64_t getNumThunks() const { return Thunks.size(); } |
2593 | | |
2594 | 1.28k | ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); } |
2595 | | |
2596 | 1.28k | ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); } |
2597 | | |
2598 | 1.28k | method_locations_range vtable_locations() const { |
2599 | 1.28k | return method_locations_range(MethodVFTableLocations.begin(), |
2600 | 1.28k | MethodVFTableLocations.end()); |
2601 | 1.28k | } |
2602 | | |
2603 | 1.28k | ArrayRef<VTableComponent> vtable_components() const { return Components; } |
2604 | | |
2605 | 1.28k | VTableThunksMapTy::const_iterator vtable_thunks_begin() const { |
2606 | 1.28k | return VTableThunks.begin(); |
2607 | 1.28k | } |
2608 | | |
2609 | 1.28k | VTableThunksMapTy::const_iterator vtable_thunks_end() const { |
2610 | 1.28k | return VTableThunks.end(); |
2611 | 1.28k | } |
2612 | | |
2613 | | void dumpLayout(raw_ostream &); |
2614 | | }; |
2615 | | |
2616 | | } // end namespace |
2617 | | |
2618 | | // Let's study one class hierarchy as an example: |
2619 | | // struct A { |
2620 | | // virtual void f(); |
2621 | | // int x; |
2622 | | // }; |
2623 | | // |
2624 | | // struct B : virtual A { |
2625 | | // virtual void f(); |
2626 | | // }; |
2627 | | // |
2628 | | // Record layouts: |
2629 | | // struct A: |
2630 | | // 0 | (A vftable pointer) |
2631 | | // 4 | int x |
2632 | | // |
2633 | | // struct B: |
2634 | | // 0 | (B vbtable pointer) |
2635 | | // 4 | struct A (virtual base) |
2636 | | // 4 | (A vftable pointer) |
2637 | | // 8 | int x |
2638 | | // |
2639 | | // Let's assume we have a pointer to the A part of an object of dynamic type B: |
2640 | | // B b; |
2641 | | // A *a = (A*)&b; |
2642 | | // a->f(); |
2643 | | // |
2644 | | // In this hierarchy, f() belongs to the vftable of A, so B::f() expects |
2645 | | // "this" parameter to point at the A subobject, which is B+4. |
2646 | | // In the B::f() prologue, it adjusts "this" back to B by subtracting 4, |
2647 | | // performed as a *static* adjustment. |
2648 | | // |
2649 | | // Interesting thing happens when we alter the relative placement of A and B |
2650 | | // subobjects in a class: |
2651 | | // struct C : virtual B { }; |
2652 | | // |
2653 | | // C c; |
2654 | | // A *a = (A*)&c; |
2655 | | // a->f(); |
2656 | | // |
2657 | | // Respective record layout is: |
2658 | | // 0 | (C vbtable pointer) |
2659 | | // 4 | struct A (virtual base) |
2660 | | // 4 | (A vftable pointer) |
2661 | | // 8 | int x |
2662 | | // 12 | struct B (virtual base) |
2663 | | // 12 | (B vbtable pointer) |
2664 | | // |
2665 | | // The final overrider of f() in class C is still B::f(), so B+4 should be |
2666 | | // passed as "this" to that code. However, "a" points at B-8, so the respective |
2667 | | // vftable entry should hold a thunk that adds 12 to the "this" argument before |
2668 | | // performing a tail call to B::f(). |
2669 | | // |
2670 | | // With this example in mind, we can now calculate the 'this' argument offset |
2671 | | // for the given method, relative to the beginning of the MostDerivedClass. |
2672 | | CharUnits |
2673 | 2.77k | VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) { |
2674 | 2.77k | BasesSetVectorTy Bases; |
2675 | | |
2676 | 2.77k | { |
2677 | | // Find the set of least derived bases that define the given method. |
2678 | 2.77k | OverriddenMethodsSetTy VisitedOverriddenMethods; |
2679 | 2.77k | auto InitialOverriddenDefinitionCollector = [&]( |
2680 | 2.77k | const CXXMethodDecl *OverriddenMD) { |
2681 | 2.68k | if (OverriddenMD->size_overridden_methods() == 0) |
2682 | 2.08k | Bases.insert(OverriddenMD->getParent()); |
2683 | | // Don't recurse on this method if we've already collected it. |
2684 | 2.68k | return VisitedOverriddenMethods.insert(OverriddenMD).second; |
2685 | 2.68k | }; |
2686 | 2.77k | visitAllOverriddenMethods(Overrider.Method, |
2687 | 2.77k | InitialOverriddenDefinitionCollector); |
2688 | 2.77k | } |
2689 | | |
2690 | | // If there are no overrides then 'this' is located |
2691 | | // in the base that defines the method. |
2692 | 2.77k | if (Bases.size() == 0) |
2693 | 1.21k | return Overrider.Offset; |
2694 | | |
2695 | 1.56k | CXXBasePaths Paths; |
2696 | 1.56k | Overrider.Method->getParent()->lookupInBases( |
2697 | 3.75k | [&Bases](const CXXBaseSpecifier *Specifier, CXXBasePath &) { |
2698 | 3.75k | return Bases.count(Specifier->getType()->getAsCXXRecordDecl()); |
2699 | 3.75k | }, |
2700 | 1.56k | Paths); |
2701 | | |
2702 | | // This will hold the smallest this offset among overridees of MD. |
2703 | | // This implies that an offset of a non-virtual base will dominate an offset |
2704 | | // of a virtual base to potentially reduce the number of thunks required |
2705 | | // in the derived classes that inherit this method. |
2706 | 1.56k | CharUnits Ret; |
2707 | 1.56k | bool First = true; |
2708 | | |
2709 | 1.56k | const ASTRecordLayout &OverriderRDLayout = |
2710 | 1.56k | Context.getASTRecordLayout(Overrider.Method->getParent()); |
2711 | 2.14k | for (const CXXBasePath &Path : Paths) { |
2712 | 2.14k | CharUnits ThisOffset = Overrider.Offset; |
2713 | 2.14k | CharUnits LastVBaseOffset; |
2714 | | |
2715 | | // For each path from the overrider to the parents of the overridden |
2716 | | // methods, traverse the path, calculating the this offset in the most |
2717 | | // derived class. |
2718 | 3.23k | for (const CXXBasePathElement &Element : Path) { |
2719 | 3.23k | QualType CurTy = Element.Base->getType(); |
2720 | 3.23k | const CXXRecordDecl *PrevRD = Element.Class, |
2721 | 3.23k | *CurRD = CurTy->getAsCXXRecordDecl(); |
2722 | 3.23k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD); |
2723 | | |
2724 | 3.23k | if (Element.Base->isVirtual()) { |
2725 | | // The interesting things begin when you have virtual inheritance. |
2726 | | // The final overrider will use a static adjustment equal to the offset |
2727 | | // of the vbase in the final overrider class. |
2728 | | // For example, if the final overrider is in a vbase B of the most |
2729 | | // derived class and it overrides a method of the B's own vbase A, |
2730 | | // it uses A* as "this". In its prologue, it can cast A* to B* with |
2731 | | // a static offset. This offset is used regardless of the actual |
2732 | | // offset of A from B in the most derived class, requiring an |
2733 | | // this-adjusting thunk in the vftable if A and B are laid out |
2734 | | // differently in the most derived class. |
2735 | 1.07k | LastVBaseOffset = ThisOffset = |
2736 | 1.07k | Overrider.Offset + OverriderRDLayout.getVBaseClassOffset(CurRD); |
2737 | 2.15k | } else { |
2738 | 2.15k | ThisOffset += Layout.getBaseClassOffset(CurRD); |
2739 | 2.15k | } |
2740 | 3.23k | } |
2741 | | |
2742 | 2.14k | if (isa<CXXDestructorDecl>(Overrider.Method)) { |
2743 | 853 | if (LastVBaseOffset.isZero()) { |
2744 | | // If a "Base" class has at least one non-virtual base with a virtual |
2745 | | // destructor, the "Base" virtual destructor will take the address |
2746 | | // of the "Base" subobject as the "this" argument. |
2747 | 356 | ThisOffset = Overrider.Offset; |
2748 | 497 | } else { |
2749 | | // A virtual destructor of a virtual base takes the address of the |
2750 | | // virtual base subobject as the "this" argument. |
2751 | 497 | ThisOffset = LastVBaseOffset; |
2752 | 497 | } |
2753 | 853 | } |
2754 | | |
2755 | 2.14k | if (Ret > ThisOffset || First2.12k ) { |
2756 | 1.57k | First = false; |
2757 | 1.57k | Ret = ThisOffset; |
2758 | 1.57k | } |
2759 | 2.14k | } |
2760 | | |
2761 | 1.56k | assert(!First && "Method not found in the given subobject?"); |
2762 | 1.56k | return Ret; |
2763 | 1.56k | } |
2764 | | |
2765 | | // Things are getting even more complex when the "this" adjustment has to |
2766 | | // use a dynamic offset instead of a static one, or even two dynamic offsets. |
2767 | | // This is sometimes required when a virtual call happens in the middle of |
2768 | | // a non-most-derived class construction or destruction. |
2769 | | // |
2770 | | // Let's take a look at the following example: |
2771 | | // struct A { |
2772 | | // virtual void f(); |
2773 | | // }; |
2774 | | // |
2775 | | // void foo(A *a) { a->f(); } // Knows nothing about siblings of A. |
2776 | | // |
2777 | | // struct B : virtual A { |
2778 | | // virtual void f(); |
2779 | | // B() { |
2780 | | // foo(this); |
2781 | | // } |
2782 | | // }; |
2783 | | // |
2784 | | // struct C : virtual B { |
2785 | | // virtual void f(); |
2786 | | // }; |
2787 | | // |
2788 | | // Record layouts for these classes are: |
2789 | | // struct A |
2790 | | // 0 | (A vftable pointer) |
2791 | | // |
2792 | | // struct B |
2793 | | // 0 | (B vbtable pointer) |
2794 | | // 4 | (vtordisp for vbase A) |
2795 | | // 8 | struct A (virtual base) |
2796 | | // 8 | (A vftable pointer) |
2797 | | // |
2798 | | // struct C |
2799 | | // 0 | (C vbtable pointer) |
2800 | | // 4 | (vtordisp for vbase A) |
2801 | | // 8 | struct A (virtual base) // A precedes B! |
2802 | | // 8 | (A vftable pointer) |
2803 | | // 12 | struct B (virtual base) |
2804 | | // 12 | (B vbtable pointer) |
2805 | | // |
2806 | | // When one creates an object of type C, the C constructor: |
2807 | | // - initializes all the vbptrs, then |
2808 | | // - calls the A subobject constructor |
2809 | | // (initializes A's vfptr with an address of A vftable), then |
2810 | | // - calls the B subobject constructor |
2811 | | // (initializes A's vfptr with an address of B vftable and vtordisp for A), |
2812 | | // that in turn calls foo(), then |
2813 | | // - initializes A's vfptr with an address of C vftable and zeroes out the |
2814 | | // vtordisp |
2815 | | // FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable |
2816 | | // without vtordisp thunks? |
2817 | | // FIXME: how are vtordisp handled in the presence of nooverride/final? |
2818 | | // |
2819 | | // When foo() is called, an object with a layout of class C has a vftable |
2820 | | // referencing B::f() that assumes a B layout, so the "this" adjustments are |
2821 | | // incorrect, unless an extra adjustment is done. This adjustment is called |
2822 | | // "vtordisp adjustment". Vtordisp basically holds the difference between the |
2823 | | // actual location of a vbase in the layout class and the location assumed by |
2824 | | // the vftable of the class being constructed/destructed. Vtordisp is only |
2825 | | // needed if "this" escapes a |
2826 | | // structor (or we can't prove otherwise). |
2827 | | // [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an |
2828 | | // estimation of a dynamic adjustment] |
2829 | | // |
2830 | | // foo() gets a pointer to the A vbase and doesn't know anything about B or C, |
2831 | | // so it just passes that pointer as "this" in a virtual call. |
2832 | | // If there was no vtordisp, that would just dispatch to B::f(). |
2833 | | // However, B::f() assumes B+8 is passed as "this", |
2834 | | // yet the pointer foo() passes along is B-4 (i.e. C+8). |
2835 | | // An extra adjustment is needed, so we emit a thunk into the B vftable. |
2836 | | // This vtordisp thunk subtracts the value of vtordisp |
2837 | | // from the "this" argument (-12) before making a tailcall to B::f(). |
2838 | | // |
2839 | | // Let's consider an even more complex example: |
2840 | | // struct D : virtual B, virtual C { |
2841 | | // D() { |
2842 | | // foo(this); |
2843 | | // } |
2844 | | // }; |
2845 | | // |
2846 | | // struct D |
2847 | | // 0 | (D vbtable pointer) |
2848 | | // 4 | (vtordisp for vbase A) |
2849 | | // 8 | struct A (virtual base) // A precedes both B and C! |
2850 | | // 8 | (A vftable pointer) |
2851 | | // 12 | struct B (virtual base) // B precedes C! |
2852 | | // 12 | (B vbtable pointer) |
2853 | | // 16 | struct C (virtual base) |
2854 | | // 16 | (C vbtable pointer) |
2855 | | // |
2856 | | // When D::D() calls foo(), we find ourselves in a thunk that should tailcall |
2857 | | // to C::f(), which assumes C+8 as its "this" parameter. This time, foo() |
2858 | | // passes along A, which is C-8. The A vtordisp holds |
2859 | | // "D.vbptr[index_of_A] - offset_of_A_in_D" |
2860 | | // and we statically know offset_of_A_in_D, so can get a pointer to D. |
2861 | | // When we know it, we can make an extra vbtable lookup to locate the C vbase |
2862 | | // and one extra static adjustment to calculate the expected value of C+8. |
2863 | | void VFTableBuilder::CalculateVtordispAdjustment( |
2864 | | FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset, |
2865 | 696 | ThisAdjustment &TA) { |
2866 | 696 | const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap = |
2867 | 696 | MostDerivedClassLayout.getVBaseOffsetsMap(); |
2868 | 696 | const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry = |
2869 | 696 | VBaseMap.find(WhichVFPtr.getVBaseWithVPtr()); |
2870 | 696 | assert(VBaseMapEntry != VBaseMap.end()); |
2871 | | |
2872 | | // If there's no vtordisp or the final overrider is defined in the same vbase |
2873 | | // as the initial declaration, we don't need any vtordisp adjustment. |
2874 | 696 | if (!VBaseMapEntry->second.hasVtorDisp() || |
2875 | 696 | Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr()399 ) |
2876 | 313 | return; |
2877 | | |
2878 | | // OK, now we know we need to use a vtordisp thunk. |
2879 | | // The implicit vtordisp field is located right before the vbase. |
2880 | 383 | CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset; |
2881 | 383 | TA.Virtual.Microsoft.VtordispOffset = |
2882 | 383 | (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4; |
2883 | | |
2884 | | // A simple vtordisp thunk will suffice if the final overrider is defined |
2885 | | // in either the most derived class or its non-virtual base. |
2886 | 383 | if (Overrider.Method->getParent() == MostDerivedClass || |
2887 | 383 | !Overrider.VirtualBase70 ) |
2888 | 339 | return; |
2889 | | |
2890 | | // Otherwise, we need to do use the dynamic offset of the final overrider |
2891 | | // in order to get "this" adjustment right. |
2892 | 44 | TA.Virtual.Microsoft.VBPtrOffset = |
2893 | 44 | (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset - |
2894 | 44 | MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); |
2895 | 44 | TA.Virtual.Microsoft.VBOffsetOffset = |
2896 | 44 | Context.getTypeSizeInChars(Context.IntTy).getQuantity() * |
2897 | 44 | VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase); |
2898 | | |
2899 | 44 | TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity(); |
2900 | 44 | } |
2901 | | |
2902 | | static void GroupNewVirtualOverloads( |
2903 | | const CXXRecordDecl *RD, |
2904 | 2.28k | SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) { |
2905 | | // Put the virtual methods into VirtualMethods in the proper order: |
2906 | | // 1) Group overloads by declaration name. New groups are added to the |
2907 | | // vftable in the order of their first declarations in this class |
2908 | | // (including overrides, non-virtual methods and any other named decl that |
2909 | | // might be nested within the class). |
2910 | | // 2) In each group, new overloads appear in the reverse order of declaration. |
2911 | 2.28k | typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup; |
2912 | 2.28k | SmallVector<MethodGroup, 10> Groups; |
2913 | 2.28k | typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy; |
2914 | 2.28k | VisitedGroupIndicesTy VisitedGroupIndices; |
2915 | 16.3k | for (const auto *D : RD->decls()) { |
2916 | 16.3k | const auto *ND = dyn_cast<NamedDecl>(D); |
2917 | 16.3k | if (!ND) |
2918 | 205 | continue; |
2919 | 16.1k | VisitedGroupIndicesTy::iterator J; |
2920 | 16.1k | bool Inserted; |
2921 | 16.1k | std::tie(J, Inserted) = VisitedGroupIndices.insert( |
2922 | 16.1k | std::make_pair(ND->getDeclName(), Groups.size())); |
2923 | 16.1k | if (Inserted) |
2924 | 11.4k | Groups.push_back(MethodGroup()); |
2925 | 16.1k | if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) |
2926 | 13.4k | if (MicrosoftVTableContext::hasVtableSlot(MD)) |
2927 | 2.77k | Groups[J->second].push_back(MD->getCanonicalDecl()); |
2928 | 16.1k | } |
2929 | | |
2930 | 2.28k | for (const MethodGroup &Group : Groups) |
2931 | 11.4k | VirtualMethods.append(Group.rbegin(), Group.rend()); |
2932 | 2.28k | } |
2933 | | |
2934 | 997 | static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) { |
2935 | 1.53k | for (const auto &B : RD->bases()) { |
2936 | 1.53k | if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base412 ) |
2937 | 322 | return true; |
2938 | 1.53k | } |
2939 | 675 | return false; |
2940 | 997 | } |
2941 | | |
2942 | | void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, |
2943 | | const CXXRecordDecl *LastVBase, |
2944 | 2.28k | BasesSetVectorTy &VisitedBases) { |
2945 | 2.28k | const CXXRecordDecl *RD = Base.getBase(); |
2946 | 2.28k | if (!RD->isPolymorphic()) |
2947 | 0 | return; |
2948 | | |
2949 | 2.28k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
2950 | | |
2951 | | // See if this class expands a vftable of the base we look at, which is either |
2952 | | // the one defined by the vfptr base path or the primary base of the current |
2953 | | // class. |
2954 | 2.28k | const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase; |
2955 | 2.28k | CharUnits NextBaseOffset; |
2956 | 2.28k | if (BaseDepth < WhichVFPtr.PathToIntroducingObject.size()) { |
2957 | 997 | NextBase = WhichVFPtr.PathToIntroducingObject[BaseDepth]; |
2958 | 997 | if (isDirectVBase(NextBase, RD)) { |
2959 | 322 | NextLastVBase = NextBase; |
2960 | 322 | NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase); |
2961 | 675 | } else { |
2962 | 675 | NextBaseOffset = |
2963 | 675 | Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase); |
2964 | 675 | } |
2965 | 1.28k | } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { |
2966 | 0 | assert(!Layout.isPrimaryBaseVirtual() && |
2967 | 0 | "No primary virtual bases in this ABI"); |
2968 | 0 | NextBase = PrimaryBase; |
2969 | 0 | NextBaseOffset = Base.getBaseOffset(); |
2970 | 0 | } |
2971 | | |
2972 | 2.28k | if (NextBase) { |
2973 | 997 | AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1, |
2974 | 997 | NextLastVBase, VisitedBases); |
2975 | 997 | if (!VisitedBases.insert(NextBase)) |
2976 | 0 | llvm_unreachable("Found a duplicate primary base!"); |
2977 | 997 | } |
2978 | | |
2979 | 2.28k | SmallVector<const CXXMethodDecl*, 10> VirtualMethods; |
2980 | | // Put virtual methods in the proper order. |
2981 | 2.28k | GroupNewVirtualOverloads(RD, VirtualMethods); |
2982 | | |
2983 | | // Now go through all virtual member functions and add them to the current |
2984 | | // vftable. This is done by |
2985 | | // - replacing overridden methods in their existing slots, as long as they |
2986 | | // don't require return adjustment; calculating This adjustment if needed. |
2987 | | // - adding new slots for methods of the current base not present in any |
2988 | | // sub-bases; |
2989 | | // - adding new slots for methods that require Return adjustment. |
2990 | | // We keep track of the methods visited in the sub-bases in MethodInfoMap. |
2991 | 2.77k | for (const CXXMethodDecl *MD : VirtualMethods) { |
2992 | 2.77k | FinalOverriders::OverriderInfo FinalOverrider = |
2993 | 2.77k | Overriders.getOverrider(MD, Base.getBaseOffset()); |
2994 | 2.77k | const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method; |
2995 | 2.77k | const CXXMethodDecl *OverriddenMD = |
2996 | 2.77k | FindNearestOverriddenMethod(MD, VisitedBases); |
2997 | | |
2998 | 2.77k | ThisAdjustment ThisAdjustmentOffset; |
2999 | 2.77k | bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false; |
3000 | 2.77k | CharUnits ThisOffset = ComputeThisOffset(FinalOverrider); |
3001 | 2.77k | ThisAdjustmentOffset.NonVirtual = |
3002 | 2.77k | (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity(); |
3003 | 2.77k | if ((OverriddenMD || FinalOverriderMD != MD2.00k ) && |
3004 | 2.77k | WhichVFPtr.getVBaseWithVPtr()1.41k ) |
3005 | 696 | CalculateVtordispAdjustment(FinalOverrider, ThisOffset, |
3006 | 696 | ThisAdjustmentOffset); |
3007 | | |
3008 | 2.77k | unsigned VBIndex = |
3009 | 2.77k | LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase)555 : 02.22k ; |
3010 | | |
3011 | 2.77k | if (OverriddenMD) { |
3012 | | // If MD overrides anything in this vftable, we need to update the |
3013 | | // entries. |
3014 | 773 | MethodInfoMapTy::iterator OverriddenMDIterator = |
3015 | 773 | MethodInfoMap.find(OverriddenMD); |
3016 | | |
3017 | | // If the overridden method went to a different vftable, skip it. |
3018 | 773 | if (OverriddenMDIterator == MethodInfoMap.end()) |
3019 | 32 | continue; |
3020 | | |
3021 | 741 | MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; |
3022 | | |
3023 | 741 | VBIndex = OverriddenMethodInfo.VBTableIndex; |
3024 | | |
3025 | | // Let's check if the overrider requires any return adjustments. |
3026 | | // We must create a new slot if the MD's return type is not trivially |
3027 | | // convertible to the OverriddenMD's one. |
3028 | | // Once a chain of method overrides adds a return adjusting vftable slot, |
3029 | | // all subsequent overrides will also use an extra method slot. |
3030 | 741 | ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset( |
3031 | 741 | Context, MD, OverriddenMD).isEmpty() || |
3032 | 741 | OverriddenMethodInfo.UsesExtraSlot675 ; |
3033 | | |
3034 | 741 | if (!ReturnAdjustingThunk) { |
3035 | | // No return adjustment needed - just replace the overridden method info |
3036 | | // with the current info. |
3037 | 666 | MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex); |
3038 | 666 | MethodInfoMap.erase(OverriddenMDIterator); |
3039 | | |
3040 | 666 | assert(!MethodInfoMap.count(MD) && |
3041 | 666 | "Should not have method info for this method yet!"); |
3042 | 666 | MethodInfoMap.insert(std::make_pair(MD, MI)); |
3043 | 666 | continue; |
3044 | 666 | } |
3045 | | |
3046 | | // In case we need a return adjustment, we'll add a new slot for |
3047 | | // the overrider. Mark the overridden method as shadowed by the new slot. |
3048 | 75 | OverriddenMethodInfo.Shadowed = true; |
3049 | | |
3050 | | // Force a special name mangling for a return-adjusting thunk |
3051 | | // unless the method is the final overrider without this adjustment. |
3052 | 75 | ForceReturnAdjustmentMangling = |
3053 | 75 | !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty()61 ); |
3054 | 2.00k | } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC || |
3055 | 2.00k | MD->size_overridden_methods()1.86k ) { |
3056 | | // Skip methods that don't belong to the vftable of the current class, |
3057 | | // e.g. each method that wasn't seen in any of the visited sub-bases |
3058 | | // but overrides multiple methods of other sub-bases. |
3059 | 238 | continue; |
3060 | 238 | } |
3061 | | |
3062 | | // If we got here, MD is a method not seen in any of the sub-bases or |
3063 | | // it requires return adjustment. Insert the method info for this method. |
3064 | 1.84k | MethodInfo MI(VBIndex, |
3065 | 1.84k | HasRTTIComponent ? Components.size() - 1613 : Components.size()1.22k , |
3066 | 1.84k | ReturnAdjustingThunk); |
3067 | | |
3068 | 1.84k | assert(!MethodInfoMap.count(MD) && |
3069 | 1.84k | "Should not have method info for this method yet!"); |
3070 | 1.84k | MethodInfoMap.insert(std::make_pair(MD, MI)); |
3071 | | |
3072 | | // Check if this overrider needs a return adjustment. |
3073 | | // We don't want to do this for pure virtual member functions. |
3074 | 1.84k | BaseOffset ReturnAdjustmentOffset; |
3075 | 1.84k | ReturnAdjustment ReturnAdjustment; |
3076 | 1.84k | if (!FinalOverriderMD->isPure()) { |
3077 | 1.80k | ReturnAdjustmentOffset = |
3078 | 1.80k | ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD); |
3079 | 1.80k | } |
3080 | 1.84k | if (!ReturnAdjustmentOffset.isEmpty()) { |
3081 | 66 | ForceReturnAdjustmentMangling = true; |
3082 | 66 | ReturnAdjustment.NonVirtual = |
3083 | 66 | ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); |
3084 | 66 | if (ReturnAdjustmentOffset.VirtualBase) { |
3085 | 36 | const ASTRecordLayout &DerivedLayout = |
3086 | 36 | Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass); |
3087 | 36 | ReturnAdjustment.Virtual.Microsoft.VBPtrOffset = |
3088 | 36 | DerivedLayout.getVBPtrOffset().getQuantity(); |
3089 | 36 | ReturnAdjustment.Virtual.Microsoft.VBIndex = |
3090 | 36 | VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass, |
3091 | 36 | ReturnAdjustmentOffset.VirtualBase); |
3092 | 36 | } |
3093 | 66 | } |
3094 | | |
3095 | 1.84k | AddMethod(FinalOverriderMD, |
3096 | 1.84k | ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, |
3097 | 1.84k | ForceReturnAdjustmentMangling ? MD91 : nullptr1.75k )); |
3098 | 1.84k | } |
3099 | 2.28k | } |
3100 | | |
3101 | 394 | static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out) { |
3102 | 485 | for (const CXXRecordDecl *Elem : llvm::reverse(Path)) { |
3103 | 485 | Out << "'"; |
3104 | 485 | Elem->printQualifiedName(Out); |
3105 | 485 | Out << "' in "; |
3106 | 485 | } |
3107 | 394 | } |
3108 | | |
3109 | | static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, |
3110 | 366 | bool ContinueFirstLine) { |
3111 | 366 | const ReturnAdjustment &R = TI.Return; |
3112 | 366 | bool Multiline = false; |
3113 | 366 | const char *LinePrefix = "\n "; |
3114 | 366 | if (!R.isEmpty() || TI.Method290 ) { |
3115 | 104 | if (!ContinueFirstLine) |
3116 | 52 | Out << LinePrefix; |
3117 | 104 | Out << "[return adjustment (to type '" |
3118 | 104 | << TI.Method->getReturnType().getCanonicalType() << "'): "; |
3119 | 104 | if (R.Virtual.Microsoft.VBPtrOffset) |
3120 | 2 | Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", "; |
3121 | 104 | if (R.Virtual.Microsoft.VBIndex) |
3122 | 34 | Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", "; |
3123 | 104 | Out << R.NonVirtual << " non-virtual]"; |
3124 | 104 | Multiline = true; |
3125 | 104 | } |
3126 | | |
3127 | 366 | const ThisAdjustment &T = TI.This; |
3128 | 366 | if (!T.isEmpty()) { |
3129 | 300 | if (Multiline || !ContinueFirstLine262 ) |
3130 | 169 | Out << LinePrefix; |
3131 | 300 | Out << "[this adjustment: "; |
3132 | 300 | if (!TI.This.Virtual.isEmpty()) { |
3133 | 210 | assert(T.Virtual.Microsoft.VtordispOffset < 0); |
3134 | 210 | Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", "; |
3135 | 210 | if (T.Virtual.Microsoft.VBPtrOffset) { |
3136 | 40 | Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset |
3137 | 40 | << " to the left,"; |
3138 | 40 | assert(T.Virtual.Microsoft.VBOffsetOffset > 0); |
3139 | 40 | Out << LinePrefix << " vboffset at " |
3140 | 40 | << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, "; |
3141 | 40 | } |
3142 | 210 | } |
3143 | 300 | Out << T.NonVirtual << " non-virtual]"; |
3144 | 300 | } |
3145 | 366 | } |
3146 | | |
3147 | 394 | void VFTableBuilder::dumpLayout(raw_ostream &Out) { |
3148 | 394 | Out << "VFTable for "; |
3149 | 394 | PrintBasePath(WhichVFPtr.PathToIntroducingObject, Out); |
3150 | 394 | Out << "'"; |
3151 | 394 | MostDerivedClass->printQualifiedName(Out); |
3152 | 394 | Out << "' (" << Components.size() |
3153 | 394 | << (Components.size() == 1 ? " entry"137 : " entries"257 ) << ").\n"; |
3154 | | |
3155 | 1.12k | for (unsigned I = 0, E = Components.size(); I != E; ++I733 ) { |
3156 | 733 | Out << llvm::format("%4d | ", I); |
3157 | | |
3158 | 733 | const VTableComponent &Component = Components[I]; |
3159 | | |
3160 | | // Dump the component. |
3161 | 733 | switch (Component.getKind()) { |
3162 | 0 | case VTableComponent::CK_RTTI: |
3163 | 0 | Component.getRTTIDecl()->printQualifiedName(Out); |
3164 | 0 | Out << " RTTI"; |
3165 | 0 | break; |
3166 | | |
3167 | 634 | case VTableComponent::CK_FunctionPointer: { |
3168 | 634 | const CXXMethodDecl *MD = Component.getFunctionDecl(); |
3169 | | |
3170 | | // FIXME: Figure out how to print the real thunk type, since they can |
3171 | | // differ in the return type. |
3172 | 634 | std::string Str = PredefinedExpr::ComputeName( |
3173 | 634 | PredefinedExpr::PrettyFunctionNoVirtual, MD); |
3174 | 634 | Out << Str; |
3175 | 634 | if (MD->isPure()) |
3176 | 5 | Out << " [pure]"; |
3177 | | |
3178 | 634 | if (MD->isDeleted()) |
3179 | 1 | Out << " [deleted]"; |
3180 | | |
3181 | 634 | ThunkInfo Thunk = VTableThunks.lookup(I); |
3182 | 634 | if (!Thunk.isEmpty()) |
3183 | 119 | dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); |
3184 | | |
3185 | 634 | break; |
3186 | 0 | } |
3187 | | |
3188 | 99 | case VTableComponent::CK_DeletingDtorPointer: { |
3189 | 99 | const CXXDestructorDecl *DD = Component.getDestructorDecl(); |
3190 | | |
3191 | 99 | DD->printQualifiedName(Out); |
3192 | 99 | Out << "() [scalar deleting]"; |
3193 | | |
3194 | 99 | if (DD->isPure()) |
3195 | 0 | Out << " [pure]"; |
3196 | | |
3197 | 99 | ThunkInfo Thunk = VTableThunks.lookup(I); |
3198 | 99 | if (!Thunk.isEmpty()) { |
3199 | 64 | assert(Thunk.Return.isEmpty() && |
3200 | 64 | "No return adjustment needed for destructors!"); |
3201 | 64 | dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); |
3202 | 64 | } |
3203 | | |
3204 | 99 | break; |
3205 | 99 | } |
3206 | | |
3207 | 99 | default: |
3208 | 0 | DiagnosticsEngine &Diags = Context.getDiagnostics(); |
3209 | 0 | unsigned DiagID = Diags.getCustomDiagID( |
3210 | 0 | DiagnosticsEngine::Error, |
3211 | 0 | "Unexpected vftable component type %0 for component number %1"); |
3212 | 0 | Diags.Report(MostDerivedClass->getLocation(), DiagID) |
3213 | 0 | << I << Component.getKind(); |
3214 | 733 | } |
3215 | | |
3216 | 733 | Out << '\n'; |
3217 | 733 | } |
3218 | | |
3219 | 394 | Out << '\n'; |
3220 | | |
3221 | 394 | if (!Thunks.empty()) { |
3222 | | // We store the method names in a map to get a stable order. |
3223 | 121 | std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; |
3224 | | |
3225 | 164 | for (const auto &I : Thunks) { |
3226 | 164 | const CXXMethodDecl *MD = I.first; |
3227 | 164 | std::string MethodName = PredefinedExpr::ComputeName( |
3228 | 164 | PredefinedExpr::PrettyFunctionNoVirtual, MD); |
3229 | | |
3230 | 164 | MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); |
3231 | 164 | } |
3232 | | |
3233 | 164 | for (const auto &MethodNameAndDecl : MethodNamesAndDecls) { |
3234 | 164 | const std::string &MethodName = MethodNameAndDecl.first; |
3235 | 164 | const CXXMethodDecl *MD = MethodNameAndDecl.second; |
3236 | | |
3237 | 164 | ThunkInfoVectorTy ThunksVector = Thunks[MD]; |
3238 | 164 | llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS, |
3239 | 164 | const ThunkInfo &RHS) { |
3240 | | // Keep different thunks with the same adjustments in the order they |
3241 | | // were put into the vector. |
3242 | 23 | return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); |
3243 | 23 | }); |
3244 | | |
3245 | 164 | Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); |
3246 | 164 | Out << (ThunksVector.size() == 1 ? " entry"149 : " entries"15 ) << ").\n"; |
3247 | | |
3248 | 347 | for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I183 ) { |
3249 | 183 | const ThunkInfo &Thunk = ThunksVector[I]; |
3250 | | |
3251 | 183 | Out << llvm::format("%4d | ", I); |
3252 | 183 | dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true); |
3253 | 183 | Out << '\n'; |
3254 | 183 | } |
3255 | | |
3256 | 164 | Out << '\n'; |
3257 | 164 | } |
3258 | 121 | } |
3259 | | |
3260 | 394 | Out.flush(); |
3261 | 394 | } |
3262 | | |
3263 | | static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A, |
3264 | 1.10k | ArrayRef<const CXXRecordDecl *> B) { |
3265 | 1.10k | for (const CXXRecordDecl *Decl : B) { |
3266 | 310 | if (A.count(Decl)) |
3267 | 39 | return true; |
3268 | 310 | } |
3269 | 1.06k | return false; |
3270 | 1.10k | } |
3271 | | |
3272 | | static bool rebucketPaths(VPtrInfoVector &Paths); |
3273 | | |
3274 | | /// Produces MSVC-compatible vbtable data. The symbols produced by this |
3275 | | /// algorithm match those produced by MSVC 2012 and newer, which is different |
3276 | | /// from MSVC 2010. |
3277 | | /// |
3278 | | /// MSVC 2012 appears to minimize the vbtable names using the following |
3279 | | /// algorithm. First, walk the class hierarchy in the usual order, depth first, |
3280 | | /// left to right, to find all of the subobjects which contain a vbptr field. |
3281 | | /// Visiting each class node yields a list of inheritance paths to vbptrs. Each |
3282 | | /// record with a vbptr creates an initially empty path. |
3283 | | /// |
3284 | | /// To combine paths from child nodes, the paths are compared to check for |
3285 | | /// ambiguity. Paths are "ambiguous" if multiple paths have the same set of |
3286 | | /// components in the same order. Each group of ambiguous paths is extended by |
3287 | | /// appending the class of the base from which it came. If the current class |
3288 | | /// node produced an ambiguous path, its path is extended with the current class. |
3289 | | /// After extending paths, MSVC again checks for ambiguity, and extends any |
3290 | | /// ambiguous path which wasn't already extended. Because each node yields an |
3291 | | /// unambiguous set of paths, MSVC doesn't need to extend any path more than once |
3292 | | /// to produce an unambiguous set of paths. |
3293 | | /// |
3294 | | /// TODO: Presumably vftables use the same algorithm. |
3295 | | void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables, |
3296 | | const CXXRecordDecl *RD, |
3297 | 1.81k | VPtrInfoVector &Paths) { |
3298 | 1.81k | assert(Paths.empty()); |
3299 | 1.81k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
3300 | | |
3301 | | // Base case: this subobject has its own vptr. |
3302 | 1.81k | if (ForVBTables ? Layout.hasOwnVBPtr()617 : Layout.hasOwnVFPtr()1.19k ) |
3303 | 872 | Paths.push_back(std::make_unique<VPtrInfo>(RD)); |
3304 | | |
3305 | | // Recursive case: get all the vbtables from our bases and remove anything |
3306 | | // that shares a virtual base. |
3307 | 1.81k | llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen; |
3308 | 1.81k | for (const auto &B : RD->bases()) { |
3309 | 1.61k | const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); |
3310 | 1.61k | if (B.isVirtual() && VBasesSeen.count(Base)706 ) |
3311 | 52 | continue; |
3312 | | |
3313 | 1.56k | if (!Base->isDynamicClass()) |
3314 | 241 | continue; |
3315 | | |
3316 | 1.32k | const VPtrInfoVector &BasePaths = |
3317 | 1.32k | ForVBTables ? enumerateVBTables(Base)520 : getVFPtrOffsets(Base)800 ; |
3318 | | |
3319 | 1.32k | for (const std::unique_ptr<VPtrInfo> &BaseInfo : BasePaths) { |
3320 | | // Don't include the path if it goes through a virtual base that we've |
3321 | | // already included. |
3322 | 1.10k | if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases)) |
3323 | 39 | continue; |
3324 | | |
3325 | | // Copy the path and adjust it as necessary. |
3326 | 1.06k | auto P = std::make_unique<VPtrInfo>(*BaseInfo); |
3327 | | |
3328 | | // We mangle Base into the path if the path would've been ambiguous and it |
3329 | | // wasn't already extended with Base. |
3330 | 1.06k | if (P->MangledPath.empty() || P->MangledPath.back() != Base259 ) |
3331 | 1.02k | P->NextBaseToMangle = Base; |
3332 | | |
3333 | | // Keep track of which vtable the derived class is going to extend with |
3334 | | // new methods or bases. We append to either the vftable of our primary |
3335 | | // base, or the first non-virtual base that has a vbtable. |
3336 | 1.06k | if (P->ObjectWithVPtr == Base && |
3337 | 1.06k | Base == (828 ForVBTables828 ? Layout.getBaseSharingVBPtr()265 |
3338 | 828 | : Layout.getPrimaryBase()563 )) |
3339 | 417 | P->ObjectWithVPtr = RD; |
3340 | | |
3341 | | // Keep track of the full adjustment from the MDC to this vtable. The |
3342 | | // adjustment is captured by an optional vbase and a non-virtual offset. |
3343 | 1.06k | if (B.isVirtual()) |
3344 | 337 | P->ContainingVBases.push_back(Base); |
3345 | 731 | else if (P->ContainingVBases.empty()) |
3346 | 632 | P->NonVirtualOffset += Layout.getBaseClassOffset(Base); |
3347 | | |
3348 | | // Update the full offset in the MDC. |
3349 | 1.06k | P->FullOffsetInMDC = P->NonVirtualOffset; |
3350 | 1.06k | if (const CXXRecordDecl *VB = P->getVBaseWithVPtr()) |
3351 | 436 | P->FullOffsetInMDC += Layout.getVBaseClassOffset(VB); |
3352 | | |
3353 | 1.06k | Paths.push_back(std::move(P)); |
3354 | 1.06k | } |
3355 | | |
3356 | 1.32k | if (B.isVirtual()) |
3357 | 473 | VBasesSeen.insert(Base); |
3358 | | |
3359 | | // After visiting any direct base, we've transitively visited all of its |
3360 | | // morally virtual bases. |
3361 | 1.32k | for (const auto &VB : Base->vbases()) |
3362 | 697 | VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl()); |
3363 | 1.32k | } |
3364 | | |
3365 | | // Sort the paths into buckets, and if any of them are ambiguous, extend all |
3366 | | // paths in ambiguous buckets. |
3367 | 1.81k | bool Changed = true; |
3368 | 3.89k | while (Changed) |
3369 | 2.08k | Changed = rebucketPaths(Paths); |
3370 | 1.81k | } |
3371 | | |
3372 | 584 | static bool extendPath(VPtrInfo &P) { |
3373 | 584 | if (P.NextBaseToMangle) { |
3374 | 564 | P.MangledPath.push_back(P.NextBaseToMangle); |
3375 | 564 | P.NextBaseToMangle = nullptr;// Prevent the path from being extended twice. |
3376 | 564 | return true; |
3377 | 564 | } |
3378 | 20 | return false; |
3379 | 584 | } |
3380 | | |
3381 | 2.08k | static bool rebucketPaths(VPtrInfoVector &Paths) { |
3382 | | // What we're essentially doing here is bucketing together ambiguous paths. |
3383 | | // Any bucket with more than one path in it gets extended by NextBase, which |
3384 | | // is usually the direct base of the inherited the vbptr. This code uses a |
3385 | | // sorted vector to implement a multiset to form the buckets. Note that the |
3386 | | // ordering is based on pointers, but it doesn't change our output order. The |
3387 | | // current algorithm is designed to match MSVC 2012's names. |
3388 | 2.08k | llvm::SmallVector<std::reference_wrapper<VPtrInfo>, 2> PathsSorted( |
3389 | 2.08k | llvm::make_pointee_range(Paths)); |
3390 | 2.08k | llvm::sort(PathsSorted, [](const VPtrInfo &LHS, const VPtrInfo &RHS) { |
3391 | 1.26k | return LHS.MangledPath < RHS.MangledPath; |
3392 | 1.26k | }); |
3393 | 2.08k | bool Changed = false; |
3394 | 4.37k | for (size_t I = 0, E = PathsSorted.size(); I != E;) { |
3395 | | // Scan forward to find the end of the bucket. |
3396 | 2.29k | size_t BucketStart = I; |
3397 | 2.59k | do { |
3398 | 2.59k | ++I; |
3399 | 2.59k | } while (I != E && |
3400 | 2.59k | PathsSorted[BucketStart].get().MangledPath == |
3401 | 856 | PathsSorted[I].get().MangledPath); |
3402 | | |
3403 | | // If this bucket has multiple paths, extend them all. |
3404 | 2.29k | if (I - BucketStart > 1) { |
3405 | 866 | for (size_t II = BucketStart; II != I; ++II584 ) |
3406 | 584 | Changed |= extendPath(PathsSorted[II]); |
3407 | 282 | assert(Changed && "no paths were extended to fix ambiguity"); |
3408 | 282 | } |
3409 | 2.29k | } |
3410 | 2.08k | return Changed; |
3411 | 2.08k | } |
3412 | | |
3413 | 823 | MicrosoftVTableContext::~MicrosoftVTableContext() {} |
3414 | | |
3415 | | namespace { |
3416 | | typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>, |
3417 | | llvm::DenseSet<BaseSubobject>> FullPathTy; |
3418 | | } |
3419 | | |
3420 | | // This recursive function finds all paths from a subobject centered at |
3421 | | // (RD, Offset) to the subobject located at IntroducingObject. |
3422 | | static void findPathsToSubobject(ASTContext &Context, |
3423 | | const ASTRecordLayout &MostDerivedLayout, |
3424 | | const CXXRecordDecl *RD, CharUnits Offset, |
3425 | | BaseSubobject IntroducingObject, |
3426 | | FullPathTy &FullPath, |
3427 | 2.99k | std::list<FullPathTy> &Paths) { |
3428 | 2.99k | if (BaseSubobject(RD, Offset) == IntroducingObject) { |
3429 | 1.32k | Paths.push_back(FullPath); |
3430 | 1.32k | return; |
3431 | 1.32k | } |
3432 | | |
3433 | 1.67k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
3434 | | |
3435 | 1.71k | for (const CXXBaseSpecifier &BS : RD->bases()) { |
3436 | 1.71k | const CXXRecordDecl *Base = BS.getType()->getAsCXXRecordDecl(); |
3437 | 1.71k | CharUnits NewOffset = BS.isVirtual() |
3438 | 1.71k | ? MostDerivedLayout.getVBaseClassOffset(Base)495 |
3439 | 1.71k | : Offset + Layout.getBaseClassOffset(Base)1.21k ; |
3440 | 1.71k | FullPath.insert(BaseSubobject(Base, NewOffset)); |
3441 | 1.71k | findPathsToSubobject(Context, MostDerivedLayout, Base, NewOffset, |
3442 | 1.71k | IntroducingObject, FullPath, Paths); |
3443 | 1.71k | FullPath.pop_back(); |
3444 | 1.71k | } |
3445 | 1.67k | } |
3446 | | |
3447 | | // Return the paths which are not subsets of other paths. |
3448 | 1.28k | static void removeRedundantPaths(std::list<FullPathTy> &FullPaths) { |
3449 | 1.32k | FullPaths.remove_if([&](const FullPathTy &SpecificPath) { |
3450 | 1.38k | for (const FullPathTy &OtherPath : FullPaths) { |
3451 | 1.38k | if (&SpecificPath == &OtherPath) |
3452 | 1.31k | continue; |
3453 | 84 | if (77 llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) 77 { |
3454 | 84 | return OtherPath.contains(BSO); |
3455 | 84 | })) { |
3456 | 16 | return true; |
3457 | 16 | } |
3458 | 77 | } |
3459 | 1.30k | return false; |
3460 | 1.32k | }); |
3461 | 1.28k | } |
3462 | | |
3463 | | static CharUnits getOffsetOfFullPath(ASTContext &Context, |
3464 | | const CXXRecordDecl *RD, |
3465 | 44 | const FullPathTy &FullPath) { |
3466 | 44 | const ASTRecordLayout &MostDerivedLayout = |
3467 | 44 | Context.getASTRecordLayout(RD); |
3468 | 44 | CharUnits Offset = CharUnits::fromQuantity(-1); |
3469 | 102 | for (const BaseSubobject &BSO : FullPath) { |
3470 | 102 | const CXXRecordDecl *Base = BSO.getBase(); |
3471 | | // The first entry in the path is always the most derived record, skip it. |
3472 | 102 | if (Base == RD) { |
3473 | 44 | assert(Offset.getQuantity() == -1); |
3474 | 44 | Offset = CharUnits::Zero(); |
3475 | 44 | continue; |
3476 | 44 | } |
3477 | 58 | assert(Offset.getQuantity() != -1); |
3478 | 58 | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
3479 | | // While we know which base has to be traversed, we don't know if that base |
3480 | | // was a virtual base. |
3481 | 58 | const CXXBaseSpecifier *BaseBS = std::find_if( |
3482 | 63 | RD->bases_begin(), RD->bases_end(), [&](const CXXBaseSpecifier &BS) { |
3483 | 63 | return BS.getType()->getAsCXXRecordDecl() == Base; |
3484 | 63 | }); |
3485 | 58 | Offset = BaseBS->isVirtual() ? MostDerivedLayout.getVBaseClassOffset(Base)48 |
3486 | 58 | : Offset + Layout.getBaseClassOffset(Base)10 ; |
3487 | 58 | RD = Base; |
3488 | 58 | } |
3489 | 44 | return Offset; |
3490 | 44 | } |
3491 | | |
3492 | | // We want to select the path which introduces the most covariant overrides. If |
3493 | | // two paths introduce overrides which the other path doesn't contain, issue a |
3494 | | // diagnostic. |
3495 | | static const FullPathTy *selectBestPath(ASTContext &Context, |
3496 | | const CXXRecordDecl *RD, |
3497 | | const VPtrInfo &Info, |
3498 | 1.28k | std::list<FullPathTy> &FullPaths) { |
3499 | | // Handle some easy cases first. |
3500 | 1.28k | if (FullPaths.empty()) |
3501 | 0 | return nullptr; |
3502 | 1.28k | if (FullPaths.size() == 1) |
3503 | 1.26k | return &FullPaths.front(); |
3504 | | |
3505 | 22 | const FullPathTy *BestPath = nullptr; |
3506 | 22 | typedef std::set<const CXXMethodDecl *> OverriderSetTy; |
3507 | 22 | OverriderSetTy LastOverrides; |
3508 | 44 | for (const FullPathTy &SpecificPath : FullPaths) { |
3509 | 44 | assert(!SpecificPath.empty()); |
3510 | 44 | OverriderSetTy CurrentOverrides; |
3511 | 44 | const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase(); |
3512 | | // Find the distance from the start of the path to the subobject with the |
3513 | | // VPtr. |
3514 | 44 | CharUnits BaseOffset = |
3515 | 44 | getOffsetOfFullPath(Context, TopLevelRD, SpecificPath); |
3516 | 44 | FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD); |
3517 | 280 | for (const CXXMethodDecl *MD : Info.IntroducingObject->methods()) { |
3518 | 280 | if (!MicrosoftVTableContext::hasVtableSlot(MD)) |
3519 | 222 | continue; |
3520 | 58 | FinalOverriders::OverriderInfo OI = |
3521 | 58 | Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset); |
3522 | 58 | const CXXMethodDecl *OverridingMethod = OI.Method; |
3523 | | // Only overriders which have a return adjustment introduce problematic |
3524 | | // thunks. |
3525 | 58 | if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD) |
3526 | 58 | .isEmpty()) |
3527 | 49 | continue; |
3528 | | // It's possible that the overrider isn't in this path. If so, skip it |
3529 | | // because this path didn't introduce it. |
3530 | 9 | const CXXRecordDecl *OverridingParent = OverridingMethod->getParent(); |
3531 | 15 | if (llvm::none_of(SpecificPath, [&](const BaseSubobject &BSO) 9 { |
3532 | 15 | return BSO.getBase() == OverridingParent; |
3533 | 15 | })) |
3534 | 0 | continue; |
3535 | 9 | CurrentOverrides.insert(OverridingMethod); |
3536 | 9 | } |
3537 | 44 | OverriderSetTy NewOverrides = |
3538 | 44 | llvm::set_difference(CurrentOverrides, LastOverrides); |
3539 | 44 | if (NewOverrides.empty()) |
3540 | 37 | continue; |
3541 | 7 | OverriderSetTy MissingOverrides = |
3542 | 7 | llvm::set_difference(LastOverrides, CurrentOverrides); |
3543 | 7 | if (MissingOverrides.empty()) { |
3544 | | // This path is a strict improvement over the last path, let's use it. |
3545 | 5 | BestPath = &SpecificPath; |
3546 | 5 | std::swap(CurrentOverrides, LastOverrides); |
3547 | 5 | } else { |
3548 | | // This path introduces an overrider with a conflicting covariant thunk. |
3549 | 2 | DiagnosticsEngine &Diags = Context.getDiagnostics(); |
3550 | 2 | const CXXMethodDecl *CovariantMD = *NewOverrides.begin(); |
3551 | 2 | const CXXMethodDecl *ConflictMD = *MissingOverrides.begin(); |
3552 | 2 | Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component) |
3553 | 2 | << RD; |
3554 | 2 | Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk) |
3555 | 2 | << CovariantMD; |
3556 | 2 | Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk) |
3557 | 2 | << ConflictMD; |
3558 | 2 | } |
3559 | 7 | } |
3560 | | // Go with the path that introduced the most covariant overrides. If there is |
3561 | | // no such path, pick the first path. |
3562 | 22 | return BestPath ? BestPath5 : &FullPaths.front()17 ; |
3563 | 22 | } |
3564 | | |
3565 | | static void computeFullPathsForVFTables(ASTContext &Context, |
3566 | | const CXXRecordDecl *RD, |
3567 | 1.19k | VPtrInfoVector &Paths) { |
3568 | 1.19k | const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD); |
3569 | 1.19k | FullPathTy FullPath; |
3570 | 1.19k | std::list<FullPathTy> FullPaths; |
3571 | 1.28k | for (const std::unique_ptr<VPtrInfo>& Info : Paths) { |
3572 | 1.28k | findPathsToSubobject( |
3573 | 1.28k | Context, MostDerivedLayout, RD, CharUnits::Zero(), |
3574 | 1.28k | BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath, |
3575 | 1.28k | FullPaths); |
3576 | 1.28k | FullPath.clear(); |
3577 | 1.28k | removeRedundantPaths(FullPaths); |
3578 | 1.28k | Info->PathToIntroducingObject.clear(); |
3579 | 1.28k | if (const FullPathTy *BestPath = |
3580 | 1.28k | selectBestPath(Context, RD, *Info, FullPaths)) |
3581 | 1.28k | for (const BaseSubobject &BSO : *BestPath) |
3582 | 997 | Info->PathToIntroducingObject.push_back(BSO.getBase()); |
3583 | 1.28k | FullPaths.clear(); |
3584 | 1.28k | } |
3585 | 1.19k | } |
3586 | | |
3587 | | static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, |
3588 | | const MethodVFTableLocation &LHS, |
3589 | 102 | const MethodVFTableLocation &RHS) { |
3590 | 102 | CharUnits L = LHS.VFPtrOffset; |
3591 | 102 | CharUnits R = RHS.VFPtrOffset; |
3592 | 102 | if (LHS.VBase) |
3593 | 34 | L += Layout.getVBaseClassOffset(LHS.VBase); |
3594 | 102 | if (RHS.VBase) |
3595 | 31 | R += Layout.getVBaseClassOffset(RHS.VBase); |
3596 | 102 | return L < R; |
3597 | 102 | } |
3598 | | |
3599 | | void MicrosoftVTableContext::computeVTableRelatedInformation( |
3600 | 5.38k | const CXXRecordDecl *RD) { |
3601 | 5.38k | assert(RD->isDynamicClass()); |
3602 | | |
3603 | | // Check if we've computed this information before. |
3604 | 5.38k | if (VFPtrLocations.count(RD)) |
3605 | 4.18k | return; |
3606 | | |
3607 | 1.19k | const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap; |
3608 | | |
3609 | 1.19k | { |
3610 | 1.19k | auto VFPtrs = std::make_unique<VPtrInfoVector>(); |
3611 | 1.19k | computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs); |
3612 | 1.19k | computeFullPathsForVFTables(Context, RD, *VFPtrs); |
3613 | 1.19k | VFPtrLocations[RD] = std::move(VFPtrs); |
3614 | 1.19k | } |
3615 | | |
3616 | 1.19k | MethodVFTableLocationsTy NewMethodLocations; |
3617 | 1.28k | for (const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) { |
3618 | 1.28k | VFTableBuilder Builder(*this, RD, *VFPtr); |
3619 | | |
3620 | 1.28k | VFTableIdTy id(RD, VFPtr->FullOffsetInMDC); |
3621 | 1.28k | assert(VFTableLayouts.count(id) == 0); |
3622 | 1.28k | SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks( |
3623 | 1.28k | Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); |
3624 | 1.28k | VFTableLayouts[id] = std::make_unique<VTableLayout>( |
3625 | 1.28k | ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks, |
3626 | 1.28k | EmptyAddressPointsMap); |
3627 | 1.28k | Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); |
3628 | | |
3629 | 1.28k | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
3630 | 1.31k | for (const auto &Loc : Builder.vtable_locations()) { |
3631 | 1.31k | auto Insert = NewMethodLocations.insert(Loc); |
3632 | 1.31k | if (!Insert.second) { |
3633 | 102 | const MethodVFTableLocation &NewLoc = Loc.second; |
3634 | 102 | MethodVFTableLocation &OldLoc = Insert.first->second; |
3635 | 102 | if (vfptrIsEarlierInMDC(Layout, NewLoc, OldLoc)) |
3636 | 3 | OldLoc = NewLoc; |
3637 | 102 | } |
3638 | 1.31k | } |
3639 | 1.28k | } |
3640 | | |
3641 | 1.19k | MethodVFTableLocations.insert(NewMethodLocations.begin(), |
3642 | 1.19k | NewMethodLocations.end()); |
3643 | 1.19k | if (Context.getLangOpts().DumpVTableLayouts) |
3644 | 288 | dumpMethodLocations(RD, NewMethodLocations, llvm::outs()); |
3645 | 1.19k | } |
3646 | | |
3647 | | void MicrosoftVTableContext::dumpMethodLocations( |
3648 | | const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods, |
3649 | 288 | raw_ostream &Out) { |
3650 | | // Compute the vtable indices for all the member functions. |
3651 | | // Store them in a map keyed by the location so we'll get a sorted table. |
3652 | 288 | std::map<MethodVFTableLocation, std::string> IndicesMap; |
3653 | 288 | bool HasNonzeroOffset = false; |
3654 | | |
3655 | 340 | for (const auto &I : NewMethods) { |
3656 | 340 | const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl()); |
3657 | 340 | assert(hasVtableSlot(MD)); |
3658 | | |
3659 | 340 | std::string MethodName = PredefinedExpr::ComputeName( |
3660 | 340 | PredefinedExpr::PrettyFunctionNoVirtual, MD); |
3661 | | |
3662 | 340 | if (isa<CXXDestructorDecl>(MD)) { |
3663 | 71 | IndicesMap[I.second] = MethodName + " [scalar deleting]"; |
3664 | 269 | } else { |
3665 | 269 | IndicesMap[I.second] = MethodName; |
3666 | 269 | } |
3667 | | |
3668 | 340 | if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0310 ) |
3669 | 101 | HasNonzeroOffset = true; |
3670 | 340 | } |
3671 | | |
3672 | | // Print the vtable indices for all the member functions. |
3673 | 288 | if (!IndicesMap.empty()) { |
3674 | 239 | Out << "VFTable indices for "; |
3675 | 239 | Out << "'"; |
3676 | 239 | RD->printQualifiedName(Out); |
3677 | 239 | Out << "' (" << IndicesMap.size() |
3678 | 239 | << (IndicesMap.size() == 1 ? " entry"162 : " entries"77 ) << ").\n"; |
3679 | | |
3680 | 239 | CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1); |
3681 | 239 | uint64_t LastVBIndex = 0; |
3682 | 340 | for (const auto &I : IndicesMap) { |
3683 | 340 | CharUnits VFPtrOffset = I.first.VFPtrOffset; |
3684 | 340 | uint64_t VBIndex = I.first.VBTableIndex; |
3685 | 340 | if (HasNonzeroOffset && |
3686 | 340 | (110 VFPtrOffset != LastVFPtrOffset110 || VBIndex != LastVBIndex19 )) { |
3687 | 96 | assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset); |
3688 | 96 | Out << " -- accessible via "; |
3689 | 96 | if (VBIndex) |
3690 | 65 | Out << "vbtable index " << VBIndex << ", "; |
3691 | 96 | Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n"; |
3692 | 96 | LastVFPtrOffset = VFPtrOffset; |
3693 | 96 | LastVBIndex = VBIndex; |
3694 | 96 | } |
3695 | | |
3696 | 340 | uint64_t VTableIndex = I.first.Index; |
3697 | 340 | const std::string &MethodName = I.second; |
3698 | 340 | Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n'; |
3699 | 340 | } |
3700 | 239 | Out << '\n'; |
3701 | 239 | } |
3702 | | |
3703 | 288 | Out.flush(); |
3704 | 288 | } |
3705 | | |
3706 | | const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation( |
3707 | 3.14k | const CXXRecordDecl *RD) { |
3708 | 3.14k | VirtualBaseInfo *VBI; |
3709 | | |
3710 | 3.14k | { |
3711 | | // Get or create a VBI for RD. Don't hold a reference to the DenseMap cell, |
3712 | | // as it may be modified and rehashed under us. |
3713 | 3.14k | std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD]; |
3714 | 3.14k | if (Entry) |
3715 | 2.53k | return *Entry; |
3716 | 617 | Entry = std::make_unique<VirtualBaseInfo>(); |
3717 | 617 | VBI = Entry.get(); |
3718 | 617 | } |
3719 | | |
3720 | 0 | computeVTablePaths(/*ForVBTables=*/true, RD, VBI->VBPtrPaths); |
3721 | | |
3722 | | // First, see if the Derived class shared the vbptr with a non-virtual base. |
3723 | 617 | const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); |
3724 | 617 | if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) { |
3725 | | // If the Derived class shares the vbptr with a non-virtual base, the shared |
3726 | | // virtual bases come first so that the layout is the same. |
3727 | 139 | const VirtualBaseInfo &BaseInfo = |
3728 | 139 | computeVBTableRelatedInformation(VBPtrBase); |
3729 | 139 | VBI->VBTableIndices.insert(BaseInfo.VBTableIndices.begin(), |
3730 | 139 | BaseInfo.VBTableIndices.end()); |
3731 | 139 | } |
3732 | | |
3733 | | // New vbases are added to the end of the vbtable. |
3734 | | // Skip the self entry and vbases visited in the non-virtual base, if any. |
3735 | 617 | unsigned VBTableIndex = 1 + VBI->VBTableIndices.size(); |
3736 | 618 | for (const auto &VB : RD->vbases()) { |
3737 | 618 | const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl(); |
3738 | 618 | if (!VBI->VBTableIndices.count(CurVBase)) |
3739 | 450 | VBI->VBTableIndices[CurVBase] = VBTableIndex++; |
3740 | 618 | } |
3741 | | |
3742 | 617 | return *VBI; |
3743 | 3.14k | } |
3744 | | |
3745 | | unsigned MicrosoftVTableContext::getVBTableIndex(const CXXRecordDecl *Derived, |
3746 | 2.11k | const CXXRecordDecl *VBase) { |
3747 | 2.11k | const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived); |
3748 | 2.11k | assert(VBInfo.VBTableIndices.count(VBase)); |
3749 | 2.11k | return VBInfo.VBTableIndices.find(VBase)->second; |
3750 | 2.11k | } |
3751 | | |
3752 | | const VPtrInfoVector & |
3753 | 893 | MicrosoftVTableContext::enumerateVBTables(const CXXRecordDecl *RD) { |
3754 | 893 | return computeVBTableRelatedInformation(RD).VBPtrPaths; |
3755 | 893 | } |
3756 | | |
3757 | | const VPtrInfoVector & |
3758 | 3.02k | MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { |
3759 | 3.02k | computeVTableRelatedInformation(RD); |
3760 | | |
3761 | 3.02k | assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations"); |
3762 | 3.02k | return *VFPtrLocations[RD]; |
3763 | 3.02k | } |
3764 | | |
3765 | | const VTableLayout & |
3766 | | MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD, |
3767 | 1.64k | CharUnits VFPtrOffset) { |
3768 | 1.64k | computeVTableRelatedInformation(RD); |
3769 | | |
3770 | 1.64k | VFTableIdTy id(RD, VFPtrOffset); |
3771 | 1.64k | assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset"); |
3772 | 1.64k | return *VFTableLayouts[id]; |
3773 | 1.64k | } |
3774 | | |
3775 | | MethodVFTableLocation |
3776 | 7.92k | MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) { |
3777 | 7.92k | assert(hasVtableSlot(cast<CXXMethodDecl>(GD.getDecl())) && |
3778 | 7.92k | "Only use this method for virtual methods or dtors"); |
3779 | 7.92k | if (isa<CXXDestructorDecl>(GD.getDecl())) |
3780 | 4.48k | assert(GD.getDtorType() == Dtor_Deleting); |
3781 | | |
3782 | 7.92k | GD = GD.getCanonicalDecl(); |
3783 | | |
3784 | 7.92k | MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD); |
3785 | 7.92k | if (I != MethodVFTableLocations.end()) |
3786 | 7.65k | return I->second; |
3787 | | |
3788 | 275 | const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); |
3789 | | |
3790 | 275 | computeVTableRelatedInformation(RD); |
3791 | | |
3792 | 275 | I = MethodVFTableLocations.find(GD); |
3793 | 275 | assert(I != MethodVFTableLocations.end() && "Did not find index!"); |
3794 | 275 | return I->second; |
3795 | 275 | } |