xref: /aosp_15_r20/external/clang/lib/AST/VTTBuilder.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This contains code dealing with generation of the layout of virtual table
11*67e74705SXin Li // tables (VTT).
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li 
15*67e74705SXin Li #include "clang/AST/VTTBuilder.h"
16*67e74705SXin Li #include "clang/AST/ASTContext.h"
17*67e74705SXin Li #include "clang/AST/CXXInheritance.h"
18*67e74705SXin Li #include "clang/AST/RecordLayout.h"
19*67e74705SXin Li #include "clang/Basic/TargetInfo.h"
20*67e74705SXin Li #include "llvm/Support/Format.h"
21*67e74705SXin Li #include <algorithm>
22*67e74705SXin Li #include <cstdio>
23*67e74705SXin Li 
24*67e74705SXin Li using namespace clang;
25*67e74705SXin Li 
26*67e74705SXin Li #define DUMP_OVERRIDERS 0
27*67e74705SXin Li 
VTTBuilder(ASTContext & Ctx,const CXXRecordDecl * MostDerivedClass,bool GenerateDefinition)28*67e74705SXin Li VTTBuilder::VTTBuilder(ASTContext &Ctx,
29*67e74705SXin Li                        const CXXRecordDecl *MostDerivedClass,
30*67e74705SXin Li                        bool GenerateDefinition)
31*67e74705SXin Li   : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
32*67e74705SXin Li   MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
33*67e74705SXin Li     GenerateDefinition(GenerateDefinition) {
34*67e74705SXin Li   // Lay out this VTT.
35*67e74705SXin Li   LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
36*67e74705SXin Li             /*BaseIsVirtual=*/false);
37*67e74705SXin Li }
38*67e74705SXin Li 
AddVTablePointer(BaseSubobject Base,uint64_t VTableIndex,const CXXRecordDecl * VTableClass)39*67e74705SXin Li void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
40*67e74705SXin Li                                   const CXXRecordDecl *VTableClass) {
41*67e74705SXin Li   // Store the vtable pointer index if we're generating the primary VTT.
42*67e74705SXin Li   if (VTableClass == MostDerivedClass) {
43*67e74705SXin Li     assert(!SecondaryVirtualPointerIndices.count(Base) &&
44*67e74705SXin Li            "A virtual pointer index already exists for this base subobject!");
45*67e74705SXin Li     SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
46*67e74705SXin Li   }
47*67e74705SXin Li 
48*67e74705SXin Li   if (!GenerateDefinition) {
49*67e74705SXin Li     VTTComponents.push_back(VTTComponent());
50*67e74705SXin Li     return;
51*67e74705SXin Li   }
52*67e74705SXin Li 
53*67e74705SXin Li   VTTComponents.push_back(VTTComponent(VTableIndex, Base));
54*67e74705SXin Li }
55*67e74705SXin Li 
LayoutSecondaryVTTs(BaseSubobject Base)56*67e74705SXin Li void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
57*67e74705SXin Li   const CXXRecordDecl *RD = Base.getBase();
58*67e74705SXin Li 
59*67e74705SXin Li   for (const auto &I : RD->bases()) {
60*67e74705SXin Li     // Don't layout virtual bases.
61*67e74705SXin Li     if (I.isVirtual())
62*67e74705SXin Li         continue;
63*67e74705SXin Li 
64*67e74705SXin Li     const CXXRecordDecl *BaseDecl =
65*67e74705SXin Li       cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
66*67e74705SXin Li 
67*67e74705SXin Li     const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
68*67e74705SXin Li     CharUnits BaseOffset = Base.getBaseOffset() +
69*67e74705SXin Li       Layout.getBaseClassOffset(BaseDecl);
70*67e74705SXin Li 
71*67e74705SXin Li     // Layout the VTT for this base.
72*67e74705SXin Li     LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
73*67e74705SXin Li   }
74*67e74705SXin Li }
75*67e74705SXin Li 
76*67e74705SXin Li void
LayoutSecondaryVirtualPointers(BaseSubobject Base,bool BaseIsMorallyVirtual,uint64_t VTableIndex,const CXXRecordDecl * VTableClass,VisitedVirtualBasesSetTy & VBases)77*67e74705SXin Li VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
78*67e74705SXin Li                                            bool BaseIsMorallyVirtual,
79*67e74705SXin Li                                            uint64_t VTableIndex,
80*67e74705SXin Li                                            const CXXRecordDecl *VTableClass,
81*67e74705SXin Li                                            VisitedVirtualBasesSetTy &VBases) {
82*67e74705SXin Li   const CXXRecordDecl *RD = Base.getBase();
83*67e74705SXin Li 
84*67e74705SXin Li   // We're not interested in bases that don't have virtual bases, and not
85*67e74705SXin Li   // morally virtual bases.
86*67e74705SXin Li   if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
87*67e74705SXin Li     return;
88*67e74705SXin Li 
89*67e74705SXin Li   for (const auto &I : RD->bases()) {
90*67e74705SXin Li     const CXXRecordDecl *BaseDecl =
91*67e74705SXin Li       cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
92*67e74705SXin Li 
93*67e74705SXin Li     // Itanium C++ ABI 2.6.2:
94*67e74705SXin Li     //   Secondary virtual pointers are present for all bases with either
95*67e74705SXin Li     //   virtual bases or virtual function declarations overridden along a
96*67e74705SXin Li     //   virtual path.
97*67e74705SXin Li     //
98*67e74705SXin Li     // If the base class is not dynamic, we don't want to add it, nor any
99*67e74705SXin Li     // of its base classes.
100*67e74705SXin Li     if (!BaseDecl->isDynamicClass())
101*67e74705SXin Li       continue;
102*67e74705SXin Li 
103*67e74705SXin Li     bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
104*67e74705SXin Li     bool BaseDeclIsNonVirtualPrimaryBase = false;
105*67e74705SXin Li     CharUnits BaseOffset;
106*67e74705SXin Li     if (I.isVirtual()) {
107*67e74705SXin Li       // Ignore virtual bases that we've already visited.
108*67e74705SXin Li       if (!VBases.insert(BaseDecl).second)
109*67e74705SXin Li         continue;
110*67e74705SXin Li 
111*67e74705SXin Li       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
112*67e74705SXin Li       BaseDeclIsMorallyVirtual = true;
113*67e74705SXin Li     } else {
114*67e74705SXin Li       const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
115*67e74705SXin Li 
116*67e74705SXin Li       BaseOffset = Base.getBaseOffset() +
117*67e74705SXin Li         Layout.getBaseClassOffset(BaseDecl);
118*67e74705SXin Li 
119*67e74705SXin Li       if (!Layout.isPrimaryBaseVirtual() &&
120*67e74705SXin Li           Layout.getPrimaryBase() == BaseDecl)
121*67e74705SXin Li         BaseDeclIsNonVirtualPrimaryBase = true;
122*67e74705SXin Li     }
123*67e74705SXin Li 
124*67e74705SXin Li     // Itanium C++ ABI 2.6.2:
125*67e74705SXin Li     //   Secondary virtual pointers: for each base class X which (a) has virtual
126*67e74705SXin Li     //   bases or is reachable along a virtual path from D, and (b) is not a
127*67e74705SXin Li     //   non-virtual primary base, the address of the virtual table for X-in-D
128*67e74705SXin Li     //   or an appropriate construction virtual table.
129*67e74705SXin Li     if (!BaseDeclIsNonVirtualPrimaryBase &&
130*67e74705SXin Li         (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
131*67e74705SXin Li       // Add the vtable pointer.
132*67e74705SXin Li       AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
133*67e74705SXin Li                        VTableClass);
134*67e74705SXin Li     }
135*67e74705SXin Li 
136*67e74705SXin Li     // And lay out the secondary virtual pointers for the base class.
137*67e74705SXin Li     LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
138*67e74705SXin Li                                    BaseDeclIsMorallyVirtual, VTableIndex,
139*67e74705SXin Li                                    VTableClass, VBases);
140*67e74705SXin Li   }
141*67e74705SXin Li }
142*67e74705SXin Li 
143*67e74705SXin Li void
LayoutSecondaryVirtualPointers(BaseSubobject Base,uint64_t VTableIndex)144*67e74705SXin Li VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
145*67e74705SXin Li                                            uint64_t VTableIndex) {
146*67e74705SXin Li   VisitedVirtualBasesSetTy VBases;
147*67e74705SXin Li   LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
148*67e74705SXin Li                                  VTableIndex, Base.getBase(), VBases);
149*67e74705SXin Li }
150*67e74705SXin Li 
LayoutVirtualVTTs(const CXXRecordDecl * RD,VisitedVirtualBasesSetTy & VBases)151*67e74705SXin Li void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
152*67e74705SXin Li                                    VisitedVirtualBasesSetTy &VBases) {
153*67e74705SXin Li   for (const auto &I : RD->bases()) {
154*67e74705SXin Li     const CXXRecordDecl *BaseDecl =
155*67e74705SXin Li       cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
156*67e74705SXin Li 
157*67e74705SXin Li     // Check if this is a virtual base.
158*67e74705SXin Li     if (I.isVirtual()) {
159*67e74705SXin Li       // Check if we've seen this base before.
160*67e74705SXin Li       if (!VBases.insert(BaseDecl).second)
161*67e74705SXin Li         continue;
162*67e74705SXin Li 
163*67e74705SXin Li       CharUnits BaseOffset =
164*67e74705SXin Li         MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
165*67e74705SXin Li 
166*67e74705SXin Li       LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
167*67e74705SXin Li     }
168*67e74705SXin Li 
169*67e74705SXin Li     // We only need to layout virtual VTTs for this base if it actually has
170*67e74705SXin Li     // virtual bases.
171*67e74705SXin Li     if (BaseDecl->getNumVBases())
172*67e74705SXin Li       LayoutVirtualVTTs(BaseDecl, VBases);
173*67e74705SXin Li   }
174*67e74705SXin Li }
175*67e74705SXin Li 
LayoutVTT(BaseSubobject Base,bool BaseIsVirtual)176*67e74705SXin Li void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
177*67e74705SXin Li   const CXXRecordDecl *RD = Base.getBase();
178*67e74705SXin Li 
179*67e74705SXin Li   // Itanium C++ ABI 2.6.2:
180*67e74705SXin Li   //   An array of virtual table addresses, called the VTT, is declared for
181*67e74705SXin Li   //   each class type that has indirect or direct virtual base classes.
182*67e74705SXin Li   if (RD->getNumVBases() == 0)
183*67e74705SXin Li     return;
184*67e74705SXin Li 
185*67e74705SXin Li   bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
186*67e74705SXin Li 
187*67e74705SXin Li   if (!IsPrimaryVTT) {
188*67e74705SXin Li     // Remember the sub-VTT index.
189*67e74705SXin Li     SubVTTIndicies[Base] = VTTComponents.size();
190*67e74705SXin Li   }
191*67e74705SXin Li 
192*67e74705SXin Li   uint64_t VTableIndex = VTTVTables.size();
193*67e74705SXin Li   VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
194*67e74705SXin Li 
195*67e74705SXin Li   // Add the primary vtable pointer.
196*67e74705SXin Li   AddVTablePointer(Base, VTableIndex, RD);
197*67e74705SXin Li 
198*67e74705SXin Li   // Add the secondary VTTs.
199*67e74705SXin Li   LayoutSecondaryVTTs(Base);
200*67e74705SXin Li 
201*67e74705SXin Li   // Add the secondary virtual pointers.
202*67e74705SXin Li   LayoutSecondaryVirtualPointers(Base, VTableIndex);
203*67e74705SXin Li 
204*67e74705SXin Li   // If this is the primary VTT, we want to lay out virtual VTTs as well.
205*67e74705SXin Li   if (IsPrimaryVTT) {
206*67e74705SXin Li     VisitedVirtualBasesSetTy VBases;
207*67e74705SXin Li     LayoutVirtualVTTs(Base.getBase(), VBases);
208*67e74705SXin Li   }
209*67e74705SXin Li }
210