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