//===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code dealing with generation of the layout of virtual table // tables (VTT). // //===----------------------------------------------------------------------===// #include "clang/AST/VTTBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/Format.h" #include <algorithm> #include <cstdio> using namespace clang; #define DUMP_OVERRIDERS 0 VTTBuilder::VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, bool GenerateDefinition) : Ctx(Ctx), MostDerivedClass(MostDerivedClass), MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)), GenerateDefinition(GenerateDefinition) { // Lay out this VTT. LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), /*BaseIsVirtual=*/false); } void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, const CXXRecordDecl *VTableClass) { // Store the vtable pointer index if we're generating the primary VTT. if (VTableClass == MostDerivedClass) { assert(!SecondaryVirtualPointerIndices.count(Base) && "A virtual pointer index already exists for this base subobject!"); SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); } if (!GenerateDefinition) { VTTComponents.push_back(VTTComponent()); return; } VTTComponents.push_back(VTTComponent(VTableIndex, Base)); } void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { const CXXRecordDecl *RD = Base.getBase(); for (const auto &I : RD->bases()) { // Don't layout virtual bases. if (I.isVirtual()) continue; const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl()); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); // Layout the VTT for this base. LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); } } void VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, bool BaseIsMorallyVirtual, uint64_t VTableIndex, const CXXRecordDecl *VTableClass, VisitedVirtualBasesSetTy &VBases) { const CXXRecordDecl *RD = Base.getBase(); // We're not interested in bases that don't have virtual bases, and not // morally virtual bases. if (!RD->getNumVBases() && !BaseIsMorallyVirtual) return; for (const auto &I : RD->bases()) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl()); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either // virtual bases or virtual function declarations overridden along a // virtual path. // // If the base class is not dynamic, we don't want to add it, nor any // of its base classes. if (!BaseDecl->isDynamicClass()) continue; bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; bool BaseDeclIsNonVirtualPrimaryBase = false; CharUnits BaseOffset; if (I.isVirtual()) { // Ignore virtual bases that we've already visited. if (!VBases.insert(BaseDecl).second) continue; BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); BaseDeclIsMorallyVirtual = true; } else { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); if (!Layout.isPrimaryBaseVirtual() && Layout.getPrimaryBase() == BaseDecl) BaseDeclIsNonVirtualPrimaryBase = true; } // Itanium C++ ABI 2.6.2: // Secondary virtual pointers: for each base class X which (a) has virtual // bases or is reachable along a virtual path from D, and (b) is not a // non-virtual primary base, the address of the virtual table for X-in-D // or an appropriate construction virtual table. if (!BaseDeclIsNonVirtualPrimaryBase && (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { // Add the vtable pointer. AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex, VTableClass); } // And lay out the secondary virtual pointers for the base class. LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), BaseDeclIsMorallyVirtual, VTableIndex, VTableClass, VBases); } } void VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, uint64_t VTableIndex) { VisitedVirtualBasesSetTy VBases; LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, VTableIndex, Base.getBase(), VBases); } void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl()); // Check if this is a virtual base. if (I.isVirtual()) { // Check if we've seen this base before. if (!VBases.insert(BaseDecl).second) continue; CharUnits BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); } // We only need to layout virtual VTTs for this base if it actually has // virtual bases. if (BaseDecl->getNumVBases()) LayoutVirtualVTTs(BaseDecl, VBases); } } void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { const CXXRecordDecl *RD = Base.getBase(); // Itanium C++ ABI 2.6.2: // An array of virtual table addresses, called the VTT, is declared for // each class type that has indirect or direct virtual base classes. if (RD->getNumVBases() == 0) return; bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; if (!IsPrimaryVTT) { // Remember the sub-VTT index. SubVTTIndicies[Base] = VTTComponents.size(); } uint64_t VTableIndex = VTTVTables.size(); VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual)); // Add the primary vtable pointer. AddVTablePointer(Base, VTableIndex, RD); // Add the secondary VTTs. LayoutSecondaryVTTs(Base); // Add the secondary virtual pointers. LayoutSecondaryVirtualPointers(Base, VTableIndex); // If this is the primary VTT, we want to lay out virtual VTTs as well. if (IsPrimaryVTT) { VisitedVirtualBasesSetTy VBases; LayoutVirtualVTTs(Base.getBase(), VBases); } }