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