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