10b57cec5SDimitry Andric //===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This contains code dealing with generation of the layout of virtual table 100b57cec5SDimitry Andric // tables (VTT). 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "clang/AST/VTTBuilder.h" 150b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 160b57cec5SDimitry Andric #include "clang/AST/BaseSubobject.h" 170b57cec5SDimitry Andric #include "clang/AST/CharUnits.h" 180b57cec5SDimitry Andric #include "clang/AST/Decl.h" 190b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 200b57cec5SDimitry Andric #include "clang/AST/RecordLayout.h" 210b57cec5SDimitry Andric #include "clang/AST/Type.h" 220b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 230b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 240b57cec5SDimitry Andric #include <cassert> 250b57cec5SDimitry Andric #include <cstdint> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DUMP_OVERRIDERS 0 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric VTTBuilder::VTTBuilder(ASTContext &Ctx, 320b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass, 330b57cec5SDimitry Andric bool GenerateDefinition) 340b57cec5SDimitry Andric : Ctx(Ctx), MostDerivedClass(MostDerivedClass), 350b57cec5SDimitry Andric MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)), 360b57cec5SDimitry Andric GenerateDefinition(GenerateDefinition) { 370b57cec5SDimitry Andric // Lay out this VTT. 380b57cec5SDimitry Andric LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 390b57cec5SDimitry Andric /*BaseIsVirtual=*/false); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, 430b57cec5SDimitry Andric const CXXRecordDecl *VTableClass) { 440b57cec5SDimitry Andric // Store the vtable pointer index if we're generating the primary VTT. 450b57cec5SDimitry Andric if (VTableClass == MostDerivedClass) { 460b57cec5SDimitry Andric assert(!SecondaryVirtualPointerIndices.count(Base) && 470b57cec5SDimitry Andric "A virtual pointer index already exists for this base subobject!"); 480b57cec5SDimitry Andric SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric if (!GenerateDefinition) { 520b57cec5SDimitry Andric VTTComponents.push_back(VTTComponent()); 530b57cec5SDimitry Andric return; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric VTTComponents.push_back(VTTComponent(VTableIndex, Base)); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { 600b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric for (const auto &I : RD->bases()) { 630b57cec5SDimitry Andric // Don't layout virtual bases. 640b57cec5SDimitry Andric if (I.isVirtual()) 650b57cec5SDimitry Andric continue; 660b57cec5SDimitry Andric 67a7dea167SDimitry Andric const auto *BaseDecl = 68a7dea167SDimitry Andric cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); 710b57cec5SDimitry Andric CharUnits BaseOffset = Base.getBaseOffset() + 720b57cec5SDimitry Andric Layout.getBaseClassOffset(BaseDecl); 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // Layout the VTT for this base. 750b57cec5SDimitry Andric LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric void 800b57cec5SDimitry Andric VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, 810b57cec5SDimitry Andric bool BaseIsMorallyVirtual, 820b57cec5SDimitry Andric uint64_t VTableIndex, 830b57cec5SDimitry Andric const CXXRecordDecl *VTableClass, 840b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VBases) { 850b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric // We're not interested in bases that don't have virtual bases, and not 880b57cec5SDimitry Andric // morally virtual bases. 890b57cec5SDimitry Andric if (!RD->getNumVBases() && !BaseIsMorallyVirtual) 900b57cec5SDimitry Andric return; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric for (const auto &I : RD->bases()) { 93a7dea167SDimitry Andric const auto *BaseDecl = 94a7dea167SDimitry Andric cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric // Itanium C++ ABI 2.6.2: 970b57cec5SDimitry Andric // Secondary virtual pointers are present for all bases with either 980b57cec5SDimitry Andric // virtual bases or virtual function declarations overridden along a 990b57cec5SDimitry Andric // virtual path. 1000b57cec5SDimitry Andric // 1010b57cec5SDimitry Andric // If the base class is not dynamic, we don't want to add it, nor any 1020b57cec5SDimitry Andric // of its base classes. 1030b57cec5SDimitry Andric if (!BaseDecl->isDynamicClass()) 1040b57cec5SDimitry Andric continue; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; 1070b57cec5SDimitry Andric bool BaseDeclIsNonVirtualPrimaryBase = false; 1080b57cec5SDimitry Andric CharUnits BaseOffset; 1090b57cec5SDimitry Andric if (I.isVirtual()) { 1100b57cec5SDimitry Andric // Ignore virtual bases that we've already visited. 1110b57cec5SDimitry Andric if (!VBases.insert(BaseDecl).second) 1120b57cec5SDimitry Andric continue; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); 1150b57cec5SDimitry Andric BaseDeclIsMorallyVirtual = true; 1160b57cec5SDimitry Andric } else { 1170b57cec5SDimitry Andric const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric BaseOffset = Base.getBaseOffset() + 1200b57cec5SDimitry Andric Layout.getBaseClassOffset(BaseDecl); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric if (!Layout.isPrimaryBaseVirtual() && 1230b57cec5SDimitry Andric Layout.getPrimaryBase() == BaseDecl) 1240b57cec5SDimitry Andric BaseDeclIsNonVirtualPrimaryBase = true; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric // Itanium C++ ABI 2.6.2: 1280b57cec5SDimitry Andric // Secondary virtual pointers: for each base class X which (a) has virtual 1290b57cec5SDimitry Andric // bases or is reachable along a virtual path from D, and (b) is not a 1300b57cec5SDimitry Andric // non-virtual primary base, the address of the virtual table for X-in-D 1310b57cec5SDimitry Andric // or an appropriate construction virtual table. 1320b57cec5SDimitry Andric if (!BaseDeclIsNonVirtualPrimaryBase && 1330b57cec5SDimitry Andric (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { 1340b57cec5SDimitry Andric // Add the vtable pointer. 1350b57cec5SDimitry Andric AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex, 1360b57cec5SDimitry Andric VTableClass); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // And lay out the secondary virtual pointers for the base class. 1400b57cec5SDimitry Andric LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), 1410b57cec5SDimitry Andric BaseDeclIsMorallyVirtual, VTableIndex, 1420b57cec5SDimitry Andric VTableClass, VBases); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric void 1470b57cec5SDimitry Andric VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, 1480b57cec5SDimitry Andric uint64_t VTableIndex) { 1490b57cec5SDimitry Andric VisitedVirtualBasesSetTy VBases; 1500b57cec5SDimitry Andric LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, 1510b57cec5SDimitry Andric VTableIndex, Base.getBase(), VBases); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, 1550b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VBases) { 1560b57cec5SDimitry Andric for (const auto &I : RD->bases()) { 157a7dea167SDimitry Andric const auto *BaseDecl = 158a7dea167SDimitry Andric cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // Check if this is a virtual base. 1610b57cec5SDimitry Andric if (I.isVirtual()) { 1620b57cec5SDimitry Andric // Check if we've seen this base before. 1630b57cec5SDimitry Andric if (!VBases.insert(BaseDecl).second) 1640b57cec5SDimitry Andric continue; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric CharUnits BaseOffset = 1670b57cec5SDimitry Andric MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric // We only need to layout virtual VTTs for this base if it actually has 1730b57cec5SDimitry Andric // virtual bases. 1740b57cec5SDimitry Andric if (BaseDecl->getNumVBases()) 1750b57cec5SDimitry Andric LayoutVirtualVTTs(BaseDecl, VBases); 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { 1800b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric // Itanium C++ ABI 2.6.2: 1830b57cec5SDimitry Andric // An array of virtual table addresses, called the VTT, is declared for 1840b57cec5SDimitry Andric // each class type that has indirect or direct virtual base classes. 1850b57cec5SDimitry Andric if (RD->getNumVBases() == 0) 1860b57cec5SDimitry Andric return; 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric if (!IsPrimaryVTT) { 1910b57cec5SDimitry Andric // Remember the sub-VTT index. 192*0fca6ea1SDimitry Andric SubVTTIndices[Base] = VTTComponents.size(); 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric uint64_t VTableIndex = VTTVTables.size(); 1960b57cec5SDimitry Andric VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual)); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric // Add the primary vtable pointer. 1990b57cec5SDimitry Andric AddVTablePointer(Base, VTableIndex, RD); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // Add the secondary VTTs. 2020b57cec5SDimitry Andric LayoutSecondaryVTTs(Base); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric // Add the secondary virtual pointers. 2050b57cec5SDimitry Andric LayoutSecondaryVirtualPointers(Base, VTableIndex); 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // If this is the primary VTT, we want to lay out virtual VTTs as well. 2080b57cec5SDimitry Andric if (IsPrimaryVTT) { 2090b57cec5SDimitry Andric VisitedVirtualBasesSetTy VBases; 2100b57cec5SDimitry Andric LayoutVirtualVTTs(Base.getBase(), VBases); 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric } 213