208 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This contains code dealing with generation of the layout of virtual table10// 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 <cassert>24#include <cstdint>25 26using namespace clang;27 28#define DUMP_OVERRIDERS 029 30VTTBuilder::VTTBuilder(ASTContext &Ctx,31 const CXXRecordDecl *MostDerivedClass,32 bool GenerateDefinition)33 : Ctx(Ctx), MostDerivedClass(MostDerivedClass),34 MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),35 GenerateDefinition(GenerateDefinition) {36 // Lay out this VTT.37 LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),38 /*BaseIsVirtual=*/false);39}40 41void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,42 const CXXRecordDecl *VTableClass) {43 // Store the vtable pointer index if we're generating the primary VTT.44 if (VTableClass == MostDerivedClass) {45 assert(!SecondaryVirtualPointerIndices.count(Base) &&46 "A virtual pointer index already exists for this base subobject!");47 SecondaryVirtualPointerIndices[Base] = VTTComponents.size();48 }49 50 if (!GenerateDefinition) {51 VTTComponents.push_back(VTTComponent());52 return;53 }54 55 VTTComponents.push_back(VTTComponent(VTableIndex, Base));56}57 58void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {59 const CXXRecordDecl *RD = Base.getBase();60 61 for (const auto &I : RD->bases()) {62 // Don't layout virtual bases.63 if (I.isVirtual())64 continue;65 66 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();67 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);68 CharUnits BaseOffset = Base.getBaseOffset() +69 Layout.getBaseClassOffset(BaseDecl);70 71 // Layout the VTT for this base.72 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);73 }74}75 76void77VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,78 bool BaseIsMorallyVirtual,79 uint64_t VTableIndex,80 const CXXRecordDecl *VTableClass,81 VisitedVirtualBasesSetTy &VBases) {82 const CXXRecordDecl *RD = Base.getBase();83 84 // We're not interested in bases that don't have virtual bases, and not85 // morally virtual bases.86 if (!RD->getNumVBases() && !BaseIsMorallyVirtual)87 return;88 89 for (const auto &I : RD->bases()) {90 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();91 92 // Itanium C++ ABI 2.6.2:93 // Secondary virtual pointers are present for all bases with either94 // virtual bases or virtual function declarations overridden along a95 // virtual path.96 //97 // If the base class is not dynamic, we don't want to add it, nor any98 // of its base classes.99 if (!BaseDecl->isDynamicClass())100 continue;101 102 bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;103 bool BaseDeclIsNonVirtualPrimaryBase = false;104 CharUnits BaseOffset;105 if (I.isVirtual()) {106 // Ignore virtual bases that we've already visited.107 if (!VBases.insert(BaseDecl).second)108 continue;109 110 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);111 BaseDeclIsMorallyVirtual = true;112 } else {113 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);114 115 BaseOffset = Base.getBaseOffset() +116 Layout.getBaseClassOffset(BaseDecl);117 118 if (!Layout.isPrimaryBaseVirtual() &&119 Layout.getPrimaryBase() == BaseDecl)120 BaseDeclIsNonVirtualPrimaryBase = true;121 }122 123 // Itanium C++ ABI 2.6.2:124 // Secondary virtual pointers: for each base class X which (a) has virtual125 // bases or is reachable along a virtual path from D, and (b) is not a126 // non-virtual primary base, the address of the virtual table for X-in-D127 // or an appropriate construction virtual table.128 if (!BaseDeclIsNonVirtualPrimaryBase &&129 (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {130 // Add the vtable pointer.131 AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,132 VTableClass);133 }134 135 // And lay out the secondary virtual pointers for the base class.136 LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),137 BaseDeclIsMorallyVirtual, VTableIndex,138 VTableClass, VBases);139 }140}141 142void143VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,144 uint64_t VTableIndex) {145 VisitedVirtualBasesSetTy VBases;146 LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,147 VTableIndex, Base.getBase(), VBases);148}149 150void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,151 VisitedVirtualBasesSetTy &VBases) {152 for (const auto &I : RD->bases()) {153 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();154 155 // Check if this is a virtual base.156 if (I.isVirtual()) {157 // Check if we've seen this base before.158 if (!VBases.insert(BaseDecl).second)159 continue;160 161 CharUnits BaseOffset =162 MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);163 164 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);165 }166 167 // We only need to layout virtual VTTs for this base if it actually has168 // virtual bases.169 if (BaseDecl->getNumVBases())170 LayoutVirtualVTTs(BaseDecl, VBases);171 }172}173 174void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {175 const CXXRecordDecl *RD = Base.getBase();176 177 // Itanium C++ ABI 2.6.2:178 // An array of virtual table addresses, called the VTT, is declared for179 // each class type that has indirect or direct virtual base classes.180 if (RD->getNumVBases() == 0)181 return;182 183 bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;184 185 if (!IsPrimaryVTT) {186 // Remember the sub-VTT index.187 SubVTTIndices[Base] = VTTComponents.size();188 }189 190 uint64_t VTableIndex = VTTVTables.size();191 VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));192 193 // Add the primary vtable pointer.194 AddVTablePointer(Base, VTableIndex, RD);195 196 // Add the secondary VTTs.197 LayoutSecondaryVTTs(Base);198 199 // Add the secondary virtual pointers.200 LayoutSecondaryVirtualPointers(Base, VTableIndex);201 202 // If this is the primary VTT, we want to lay out virtual VTTs as well.203 if (IsPrimaryVTT) {204 VisitedVirtualBasesSetTy VBases;205 LayoutVirtualVTTs(Base.getBase(), VBases);206 }207}208