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