blob: a3f3dbdfb4f93a4f02a73d1f2317713deb87a0b3 [file] [log] [blame]
Eugene Zelenko3d775712017-12-01 22:04:49 +00001//===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===//
Peter Collingbourne2d259522011-09-26 01:56:24 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This contains code dealing with generation of the layout of virtual table
11// tables (VTT).
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/VTTBuilder.h"
Benjamin Kramer2ef30312012-07-04 18:45:14 +000016#include "clang/AST/ASTContext.h"
Eugene Zelenko3d775712017-12-01 22:04:49 +000017#include "clang/AST/BaseSubobject.h"
18#include "clang/AST/CharUnits.h"
19#include "clang/AST/Decl.h"
20#include "clang/AST/DeclCXX.h"
Peter Collingbourne2d259522011-09-26 01:56:24 +000021#include "clang/AST/RecordLayout.h"
Eugene Zelenko3d775712017-12-01 22:04:49 +000022#include "clang/AST/Type.h"
23#include "clang/Basic/LLVM.h"
24#include "llvm/Support/Casting.h"
25#include <cassert>
26#include <cstdint>
Peter Collingbourne2d259522011-09-26 01:56:24 +000027
28using namespace clang;
29
30#define DUMP_OVERRIDERS 0
31
32VTTBuilder::VTTBuilder(ASTContext &Ctx,
33 const CXXRecordDecl *MostDerivedClass,
34 bool GenerateDefinition)
Fangrui Song6907ce22018-07-30 19:24:48 +000035 : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
Eugene Zelenko3d775712017-12-01 22:04:49 +000036 MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
37 GenerateDefinition(GenerateDefinition) {
Peter Collingbourne2d259522011-09-26 01:56:24 +000038 // Lay out this VTT.
Fangrui Song6907ce22018-07-30 19:24:48 +000039 LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
Peter Collingbourne2d259522011-09-26 01:56:24 +000040 /*BaseIsVirtual=*/false);
41}
42
43void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
44 const CXXRecordDecl *VTableClass) {
45 // Store the vtable pointer index if we're generating the primary VTT.
46 if (VTableClass == MostDerivedClass) {
47 assert(!SecondaryVirtualPointerIndices.count(Base) &&
48 "A virtual pointer index already exists for this base subobject!");
49 SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
50 }
51
52 if (!GenerateDefinition) {
53 VTTComponents.push_back(VTTComponent());
54 return;
55 }
56
57 VTTComponents.push_back(VTTComponent(VTableIndex, Base));
58}
59
60void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
61 const CXXRecordDecl *RD = Base.getBase();
62
Eugene Zelenko3d775712017-12-01 22:04:49 +000063 for (const auto &I : RD->bases()) {
Peter Collingbourne2d259522011-09-26 01:56:24 +000064 // Don't layout virtual bases.
Aaron Ballman574705e2014-03-13 15:41:46 +000065 if (I.isVirtual())
Peter Collingbourne2d259522011-09-26 01:56:24 +000066 continue;
67
68 const CXXRecordDecl *BaseDecl =
Aaron Ballman574705e2014-03-13 15:41:46 +000069 cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
Peter Collingbourne2d259522011-09-26 01:56:24 +000070
71 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Fangrui Song6907ce22018-07-30 19:24:48 +000072 CharUnits BaseOffset = Base.getBaseOffset() +
Peter Collingbourne2d259522011-09-26 01:56:24 +000073 Layout.getBaseClassOffset(BaseDecl);
Fangrui Song6907ce22018-07-30 19:24:48 +000074
Peter Collingbourne2d259522011-09-26 01:56:24 +000075 // Layout the VTT for this base.
76 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
77 }
78}
79
80void
Fangrui Song6907ce22018-07-30 19:24:48 +000081VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
Peter Collingbourne2d259522011-09-26 01:56:24 +000082 bool BaseIsMorallyVirtual,
83 uint64_t VTableIndex,
84 const CXXRecordDecl *VTableClass,
85 VisitedVirtualBasesSetTy &VBases) {
86 const CXXRecordDecl *RD = Base.getBase();
Fangrui Song6907ce22018-07-30 19:24:48 +000087
Peter Collingbourne2d259522011-09-26 01:56:24 +000088 // We're not interested in bases that don't have virtual bases, and not
89 // morally virtual bases.
90 if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
91 return;
92
Aaron Ballman574705e2014-03-13 15:41:46 +000093 for (const auto &I : RD->bases()) {
Peter Collingbourne2d259522011-09-26 01:56:24 +000094 const CXXRecordDecl *BaseDecl =
Aaron Ballman574705e2014-03-13 15:41:46 +000095 cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
Peter Collingbourne2d259522011-09-26 01:56:24 +000096
97 // Itanium C++ ABI 2.6.2:
98 // Secondary virtual pointers are present for all bases with either
Fangrui Song6907ce22018-07-30 19:24:48 +000099 // virtual bases or virtual function declarations overridden along a
Peter Collingbourne2d259522011-09-26 01:56:24 +0000100 // virtual path.
101 //
102 // If the base class is not dynamic, we don't want to add it, nor any
103 // of its base classes.
104 if (!BaseDecl->isDynamicClass())
105 continue;
Fangrui Song6907ce22018-07-30 19:24:48 +0000106
Peter Collingbourne2d259522011-09-26 01:56:24 +0000107 bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
108 bool BaseDeclIsNonVirtualPrimaryBase = false;
109 CharUnits BaseOffset;
Aaron Ballman574705e2014-03-13 15:41:46 +0000110 if (I.isVirtual()) {
Peter Collingbourne2d259522011-09-26 01:56:24 +0000111 // Ignore virtual bases that we've already visited.
David Blaikie82e95a32014-11-19 07:49:47 +0000112 if (!VBases.insert(BaseDecl).second)
Peter Collingbourne2d259522011-09-26 01:56:24 +0000113 continue;
Fangrui Song6907ce22018-07-30 19:24:48 +0000114
Peter Collingbourne2d259522011-09-26 01:56:24 +0000115 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
116 BaseDeclIsMorallyVirtual = true;
117 } else {
118 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Fangrui Song6907ce22018-07-30 19:24:48 +0000119
120 BaseOffset = Base.getBaseOffset() +
Peter Collingbourne2d259522011-09-26 01:56:24 +0000121 Layout.getBaseClassOffset(BaseDecl);
Fangrui Song6907ce22018-07-30 19:24:48 +0000122
Peter Collingbourne2d259522011-09-26 01:56:24 +0000123 if (!Layout.isPrimaryBaseVirtual() &&
124 Layout.getPrimaryBase() == BaseDecl)
125 BaseDeclIsNonVirtualPrimaryBase = true;
126 }
127
128 // Itanium C++ ABI 2.6.2:
129 // Secondary virtual pointers: for each base class X which (a) has virtual
130 // bases or is reachable along a virtual path from D, and (b) is not a
131 // non-virtual primary base, the address of the virtual table for X-in-D
132 // or an appropriate construction virtual table.
133 if (!BaseDeclIsNonVirtualPrimaryBase &&
134 (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
135 // Add the vtable pointer.
Fangrui Song6907ce22018-07-30 19:24:48 +0000136 AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
Peter Collingbourne2d259522011-09-26 01:56:24 +0000137 VTableClass);
138 }
139
140 // And lay out the secondary virtual pointers for the base class.
141 LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
Fangrui Song6907ce22018-07-30 19:24:48 +0000142 BaseDeclIsMorallyVirtual, VTableIndex,
Peter Collingbourne2d259522011-09-26 01:56:24 +0000143 VTableClass, VBases);
144 }
145}
146
Fangrui Song6907ce22018-07-30 19:24:48 +0000147void
148VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
Peter Collingbourne2d259522011-09-26 01:56:24 +0000149 uint64_t VTableIndex) {
150 VisitedVirtualBasesSetTy VBases;
151 LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
152 VTableIndex, Base.getBase(), VBases);
153}
154
155void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
156 VisitedVirtualBasesSetTy &VBases) {
Aaron Ballman574705e2014-03-13 15:41:46 +0000157 for (const auto &I : RD->bases()) {
Fangrui Song6907ce22018-07-30 19:24:48 +0000158 const CXXRecordDecl *BaseDecl =
Aaron Ballman574705e2014-03-13 15:41:46 +0000159 cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
Fangrui Song6907ce22018-07-30 19:24:48 +0000160
Peter Collingbourne2d259522011-09-26 01:56:24 +0000161 // Check if this is a virtual base.
Aaron Ballman574705e2014-03-13 15:41:46 +0000162 if (I.isVirtual()) {
Peter Collingbourne2d259522011-09-26 01:56:24 +0000163 // Check if we've seen this base before.
David Blaikie82e95a32014-11-19 07:49:47 +0000164 if (!VBases.insert(BaseDecl).second)
Peter Collingbourne2d259522011-09-26 01:56:24 +0000165 continue;
Fangrui Song6907ce22018-07-30 19:24:48 +0000166
167 CharUnits BaseOffset =
Peter Collingbourne2d259522011-09-26 01:56:24 +0000168 MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
Fangrui Song6907ce22018-07-30 19:24:48 +0000169
Peter Collingbourne2d259522011-09-26 01:56:24 +0000170 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
171 }
Fangrui Song6907ce22018-07-30 19:24:48 +0000172
Peter Collingbourne2d259522011-09-26 01:56:24 +0000173 // We only need to layout virtual VTTs for this base if it actually has
174 // virtual bases.
175 if (BaseDecl->getNumVBases())
176 LayoutVirtualVTTs(BaseDecl, VBases);
177 }
178}
179
180void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
181 const CXXRecordDecl *RD = Base.getBase();
182
183 // Itanium C++ ABI 2.6.2:
Fangrui Song6907ce22018-07-30 19:24:48 +0000184 // An array of virtual table addresses, called the VTT, is declared for
Peter Collingbourne2d259522011-09-26 01:56:24 +0000185 // each class type that has indirect or direct virtual base classes.
186 if (RD->getNumVBases() == 0)
187 return;
188
189 bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
190
191 if (!IsPrimaryVTT) {
192 // Remember the sub-VTT index.
193 SubVTTIndicies[Base] = VTTComponents.size();
194 }
195
196 uint64_t VTableIndex = VTTVTables.size();
197 VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
198
199 // Add the primary vtable pointer.
200 AddVTablePointer(Base, VTableIndex, RD);
201
202 // Add the secondary VTTs.
203 LayoutSecondaryVTTs(Base);
Fangrui Song6907ce22018-07-30 19:24:48 +0000204
Peter Collingbourne2d259522011-09-26 01:56:24 +0000205 // Add the secondary virtual pointers.
206 LayoutSecondaryVirtualPointers(Base, VTableIndex);
Fangrui Song6907ce22018-07-30 19:24:48 +0000207
Peter Collingbourne2d259522011-09-26 01:56:24 +0000208 // If this is the primary VTT, we want to lay out virtual VTTs as well.
209 if (IsPrimaryVTT) {
210 VisitedVirtualBasesSetTy VBases;
211 LayoutVirtualVTTs(Base.getBase(), VBases);
212 }
213}