brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 89b58b5 Raw
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