10b57cec5SDimitry Andric //===--- VTableBuilder.cpp - C++ vtable 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 tables. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/AST/VTableBuilder.h" 140b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 150b57cec5SDimitry Andric #include "clang/AST/ASTDiagnostic.h" 160b57cec5SDimitry Andric #include "clang/AST/CXXInheritance.h" 170b57cec5SDimitry Andric #include "clang/AST/RecordLayout.h" 180b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 190b57cec5SDimitry Andric #include "llvm/ADT/SetOperations.h" 2081ad6265SDimitry Andric #include "llvm/ADT/SetVector.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 220b57cec5SDimitry Andric #include "llvm/Support/Format.h" 230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 240b57cec5SDimitry Andric #include <algorithm> 250b57cec5SDimitry Andric #include <cstdio> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DUMP_OVERRIDERS 0 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric /// BaseOffset - Represents an offset from a derived class to a direct or 340b57cec5SDimitry Andric /// indirect base class. 350b57cec5SDimitry Andric struct BaseOffset { 360b57cec5SDimitry Andric /// DerivedClass - The derived class. 370b57cec5SDimitry Andric const CXXRecordDecl *DerivedClass; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric /// VirtualBase - If the path from the derived class to the base class 400b57cec5SDimitry Andric /// involves virtual base classes, this holds the declaration of the last 410b57cec5SDimitry Andric /// virtual base in this path (i.e. closest to the base class). 420b57cec5SDimitry Andric const CXXRecordDecl *VirtualBase; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric /// NonVirtualOffset - The offset from the derived class to the base class. 450b57cec5SDimitry Andric /// (Or the offset from the virtual base class to the base class, if the 460b57cec5SDimitry Andric /// path from the derived class to the base class involves a virtual base 470b57cec5SDimitry Andric /// class. 480b57cec5SDimitry Andric CharUnits NonVirtualOffset; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric BaseOffset() : DerivedClass(nullptr), VirtualBase(nullptr), 510b57cec5SDimitry Andric NonVirtualOffset(CharUnits::Zero()) { } 520b57cec5SDimitry Andric BaseOffset(const CXXRecordDecl *DerivedClass, 530b57cec5SDimitry Andric const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset) 540b57cec5SDimitry Andric : DerivedClass(DerivedClass), VirtualBase(VirtualBase), 550b57cec5SDimitry Andric NonVirtualOffset(NonVirtualOffset) { } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; } 580b57cec5SDimitry Andric }; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric /// FinalOverriders - Contains the final overrider member functions for all 610b57cec5SDimitry Andric /// member functions in the base subobjects of a class. 620b57cec5SDimitry Andric class FinalOverriders { 630b57cec5SDimitry Andric public: 640b57cec5SDimitry Andric /// OverriderInfo - Information about a final overrider. 650b57cec5SDimitry Andric struct OverriderInfo { 660b57cec5SDimitry Andric /// Method - The method decl of the overrider. 670b57cec5SDimitry Andric const CXXMethodDecl *Method; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric /// VirtualBase - The virtual base class subobject of this overrider. 700b57cec5SDimitry Andric /// Note that this records the closest derived virtual base class subobject. 710b57cec5SDimitry Andric const CXXRecordDecl *VirtualBase; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric /// Offset - the base offset of the overrider's parent in the layout class. 740b57cec5SDimitry Andric CharUnits Offset; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric OverriderInfo() : Method(nullptr), VirtualBase(nullptr), 770b57cec5SDimitry Andric Offset(CharUnits::Zero()) { } 780b57cec5SDimitry Andric }; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric private: 810b57cec5SDimitry Andric /// MostDerivedClass - The most derived class for which the final overriders 820b57cec5SDimitry Andric /// are stored. 830b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass; 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric /// MostDerivedClassOffset - If we're building final overriders for a 860b57cec5SDimitry Andric /// construction vtable, this holds the offset from the layout class to the 870b57cec5SDimitry Andric /// most derived class. 880b57cec5SDimitry Andric const CharUnits MostDerivedClassOffset; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric /// LayoutClass - The class we're using for layout information. Will be 910b57cec5SDimitry Andric /// different than the most derived class if the final overriders are for a 920b57cec5SDimitry Andric /// construction vtable. 930b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric ASTContext &Context; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric /// MostDerivedClassLayout - the AST record layout of the most derived class. 980b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedClassLayout; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric /// MethodBaseOffsetPairTy - Uniquely identifies a member function 1010b57cec5SDimitry Andric /// in a base subobject. 1020b57cec5SDimitry Andric typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric typedef llvm::DenseMap<MethodBaseOffsetPairTy, 1050b57cec5SDimitry Andric OverriderInfo> OverridersMapTy; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric /// OverridersMap - The final overriders for all virtual member functions of 1080b57cec5SDimitry Andric /// all the base subobjects of the most derived class. 1090b57cec5SDimitry Andric OverridersMapTy OverridersMap; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented 1120b57cec5SDimitry Andric /// as a record decl and a subobject number) and its offsets in the most 1130b57cec5SDimitry Andric /// derived class as well as the layout class. 1140b57cec5SDimitry Andric typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>, 1150b57cec5SDimitry Andric CharUnits> SubobjectOffsetMapTy; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the 1200b57cec5SDimitry Andric /// given base. 1210b57cec5SDimitry Andric void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, 1220b57cec5SDimitry Andric CharUnits OffsetInLayoutClass, 1230b57cec5SDimitry Andric SubobjectOffsetMapTy &SubobjectOffsets, 1240b57cec5SDimitry Andric SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, 1250b57cec5SDimitry Andric SubobjectCountMapTy &SubobjectCounts); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric /// dump - dump the final overriders for a base subobject, and all its direct 1300b57cec5SDimitry Andric /// and indirect base subobjects. 1310b57cec5SDimitry Andric void dump(raw_ostream &Out, BaseSubobject Base, 1320b57cec5SDimitry Andric VisitedVirtualBasesSetTy& VisitedVirtualBases); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric public: 1350b57cec5SDimitry Andric FinalOverriders(const CXXRecordDecl *MostDerivedClass, 1360b57cec5SDimitry Andric CharUnits MostDerivedClassOffset, 1370b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric /// getOverrider - Get the final overrider for the given method declaration in 1400b57cec5SDimitry Andric /// the subobject with the given base offset. 1410b57cec5SDimitry Andric OverriderInfo getOverrider(const CXXMethodDecl *MD, 1420b57cec5SDimitry Andric CharUnits BaseOffset) const { 1430b57cec5SDimitry Andric assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) && 1440b57cec5SDimitry Andric "Did not find overrider!"); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric return OverridersMap.lookup(std::make_pair(MD, BaseOffset)); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric /// dump - dump the final overriders. 1500b57cec5SDimitry Andric void dump() { 1510b57cec5SDimitry Andric VisitedVirtualBasesSetTy VisitedVirtualBases; 1520b57cec5SDimitry Andric dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()), 1530b57cec5SDimitry Andric VisitedVirtualBases); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric }; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, 1590b57cec5SDimitry Andric CharUnits MostDerivedClassOffset, 1600b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass) 1610b57cec5SDimitry Andric : MostDerivedClass(MostDerivedClass), 1620b57cec5SDimitry Andric MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), 1630b57cec5SDimitry Andric Context(MostDerivedClass->getASTContext()), 1640b57cec5SDimitry Andric MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // Compute base offsets. 1670b57cec5SDimitry Andric SubobjectOffsetMapTy SubobjectOffsets; 1680b57cec5SDimitry Andric SubobjectOffsetMapTy SubobjectLayoutClassOffsets; 1690b57cec5SDimitry Andric SubobjectCountMapTy SubobjectCounts; 1700b57cec5SDimitry Andric ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 1710b57cec5SDimitry Andric /*IsVirtual=*/false, 1720b57cec5SDimitry Andric MostDerivedClassOffset, 1730b57cec5SDimitry Andric SubobjectOffsets, SubobjectLayoutClassOffsets, 1740b57cec5SDimitry Andric SubobjectCounts); 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric // Get the final overriders. 1770b57cec5SDimitry Andric CXXFinalOverriderMap FinalOverriders; 1780b57cec5SDimitry Andric MostDerivedClass->getFinalOverriders(FinalOverriders); 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric for (const auto &Overrider : FinalOverriders) { 1810b57cec5SDimitry Andric const CXXMethodDecl *MD = Overrider.first; 1820b57cec5SDimitry Andric const OverridingMethods &Methods = Overrider.second; 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric for (const auto &M : Methods) { 1850b57cec5SDimitry Andric unsigned SubobjectNumber = M.first; 1860b57cec5SDimitry Andric assert(SubobjectOffsets.count(std::make_pair(MD->getParent(), 1870b57cec5SDimitry Andric SubobjectNumber)) && 1880b57cec5SDimitry Andric "Did not find subobject offset!"); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), 1910b57cec5SDimitry Andric SubobjectNumber)]; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric assert(M.second.size() == 1 && "Final overrider is not unique!"); 1940b57cec5SDimitry Andric const UniqueVirtualMethod &Method = M.second.front(); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric const CXXRecordDecl *OverriderRD = Method.Method->getParent(); 1970b57cec5SDimitry Andric assert(SubobjectLayoutClassOffsets.count( 1980b57cec5SDimitry Andric std::make_pair(OverriderRD, Method.Subobject)) 1990b57cec5SDimitry Andric && "Did not find subobject offset!"); 2000b57cec5SDimitry Andric CharUnits OverriderOffset = 2010b57cec5SDimitry Andric SubobjectLayoutClassOffsets[std::make_pair(OverriderRD, 2020b57cec5SDimitry Andric Method.Subobject)]; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)]; 2050b57cec5SDimitry Andric assert(!Overrider.Method && "Overrider should not exist yet!"); 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric Overrider.Offset = OverriderOffset; 2080b57cec5SDimitry Andric Overrider.Method = Method.Method; 2090b57cec5SDimitry Andric Overrider.VirtualBase = Method.InVirtualSubobject; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric #if DUMP_OVERRIDERS 2140b57cec5SDimitry Andric // And dump them (for now). 2150b57cec5SDimitry Andric dump(); 2160b57cec5SDimitry Andric #endif 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric static BaseOffset ComputeBaseOffset(const ASTContext &Context, 2200b57cec5SDimitry Andric const CXXRecordDecl *DerivedRD, 2210b57cec5SDimitry Andric const CXXBasePath &Path) { 2220b57cec5SDimitry Andric CharUnits NonVirtualOffset = CharUnits::Zero(); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric unsigned NonVirtualStart = 0; 2250b57cec5SDimitry Andric const CXXRecordDecl *VirtualBase = nullptr; 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric // First, look for the virtual base class. 2280b57cec5SDimitry Andric for (int I = Path.size(), E = 0; I != E; --I) { 2290b57cec5SDimitry Andric const CXXBasePathElement &Element = Path[I - 1]; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric if (Element.Base->isVirtual()) { 2320b57cec5SDimitry Andric NonVirtualStart = I; 2330b57cec5SDimitry Andric QualType VBaseType = Element.Base->getType(); 2340b57cec5SDimitry Andric VirtualBase = VBaseType->getAsCXXRecordDecl(); 2350b57cec5SDimitry Andric break; 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric // Now compute the non-virtual offset. 2400b57cec5SDimitry Andric for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { 2410b57cec5SDimitry Andric const CXXBasePathElement &Element = Path[I]; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric // Check the base class offset. 2440b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl(); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric NonVirtualOffset += Layout.getBaseClassOffset(Base); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // FIXME: This should probably use CharUnits or something. Maybe we should 2520b57cec5SDimitry Andric // even change the base offsets in ASTRecordLayout to be specified in 2530b57cec5SDimitry Andric // CharUnits. 2540b57cec5SDimitry Andric return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset); 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric static BaseOffset ComputeBaseOffset(const ASTContext &Context, 2590b57cec5SDimitry Andric const CXXRecordDecl *BaseRD, 2600b57cec5SDimitry Andric const CXXRecordDecl *DerivedRD) { 2610b57cec5SDimitry Andric CXXBasePaths Paths(/*FindAmbiguities=*/false, 2620b57cec5SDimitry Andric /*RecordPaths=*/true, /*DetectVirtual=*/false); 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric if (!DerivedRD->isDerivedFrom(BaseRD, Paths)) 2650b57cec5SDimitry Andric llvm_unreachable("Class must be derived from the passed in base class!"); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric return ComputeBaseOffset(Context, DerivedRD, Paths.front()); 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric static BaseOffset 2710b57cec5SDimitry Andric ComputeReturnAdjustmentBaseOffset(ASTContext &Context, 2720b57cec5SDimitry Andric const CXXMethodDecl *DerivedMD, 2730b57cec5SDimitry Andric const CXXMethodDecl *BaseMD) { 274480093f4SDimitry Andric const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>(); 275480093f4SDimitry Andric const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>(); 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric // Canonicalize the return types. 2780b57cec5SDimitry Andric CanQualType CanDerivedReturnType = 2790b57cec5SDimitry Andric Context.getCanonicalType(DerivedFT->getReturnType()); 2800b57cec5SDimitry Andric CanQualType CanBaseReturnType = 2810b57cec5SDimitry Andric Context.getCanonicalType(BaseFT->getReturnType()); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric assert(CanDerivedReturnType->getTypeClass() == 2840b57cec5SDimitry Andric CanBaseReturnType->getTypeClass() && 2850b57cec5SDimitry Andric "Types must have same type class!"); 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric if (CanDerivedReturnType == CanBaseReturnType) { 2880b57cec5SDimitry Andric // No adjustment needed. 2890b57cec5SDimitry Andric return BaseOffset(); 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric if (isa<ReferenceType>(CanDerivedReturnType)) { 2930b57cec5SDimitry Andric CanDerivedReturnType = 2940b57cec5SDimitry Andric CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType(); 2950b57cec5SDimitry Andric CanBaseReturnType = 2960b57cec5SDimitry Andric CanBaseReturnType->getAs<ReferenceType>()->getPointeeType(); 2970b57cec5SDimitry Andric } else if (isa<PointerType>(CanDerivedReturnType)) { 2980b57cec5SDimitry Andric CanDerivedReturnType = 2990b57cec5SDimitry Andric CanDerivedReturnType->getAs<PointerType>()->getPointeeType(); 3000b57cec5SDimitry Andric CanBaseReturnType = 3010b57cec5SDimitry Andric CanBaseReturnType->getAs<PointerType>()->getPointeeType(); 3020b57cec5SDimitry Andric } else { 3030b57cec5SDimitry Andric llvm_unreachable("Unexpected return type!"); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric // We need to compare unqualified types here; consider 3070b57cec5SDimitry Andric // const T *Base::foo(); 3080b57cec5SDimitry Andric // T *Derived::foo(); 3090b57cec5SDimitry Andric if (CanDerivedReturnType.getUnqualifiedType() == 3100b57cec5SDimitry Andric CanBaseReturnType.getUnqualifiedType()) { 3110b57cec5SDimitry Andric // No adjustment needed. 3120b57cec5SDimitry Andric return BaseOffset(); 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric const CXXRecordDecl *DerivedRD = 3160b57cec5SDimitry Andric cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric const CXXRecordDecl *BaseRD = 3190b57cec5SDimitry Andric cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric return ComputeBaseOffset(Context, BaseRD, DerivedRD); 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric void 3250b57cec5SDimitry Andric FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, 3260b57cec5SDimitry Andric CharUnits OffsetInLayoutClass, 3270b57cec5SDimitry Andric SubobjectOffsetMapTy &SubobjectOffsets, 3280b57cec5SDimitry Andric SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, 3290b57cec5SDimitry Andric SubobjectCountMapTy &SubobjectCounts) { 3300b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric unsigned SubobjectNumber = 0; 3330b57cec5SDimitry Andric if (!IsVirtual) 3340b57cec5SDimitry Andric SubobjectNumber = ++SubobjectCounts[RD]; 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric // Set up the subobject to offset mapping. 3370b57cec5SDimitry Andric assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber)) 3380b57cec5SDimitry Andric && "Subobject offset already exists!"); 3390b57cec5SDimitry Andric assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber)) 3400b57cec5SDimitry Andric && "Subobject offset already exists!"); 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset(); 3430b57cec5SDimitry Andric SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] = 3440b57cec5SDimitry Andric OffsetInLayoutClass; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // Traverse our bases. 3470b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 3480b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric CharUnits BaseOffset; 3510b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass; 3520b57cec5SDimitry Andric if (B.isVirtual()) { 3530b57cec5SDimitry Andric // Check if we've visited this virtual base before. 3540b57cec5SDimitry Andric if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0))) 3550b57cec5SDimitry Andric continue; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 3580b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); 3610b57cec5SDimitry Andric BaseOffsetInLayoutClass = 3620b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(BaseDecl); 3630b57cec5SDimitry Andric } else { 3640b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 3650b57cec5SDimitry Andric CharUnits Offset = Layout.getBaseClassOffset(BaseDecl); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric BaseOffset = Base.getBaseOffset() + Offset; 3680b57cec5SDimitry Andric BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset; 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), 3720b57cec5SDimitry Andric B.isVirtual(), BaseOffsetInLayoutClass, 3730b57cec5SDimitry Andric SubobjectOffsets, SubobjectLayoutClassOffsets, 3740b57cec5SDimitry Andric SubobjectCounts); 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, 3790b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VisitedVirtualBases) { 3800b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 3810b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 3840b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric // Ignore bases that don't have any virtual member functions. 3870b57cec5SDimitry Andric if (!BaseDecl->isPolymorphic()) 3880b57cec5SDimitry Andric continue; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric CharUnits BaseOffset; 3910b57cec5SDimitry Andric if (B.isVirtual()) { 3920b57cec5SDimitry Andric if (!VisitedVirtualBases.insert(BaseDecl).second) { 3930b57cec5SDimitry Andric // We've visited this base before. 3940b57cec5SDimitry Andric continue; 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); 3980b57cec5SDimitry Andric } else { 3990b57cec5SDimitry Andric BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric Out << "Final overriders for ("; 4060b57cec5SDimitry Andric RD->printQualifiedName(Out); 4070b57cec5SDimitry Andric Out << ", "; 4080b57cec5SDimitry Andric Out << Base.getBaseOffset().getQuantity() << ")\n"; 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric // Now dump the overriders for this base subobject. 4110b57cec5SDimitry Andric for (const auto *MD : RD->methods()) { 4125ffd83dbSDimitry Andric if (!VTableContextBase::hasVtableSlot(MD)) 4130b57cec5SDimitry Andric continue; 4140b57cec5SDimitry Andric MD = MD->getCanonicalDecl(); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset()); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric Out << " "; 4190b57cec5SDimitry Andric MD->printQualifiedName(Out); 4200b57cec5SDimitry Andric Out << " - ("; 4210b57cec5SDimitry Andric Overrider.Method->printQualifiedName(Out); 4220b57cec5SDimitry Andric Out << ", " << Overrider.Offset.getQuantity() << ')'; 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric BaseOffset Offset; 4257a6dacacSDimitry Andric if (!Overrider.Method->isPureVirtual()) 4260b57cec5SDimitry Andric Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric if (!Offset.isEmpty()) { 4290b57cec5SDimitry Andric Out << " [ret-adj: "; 4300b57cec5SDimitry Andric if (Offset.VirtualBase) { 4310b57cec5SDimitry Andric Offset.VirtualBase->printQualifiedName(Out); 4320b57cec5SDimitry Andric Out << " vbase, "; 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric Out << Offset.NonVirtualOffset.getQuantity() << " nv]"; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric Out << "\n"; 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric } 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric /// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. 4430b57cec5SDimitry Andric struct VCallOffsetMap { 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy; 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric /// Offsets - Keeps track of methods and their offsets. 4480b57cec5SDimitry Andric // FIXME: This should be a real map and not a vector. 4490b57cec5SDimitry Andric SmallVector<MethodAndOffsetPairTy, 16> Offsets; 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric /// MethodsCanShareVCallOffset - Returns whether two virtual member functions 4520b57cec5SDimitry Andric /// can share the same vcall offset. 4530b57cec5SDimitry Andric static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, 4540b57cec5SDimitry Andric const CXXMethodDecl *RHS); 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric public: 4570b57cec5SDimitry Andric /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the 4580b57cec5SDimitry Andric /// add was successful, or false if there was already a member function with 4590b57cec5SDimitry Andric /// the same signature in the map. 4600b57cec5SDimitry Andric bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset); 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the 4630b57cec5SDimitry Andric /// vtable address point) for the given virtual member function. 4640b57cec5SDimitry Andric CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD); 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // empty - Return whether the offset map is empty or not. 4670b57cec5SDimitry Andric bool empty() const { return Offsets.empty(); } 4680b57cec5SDimitry Andric }; 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, 4710b57cec5SDimitry Andric const CXXMethodDecl *RHS) { 4720b57cec5SDimitry Andric const FunctionProtoType *LT = 4730b57cec5SDimitry Andric cast<FunctionProtoType>(LHS->getType().getCanonicalType()); 4740b57cec5SDimitry Andric const FunctionProtoType *RT = 4750b57cec5SDimitry Andric cast<FunctionProtoType>(RHS->getType().getCanonicalType()); 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric // Fast-path matches in the canonical types. 4780b57cec5SDimitry Andric if (LT == RT) return true; 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric // Force the signatures to match. We can't rely on the overrides 4810b57cec5SDimitry Andric // list here because there isn't necessarily an inheritance 4820b57cec5SDimitry Andric // relationship between the two methods. 4830b57cec5SDimitry Andric if (LT->getMethodQuals() != RT->getMethodQuals()) 4840b57cec5SDimitry Andric return false; 4850b57cec5SDimitry Andric return LT->getParamTypes() == RT->getParamTypes(); 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, 4890b57cec5SDimitry Andric const CXXMethodDecl *RHS) { 4905ffd83dbSDimitry Andric assert(VTableContextBase::hasVtableSlot(LHS) && "LHS must be virtual!"); 491fe6060f1SDimitry Andric assert(VTableContextBase::hasVtableSlot(RHS) && "RHS must be virtual!"); 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric // A destructor can share a vcall offset with another destructor. 4940b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(LHS)) 4950b57cec5SDimitry Andric return isa<CXXDestructorDecl>(RHS); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // FIXME: We need to check more things here. 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric // The methods must have the same name. 5000b57cec5SDimitry Andric DeclarationName LHSName = LHS->getDeclName(); 5010b57cec5SDimitry Andric DeclarationName RHSName = RHS->getDeclName(); 5020b57cec5SDimitry Andric if (LHSName != RHSName) 5030b57cec5SDimitry Andric return false; 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric // And the same signatures. 5060b57cec5SDimitry Andric return HasSameVirtualSignature(LHS, RHS); 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, 5100b57cec5SDimitry Andric CharUnits OffsetOffset) { 5110b57cec5SDimitry Andric // Check if we can reuse an offset. 5120b57cec5SDimitry Andric for (const auto &OffsetPair : Offsets) { 5130b57cec5SDimitry Andric if (MethodsCanShareVCallOffset(OffsetPair.first, MD)) 5140b57cec5SDimitry Andric return false; 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric // Add the offset. 5180b57cec5SDimitry Andric Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); 5190b57cec5SDimitry Andric return true; 5200b57cec5SDimitry Andric } 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { 5230b57cec5SDimitry Andric // Look for an offset. 5240b57cec5SDimitry Andric for (const auto &OffsetPair : Offsets) { 5250b57cec5SDimitry Andric if (MethodsCanShareVCallOffset(OffsetPair.first, MD)) 5260b57cec5SDimitry Andric return OffsetPair.second; 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric llvm_unreachable("Should always find a vcall offset offset!"); 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric /// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. 5330b57cec5SDimitry Andric class VCallAndVBaseOffsetBuilder { 5340b57cec5SDimitry Andric public: 5350b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> 5360b57cec5SDimitry Andric VBaseOffsetOffsetsMapTy; 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric private: 5395ffd83dbSDimitry Andric const ItaniumVTableContext &VTables; 5405ffd83dbSDimitry Andric 5410b57cec5SDimitry Andric /// MostDerivedClass - The most derived class for which we're building vcall 5420b57cec5SDimitry Andric /// and vbase offsets. 5430b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass; 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric /// LayoutClass - The class we're using for layout information. Will be 5460b57cec5SDimitry Andric /// different than the most derived class if we're building a construction 5470b57cec5SDimitry Andric /// vtable. 5480b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass; 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric /// Context - The ASTContext which we will use for layout information. 5510b57cec5SDimitry Andric ASTContext &Context; 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric /// Components - vcall and vbase offset components 5540b57cec5SDimitry Andric typedef SmallVector<VTableComponent, 64> VTableComponentVectorTy; 5550b57cec5SDimitry Andric VTableComponentVectorTy Components; 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric /// VisitedVirtualBases - Visited virtual bases. 5580b57cec5SDimitry Andric llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric /// VCallOffsets - Keeps track of vcall offsets. 5610b57cec5SDimitry Andric VCallOffsetMap VCallOffsets; 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, 5650b57cec5SDimitry Andric /// relative to the address point. 5660b57cec5SDimitry Andric VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric /// FinalOverriders - The final overriders of the most derived class. 5690b57cec5SDimitry Andric /// (Can be null when we're not building a vtable of the most derived class). 5700b57cec5SDimitry Andric const FinalOverriders *Overriders; 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the 5730b57cec5SDimitry Andric /// given base subobject. 5740b57cec5SDimitry Andric void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, 5750b57cec5SDimitry Andric CharUnits RealBaseOffset); 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric /// AddVCallOffsets - Add vcall offsets for the given base subobject. 5780b57cec5SDimitry Andric void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset); 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric /// AddVBaseOffsets - Add vbase offsets for the given class. 5810b57cec5SDimitry Andric void AddVBaseOffsets(const CXXRecordDecl *Base, 5820b57cec5SDimitry Andric CharUnits OffsetInLayoutClass); 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in 5850b57cec5SDimitry Andric /// chars, relative to the vtable address point. 5860b57cec5SDimitry Andric CharUnits getCurrentOffsetOffset() const; 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric public: 5895ffd83dbSDimitry Andric VCallAndVBaseOffsetBuilder(const ItaniumVTableContext &VTables, 5905ffd83dbSDimitry Andric const CXXRecordDecl *MostDerivedClass, 5910b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass, 5920b57cec5SDimitry Andric const FinalOverriders *Overriders, 5930b57cec5SDimitry Andric BaseSubobject Base, bool BaseIsVirtual, 5940b57cec5SDimitry Andric CharUnits OffsetInLayoutClass) 5955ffd83dbSDimitry Andric : VTables(VTables), MostDerivedClass(MostDerivedClass), 5965ffd83dbSDimitry Andric LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), 5975ffd83dbSDimitry Andric Overriders(Overriders) { 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric // Add vcall and vbase offsets. 6000b57cec5SDimitry Andric AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric /// Methods for iterating over the components. 6040b57cec5SDimitry Andric typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; 6050b57cec5SDimitry Andric const_iterator components_begin() const { return Components.rbegin(); } 6060b57cec5SDimitry Andric const_iterator components_end() const { return Components.rend(); } 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } 6090b57cec5SDimitry Andric const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { 6100b57cec5SDimitry Andric return VBaseOffsetOffsets; 6110b57cec5SDimitry Andric } 6120b57cec5SDimitry Andric }; 6130b57cec5SDimitry Andric 6140b57cec5SDimitry Andric void 6150b57cec5SDimitry Andric VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, 6160b57cec5SDimitry Andric bool BaseIsVirtual, 6170b57cec5SDimitry Andric CharUnits RealBaseOffset) { 6180b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric // Itanium C++ ABI 2.5.2: 6210b57cec5SDimitry Andric // ..in classes sharing a virtual table with a primary base class, the vcall 6220b57cec5SDimitry Andric // and vbase offsets added by the derived class all come before the vcall 6230b57cec5SDimitry Andric // and vbase offsets required by the base class, so that the latter may be 6240b57cec5SDimitry Andric // laid out as required by the base class without regard to additions from 6250b57cec5SDimitry Andric // the derived class(es). 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric // (Since we're emitting the vcall and vbase offsets in reverse order, we'll 6280b57cec5SDimitry Andric // emit them for the primary base first). 6290b57cec5SDimitry Andric if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { 6300b57cec5SDimitry Andric bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric CharUnits PrimaryBaseOffset; 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric // Get the base offset of the primary base. 6350b57cec5SDimitry Andric if (PrimaryBaseIsVirtual) { 6360b57cec5SDimitry Andric assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && 6370b57cec5SDimitry Andric "Primary vbase should have a zero offset!"); 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedClassLayout = 6400b57cec5SDimitry Andric Context.getASTRecordLayout(MostDerivedClass); 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric PrimaryBaseOffset = 6430b57cec5SDimitry Andric MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); 6440b57cec5SDimitry Andric } else { 6450b57cec5SDimitry Andric assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && 6460b57cec5SDimitry Andric "Primary base should have a zero offset!"); 6470b57cec5SDimitry Andric 6480b57cec5SDimitry Andric PrimaryBaseOffset = Base.getBaseOffset(); 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric AddVCallAndVBaseOffsets( 6520b57cec5SDimitry Andric BaseSubobject(PrimaryBase,PrimaryBaseOffset), 6530b57cec5SDimitry Andric PrimaryBaseIsVirtual, RealBaseOffset); 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric AddVBaseOffsets(Base.getBase(), RealBaseOffset); 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric // We only want to add vcall offsets for virtual bases. 6590b57cec5SDimitry Andric if (BaseIsVirtual) 6600b57cec5SDimitry Andric AddVCallOffsets(Base, RealBaseOffset); 6610b57cec5SDimitry Andric } 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { 6640b57cec5SDimitry Andric // OffsetIndex is the index of this vcall or vbase offset, relative to the 6650b57cec5SDimitry Andric // vtable address point. (We subtract 3 to account for the information just 6660b57cec5SDimitry Andric // above the address point, the RTTI info, the offset to top, and the 6670b57cec5SDimitry Andric // vcall offset itself). 6685f757f3fSDimitry Andric size_t NumComponentsAboveAddrPoint = 3; 6695f757f3fSDimitry Andric if (Context.getLangOpts().OmitVTableRTTI) 6705f757f3fSDimitry Andric NumComponentsAboveAddrPoint--; 6715f757f3fSDimitry Andric int64_t OffsetIndex = 6725f757f3fSDimitry Andric -(int64_t)(NumComponentsAboveAddrPoint + Components.size()); 6730b57cec5SDimitry Andric 6745ffd83dbSDimitry Andric // Under the relative ABI, the offset widths are 32-bit ints instead of 6755ffd83dbSDimitry Andric // pointer widths. 6765ffd83dbSDimitry Andric CharUnits OffsetWidth = Context.toCharUnitsFromBits( 677bdd1243dSDimitry Andric VTables.isRelativeLayout() 678bdd1243dSDimitry Andric ? 32 679bdd1243dSDimitry Andric : Context.getTargetInfo().getPointerWidth(LangAS::Default)); 6805ffd83dbSDimitry Andric CharUnits OffsetOffset = OffsetWidth * OffsetIndex; 6815ffd83dbSDimitry Andric 6820b57cec5SDimitry Andric return OffsetOffset; 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, 6860b57cec5SDimitry Andric CharUnits VBaseOffset) { 6870b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 6880b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric // Handle the primary base first. 6930b57cec5SDimitry Andric // We only want to add vcall offsets if the base is non-virtual; a virtual 6940b57cec5SDimitry Andric // primary base will have its vcall and vbase offsets emitted already. 6950b57cec5SDimitry Andric if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) { 6960b57cec5SDimitry Andric // Get the base offset of the primary base. 6970b57cec5SDimitry Andric assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && 6980b57cec5SDimitry Andric "Primary base should have a zero offset!"); 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), 7010b57cec5SDimitry Andric VBaseOffset); 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric // Add the vcall offsets. 7050b57cec5SDimitry Andric for (const auto *MD : RD->methods()) { 7065ffd83dbSDimitry Andric if (!VTableContextBase::hasVtableSlot(MD)) 7070b57cec5SDimitry Andric continue; 7080b57cec5SDimitry Andric MD = MD->getCanonicalDecl(); 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric CharUnits OffsetOffset = getCurrentOffsetOffset(); 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric // Don't add a vcall offset if we already have one for this member function 7130b57cec5SDimitry Andric // signature. 7140b57cec5SDimitry Andric if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) 7150b57cec5SDimitry Andric continue; 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric CharUnits Offset = CharUnits::Zero(); 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric if (Overriders) { 7200b57cec5SDimitry Andric // Get the final overrider. 7210b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider = 7220b57cec5SDimitry Andric Overriders->getOverrider(MD, Base.getBaseOffset()); 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric /// The vcall offset is the offset from the virtual base to the object 7250b57cec5SDimitry Andric /// where the function was overridden. 7260b57cec5SDimitry Andric Offset = Overrider.Offset - VBaseOffset; 7270b57cec5SDimitry Andric } 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric Components.push_back( 7300b57cec5SDimitry Andric VTableComponent::MakeVCallOffset(Offset)); 7310b57cec5SDimitry Andric } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric // And iterate over all non-virtual bases (ignoring the primary base). 7340b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 7350b57cec5SDimitry Andric if (B.isVirtual()) 7360b57cec5SDimitry Andric continue; 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 7390b57cec5SDimitry Andric if (BaseDecl == PrimaryBase) 7400b57cec5SDimitry Andric continue; 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric // Get the base offset of this base. 7430b57cec5SDimitry Andric CharUnits BaseOffset = Base.getBaseOffset() + 7440b57cec5SDimitry Andric Layout.getBaseClassOffset(BaseDecl); 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), 7470b57cec5SDimitry Andric VBaseOffset); 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric void 7520b57cec5SDimitry Andric VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, 7530b57cec5SDimitry Andric CharUnits OffsetInLayoutClass) { 7540b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 7550b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric // Add vbase offsets. 7580b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 7590b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric // Check if this is a virtual base that we haven't visited before. 7620b57cec5SDimitry Andric if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) { 7630b57cec5SDimitry Andric CharUnits Offset = 7640b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric // Add the vbase offset offset. 7670b57cec5SDimitry Andric assert(!VBaseOffsetOffsets.count(BaseDecl) && 7680b57cec5SDimitry Andric "vbase offset offset already exists!"); 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric CharUnits VBaseOffsetOffset = getCurrentOffsetOffset(); 7710b57cec5SDimitry Andric VBaseOffsetOffsets.insert( 7720b57cec5SDimitry Andric std::make_pair(BaseDecl, VBaseOffsetOffset)); 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric Components.push_back( 7750b57cec5SDimitry Andric VTableComponent::MakeVBaseOffset(Offset)); 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric // Check the base class looking for more vbase offsets. 7790b57cec5SDimitry Andric AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric } 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric /// ItaniumVTableBuilder - Class for building vtable layout information. 7840b57cec5SDimitry Andric class ItaniumVTableBuilder { 7850b57cec5SDimitry Andric public: 7860b57cec5SDimitry Andric /// PrimaryBasesSetVectorTy - A set vector of direct and indirect 7870b57cec5SDimitry Andric /// primary bases. 7880b57cec5SDimitry Andric typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> 7890b57cec5SDimitry Andric PrimaryBasesSetVectorTy; 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> 7920b57cec5SDimitry Andric VBaseOffsetOffsetsMapTy; 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric typedef VTableLayout::AddressPointsMapTy AddressPointsMapTy; 7950b57cec5SDimitry Andric 7960b57cec5SDimitry Andric typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric private: 7990b57cec5SDimitry Andric /// VTables - Global vtable information. 8000b57cec5SDimitry Andric ItaniumVTableContext &VTables; 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric /// MostDerivedClass - The most derived class for which we're building this 8030b57cec5SDimitry Andric /// vtable. 8040b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass; 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric /// MostDerivedClassOffset - If we're building a construction vtable, this 8070b57cec5SDimitry Andric /// holds the offset from the layout class to the most derived class. 8080b57cec5SDimitry Andric const CharUnits MostDerivedClassOffset; 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual 8110b57cec5SDimitry Andric /// base. (This only makes sense when building a construction vtable). 8120b57cec5SDimitry Andric bool MostDerivedClassIsVirtual; 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric /// LayoutClass - The class we're using for layout information. Will be 8150b57cec5SDimitry Andric /// different than the most derived class if we're building a construction 8160b57cec5SDimitry Andric /// vtable. 8170b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass; 8180b57cec5SDimitry Andric 8190b57cec5SDimitry Andric /// Context - The ASTContext which we will use for layout information. 8200b57cec5SDimitry Andric ASTContext &Context; 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric /// FinalOverriders - The final overriders of the most derived class. 8230b57cec5SDimitry Andric const FinalOverriders Overriders; 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual 8260b57cec5SDimitry Andric /// bases in this vtable. 8270b57cec5SDimitry Andric llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for 8300b57cec5SDimitry Andric /// the most derived class. 8310b57cec5SDimitry Andric VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric /// Components - The components of the vtable being built. 8340b57cec5SDimitry Andric SmallVector<VTableComponent, 64> Components; 8350b57cec5SDimitry Andric 8360b57cec5SDimitry Andric /// AddressPoints - Address points for the vtable being built. 8370b57cec5SDimitry Andric AddressPointsMapTy AddressPoints; 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric /// MethodInfo - Contains information about a method in a vtable. 8400b57cec5SDimitry Andric /// (Used for computing 'this' pointer adjustment thunks. 8410b57cec5SDimitry Andric struct MethodInfo { 8420b57cec5SDimitry Andric /// BaseOffset - The base offset of this method. 8430b57cec5SDimitry Andric const CharUnits BaseOffset; 8440b57cec5SDimitry Andric 8450b57cec5SDimitry Andric /// BaseOffsetInLayoutClass - The base offset in the layout class of this 8460b57cec5SDimitry Andric /// method. 8470b57cec5SDimitry Andric const CharUnits BaseOffsetInLayoutClass; 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric /// VTableIndex - The index in the vtable that this method has. 8500b57cec5SDimitry Andric /// (For destructors, this is the index of the complete destructor). 8510b57cec5SDimitry Andric const uint64_t VTableIndex; 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass, 8540b57cec5SDimitry Andric uint64_t VTableIndex) 8550b57cec5SDimitry Andric : BaseOffset(BaseOffset), 8560b57cec5SDimitry Andric BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), 8570b57cec5SDimitry Andric VTableIndex(VTableIndex) { } 8580b57cec5SDimitry Andric 8590b57cec5SDimitry Andric MethodInfo() 8600b57cec5SDimitry Andric : BaseOffset(CharUnits::Zero()), 8610b57cec5SDimitry Andric BaseOffsetInLayoutClass(CharUnits::Zero()), 8620b57cec5SDimitry Andric VTableIndex(0) { } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric MethodInfo(MethodInfo const&) = default; 8650b57cec5SDimitry Andric }; 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; 8680b57cec5SDimitry Andric 8690b57cec5SDimitry Andric /// MethodInfoMap - The information for all methods in the vtable we're 8700b57cec5SDimitry Andric /// currently building. 8710b57cec5SDimitry Andric MethodInfoMapTy MethodInfoMap; 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric /// MethodVTableIndices - Contains the index (relative to the vtable address 8740b57cec5SDimitry Andric /// point) where the function pointer for a virtual function is stored. 8750b57cec5SDimitry Andric MethodVTableIndicesTy MethodVTableIndices; 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric /// VTableThunks - The thunks by vtable index in the vtable currently being 8800b57cec5SDimitry Andric /// built. 8810b57cec5SDimitry Andric VTableThunksMapTy VTableThunks; 8820b57cec5SDimitry Andric 8830b57cec5SDimitry Andric typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 8840b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric /// Thunks - A map that contains all the thunks needed for all methods in the 8870b57cec5SDimitry Andric /// most derived class for which the vtable is currently being built. 8880b57cec5SDimitry Andric ThunksMapTy Thunks; 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric /// AddThunk - Add a thunk for the given method. 8910b57cec5SDimitry Andric void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the 8940b57cec5SDimitry Andric /// part of the vtable we're currently building. 8950b57cec5SDimitry Andric void ComputeThisAdjustments(); 8960b57cec5SDimitry Andric 8970b57cec5SDimitry Andric typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric /// PrimaryVirtualBases - All known virtual bases who are a primary base of 9000b57cec5SDimitry Andric /// some other base. 9010b57cec5SDimitry Andric VisitedVirtualBasesSetTy PrimaryVirtualBases; 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric /// ComputeReturnAdjustment - Compute the return adjustment given a return 9040b57cec5SDimitry Andric /// adjustment base offset. 9050b57cec5SDimitry Andric ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting 9080b57cec5SDimitry Andric /// the 'this' pointer from the base subobject to the derived subobject. 9090b57cec5SDimitry Andric BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, 9100b57cec5SDimitry Andric BaseSubobject Derived) const; 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the 9130b57cec5SDimitry Andric /// given virtual member function, its offset in the layout class and its 9140b57cec5SDimitry Andric /// final overrider. 9150b57cec5SDimitry Andric ThisAdjustment 9160b57cec5SDimitry Andric ComputeThisAdjustment(const CXXMethodDecl *MD, 9170b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass, 9180b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider); 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric /// AddMethod - Add a single virtual member function to the vtable 9210b57cec5SDimitry Andric /// components vector. 9220b57cec5SDimitry Andric void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric /// IsOverriderUsed - Returns whether the overrider will ever be used in this 9250b57cec5SDimitry Andric /// part of the vtable. 9260b57cec5SDimitry Andric /// 9270b57cec5SDimitry Andric /// Itanium C++ ABI 2.5.2: 9280b57cec5SDimitry Andric /// 9290b57cec5SDimitry Andric /// struct A { virtual void f(); }; 9300b57cec5SDimitry Andric /// struct B : virtual public A { int i; }; 9310b57cec5SDimitry Andric /// struct C : virtual public A { int j; }; 9320b57cec5SDimitry Andric /// struct D : public B, public C {}; 9330b57cec5SDimitry Andric /// 9340b57cec5SDimitry Andric /// When B and C are declared, A is a primary base in each case, so although 9350b57cec5SDimitry Andric /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this 9360b57cec5SDimitry Andric /// adjustment is required and no thunk is generated. However, inside D 9370b57cec5SDimitry Andric /// objects, A is no longer a primary base of C, so if we allowed calls to 9380b57cec5SDimitry Andric /// C::f() to use the copy of A's vtable in the C subobject, we would need 9390b57cec5SDimitry Andric /// to adjust this from C* to B::A*, which would require a third-party 9400b57cec5SDimitry Andric /// thunk. Since we require that a call to C::f() first convert to A*, 9410b57cec5SDimitry Andric /// C-in-D's copy of A's vtable is never referenced, so this is not 9420b57cec5SDimitry Andric /// necessary. 9430b57cec5SDimitry Andric bool IsOverriderUsed(const CXXMethodDecl *Overrider, 9440b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass, 9450b57cec5SDimitry Andric const CXXRecordDecl *FirstBaseInPrimaryBaseChain, 9460b57cec5SDimitry Andric CharUnits FirstBaseOffsetInLayoutClass) const; 9470b57cec5SDimitry Andric 9480b57cec5SDimitry Andric 9490b57cec5SDimitry Andric /// AddMethods - Add the methods of this base subobject and all its 9500b57cec5SDimitry Andric /// primary bases to the vtable components vector. 9510b57cec5SDimitry Andric void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, 9520b57cec5SDimitry Andric const CXXRecordDecl *FirstBaseInPrimaryBaseChain, 9530b57cec5SDimitry Andric CharUnits FirstBaseOffsetInLayoutClass, 9540b57cec5SDimitry Andric PrimaryBasesSetVectorTy &PrimaryBases); 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric // LayoutVTable - Layout the vtable for the given base class, including its 9570b57cec5SDimitry Andric // secondary vtables and any vtables for virtual bases. 9580b57cec5SDimitry Andric void LayoutVTable(); 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the 9610b57cec5SDimitry Andric /// given base subobject, as well as all its secondary vtables. 9620b57cec5SDimitry Andric /// 9630b57cec5SDimitry Andric /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base 9640b57cec5SDimitry Andric /// or a direct or indirect base of a virtual base. 9650b57cec5SDimitry Andric /// 9660b57cec5SDimitry Andric /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual 9670b57cec5SDimitry Andric /// in the layout class. 9680b57cec5SDimitry Andric void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, 9690b57cec5SDimitry Andric bool BaseIsMorallyVirtual, 9700b57cec5SDimitry Andric bool BaseIsVirtualInLayoutClass, 9710b57cec5SDimitry Andric CharUnits OffsetInLayoutClass); 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric /// LayoutSecondaryVTables - Layout the secondary vtables for the given base 9740b57cec5SDimitry Andric /// subobject. 9750b57cec5SDimitry Andric /// 9760b57cec5SDimitry Andric /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base 9770b57cec5SDimitry Andric /// or a direct or indirect base of a virtual base. 9780b57cec5SDimitry Andric void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, 9790b57cec5SDimitry Andric CharUnits OffsetInLayoutClass); 9800b57cec5SDimitry Andric 9810b57cec5SDimitry Andric /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this 9820b57cec5SDimitry Andric /// class hierarchy. 9830b57cec5SDimitry Andric void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, 9840b57cec5SDimitry Andric CharUnits OffsetInLayoutClass, 9850b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VBases); 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the 9880b57cec5SDimitry Andric /// given base (excluding any primary bases). 9890b57cec5SDimitry Andric void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, 9900b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VBases); 9910b57cec5SDimitry Andric 9920b57cec5SDimitry Andric /// isBuildingConstructionVTable - Return whether this vtable builder is 9930b57cec5SDimitry Andric /// building a construction vtable. 9940b57cec5SDimitry Andric bool isBuildingConstructorVTable() const { 9950b57cec5SDimitry Andric return MostDerivedClass != LayoutClass; 9960b57cec5SDimitry Andric } 9970b57cec5SDimitry Andric 9980b57cec5SDimitry Andric public: 9990b57cec5SDimitry Andric /// Component indices of the first component of each of the vtables in the 10000b57cec5SDimitry Andric /// vtable group. 10010b57cec5SDimitry Andric SmallVector<size_t, 4> VTableIndices; 10020b57cec5SDimitry Andric 10030b57cec5SDimitry Andric ItaniumVTableBuilder(ItaniumVTableContext &VTables, 10040b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass, 10050b57cec5SDimitry Andric CharUnits MostDerivedClassOffset, 10060b57cec5SDimitry Andric bool MostDerivedClassIsVirtual, 10070b57cec5SDimitry Andric const CXXRecordDecl *LayoutClass) 10080b57cec5SDimitry Andric : VTables(VTables), MostDerivedClass(MostDerivedClass), 10090b57cec5SDimitry Andric MostDerivedClassOffset(MostDerivedClassOffset), 10100b57cec5SDimitry Andric MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), 10110b57cec5SDimitry Andric LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), 10120b57cec5SDimitry Andric Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { 10130b57cec5SDimitry Andric assert(!Context.getTargetInfo().getCXXABI().isMicrosoft()); 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andric LayoutVTable(); 10160b57cec5SDimitry Andric 10170b57cec5SDimitry Andric if (Context.getLangOpts().DumpVTableLayouts) 10180b57cec5SDimitry Andric dumpLayout(llvm::outs()); 10190b57cec5SDimitry Andric } 10200b57cec5SDimitry Andric 10210b57cec5SDimitry Andric uint64_t getNumThunks() const { 10220b57cec5SDimitry Andric return Thunks.size(); 10230b57cec5SDimitry Andric } 10240b57cec5SDimitry Andric 10250b57cec5SDimitry Andric ThunksMapTy::const_iterator thunks_begin() const { 10260b57cec5SDimitry Andric return Thunks.begin(); 10270b57cec5SDimitry Andric } 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric ThunksMapTy::const_iterator thunks_end() const { 10300b57cec5SDimitry Andric return Thunks.end(); 10310b57cec5SDimitry Andric } 10320b57cec5SDimitry Andric 10330b57cec5SDimitry Andric const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { 10340b57cec5SDimitry Andric return VBaseOffsetOffsets; 10350b57cec5SDimitry Andric } 10360b57cec5SDimitry Andric 10370b57cec5SDimitry Andric const AddressPointsMapTy &getAddressPoints() const { 10380b57cec5SDimitry Andric return AddressPoints; 10390b57cec5SDimitry Andric } 10400b57cec5SDimitry Andric 10410b57cec5SDimitry Andric MethodVTableIndicesTy::const_iterator vtable_indices_begin() const { 10420b57cec5SDimitry Andric return MethodVTableIndices.begin(); 10430b57cec5SDimitry Andric } 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric MethodVTableIndicesTy::const_iterator vtable_indices_end() const { 10460b57cec5SDimitry Andric return MethodVTableIndices.end(); 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric ArrayRef<VTableComponent> vtable_components() const { return Components; } 10500b57cec5SDimitry Andric 10510b57cec5SDimitry Andric AddressPointsMapTy::const_iterator address_points_begin() const { 10520b57cec5SDimitry Andric return AddressPoints.begin(); 10530b57cec5SDimitry Andric } 10540b57cec5SDimitry Andric 10550b57cec5SDimitry Andric AddressPointsMapTy::const_iterator address_points_end() const { 10560b57cec5SDimitry Andric return AddressPoints.end(); 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric VTableThunksMapTy::const_iterator vtable_thunks_begin() const { 10600b57cec5SDimitry Andric return VTableThunks.begin(); 10610b57cec5SDimitry Andric } 10620b57cec5SDimitry Andric 10630b57cec5SDimitry Andric VTableThunksMapTy::const_iterator vtable_thunks_end() const { 10640b57cec5SDimitry Andric return VTableThunks.end(); 10650b57cec5SDimitry Andric } 10660b57cec5SDimitry Andric 10670b57cec5SDimitry Andric /// dumpLayout - Dump the vtable layout. 10680b57cec5SDimitry Andric void dumpLayout(raw_ostream&); 10690b57cec5SDimitry Andric }; 10700b57cec5SDimitry Andric 10710b57cec5SDimitry Andric void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD, 10720b57cec5SDimitry Andric const ThunkInfo &Thunk) { 10730b57cec5SDimitry Andric assert(!isBuildingConstructorVTable() && 10740b57cec5SDimitry Andric "Can't add thunks for construction vtable"); 10750b57cec5SDimitry Andric 10760b57cec5SDimitry Andric SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD]; 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric // Check if we have this thunk already. 1079349cc55cSDimitry Andric if (llvm::is_contained(ThunksVector, Thunk)) 10800b57cec5SDimitry Andric return; 10810b57cec5SDimitry Andric 10820b57cec5SDimitry Andric ThunksVector.push_back(Thunk); 10830b57cec5SDimitry Andric } 10840b57cec5SDimitry Andric 10850b57cec5SDimitry Andric typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; 10860b57cec5SDimitry Andric 10870b57cec5SDimitry Andric /// Visit all the methods overridden by the given method recursively, 10880b57cec5SDimitry Andric /// in a depth-first pre-order. The Visitor's visitor method returns a bool 10890b57cec5SDimitry Andric /// indicating whether to continue the recursion for the given overridden 10900b57cec5SDimitry Andric /// method (i.e. returning false stops the iteration). 10910b57cec5SDimitry Andric template <class VisitorTy> 10920b57cec5SDimitry Andric static void 10930b57cec5SDimitry Andric visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { 10945ffd83dbSDimitry Andric assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!"); 10950b57cec5SDimitry Andric 10960b57cec5SDimitry Andric for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { 10970b57cec5SDimitry Andric if (!Visitor(OverriddenMD)) 10980b57cec5SDimitry Andric continue; 10990b57cec5SDimitry Andric visitAllOverriddenMethods(OverriddenMD, Visitor); 11000b57cec5SDimitry Andric } 11010b57cec5SDimitry Andric } 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric /// ComputeAllOverriddenMethods - Given a method decl, will return a set of all 11040b57cec5SDimitry Andric /// the overridden methods that the function decl overrides. 11050b57cec5SDimitry Andric static void 11060b57cec5SDimitry Andric ComputeAllOverriddenMethods(const CXXMethodDecl *MD, 11070b57cec5SDimitry Andric OverriddenMethodsSetTy& OverriddenMethods) { 11080b57cec5SDimitry Andric auto OverriddenMethodsCollector = [&](const CXXMethodDecl *MD) { 11090b57cec5SDimitry Andric // Don't recurse on this method if we've already collected it. 11100b57cec5SDimitry Andric return OverriddenMethods.insert(MD).second; 11110b57cec5SDimitry Andric }; 11120b57cec5SDimitry Andric visitAllOverriddenMethods(MD, OverriddenMethodsCollector); 11130b57cec5SDimitry Andric } 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric void ItaniumVTableBuilder::ComputeThisAdjustments() { 11160b57cec5SDimitry Andric // Now go through the method info map and see if any of the methods need 11170b57cec5SDimitry Andric // 'this' pointer adjustments. 11180b57cec5SDimitry Andric for (const auto &MI : MethodInfoMap) { 11190b57cec5SDimitry Andric const CXXMethodDecl *MD = MI.first; 11200b57cec5SDimitry Andric const MethodInfo &MethodInfo = MI.second; 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric // Ignore adjustments for unused function pointers. 11230b57cec5SDimitry Andric uint64_t VTableIndex = MethodInfo.VTableIndex; 11240b57cec5SDimitry Andric if (Components[VTableIndex].getKind() == 11250b57cec5SDimitry Andric VTableComponent::CK_UnusedFunctionPointer) 11260b57cec5SDimitry Andric continue; 11270b57cec5SDimitry Andric 11280b57cec5SDimitry Andric // Get the final overrider for this method. 11290b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider = 11300b57cec5SDimitry Andric Overriders.getOverrider(MD, MethodInfo.BaseOffset); 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric // Check if we need an adjustment at all. 11330b57cec5SDimitry Andric if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { 11340b57cec5SDimitry Andric // When a return thunk is needed by a derived class that overrides a 11350b57cec5SDimitry Andric // virtual base, gcc uses a virtual 'this' adjustment as well. 11360b57cec5SDimitry Andric // While the thunk itself might be needed by vtables in subclasses or 11370b57cec5SDimitry Andric // in construction vtables, there doesn't seem to be a reason for using 11380b57cec5SDimitry Andric // the thunk in this vtable. Still, we do so to match gcc. 11390b57cec5SDimitry Andric if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) 11400b57cec5SDimitry Andric continue; 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric ThisAdjustment ThisAdjustment = 11440b57cec5SDimitry Andric ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); 11450b57cec5SDimitry Andric 11460b57cec5SDimitry Andric if (ThisAdjustment.isEmpty()) 11470b57cec5SDimitry Andric continue; 11480b57cec5SDimitry Andric 11490b57cec5SDimitry Andric // Add it. 1150*0fca6ea1SDimitry Andric auto SetThisAdjustmentThunk = [&](uint64_t Idx) { 1151*0fca6ea1SDimitry Andric // If a this pointer adjustment is required, record the method that 1152*0fca6ea1SDimitry Andric // created the vtable entry. MD is not necessarily the method that 1153*0fca6ea1SDimitry Andric // created the entry since derived classes overwrite base class 1154*0fca6ea1SDimitry Andric // information in MethodInfoMap, hence findOriginalMethodInMap is called 1155*0fca6ea1SDimitry Andric // here. 1156*0fca6ea1SDimitry Andric // 1157*0fca6ea1SDimitry Andric // For example, in the following class hierarchy, if MD = D1::m and 1158*0fca6ea1SDimitry Andric // Overrider = D2:m, the original method that created the entry is B0:m, 1159*0fca6ea1SDimitry Andric // which is what findOriginalMethodInMap(MD) returns: 1160*0fca6ea1SDimitry Andric // 1161*0fca6ea1SDimitry Andric // struct B0 { int a; virtual void m(); }; 1162*0fca6ea1SDimitry Andric // struct D0 : B0 { int a; void m() override; }; 1163*0fca6ea1SDimitry Andric // struct D1 : B0 { int a; void m() override; }; 1164*0fca6ea1SDimitry Andric // struct D2 : D0, D1 { int a; void m() override; }; 1165*0fca6ea1SDimitry Andric // 1166*0fca6ea1SDimitry Andric // We need to record the method because we cannot 1167*0fca6ea1SDimitry Andric // call findOriginalMethod to find the method that created the entry if 1168*0fca6ea1SDimitry Andric // the method in the entry requires adjustment. 1169*0fca6ea1SDimitry Andric // 1170*0fca6ea1SDimitry Andric // Do not set ThunkInfo::Method if Idx is already in VTableThunks. This 1171*0fca6ea1SDimitry Andric // can happen when covariant return adjustment is required too. 1172*0fca6ea1SDimitry Andric if (!VTableThunks.count(Idx)) { 1173*0fca6ea1SDimitry Andric const CXXMethodDecl *Method = VTables.findOriginalMethodInMap(MD); 1174*0fca6ea1SDimitry Andric VTableThunks[Idx].Method = Method; 1175*0fca6ea1SDimitry Andric VTableThunks[Idx].ThisType = Method->getThisType().getTypePtr(); 1176*0fca6ea1SDimitry Andric } 1177*0fca6ea1SDimitry Andric VTableThunks[Idx].This = ThisAdjustment; 1178*0fca6ea1SDimitry Andric }; 1179*0fca6ea1SDimitry Andric 1180*0fca6ea1SDimitry Andric SetThisAdjustmentThunk(VTableIndex); 11810b57cec5SDimitry Andric 11820b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(MD)) { 11830b57cec5SDimitry Andric // Add an adjustment for the deleting destructor as well. 1184*0fca6ea1SDimitry Andric SetThisAdjustmentThunk(VTableIndex + 1); 11850b57cec5SDimitry Andric } 11860b57cec5SDimitry Andric } 11870b57cec5SDimitry Andric 11880b57cec5SDimitry Andric /// Clear the method info map. 11890b57cec5SDimitry Andric MethodInfoMap.clear(); 11900b57cec5SDimitry Andric 11910b57cec5SDimitry Andric if (isBuildingConstructorVTable()) { 11920b57cec5SDimitry Andric // We don't need to store thunk information for construction vtables. 11930b57cec5SDimitry Andric return; 11940b57cec5SDimitry Andric } 11950b57cec5SDimitry Andric 11960b57cec5SDimitry Andric for (const auto &TI : VTableThunks) { 11970b57cec5SDimitry Andric const VTableComponent &Component = Components[TI.first]; 11980b57cec5SDimitry Andric const ThunkInfo &Thunk = TI.second; 11990b57cec5SDimitry Andric const CXXMethodDecl *MD; 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric switch (Component.getKind()) { 12020b57cec5SDimitry Andric default: 12030b57cec5SDimitry Andric llvm_unreachable("Unexpected vtable component kind!"); 12040b57cec5SDimitry Andric case VTableComponent::CK_FunctionPointer: 12050b57cec5SDimitry Andric MD = Component.getFunctionDecl(); 12060b57cec5SDimitry Andric break; 12070b57cec5SDimitry Andric case VTableComponent::CK_CompleteDtorPointer: 12080b57cec5SDimitry Andric MD = Component.getDestructorDecl(); 12090b57cec5SDimitry Andric break; 12100b57cec5SDimitry Andric case VTableComponent::CK_DeletingDtorPointer: 12110b57cec5SDimitry Andric // We've already added the thunk when we saw the complete dtor pointer. 12120b57cec5SDimitry Andric continue; 12130b57cec5SDimitry Andric } 12140b57cec5SDimitry Andric 12150b57cec5SDimitry Andric if (MD->getParent() == MostDerivedClass) 12160b57cec5SDimitry Andric AddThunk(MD, Thunk); 12170b57cec5SDimitry Andric } 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric ReturnAdjustment 12210b57cec5SDimitry Andric ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { 12220b57cec5SDimitry Andric ReturnAdjustment Adjustment; 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric if (!Offset.isEmpty()) { 12250b57cec5SDimitry Andric if (Offset.VirtualBase) { 12260b57cec5SDimitry Andric // Get the virtual base offset offset. 12270b57cec5SDimitry Andric if (Offset.DerivedClass == MostDerivedClass) { 12280b57cec5SDimitry Andric // We can get the offset offset directly from our map. 12290b57cec5SDimitry Andric Adjustment.Virtual.Itanium.VBaseOffsetOffset = 12300b57cec5SDimitry Andric VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); 12310b57cec5SDimitry Andric } else { 12320b57cec5SDimitry Andric Adjustment.Virtual.Itanium.VBaseOffsetOffset = 12330b57cec5SDimitry Andric VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, 12340b57cec5SDimitry Andric Offset.VirtualBase).getQuantity(); 12350b57cec5SDimitry Andric } 12360b57cec5SDimitry Andric } 12370b57cec5SDimitry Andric 12380b57cec5SDimitry Andric Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); 12390b57cec5SDimitry Andric } 12400b57cec5SDimitry Andric 12410b57cec5SDimitry Andric return Adjustment; 12420b57cec5SDimitry Andric } 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset( 12450b57cec5SDimitry Andric BaseSubobject Base, BaseSubobject Derived) const { 12460b57cec5SDimitry Andric const CXXRecordDecl *BaseRD = Base.getBase(); 12470b57cec5SDimitry Andric const CXXRecordDecl *DerivedRD = Derived.getBase(); 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric CXXBasePaths Paths(/*FindAmbiguities=*/true, 12500b57cec5SDimitry Andric /*RecordPaths=*/true, /*DetectVirtual=*/true); 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric if (!DerivedRD->isDerivedFrom(BaseRD, Paths)) 12530b57cec5SDimitry Andric llvm_unreachable("Class must be derived from the passed in base class!"); 12540b57cec5SDimitry Andric 12550b57cec5SDimitry Andric // We have to go through all the paths, and see which one leads us to the 12560b57cec5SDimitry Andric // right base subobject. 12570b57cec5SDimitry Andric for (const CXXBasePath &Path : Paths) { 12580b57cec5SDimitry Andric BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path); 12590b57cec5SDimitry Andric 12600b57cec5SDimitry Andric CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset; 12610b57cec5SDimitry Andric 12620b57cec5SDimitry Andric if (Offset.VirtualBase) { 12630b57cec5SDimitry Andric // If we have a virtual base class, the non-virtual offset is relative 12640b57cec5SDimitry Andric // to the virtual base class offset. 12650b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 12660b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric /// Get the virtual base offset, relative to the most derived class 12690b57cec5SDimitry Andric /// layout. 12700b57cec5SDimitry Andric OffsetToBaseSubobject += 12710b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); 12720b57cec5SDimitry Andric } else { 12730b57cec5SDimitry Andric // Otherwise, the non-virtual offset is relative to the derived class 12740b57cec5SDimitry Andric // offset. 12750b57cec5SDimitry Andric OffsetToBaseSubobject += Derived.getBaseOffset(); 12760b57cec5SDimitry Andric } 12770b57cec5SDimitry Andric 12780b57cec5SDimitry Andric // Check if this path gives us the right base subobject. 12790b57cec5SDimitry Andric if (OffsetToBaseSubobject == Base.getBaseOffset()) { 12800b57cec5SDimitry Andric // Since we're going from the base class _to_ the derived class, we'll 12810b57cec5SDimitry Andric // invert the non-virtual offset here. 12820b57cec5SDimitry Andric Offset.NonVirtualOffset = -Offset.NonVirtualOffset; 12830b57cec5SDimitry Andric return Offset; 12840b57cec5SDimitry Andric } 12850b57cec5SDimitry Andric } 12860b57cec5SDimitry Andric 12870b57cec5SDimitry Andric return BaseOffset(); 12880b57cec5SDimitry Andric } 12890b57cec5SDimitry Andric 12900b57cec5SDimitry Andric ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment( 12910b57cec5SDimitry Andric const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass, 12920b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider) { 12930b57cec5SDimitry Andric // Ignore adjustments for pure virtual member functions. 12947a6dacacSDimitry Andric if (Overrider.Method->isPureVirtual()) 12950b57cec5SDimitry Andric return ThisAdjustment(); 12960b57cec5SDimitry Andric 12970b57cec5SDimitry Andric BaseSubobject OverriddenBaseSubobject(MD->getParent(), 12980b57cec5SDimitry Andric BaseOffsetInLayoutClass); 12990b57cec5SDimitry Andric 13000b57cec5SDimitry Andric BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), 13010b57cec5SDimitry Andric Overrider.Offset); 13020b57cec5SDimitry Andric 13030b57cec5SDimitry Andric // Compute the adjustment offset. 13040b57cec5SDimitry Andric BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, 13050b57cec5SDimitry Andric OverriderBaseSubobject); 13060b57cec5SDimitry Andric if (Offset.isEmpty()) 13070b57cec5SDimitry Andric return ThisAdjustment(); 13080b57cec5SDimitry Andric 13090b57cec5SDimitry Andric ThisAdjustment Adjustment; 13100b57cec5SDimitry Andric 13110b57cec5SDimitry Andric if (Offset.VirtualBase) { 13120b57cec5SDimitry Andric // Get the vcall offset map for this virtual base. 13130b57cec5SDimitry Andric VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; 13140b57cec5SDimitry Andric 13150b57cec5SDimitry Andric if (VCallOffsets.empty()) { 13160b57cec5SDimitry Andric // We don't have vcall offsets for this virtual base, go ahead and 13170b57cec5SDimitry Andric // build them. 13185ffd83dbSDimitry Andric VCallAndVBaseOffsetBuilder Builder( 13195ffd83dbSDimitry Andric VTables, MostDerivedClass, MostDerivedClass, 13200b57cec5SDimitry Andric /*Overriders=*/nullptr, 13215ffd83dbSDimitry Andric BaseSubobject(Offset.VirtualBase, CharUnits::Zero()), 13220b57cec5SDimitry Andric /*BaseIsVirtual=*/true, 13230b57cec5SDimitry Andric /*OffsetInLayoutClass=*/ 13240b57cec5SDimitry Andric CharUnits::Zero()); 13250b57cec5SDimitry Andric 13260b57cec5SDimitry Andric VCallOffsets = Builder.getVCallOffsets(); 13270b57cec5SDimitry Andric } 13280b57cec5SDimitry Andric 13290b57cec5SDimitry Andric Adjustment.Virtual.Itanium.VCallOffsetOffset = 13300b57cec5SDimitry Andric VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); 13310b57cec5SDimitry Andric } 13320b57cec5SDimitry Andric 13330b57cec5SDimitry Andric // Set the non-virtual part of the adjustment. 13340b57cec5SDimitry Andric Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); 13350b57cec5SDimitry Andric 13360b57cec5SDimitry Andric return Adjustment; 13370b57cec5SDimitry Andric } 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD, 13400b57cec5SDimitry Andric ReturnAdjustment ReturnAdjustment) { 13410b57cec5SDimitry Andric if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { 13420b57cec5SDimitry Andric assert(ReturnAdjustment.isEmpty() && 13430b57cec5SDimitry Andric "Destructor can't have return adjustment!"); 13440b57cec5SDimitry Andric 13450b57cec5SDimitry Andric // Add both the complete destructor and the deleting destructor. 13460b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeCompleteDtor(DD)); 13470b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeDeletingDtor(DD)); 13480b57cec5SDimitry Andric } else { 13490b57cec5SDimitry Andric // Add the return adjustment if necessary. 13500b57cec5SDimitry Andric if (!ReturnAdjustment.isEmpty()) 13510b57cec5SDimitry Andric VTableThunks[Components.size()].Return = ReturnAdjustment; 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric // Add the function. 13540b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeFunction(MD)); 13550b57cec5SDimitry Andric } 13560b57cec5SDimitry Andric } 13570b57cec5SDimitry Andric 13580b57cec5SDimitry Andric /// OverridesIndirectMethodInBase - Return whether the given member function 13590b57cec5SDimitry Andric /// overrides any methods in the set of given bases. 13600b57cec5SDimitry Andric /// Unlike OverridesMethodInBase, this checks "overriders of overriders". 13610b57cec5SDimitry Andric /// For example, if we have: 13620b57cec5SDimitry Andric /// 13630b57cec5SDimitry Andric /// struct A { virtual void f(); } 13640b57cec5SDimitry Andric /// struct B : A { virtual void f(); } 13650b57cec5SDimitry Andric /// struct C : B { virtual void f(); } 13660b57cec5SDimitry Andric /// 13670b57cec5SDimitry Andric /// OverridesIndirectMethodInBase will return true if given C::f as the method 13680b57cec5SDimitry Andric /// and { A } as the set of bases. 13690b57cec5SDimitry Andric static bool OverridesIndirectMethodInBases( 13700b57cec5SDimitry Andric const CXXMethodDecl *MD, 13710b57cec5SDimitry Andric ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) { 13720b57cec5SDimitry Andric if (Bases.count(MD->getParent())) 13730b57cec5SDimitry Andric return true; 13740b57cec5SDimitry Andric 13750b57cec5SDimitry Andric for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) { 13760b57cec5SDimitry Andric // Check "indirect overriders". 13770b57cec5SDimitry Andric if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) 13780b57cec5SDimitry Andric return true; 13790b57cec5SDimitry Andric } 13800b57cec5SDimitry Andric 13810b57cec5SDimitry Andric return false; 13820b57cec5SDimitry Andric } 13830b57cec5SDimitry Andric 13840b57cec5SDimitry Andric bool ItaniumVTableBuilder::IsOverriderUsed( 13850b57cec5SDimitry Andric const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass, 13860b57cec5SDimitry Andric const CXXRecordDecl *FirstBaseInPrimaryBaseChain, 13870b57cec5SDimitry Andric CharUnits FirstBaseOffsetInLayoutClass) const { 13880b57cec5SDimitry Andric // If the base and the first base in the primary base chain have the same 13890b57cec5SDimitry Andric // offsets, then this overrider will be used. 13900b57cec5SDimitry Andric if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) 13910b57cec5SDimitry Andric return true; 13920b57cec5SDimitry Andric 13930b57cec5SDimitry Andric // We know now that Base (or a direct or indirect base of it) is a primary 13940b57cec5SDimitry Andric // base in part of the class hierarchy, but not a primary base in the most 13950b57cec5SDimitry Andric // derived class. 13960b57cec5SDimitry Andric 13970b57cec5SDimitry Andric // If the overrider is the first base in the primary base chain, we know 13980b57cec5SDimitry Andric // that the overrider will be used. 13990b57cec5SDimitry Andric if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) 14000b57cec5SDimitry Andric return true; 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; 14030b57cec5SDimitry Andric 14040b57cec5SDimitry Andric const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; 14050b57cec5SDimitry Andric PrimaryBases.insert(RD); 14060b57cec5SDimitry Andric 14070b57cec5SDimitry Andric // Now traverse the base chain, starting with the first base, until we find 14080b57cec5SDimitry Andric // the base that is no longer a primary base. 14090b57cec5SDimitry Andric while (true) { 14100b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 14110b57cec5SDimitry Andric const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); 14120b57cec5SDimitry Andric 14130b57cec5SDimitry Andric if (!PrimaryBase) 14140b57cec5SDimitry Andric break; 14150b57cec5SDimitry Andric 14160b57cec5SDimitry Andric if (Layout.isPrimaryBaseVirtual()) { 14170b57cec5SDimitry Andric assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && 14180b57cec5SDimitry Andric "Primary base should always be at offset 0!"); 14190b57cec5SDimitry Andric 14200b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 14210b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 14220b57cec5SDimitry Andric 14230b57cec5SDimitry Andric // Now check if this is the primary base that is not a primary base in the 14240b57cec5SDimitry Andric // most derived class. 14250b57cec5SDimitry Andric if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != 14260b57cec5SDimitry Andric FirstBaseOffsetInLayoutClass) { 14270b57cec5SDimitry Andric // We found it, stop walking the chain. 14280b57cec5SDimitry Andric break; 14290b57cec5SDimitry Andric } 14300b57cec5SDimitry Andric } else { 14310b57cec5SDimitry Andric assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && 14320b57cec5SDimitry Andric "Primary base should always be at offset 0!"); 14330b57cec5SDimitry Andric } 14340b57cec5SDimitry Andric 14350b57cec5SDimitry Andric if (!PrimaryBases.insert(PrimaryBase)) 14360b57cec5SDimitry Andric llvm_unreachable("Found a duplicate primary base!"); 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric RD = PrimaryBase; 14390b57cec5SDimitry Andric } 14400b57cec5SDimitry Andric 14410b57cec5SDimitry Andric // If the final overrider is an override of one of the primary bases, 14420b57cec5SDimitry Andric // then we know that it will be used. 14430b57cec5SDimitry Andric return OverridesIndirectMethodInBases(Overrider, PrimaryBases); 14440b57cec5SDimitry Andric } 14450b57cec5SDimitry Andric 14460b57cec5SDimitry Andric typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy; 14470b57cec5SDimitry Andric 14480b57cec5SDimitry Andric /// FindNearestOverriddenMethod - Given a method, returns the overridden method 14490b57cec5SDimitry Andric /// from the nearest base. Returns null if no method was found. 14500b57cec5SDimitry Andric /// The Bases are expected to be sorted in a base-to-derived order. 14510b57cec5SDimitry Andric static const CXXMethodDecl * 14520b57cec5SDimitry Andric FindNearestOverriddenMethod(const CXXMethodDecl *MD, 14530b57cec5SDimitry Andric BasesSetVectorTy &Bases) { 14540b57cec5SDimitry Andric OverriddenMethodsSetTy OverriddenMethods; 14550b57cec5SDimitry Andric ComputeAllOverriddenMethods(MD, OverriddenMethods); 14560b57cec5SDimitry Andric 1457349cc55cSDimitry Andric for (const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) { 14580b57cec5SDimitry Andric // Now check the overridden methods. 14590b57cec5SDimitry Andric for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) { 14600b57cec5SDimitry Andric // We found our overridden method. 14610b57cec5SDimitry Andric if (OverriddenMD->getParent() == PrimaryBase) 14620b57cec5SDimitry Andric return OverriddenMD; 14630b57cec5SDimitry Andric } 14640b57cec5SDimitry Andric } 14650b57cec5SDimitry Andric 14660b57cec5SDimitry Andric return nullptr; 14670b57cec5SDimitry Andric } 14680b57cec5SDimitry Andric 14690b57cec5SDimitry Andric void ItaniumVTableBuilder::AddMethods( 14700b57cec5SDimitry Andric BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, 14710b57cec5SDimitry Andric const CXXRecordDecl *FirstBaseInPrimaryBaseChain, 14720b57cec5SDimitry Andric CharUnits FirstBaseOffsetInLayoutClass, 14730b57cec5SDimitry Andric PrimaryBasesSetVectorTy &PrimaryBases) { 14740b57cec5SDimitry Andric // Itanium C++ ABI 2.5.2: 14750b57cec5SDimitry Andric // The order of the virtual function pointers in a virtual table is the 14760b57cec5SDimitry Andric // order of declaration of the corresponding member functions in the class. 14770b57cec5SDimitry Andric // 14780b57cec5SDimitry Andric // There is an entry for any virtual function declared in a class, 14790b57cec5SDimitry Andric // whether it is a new function or overrides a base class function, 14800b57cec5SDimitry Andric // unless it overrides a function from the primary base, and conversion 14810b57cec5SDimitry Andric // between their return types does not require an adjustment. 14820b57cec5SDimitry Andric 14830b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 14840b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { 14870b57cec5SDimitry Andric CharUnits PrimaryBaseOffset; 14880b57cec5SDimitry Andric CharUnits PrimaryBaseOffsetInLayoutClass; 14890b57cec5SDimitry Andric if (Layout.isPrimaryBaseVirtual()) { 14900b57cec5SDimitry Andric assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() && 14910b57cec5SDimitry Andric "Primary vbase should have a zero offset!"); 14920b57cec5SDimitry Andric 14930b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedClassLayout = 14940b57cec5SDimitry Andric Context.getASTRecordLayout(MostDerivedClass); 14950b57cec5SDimitry Andric 14960b57cec5SDimitry Andric PrimaryBaseOffset = 14970b57cec5SDimitry Andric MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); 14980b57cec5SDimitry Andric 14990b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 15000b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 15010b57cec5SDimitry Andric 15020b57cec5SDimitry Andric PrimaryBaseOffsetInLayoutClass = 15030b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(PrimaryBase); 15040b57cec5SDimitry Andric } else { 15050b57cec5SDimitry Andric assert(Layout.getBaseClassOffset(PrimaryBase).isZero() && 15060b57cec5SDimitry Andric "Primary base should have a zero offset!"); 15070b57cec5SDimitry Andric 15080b57cec5SDimitry Andric PrimaryBaseOffset = Base.getBaseOffset(); 15090b57cec5SDimitry Andric PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; 15100b57cec5SDimitry Andric } 15110b57cec5SDimitry Andric 15120b57cec5SDimitry Andric AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), 15130b57cec5SDimitry Andric PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, 15140b57cec5SDimitry Andric FirstBaseOffsetInLayoutClass, PrimaryBases); 15150b57cec5SDimitry Andric 15160b57cec5SDimitry Andric if (!PrimaryBases.insert(PrimaryBase)) 15170b57cec5SDimitry Andric llvm_unreachable("Found a duplicate primary base!"); 15180b57cec5SDimitry Andric } 15190b57cec5SDimitry Andric 15200b57cec5SDimitry Andric typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy; 15210b57cec5SDimitry Andric NewVirtualFunctionsTy NewVirtualFunctions; 15220b57cec5SDimitry Andric 15235ffd83dbSDimitry Andric llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions; 15245ffd83dbSDimitry Andric 15250b57cec5SDimitry Andric // Now go through all virtual member functions and add them. 15260b57cec5SDimitry Andric for (const auto *MD : RD->methods()) { 15275ffd83dbSDimitry Andric if (!ItaniumVTableContext::hasVtableSlot(MD)) 15280b57cec5SDimitry Andric continue; 15290b57cec5SDimitry Andric MD = MD->getCanonicalDecl(); 15300b57cec5SDimitry Andric 15310b57cec5SDimitry Andric // Get the final overrider. 15320b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider = 15330b57cec5SDimitry Andric Overriders.getOverrider(MD, Base.getBaseOffset()); 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric // Check if this virtual member function overrides a method in a primary 15360b57cec5SDimitry Andric // base. If this is the case, and the return type doesn't require adjustment 15370b57cec5SDimitry Andric // then we can just use the member function from the primary base. 15380b57cec5SDimitry Andric if (const CXXMethodDecl *OverriddenMD = 15390b57cec5SDimitry Andric FindNearestOverriddenMethod(MD, PrimaryBases)) { 15400b57cec5SDimitry Andric if (ComputeReturnAdjustmentBaseOffset(Context, MD, 15410b57cec5SDimitry Andric OverriddenMD).isEmpty()) { 1542*0fca6ea1SDimitry Andric VTables.setOriginalMethod(MD, OverriddenMD); 1543*0fca6ea1SDimitry Andric 15440b57cec5SDimitry Andric // Replace the method info of the overridden method with our own 15450b57cec5SDimitry Andric // method. 15460b57cec5SDimitry Andric assert(MethodInfoMap.count(OverriddenMD) && 15470b57cec5SDimitry Andric "Did not find the overridden method!"); 15480b57cec5SDimitry Andric MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; 15490b57cec5SDimitry Andric 15500b57cec5SDimitry Andric MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, 15510b57cec5SDimitry Andric OverriddenMethodInfo.VTableIndex); 15520b57cec5SDimitry Andric 15530b57cec5SDimitry Andric assert(!MethodInfoMap.count(MD) && 15540b57cec5SDimitry Andric "Should not have method info for this method yet!"); 15550b57cec5SDimitry Andric 15560b57cec5SDimitry Andric MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); 15570b57cec5SDimitry Andric MethodInfoMap.erase(OverriddenMD); 15580b57cec5SDimitry Andric 15590b57cec5SDimitry Andric // If the overridden method exists in a virtual base class or a direct 15600b57cec5SDimitry Andric // or indirect base class of a virtual base class, we need to emit a 15610b57cec5SDimitry Andric // thunk if we ever have a class hierarchy where the base class is not 15620b57cec5SDimitry Andric // a primary base in the complete object. 15630b57cec5SDimitry Andric if (!isBuildingConstructorVTable() && OverriddenMD != MD) { 15640b57cec5SDimitry Andric // Compute the this adjustment. 15650b57cec5SDimitry Andric ThisAdjustment ThisAdjustment = 15660b57cec5SDimitry Andric ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, 15670b57cec5SDimitry Andric Overrider); 15680b57cec5SDimitry Andric 15690b57cec5SDimitry Andric if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset && 15700b57cec5SDimitry Andric Overrider.Method->getParent() == MostDerivedClass) { 15710b57cec5SDimitry Andric 15720b57cec5SDimitry Andric // There's no return adjustment from OverriddenMD and MD, 15730b57cec5SDimitry Andric // but that doesn't mean there isn't one between MD and 15740b57cec5SDimitry Andric // the final overrider. 15750b57cec5SDimitry Andric BaseOffset ReturnAdjustmentOffset = 15760b57cec5SDimitry Andric ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); 15770b57cec5SDimitry Andric ReturnAdjustment ReturnAdjustment = 15780b57cec5SDimitry Andric ComputeReturnAdjustment(ReturnAdjustmentOffset); 15790b57cec5SDimitry Andric 15800b57cec5SDimitry Andric // This is a virtual thunk for the most derived class, add it. 15810b57cec5SDimitry Andric AddThunk(Overrider.Method, 1582*0fca6ea1SDimitry Andric ThunkInfo(ThisAdjustment, ReturnAdjustment, 1583*0fca6ea1SDimitry Andric OverriddenMD->getThisType().getTypePtr())); 15840b57cec5SDimitry Andric } 15850b57cec5SDimitry Andric } 15860b57cec5SDimitry Andric 15870b57cec5SDimitry Andric continue; 15880b57cec5SDimitry Andric } 15890b57cec5SDimitry Andric } 15900b57cec5SDimitry Andric 15915ffd83dbSDimitry Andric if (MD->isImplicit()) 15925ffd83dbSDimitry Andric NewImplicitVirtualFunctions.push_back(MD); 15935ffd83dbSDimitry Andric else 15940b57cec5SDimitry Andric NewVirtualFunctions.push_back(MD); 15950b57cec5SDimitry Andric } 15960b57cec5SDimitry Andric 15975ffd83dbSDimitry Andric std::stable_sort( 15985ffd83dbSDimitry Andric NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(), 15995ffd83dbSDimitry Andric [](const CXXMethodDecl *A, const CXXMethodDecl *B) { 16005f757f3fSDimitry Andric if (A == B) 16015f757f3fSDimitry Andric return false; 16025ffd83dbSDimitry Andric if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator()) 16035ffd83dbSDimitry Andric return A->isCopyAssignmentOperator(); 16045ffd83dbSDimitry Andric if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator()) 16055ffd83dbSDimitry Andric return A->isMoveAssignmentOperator(); 16065ffd83dbSDimitry Andric if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B)) 16075ffd83dbSDimitry Andric return isa<CXXDestructorDecl>(A); 16085ffd83dbSDimitry Andric assert(A->getOverloadedOperator() == OO_EqualEqual && 16095ffd83dbSDimitry Andric B->getOverloadedOperator() == OO_EqualEqual && 16105ffd83dbSDimitry Andric "unexpected or duplicate implicit virtual function"); 16115ffd83dbSDimitry Andric // We rely on Sema to have declared the operator== members in the 16125ffd83dbSDimitry Andric // same order as the corresponding operator<=> members. 16135ffd83dbSDimitry Andric return false; 16145ffd83dbSDimitry Andric }); 16155ffd83dbSDimitry Andric NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(), 16165ffd83dbSDimitry Andric NewImplicitVirtualFunctions.end()); 16170b57cec5SDimitry Andric 16180b57cec5SDimitry Andric for (const CXXMethodDecl *MD : NewVirtualFunctions) { 16190b57cec5SDimitry Andric // Get the final overrider. 16200b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider = 16210b57cec5SDimitry Andric Overriders.getOverrider(MD, Base.getBaseOffset()); 16220b57cec5SDimitry Andric 16230b57cec5SDimitry Andric // Insert the method info for this method. 16240b57cec5SDimitry Andric MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, 16250b57cec5SDimitry Andric Components.size()); 16260b57cec5SDimitry Andric 16270b57cec5SDimitry Andric assert(!MethodInfoMap.count(MD) && 16280b57cec5SDimitry Andric "Should not have method info for this method yet!"); 16290b57cec5SDimitry Andric MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); 16300b57cec5SDimitry Andric 16310b57cec5SDimitry Andric // Check if this overrider is going to be used. 16320b57cec5SDimitry Andric const CXXMethodDecl *OverriderMD = Overrider.Method; 16330b57cec5SDimitry Andric if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, 16340b57cec5SDimitry Andric FirstBaseInPrimaryBaseChain, 16350b57cec5SDimitry Andric FirstBaseOffsetInLayoutClass)) { 16360b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); 16370b57cec5SDimitry Andric continue; 16380b57cec5SDimitry Andric } 16390b57cec5SDimitry Andric 16400b57cec5SDimitry Andric // Check if this overrider needs a return adjustment. 16410b57cec5SDimitry Andric // We don't want to do this for pure virtual member functions. 16420b57cec5SDimitry Andric BaseOffset ReturnAdjustmentOffset; 16437a6dacacSDimitry Andric if (!OverriderMD->isPureVirtual()) { 16440b57cec5SDimitry Andric ReturnAdjustmentOffset = 16450b57cec5SDimitry Andric ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); 16460b57cec5SDimitry Andric } 16470b57cec5SDimitry Andric 16480b57cec5SDimitry Andric ReturnAdjustment ReturnAdjustment = 16490b57cec5SDimitry Andric ComputeReturnAdjustment(ReturnAdjustmentOffset); 16500b57cec5SDimitry Andric 1651*0fca6ea1SDimitry Andric // If a return adjustment is required, record the method that created the 1652*0fca6ea1SDimitry Andric // vtable entry. We need to record the method because we cannot call 1653*0fca6ea1SDimitry Andric // findOriginalMethod to find the method that created the entry if the 1654*0fca6ea1SDimitry Andric // method in the entry requires adjustment. 1655*0fca6ea1SDimitry Andric if (!ReturnAdjustment.isEmpty()) { 1656*0fca6ea1SDimitry Andric VTableThunks[Components.size()].Method = MD; 1657*0fca6ea1SDimitry Andric VTableThunks[Components.size()].ThisType = MD->getThisType().getTypePtr(); 1658*0fca6ea1SDimitry Andric } 1659*0fca6ea1SDimitry Andric 16600b57cec5SDimitry Andric AddMethod(Overrider.Method, ReturnAdjustment); 16610b57cec5SDimitry Andric } 16620b57cec5SDimitry Andric } 16630b57cec5SDimitry Andric 16640b57cec5SDimitry Andric void ItaniumVTableBuilder::LayoutVTable() { 16650b57cec5SDimitry Andric LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 16660b57cec5SDimitry Andric CharUnits::Zero()), 16670b57cec5SDimitry Andric /*BaseIsMorallyVirtual=*/false, 16680b57cec5SDimitry Andric MostDerivedClassIsVirtual, 16690b57cec5SDimitry Andric MostDerivedClassOffset); 16700b57cec5SDimitry Andric 16710b57cec5SDimitry Andric VisitedVirtualBasesSetTy VBases; 16720b57cec5SDimitry Andric 16730b57cec5SDimitry Andric // Determine the primary virtual bases. 16740b57cec5SDimitry Andric DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, 16750b57cec5SDimitry Andric VBases); 16760b57cec5SDimitry Andric VBases.clear(); 16770b57cec5SDimitry Andric 16780b57cec5SDimitry Andric LayoutVTablesForVirtualBases(MostDerivedClass, VBases); 16790b57cec5SDimitry Andric 16800b57cec5SDimitry Andric // -fapple-kext adds an extra entry at end of vtbl. 16810b57cec5SDimitry Andric bool IsAppleKext = Context.getLangOpts().AppleKext; 16820b57cec5SDimitry Andric if (IsAppleKext) 16830b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero())); 16840b57cec5SDimitry Andric } 16850b57cec5SDimitry Andric 16860b57cec5SDimitry Andric void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables( 16870b57cec5SDimitry Andric BaseSubobject Base, bool BaseIsMorallyVirtual, 16880b57cec5SDimitry Andric bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) { 16890b57cec5SDimitry Andric assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); 16900b57cec5SDimitry Andric 16910b57cec5SDimitry Andric unsigned VTableIndex = Components.size(); 16920b57cec5SDimitry Andric VTableIndices.push_back(VTableIndex); 16930b57cec5SDimitry Andric 16940b57cec5SDimitry Andric // Add vcall and vbase offsets for this vtable. 16955ffd83dbSDimitry Andric VCallAndVBaseOffsetBuilder Builder( 16965ffd83dbSDimitry Andric VTables, MostDerivedClass, LayoutClass, &Overriders, Base, 16975ffd83dbSDimitry Andric BaseIsVirtualInLayoutClass, OffsetInLayoutClass); 16980b57cec5SDimitry Andric Components.append(Builder.components_begin(), Builder.components_end()); 16990b57cec5SDimitry Andric 17000b57cec5SDimitry Andric // Check if we need to add these vcall offsets. 17010b57cec5SDimitry Andric if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { 17020b57cec5SDimitry Andric VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; 17030b57cec5SDimitry Andric 17040b57cec5SDimitry Andric if (VCallOffsets.empty()) 17050b57cec5SDimitry Andric VCallOffsets = Builder.getVCallOffsets(); 17060b57cec5SDimitry Andric } 17070b57cec5SDimitry Andric 17080b57cec5SDimitry Andric // If we're laying out the most derived class we want to keep track of the 17090b57cec5SDimitry Andric // virtual base class offset offsets. 17100b57cec5SDimitry Andric if (Base.getBase() == MostDerivedClass) 17110b57cec5SDimitry Andric VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); 17120b57cec5SDimitry Andric 17130b57cec5SDimitry Andric // Add the offset to top. 17140b57cec5SDimitry Andric CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; 17150b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); 17160b57cec5SDimitry Andric 17170b57cec5SDimitry Andric // Next, add the RTTI. 17185f757f3fSDimitry Andric if (!Context.getLangOpts().OmitVTableRTTI) 17190b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); 17200b57cec5SDimitry Andric 17210b57cec5SDimitry Andric uint64_t AddressPoint = Components.size(); 17220b57cec5SDimitry Andric 17230b57cec5SDimitry Andric // Now go through all virtual member functions and add them. 17240b57cec5SDimitry Andric PrimaryBasesSetVectorTy PrimaryBases; 17250b57cec5SDimitry Andric AddMethods(Base, OffsetInLayoutClass, 17260b57cec5SDimitry Andric Base.getBase(), OffsetInLayoutClass, 17270b57cec5SDimitry Andric PrimaryBases); 17280b57cec5SDimitry Andric 17290b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 17300b57cec5SDimitry Andric if (RD == MostDerivedClass) { 17310b57cec5SDimitry Andric assert(MethodVTableIndices.empty()); 17320b57cec5SDimitry Andric for (const auto &I : MethodInfoMap) { 17330b57cec5SDimitry Andric const CXXMethodDecl *MD = I.first; 17340b57cec5SDimitry Andric const MethodInfo &MI = I.second; 17350b57cec5SDimitry Andric if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { 17360b57cec5SDimitry Andric MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] 17370b57cec5SDimitry Andric = MI.VTableIndex - AddressPoint; 17380b57cec5SDimitry Andric MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] 17390b57cec5SDimitry Andric = MI.VTableIndex + 1 - AddressPoint; 17400b57cec5SDimitry Andric } else { 17410b57cec5SDimitry Andric MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint; 17420b57cec5SDimitry Andric } 17430b57cec5SDimitry Andric } 17440b57cec5SDimitry Andric } 17450b57cec5SDimitry Andric 17460b57cec5SDimitry Andric // Compute 'this' pointer adjustments. 17470b57cec5SDimitry Andric ComputeThisAdjustments(); 17480b57cec5SDimitry Andric 17490b57cec5SDimitry Andric // Add all address points. 17500b57cec5SDimitry Andric while (true) { 17510b57cec5SDimitry Andric AddressPoints.insert( 17520b57cec5SDimitry Andric std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), 17530b57cec5SDimitry Andric VTableLayout::AddressPointLocation{ 17540b57cec5SDimitry Andric unsigned(VTableIndices.size() - 1), 17550b57cec5SDimitry Andric unsigned(AddressPoint - VTableIndex)})); 17560b57cec5SDimitry Andric 17570b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 17580b57cec5SDimitry Andric const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric if (!PrimaryBase) 17610b57cec5SDimitry Andric break; 17620b57cec5SDimitry Andric 17630b57cec5SDimitry Andric if (Layout.isPrimaryBaseVirtual()) { 17640b57cec5SDimitry Andric // Check if this virtual primary base is a primary base in the layout 17650b57cec5SDimitry Andric // class. If it's not, we don't want to add it. 17660b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 17670b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 17680b57cec5SDimitry Andric 17690b57cec5SDimitry Andric if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != 17700b57cec5SDimitry Andric OffsetInLayoutClass) { 17710b57cec5SDimitry Andric // We don't want to add this class (or any of its primary bases). 17720b57cec5SDimitry Andric break; 17730b57cec5SDimitry Andric } 17740b57cec5SDimitry Andric } 17750b57cec5SDimitry Andric 17760b57cec5SDimitry Andric RD = PrimaryBase; 17770b57cec5SDimitry Andric } 17780b57cec5SDimitry Andric 17790b57cec5SDimitry Andric // Layout secondary vtables. 17800b57cec5SDimitry Andric LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); 17810b57cec5SDimitry Andric } 17820b57cec5SDimitry Andric 17830b57cec5SDimitry Andric void 17840b57cec5SDimitry Andric ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, 17850b57cec5SDimitry Andric bool BaseIsMorallyVirtual, 17860b57cec5SDimitry Andric CharUnits OffsetInLayoutClass) { 17870b57cec5SDimitry Andric // Itanium C++ ABI 2.5.2: 17880b57cec5SDimitry Andric // Following the primary virtual table of a derived class are secondary 17890b57cec5SDimitry Andric // virtual tables for each of its proper base classes, except any primary 17900b57cec5SDimitry Andric // base(s) with which it shares its primary virtual table. 17910b57cec5SDimitry Andric 17920b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 17930b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 17940b57cec5SDimitry Andric const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); 17950b57cec5SDimitry Andric 17960b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 17970b57cec5SDimitry Andric // Ignore virtual bases, we'll emit them later. 17980b57cec5SDimitry Andric if (B.isVirtual()) 17990b57cec5SDimitry Andric continue; 18000b57cec5SDimitry Andric 18010b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric // Ignore bases that don't have a vtable. 18040b57cec5SDimitry Andric if (!BaseDecl->isDynamicClass()) 18050b57cec5SDimitry Andric continue; 18060b57cec5SDimitry Andric 18070b57cec5SDimitry Andric if (isBuildingConstructorVTable()) { 18080b57cec5SDimitry Andric // Itanium C++ ABI 2.6.4: 18090b57cec5SDimitry Andric // Some of the base class subobjects may not need construction virtual 18100b57cec5SDimitry Andric // tables, which will therefore not be present in the construction 18110b57cec5SDimitry Andric // virtual table group, even though the subobject virtual tables are 18120b57cec5SDimitry Andric // present in the main virtual table group for the complete object. 18130b57cec5SDimitry Andric if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) 18140b57cec5SDimitry Andric continue; 18150b57cec5SDimitry Andric } 18160b57cec5SDimitry Andric 18170b57cec5SDimitry Andric // Get the base offset of this base. 18180b57cec5SDimitry Andric CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); 18190b57cec5SDimitry Andric CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; 18200b57cec5SDimitry Andric 18210b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass = 18220b57cec5SDimitry Andric OffsetInLayoutClass + RelativeBaseOffset; 18230b57cec5SDimitry Andric 18240b57cec5SDimitry Andric // Don't emit a secondary vtable for a primary base. We might however want 18250b57cec5SDimitry Andric // to emit secondary vtables for other bases of this base. 18260b57cec5SDimitry Andric if (BaseDecl == PrimaryBase) { 18270b57cec5SDimitry Andric LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), 18280b57cec5SDimitry Andric BaseIsMorallyVirtual, BaseOffsetInLayoutClass); 18290b57cec5SDimitry Andric continue; 18300b57cec5SDimitry Andric } 18310b57cec5SDimitry Andric 18320b57cec5SDimitry Andric // Layout the primary vtable (and any secondary vtables) for this base. 18330b57cec5SDimitry Andric LayoutPrimaryAndSecondaryVTables( 18340b57cec5SDimitry Andric BaseSubobject(BaseDecl, BaseOffset), 18350b57cec5SDimitry Andric BaseIsMorallyVirtual, 18360b57cec5SDimitry Andric /*BaseIsVirtualInLayoutClass=*/false, 18370b57cec5SDimitry Andric BaseOffsetInLayoutClass); 18380b57cec5SDimitry Andric } 18390b57cec5SDimitry Andric } 18400b57cec5SDimitry Andric 18410b57cec5SDimitry Andric void ItaniumVTableBuilder::DeterminePrimaryVirtualBases( 18420b57cec5SDimitry Andric const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass, 18430b57cec5SDimitry Andric VisitedVirtualBasesSetTy &VBases) { 18440b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 18450b57cec5SDimitry Andric 18460b57cec5SDimitry Andric // Check if this base has a primary base. 18470b57cec5SDimitry Andric if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { 18480b57cec5SDimitry Andric 18490b57cec5SDimitry Andric // Check if it's virtual. 18500b57cec5SDimitry Andric if (Layout.isPrimaryBaseVirtual()) { 18510b57cec5SDimitry Andric bool IsPrimaryVirtualBase = true; 18520b57cec5SDimitry Andric 18530b57cec5SDimitry Andric if (isBuildingConstructorVTable()) { 18540b57cec5SDimitry Andric // Check if the base is actually a primary base in the class we use for 18550b57cec5SDimitry Andric // layout. 18560b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 18570b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 18580b57cec5SDimitry Andric 18590b57cec5SDimitry Andric CharUnits PrimaryBaseOffsetInLayoutClass = 18600b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(PrimaryBase); 18610b57cec5SDimitry Andric 18620b57cec5SDimitry Andric // We know that the base is not a primary base in the layout class if 18630b57cec5SDimitry Andric // the base offsets are different. 18640b57cec5SDimitry Andric if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) 18650b57cec5SDimitry Andric IsPrimaryVirtualBase = false; 18660b57cec5SDimitry Andric } 18670b57cec5SDimitry Andric 18680b57cec5SDimitry Andric if (IsPrimaryVirtualBase) 18690b57cec5SDimitry Andric PrimaryVirtualBases.insert(PrimaryBase); 18700b57cec5SDimitry Andric } 18710b57cec5SDimitry Andric } 18720b57cec5SDimitry Andric 18730b57cec5SDimitry Andric // Traverse bases, looking for more primary virtual bases. 18740b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 18750b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 18760b57cec5SDimitry Andric 18770b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass; 18780b57cec5SDimitry Andric 18790b57cec5SDimitry Andric if (B.isVirtual()) { 18800b57cec5SDimitry Andric if (!VBases.insert(BaseDecl).second) 18810b57cec5SDimitry Andric continue; 18820b57cec5SDimitry Andric 18830b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 18840b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 18850b57cec5SDimitry Andric 18860b57cec5SDimitry Andric BaseOffsetInLayoutClass = 18870b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(BaseDecl); 18880b57cec5SDimitry Andric } else { 18890b57cec5SDimitry Andric BaseOffsetInLayoutClass = 18900b57cec5SDimitry Andric OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); 18910b57cec5SDimitry Andric } 18920b57cec5SDimitry Andric 18930b57cec5SDimitry Andric DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); 18940b57cec5SDimitry Andric } 18950b57cec5SDimitry Andric } 18960b57cec5SDimitry Andric 18970b57cec5SDimitry Andric void ItaniumVTableBuilder::LayoutVTablesForVirtualBases( 18980b57cec5SDimitry Andric const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { 18990b57cec5SDimitry Andric // Itanium C++ ABI 2.5.2: 19000b57cec5SDimitry Andric // Then come the virtual base virtual tables, also in inheritance graph 19010b57cec5SDimitry Andric // order, and again excluding primary bases (which share virtual tables with 19020b57cec5SDimitry Andric // the classes for which they are primary). 19030b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 19040b57cec5SDimitry Andric const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); 19050b57cec5SDimitry Andric 19060b57cec5SDimitry Andric // Check if this base needs a vtable. (If it's virtual, not a primary base 19070b57cec5SDimitry Andric // of some other class, and we haven't visited it before). 19080b57cec5SDimitry Andric if (B.isVirtual() && BaseDecl->isDynamicClass() && 19090b57cec5SDimitry Andric !PrimaryVirtualBases.count(BaseDecl) && 19100b57cec5SDimitry Andric VBases.insert(BaseDecl).second) { 19110b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedClassLayout = 19120b57cec5SDimitry Andric Context.getASTRecordLayout(MostDerivedClass); 19130b57cec5SDimitry Andric CharUnits BaseOffset = 19140b57cec5SDimitry Andric MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); 19150b57cec5SDimitry Andric 19160b57cec5SDimitry Andric const ASTRecordLayout &LayoutClassLayout = 19170b57cec5SDimitry Andric Context.getASTRecordLayout(LayoutClass); 19180b57cec5SDimitry Andric CharUnits BaseOffsetInLayoutClass = 19190b57cec5SDimitry Andric LayoutClassLayout.getVBaseClassOffset(BaseDecl); 19200b57cec5SDimitry Andric 19210b57cec5SDimitry Andric LayoutPrimaryAndSecondaryVTables( 19220b57cec5SDimitry Andric BaseSubobject(BaseDecl, BaseOffset), 19230b57cec5SDimitry Andric /*BaseIsMorallyVirtual=*/true, 19240b57cec5SDimitry Andric /*BaseIsVirtualInLayoutClass=*/true, 19250b57cec5SDimitry Andric BaseOffsetInLayoutClass); 19260b57cec5SDimitry Andric } 19270b57cec5SDimitry Andric 19280b57cec5SDimitry Andric // We only need to check the base for virtual base vtables if it actually 19290b57cec5SDimitry Andric // has virtual bases. 19300b57cec5SDimitry Andric if (BaseDecl->getNumVBases()) 19310b57cec5SDimitry Andric LayoutVTablesForVirtualBases(BaseDecl, VBases); 19320b57cec5SDimitry Andric } 19330b57cec5SDimitry Andric } 19340b57cec5SDimitry Andric 1935*0fca6ea1SDimitry Andric static void printThunkMethod(const ThunkInfo &Info, raw_ostream &Out) { 1936*0fca6ea1SDimitry Andric if (!Info.Method) 1937*0fca6ea1SDimitry Andric return; 1938*0fca6ea1SDimitry Andric std::string Str = PredefinedExpr::ComputeName( 1939*0fca6ea1SDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, Info.Method); 1940*0fca6ea1SDimitry Andric Out << " method: " << Str; 1941*0fca6ea1SDimitry Andric } 1942*0fca6ea1SDimitry Andric 19430b57cec5SDimitry Andric /// dumpLayout - Dump the vtable layout. 19440b57cec5SDimitry Andric void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { 19450b57cec5SDimitry Andric // FIXME: write more tests that actually use the dumpLayout output to prevent 19460b57cec5SDimitry Andric // ItaniumVTableBuilder regressions. 19470b57cec5SDimitry Andric 1948*0fca6ea1SDimitry Andric Out << "Original map\n"; 1949*0fca6ea1SDimitry Andric 1950*0fca6ea1SDimitry Andric for (const auto &P : VTables.getOriginalMethodMap()) { 1951*0fca6ea1SDimitry Andric std::string Str0 = 1952*0fca6ea1SDimitry Andric PredefinedExpr::ComputeName(PredefinedIdentKind::PrettyFunctionNoVirtual, 1953*0fca6ea1SDimitry Andric P.first); 1954*0fca6ea1SDimitry Andric std::string Str1 = 1955*0fca6ea1SDimitry Andric PredefinedExpr::ComputeName(PredefinedIdentKind::PrettyFunctionNoVirtual, 1956*0fca6ea1SDimitry Andric P.second); 1957*0fca6ea1SDimitry Andric Out << " " << Str0 << " -> " << Str1 << "\n"; 1958*0fca6ea1SDimitry Andric } 1959*0fca6ea1SDimitry Andric 19600b57cec5SDimitry Andric if (isBuildingConstructorVTable()) { 19610b57cec5SDimitry Andric Out << "Construction vtable for ('"; 19620b57cec5SDimitry Andric MostDerivedClass->printQualifiedName(Out); 19630b57cec5SDimitry Andric Out << "', "; 19640b57cec5SDimitry Andric Out << MostDerivedClassOffset.getQuantity() << ") in '"; 19650b57cec5SDimitry Andric LayoutClass->printQualifiedName(Out); 19660b57cec5SDimitry Andric } else { 19670b57cec5SDimitry Andric Out << "Vtable for '"; 19680b57cec5SDimitry Andric MostDerivedClass->printQualifiedName(Out); 19690b57cec5SDimitry Andric } 19700b57cec5SDimitry Andric Out << "' (" << Components.size() << " entries).\n"; 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric // Iterate through the address points and insert them into a new map where 19730b57cec5SDimitry Andric // they are keyed by the index and not the base object. 19740b57cec5SDimitry Andric // Since an address point can be shared by multiple subobjects, we use an 19750b57cec5SDimitry Andric // STL multimap. 19760b57cec5SDimitry Andric std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex; 19770b57cec5SDimitry Andric for (const auto &AP : AddressPoints) { 19780b57cec5SDimitry Andric const BaseSubobject &Base = AP.first; 19790b57cec5SDimitry Andric uint64_t Index = 19800b57cec5SDimitry Andric VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex; 19810b57cec5SDimitry Andric 19820b57cec5SDimitry Andric AddressPointsByIndex.insert(std::make_pair(Index, Base)); 19830b57cec5SDimitry Andric } 19840b57cec5SDimitry Andric 19850b57cec5SDimitry Andric for (unsigned I = 0, E = Components.size(); I != E; ++I) { 19860b57cec5SDimitry Andric uint64_t Index = I; 19870b57cec5SDimitry Andric 19880b57cec5SDimitry Andric Out << llvm::format("%4d | ", I); 19890b57cec5SDimitry Andric 19900b57cec5SDimitry Andric const VTableComponent &Component = Components[I]; 19910b57cec5SDimitry Andric 19920b57cec5SDimitry Andric // Dump the component. 19930b57cec5SDimitry Andric switch (Component.getKind()) { 19940b57cec5SDimitry Andric 19950b57cec5SDimitry Andric case VTableComponent::CK_VCallOffset: 19960b57cec5SDimitry Andric Out << "vcall_offset (" 19970b57cec5SDimitry Andric << Component.getVCallOffset().getQuantity() 19980b57cec5SDimitry Andric << ")"; 19990b57cec5SDimitry Andric break; 20000b57cec5SDimitry Andric 20010b57cec5SDimitry Andric case VTableComponent::CK_VBaseOffset: 20020b57cec5SDimitry Andric Out << "vbase_offset (" 20030b57cec5SDimitry Andric << Component.getVBaseOffset().getQuantity() 20040b57cec5SDimitry Andric << ")"; 20050b57cec5SDimitry Andric break; 20060b57cec5SDimitry Andric 20070b57cec5SDimitry Andric case VTableComponent::CK_OffsetToTop: 20080b57cec5SDimitry Andric Out << "offset_to_top (" 20090b57cec5SDimitry Andric << Component.getOffsetToTop().getQuantity() 20100b57cec5SDimitry Andric << ")"; 20110b57cec5SDimitry Andric break; 20120b57cec5SDimitry Andric 20130b57cec5SDimitry Andric case VTableComponent::CK_RTTI: 20140b57cec5SDimitry Andric Component.getRTTIDecl()->printQualifiedName(Out); 20150b57cec5SDimitry Andric Out << " RTTI"; 20160b57cec5SDimitry Andric break; 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric case VTableComponent::CK_FunctionPointer: { 20190b57cec5SDimitry Andric const CXXMethodDecl *MD = Component.getFunctionDecl(); 20200b57cec5SDimitry Andric 20215f757f3fSDimitry Andric std::string Str = PredefinedExpr::ComputeName( 20225f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 20230b57cec5SDimitry Andric Out << Str; 20247a6dacacSDimitry Andric if (MD->isPureVirtual()) 20250b57cec5SDimitry Andric Out << " [pure]"; 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric if (MD->isDeleted()) 20280b57cec5SDimitry Andric Out << " [deleted]"; 20290b57cec5SDimitry Andric 20300b57cec5SDimitry Andric ThunkInfo Thunk = VTableThunks.lookup(I); 20310b57cec5SDimitry Andric if (!Thunk.isEmpty()) { 20320b57cec5SDimitry Andric // If this function pointer has a return adjustment, dump it. 20330b57cec5SDimitry Andric if (!Thunk.Return.isEmpty()) { 20340b57cec5SDimitry Andric Out << "\n [return adjustment: "; 20350b57cec5SDimitry Andric Out << Thunk.Return.NonVirtual << " non-virtual"; 20360b57cec5SDimitry Andric 20370b57cec5SDimitry Andric if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { 20380b57cec5SDimitry Andric Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; 20390b57cec5SDimitry Andric Out << " vbase offset offset"; 20400b57cec5SDimitry Andric } 20410b57cec5SDimitry Andric 20420b57cec5SDimitry Andric Out << ']'; 2043*0fca6ea1SDimitry Andric printThunkMethod(Thunk, Out); 20440b57cec5SDimitry Andric } 20450b57cec5SDimitry Andric 20460b57cec5SDimitry Andric // If this function pointer has a 'this' pointer adjustment, dump it. 20470b57cec5SDimitry Andric if (!Thunk.This.isEmpty()) { 20480b57cec5SDimitry Andric Out << "\n [this adjustment: "; 20490b57cec5SDimitry Andric Out << Thunk.This.NonVirtual << " non-virtual"; 20500b57cec5SDimitry Andric 20510b57cec5SDimitry Andric if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { 20520b57cec5SDimitry Andric Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; 20530b57cec5SDimitry Andric Out << " vcall offset offset"; 20540b57cec5SDimitry Andric } 20550b57cec5SDimitry Andric 20560b57cec5SDimitry Andric Out << ']'; 2057*0fca6ea1SDimitry Andric printThunkMethod(Thunk, Out); 20580b57cec5SDimitry Andric } 20590b57cec5SDimitry Andric } 20600b57cec5SDimitry Andric 20610b57cec5SDimitry Andric break; 20620b57cec5SDimitry Andric } 20630b57cec5SDimitry Andric 20640b57cec5SDimitry Andric case VTableComponent::CK_CompleteDtorPointer: 20650b57cec5SDimitry Andric case VTableComponent::CK_DeletingDtorPointer: { 20660b57cec5SDimitry Andric bool IsComplete = 20670b57cec5SDimitry Andric Component.getKind() == VTableComponent::CK_CompleteDtorPointer; 20680b57cec5SDimitry Andric 20690b57cec5SDimitry Andric const CXXDestructorDecl *DD = Component.getDestructorDecl(); 20700b57cec5SDimitry Andric 20710b57cec5SDimitry Andric DD->printQualifiedName(Out); 20720b57cec5SDimitry Andric if (IsComplete) 20730b57cec5SDimitry Andric Out << "() [complete]"; 20740b57cec5SDimitry Andric else 20750b57cec5SDimitry Andric Out << "() [deleting]"; 20760b57cec5SDimitry Andric 20777a6dacacSDimitry Andric if (DD->isPureVirtual()) 20780b57cec5SDimitry Andric Out << " [pure]"; 20790b57cec5SDimitry Andric 20800b57cec5SDimitry Andric ThunkInfo Thunk = VTableThunks.lookup(I); 20810b57cec5SDimitry Andric if (!Thunk.isEmpty()) { 20820b57cec5SDimitry Andric // If this destructor has a 'this' pointer adjustment, dump it. 20830b57cec5SDimitry Andric if (!Thunk.This.isEmpty()) { 20840b57cec5SDimitry Andric Out << "\n [this adjustment: "; 20850b57cec5SDimitry Andric Out << Thunk.This.NonVirtual << " non-virtual"; 20860b57cec5SDimitry Andric 20870b57cec5SDimitry Andric if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { 20880b57cec5SDimitry Andric Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; 20890b57cec5SDimitry Andric Out << " vcall offset offset"; 20900b57cec5SDimitry Andric } 20910b57cec5SDimitry Andric 20920b57cec5SDimitry Andric Out << ']'; 20930b57cec5SDimitry Andric } 2094*0fca6ea1SDimitry Andric printThunkMethod(Thunk, Out); 20950b57cec5SDimitry Andric } 20960b57cec5SDimitry Andric 20970b57cec5SDimitry Andric break; 20980b57cec5SDimitry Andric } 20990b57cec5SDimitry Andric 21000b57cec5SDimitry Andric case VTableComponent::CK_UnusedFunctionPointer: { 21010b57cec5SDimitry Andric const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); 21020b57cec5SDimitry Andric 21035f757f3fSDimitry Andric std::string Str = PredefinedExpr::ComputeName( 21045f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 21050b57cec5SDimitry Andric Out << "[unused] " << Str; 21067a6dacacSDimitry Andric if (MD->isPureVirtual()) 21070b57cec5SDimitry Andric Out << " [pure]"; 21080b57cec5SDimitry Andric } 21090b57cec5SDimitry Andric 21100b57cec5SDimitry Andric } 21110b57cec5SDimitry Andric 21120b57cec5SDimitry Andric Out << '\n'; 21130b57cec5SDimitry Andric 21140b57cec5SDimitry Andric // Dump the next address point. 21150b57cec5SDimitry Andric uint64_t NextIndex = Index + 1; 21160b57cec5SDimitry Andric if (AddressPointsByIndex.count(NextIndex)) { 21170b57cec5SDimitry Andric if (AddressPointsByIndex.count(NextIndex) == 1) { 21180b57cec5SDimitry Andric const BaseSubobject &Base = 21190b57cec5SDimitry Andric AddressPointsByIndex.find(NextIndex)->second; 21200b57cec5SDimitry Andric 21210b57cec5SDimitry Andric Out << " -- ("; 21220b57cec5SDimitry Andric Base.getBase()->printQualifiedName(Out); 21230b57cec5SDimitry Andric Out << ", " << Base.getBaseOffset().getQuantity(); 21240b57cec5SDimitry Andric Out << ") vtable address --\n"; 21250b57cec5SDimitry Andric } else { 21260b57cec5SDimitry Andric CharUnits BaseOffset = 21270b57cec5SDimitry Andric AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); 21280b57cec5SDimitry Andric 21290b57cec5SDimitry Andric // We store the class names in a set to get a stable order. 21300b57cec5SDimitry Andric std::set<std::string> ClassNames; 21310b57cec5SDimitry Andric for (const auto &I : 21320b57cec5SDimitry Andric llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) { 21330b57cec5SDimitry Andric assert(I.second.getBaseOffset() == BaseOffset && 21340b57cec5SDimitry Andric "Invalid base offset!"); 21350b57cec5SDimitry Andric const CXXRecordDecl *RD = I.second.getBase(); 21360b57cec5SDimitry Andric ClassNames.insert(RD->getQualifiedNameAsString()); 21370b57cec5SDimitry Andric } 21380b57cec5SDimitry Andric 21390b57cec5SDimitry Andric for (const std::string &Name : ClassNames) { 21400b57cec5SDimitry Andric Out << " -- (" << Name; 21410b57cec5SDimitry Andric Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n"; 21420b57cec5SDimitry Andric } 21430b57cec5SDimitry Andric } 21440b57cec5SDimitry Andric } 21450b57cec5SDimitry Andric } 21460b57cec5SDimitry Andric 21470b57cec5SDimitry Andric Out << '\n'; 21480b57cec5SDimitry Andric 21490b57cec5SDimitry Andric if (isBuildingConstructorVTable()) 21500b57cec5SDimitry Andric return; 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric if (MostDerivedClass->getNumVBases()) { 21530b57cec5SDimitry Andric // We store the virtual base class names and their offsets in a map to get 21540b57cec5SDimitry Andric // a stable order. 21550b57cec5SDimitry Andric 21560b57cec5SDimitry Andric std::map<std::string, CharUnits> ClassNamesAndOffsets; 21570b57cec5SDimitry Andric for (const auto &I : VBaseOffsetOffsets) { 21580b57cec5SDimitry Andric std::string ClassName = I.first->getQualifiedNameAsString(); 21590b57cec5SDimitry Andric CharUnits OffsetOffset = I.second; 21600b57cec5SDimitry Andric ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); 21610b57cec5SDimitry Andric } 21620b57cec5SDimitry Andric 21630b57cec5SDimitry Andric Out << "Virtual base offset offsets for '"; 21640b57cec5SDimitry Andric MostDerivedClass->printQualifiedName(Out); 21650b57cec5SDimitry Andric Out << "' ("; 21660b57cec5SDimitry Andric Out << ClassNamesAndOffsets.size(); 21670b57cec5SDimitry Andric Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; 21680b57cec5SDimitry Andric 21690b57cec5SDimitry Andric for (const auto &I : ClassNamesAndOffsets) 21700b57cec5SDimitry Andric Out << " " << I.first << " | " << I.second.getQuantity() << '\n'; 21710b57cec5SDimitry Andric 21720b57cec5SDimitry Andric Out << "\n"; 21730b57cec5SDimitry Andric } 21740b57cec5SDimitry Andric 21750b57cec5SDimitry Andric if (!Thunks.empty()) { 21760b57cec5SDimitry Andric // We store the method names in a map to get a stable order. 21770b57cec5SDimitry Andric std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; 21780b57cec5SDimitry Andric 21790b57cec5SDimitry Andric for (const auto &I : Thunks) { 21800b57cec5SDimitry Andric const CXXMethodDecl *MD = I.first; 21815f757f3fSDimitry Andric std::string MethodName = PredefinedExpr::ComputeName( 21825f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 21830b57cec5SDimitry Andric 21840b57cec5SDimitry Andric MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); 21850b57cec5SDimitry Andric } 21860b57cec5SDimitry Andric 21870b57cec5SDimitry Andric for (const auto &I : MethodNamesAndDecls) { 21880b57cec5SDimitry Andric const std::string &MethodName = I.first; 21890b57cec5SDimitry Andric const CXXMethodDecl *MD = I.second; 21900b57cec5SDimitry Andric 21910b57cec5SDimitry Andric ThunkInfoVectorTy ThunksVector = Thunks[MD]; 21920b57cec5SDimitry Andric llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) { 21930b57cec5SDimitry Andric return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); 21940b57cec5SDimitry Andric }); 21950b57cec5SDimitry Andric 21960b57cec5SDimitry Andric Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); 21970b57cec5SDimitry Andric Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; 21980b57cec5SDimitry Andric 21990b57cec5SDimitry Andric for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { 22000b57cec5SDimitry Andric const ThunkInfo &Thunk = ThunksVector[I]; 22010b57cec5SDimitry Andric 22020b57cec5SDimitry Andric Out << llvm::format("%4d | ", I); 22030b57cec5SDimitry Andric 22040b57cec5SDimitry Andric // If this function pointer has a return pointer adjustment, dump it. 22050b57cec5SDimitry Andric if (!Thunk.Return.isEmpty()) { 22060b57cec5SDimitry Andric Out << "return adjustment: " << Thunk.Return.NonVirtual; 22070b57cec5SDimitry Andric Out << " non-virtual"; 22080b57cec5SDimitry Andric if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { 22090b57cec5SDimitry Andric Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; 22100b57cec5SDimitry Andric Out << " vbase offset offset"; 22110b57cec5SDimitry Andric } 22120b57cec5SDimitry Andric 22130b57cec5SDimitry Andric if (!Thunk.This.isEmpty()) 22140b57cec5SDimitry Andric Out << "\n "; 22150b57cec5SDimitry Andric } 22160b57cec5SDimitry Andric 22170b57cec5SDimitry Andric // If this function pointer has a 'this' pointer adjustment, dump it. 22180b57cec5SDimitry Andric if (!Thunk.This.isEmpty()) { 22190b57cec5SDimitry Andric Out << "this adjustment: "; 22200b57cec5SDimitry Andric Out << Thunk.This.NonVirtual << " non-virtual"; 22210b57cec5SDimitry Andric 22220b57cec5SDimitry Andric if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { 22230b57cec5SDimitry Andric Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; 22240b57cec5SDimitry Andric Out << " vcall offset offset"; 22250b57cec5SDimitry Andric } 22260b57cec5SDimitry Andric } 22270b57cec5SDimitry Andric 22280b57cec5SDimitry Andric Out << '\n'; 22290b57cec5SDimitry Andric } 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric Out << '\n'; 22320b57cec5SDimitry Andric } 22330b57cec5SDimitry Andric } 22340b57cec5SDimitry Andric 22350b57cec5SDimitry Andric // Compute the vtable indices for all the member functions. 22360b57cec5SDimitry Andric // Store them in a map keyed by the index so we'll get a sorted table. 22370b57cec5SDimitry Andric std::map<uint64_t, std::string> IndicesMap; 22380b57cec5SDimitry Andric 22390b57cec5SDimitry Andric for (const auto *MD : MostDerivedClass->methods()) { 22400b57cec5SDimitry Andric // We only want virtual member functions. 22415ffd83dbSDimitry Andric if (!ItaniumVTableContext::hasVtableSlot(MD)) 22420b57cec5SDimitry Andric continue; 22430b57cec5SDimitry Andric MD = MD->getCanonicalDecl(); 22440b57cec5SDimitry Andric 22455f757f3fSDimitry Andric std::string MethodName = PredefinedExpr::ComputeName( 22465f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 22470b57cec5SDimitry Andric 22480b57cec5SDimitry Andric if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { 22490b57cec5SDimitry Andric GlobalDecl GD(DD, Dtor_Complete); 22500b57cec5SDimitry Andric assert(MethodVTableIndices.count(GD)); 22510b57cec5SDimitry Andric uint64_t VTableIndex = MethodVTableIndices[GD]; 22520b57cec5SDimitry Andric IndicesMap[VTableIndex] = MethodName + " [complete]"; 22530b57cec5SDimitry Andric IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; 22540b57cec5SDimitry Andric } else { 22550b57cec5SDimitry Andric assert(MethodVTableIndices.count(MD)); 22560b57cec5SDimitry Andric IndicesMap[MethodVTableIndices[MD]] = MethodName; 22570b57cec5SDimitry Andric } 22580b57cec5SDimitry Andric } 22590b57cec5SDimitry Andric 22600b57cec5SDimitry Andric // Print the vtable indices for all the member functions. 22610b57cec5SDimitry Andric if (!IndicesMap.empty()) { 22620b57cec5SDimitry Andric Out << "VTable indices for '"; 22630b57cec5SDimitry Andric MostDerivedClass->printQualifiedName(Out); 22640b57cec5SDimitry Andric Out << "' (" << IndicesMap.size() << " entries).\n"; 22650b57cec5SDimitry Andric 22660b57cec5SDimitry Andric for (const auto &I : IndicesMap) { 22670b57cec5SDimitry Andric uint64_t VTableIndex = I.first; 22680b57cec5SDimitry Andric const std::string &MethodName = I.second; 22690b57cec5SDimitry Andric 22700b57cec5SDimitry Andric Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName 22710b57cec5SDimitry Andric << '\n'; 22720b57cec5SDimitry Andric } 22730b57cec5SDimitry Andric } 22740b57cec5SDimitry Andric 22750b57cec5SDimitry Andric Out << '\n'; 22760b57cec5SDimitry Andric } 22770b57cec5SDimitry Andric } 22780b57cec5SDimitry Andric 22795ffd83dbSDimitry Andric static VTableLayout::AddressPointsIndexMapTy 22805ffd83dbSDimitry Andric MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints, 22815ffd83dbSDimitry Andric unsigned numVTables) { 22825ffd83dbSDimitry Andric VTableLayout::AddressPointsIndexMapTy indexMap(numVTables); 22835ffd83dbSDimitry Andric 22845ffd83dbSDimitry Andric for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it) { 22855ffd83dbSDimitry Andric const auto &addressPointLoc = it->second; 22865ffd83dbSDimitry Andric unsigned vtableIndex = addressPointLoc.VTableIndex; 22875ffd83dbSDimitry Andric unsigned addressPoint = addressPointLoc.AddressPointIndex; 22885ffd83dbSDimitry Andric if (indexMap[vtableIndex]) { 22895ffd83dbSDimitry Andric // Multiple BaseSubobjects can map to the same AddressPointLocation, but 22905ffd83dbSDimitry Andric // every vtable index should have a unique address point. 22915ffd83dbSDimitry Andric assert(indexMap[vtableIndex] == addressPoint && 22925ffd83dbSDimitry Andric "Every vtable index should have a unique address point. Found a " 22935ffd83dbSDimitry Andric "vtable that has two different address points."); 22945ffd83dbSDimitry Andric } else { 22955ffd83dbSDimitry Andric indexMap[vtableIndex] = addressPoint; 22965ffd83dbSDimitry Andric } 22975ffd83dbSDimitry Andric } 22985ffd83dbSDimitry Andric 22995ffd83dbSDimitry Andric // Note that by this point, not all the address may be initialized if the 23005ffd83dbSDimitry Andric // AddressPoints map is empty. This is ok if the map isn't needed. See 23015ffd83dbSDimitry Andric // MicrosoftVTableContext::computeVTableRelatedInformation() which uses an 23025ffd83dbSDimitry Andric // emprt map. 23035ffd83dbSDimitry Andric return indexMap; 23045ffd83dbSDimitry Andric } 23055ffd83dbSDimitry Andric 23060b57cec5SDimitry Andric VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices, 23070b57cec5SDimitry Andric ArrayRef<VTableComponent> VTableComponents, 23080b57cec5SDimitry Andric ArrayRef<VTableThunkTy> VTableThunks, 23090b57cec5SDimitry Andric const AddressPointsMapTy &AddressPoints) 23100b57cec5SDimitry Andric : VTableComponents(VTableComponents), VTableThunks(VTableThunks), 23115ffd83dbSDimitry Andric AddressPoints(AddressPoints), AddressPointIndices(MakeAddressPointIndices( 23125ffd83dbSDimitry Andric AddressPoints, VTableIndices.size())) { 23130b57cec5SDimitry Andric if (VTableIndices.size() <= 1) 23140b57cec5SDimitry Andric assert(VTableIndices.size() == 1 && VTableIndices[0] == 0); 23150b57cec5SDimitry Andric else 23160b57cec5SDimitry Andric this->VTableIndices = OwningArrayRef<size_t>(VTableIndices); 23170b57cec5SDimitry Andric 23180b57cec5SDimitry Andric llvm::sort(this->VTableThunks, [](const VTableLayout::VTableThunkTy &LHS, 23190b57cec5SDimitry Andric const VTableLayout::VTableThunkTy &RHS) { 23200b57cec5SDimitry Andric assert((LHS.first != RHS.first || LHS.second == RHS.second) && 23210b57cec5SDimitry Andric "Different thunks should have unique indices!"); 23220b57cec5SDimitry Andric return LHS.first < RHS.first; 23230b57cec5SDimitry Andric }); 23240b57cec5SDimitry Andric } 23250b57cec5SDimitry Andric 23260b57cec5SDimitry Andric VTableLayout::~VTableLayout() { } 23270b57cec5SDimitry Andric 23285ffd83dbSDimitry Andric bool VTableContextBase::hasVtableSlot(const CXXMethodDecl *MD) { 232906c3fb27SDimitry Andric return MD->isVirtual() && !MD->isImmediateFunction(); 23305ffd83dbSDimitry Andric } 23315ffd83dbSDimitry Andric 23325ffd83dbSDimitry Andric ItaniumVTableContext::ItaniumVTableContext( 23335ffd83dbSDimitry Andric ASTContext &Context, VTableComponentLayout ComponentLayout) 23345ffd83dbSDimitry Andric : VTableContextBase(/*MS=*/false), ComponentLayout(ComponentLayout) {} 23350b57cec5SDimitry Andric 23360b57cec5SDimitry Andric ItaniumVTableContext::~ItaniumVTableContext() {} 23370b57cec5SDimitry Andric 23380b57cec5SDimitry Andric uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) { 23390b57cec5SDimitry Andric GD = GD.getCanonicalDecl(); 23400b57cec5SDimitry Andric MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); 23410b57cec5SDimitry Andric if (I != MethodVTableIndices.end()) 23420b57cec5SDimitry Andric return I->second; 23430b57cec5SDimitry Andric 23440b57cec5SDimitry Andric const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); 23450b57cec5SDimitry Andric 23460b57cec5SDimitry Andric computeVTableRelatedInformation(RD); 23470b57cec5SDimitry Andric 23480b57cec5SDimitry Andric I = MethodVTableIndices.find(GD); 23490b57cec5SDimitry Andric assert(I != MethodVTableIndices.end() && "Did not find index!"); 23500b57cec5SDimitry Andric return I->second; 23510b57cec5SDimitry Andric } 23520b57cec5SDimitry Andric 23530b57cec5SDimitry Andric CharUnits 23540b57cec5SDimitry Andric ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, 23550b57cec5SDimitry Andric const CXXRecordDecl *VBase) { 23560b57cec5SDimitry Andric ClassPairTy ClassPair(RD, VBase); 23570b57cec5SDimitry Andric 23580b57cec5SDimitry Andric VirtualBaseClassOffsetOffsetsMapTy::iterator I = 23590b57cec5SDimitry Andric VirtualBaseClassOffsetOffsets.find(ClassPair); 23600b57cec5SDimitry Andric if (I != VirtualBaseClassOffsetOffsets.end()) 23610b57cec5SDimitry Andric return I->second; 23620b57cec5SDimitry Andric 23635ffd83dbSDimitry Andric VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, /*Overriders=*/nullptr, 23640b57cec5SDimitry Andric BaseSubobject(RD, CharUnits::Zero()), 23650b57cec5SDimitry Andric /*BaseIsVirtual=*/false, 23660b57cec5SDimitry Andric /*OffsetInLayoutClass=*/CharUnits::Zero()); 23670b57cec5SDimitry Andric 23680b57cec5SDimitry Andric for (const auto &I : Builder.getVBaseOffsetOffsets()) { 23690b57cec5SDimitry Andric // Insert all types. 23700b57cec5SDimitry Andric ClassPairTy ClassPair(RD, I.first); 23710b57cec5SDimitry Andric 23720b57cec5SDimitry Andric VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second)); 23730b57cec5SDimitry Andric } 23740b57cec5SDimitry Andric 23750b57cec5SDimitry Andric I = VirtualBaseClassOffsetOffsets.find(ClassPair); 23760b57cec5SDimitry Andric assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); 23770b57cec5SDimitry Andric 23780b57cec5SDimitry Andric return I->second; 23790b57cec5SDimitry Andric } 23800b57cec5SDimitry Andric 2381*0fca6ea1SDimitry Andric GlobalDecl ItaniumVTableContext::findOriginalMethod(GlobalDecl GD) { 2382*0fca6ea1SDimitry Andric const auto *MD = cast<CXXMethodDecl>(GD.getDecl()); 2383*0fca6ea1SDimitry Andric computeVTableRelatedInformation(MD->getParent()); 2384*0fca6ea1SDimitry Andric const CXXMethodDecl *OriginalMD = findOriginalMethodInMap(MD); 2385*0fca6ea1SDimitry Andric 2386*0fca6ea1SDimitry Andric if (const auto *DD = dyn_cast<CXXDestructorDecl>(OriginalMD)) 2387*0fca6ea1SDimitry Andric return GlobalDecl(DD, GD.getDtorType()); 2388*0fca6ea1SDimitry Andric return OriginalMD; 2389*0fca6ea1SDimitry Andric } 2390*0fca6ea1SDimitry Andric 2391*0fca6ea1SDimitry Andric const CXXMethodDecl * 2392*0fca6ea1SDimitry Andric ItaniumVTableContext::findOriginalMethodInMap(const CXXMethodDecl *MD) const { 2393*0fca6ea1SDimitry Andric // Traverse the chain of virtual methods until we find the method that added 2394*0fca6ea1SDimitry Andric // the v-table slot. 2395*0fca6ea1SDimitry Andric while (true) { 2396*0fca6ea1SDimitry Andric auto I = OriginalMethodMap.find(MD); 2397*0fca6ea1SDimitry Andric 2398*0fca6ea1SDimitry Andric // MD doesn't exist in OriginalMethodMap, so it must be the method we are 2399*0fca6ea1SDimitry Andric // looking for. 2400*0fca6ea1SDimitry Andric if (I == OriginalMethodMap.end()) 2401*0fca6ea1SDimitry Andric break; 2402*0fca6ea1SDimitry Andric 2403*0fca6ea1SDimitry Andric // Set MD to the overridden method. 2404*0fca6ea1SDimitry Andric MD = I->second; 2405*0fca6ea1SDimitry Andric } 2406*0fca6ea1SDimitry Andric 2407*0fca6ea1SDimitry Andric return MD; 2408*0fca6ea1SDimitry Andric } 2409*0fca6ea1SDimitry Andric 24100b57cec5SDimitry Andric static std::unique_ptr<VTableLayout> 24110b57cec5SDimitry Andric CreateVTableLayout(const ItaniumVTableBuilder &Builder) { 24120b57cec5SDimitry Andric SmallVector<VTableLayout::VTableThunkTy, 1> 24130b57cec5SDimitry Andric VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); 24140b57cec5SDimitry Andric 2415a7dea167SDimitry Andric return std::make_unique<VTableLayout>( 24160b57cec5SDimitry Andric Builder.VTableIndices, Builder.vtable_components(), VTableThunks, 24170b57cec5SDimitry Andric Builder.getAddressPoints()); 24180b57cec5SDimitry Andric } 24190b57cec5SDimitry Andric 24200b57cec5SDimitry Andric void 24210b57cec5SDimitry Andric ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) { 24220b57cec5SDimitry Andric std::unique_ptr<const VTableLayout> &Entry = VTableLayouts[RD]; 24230b57cec5SDimitry Andric 24240b57cec5SDimitry Andric // Check if we've computed this information before. 24250b57cec5SDimitry Andric if (Entry) 24260b57cec5SDimitry Andric return; 24270b57cec5SDimitry Andric 24280b57cec5SDimitry Andric ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(), 242904eeddc0SDimitry Andric /*MostDerivedClassIsVirtual=*/false, RD); 24300b57cec5SDimitry Andric Entry = CreateVTableLayout(Builder); 24310b57cec5SDimitry Andric 24320b57cec5SDimitry Andric MethodVTableIndices.insert(Builder.vtable_indices_begin(), 24330b57cec5SDimitry Andric Builder.vtable_indices_end()); 24340b57cec5SDimitry Andric 24350b57cec5SDimitry Andric // Add the known thunks. 24360b57cec5SDimitry Andric Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); 24370b57cec5SDimitry Andric 24380b57cec5SDimitry Andric // If we don't have the vbase information for this class, insert it. 24390b57cec5SDimitry Andric // getVirtualBaseOffsetOffset will compute it separately without computing 24400b57cec5SDimitry Andric // the rest of the vtable related information. 24410b57cec5SDimitry Andric if (!RD->getNumVBases()) 24420b57cec5SDimitry Andric return; 24430b57cec5SDimitry Andric 24440b57cec5SDimitry Andric const CXXRecordDecl *VBase = 24450b57cec5SDimitry Andric RD->vbases_begin()->getType()->getAsCXXRecordDecl(); 24460b57cec5SDimitry Andric 24470b57cec5SDimitry Andric if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) 24480b57cec5SDimitry Andric return; 24490b57cec5SDimitry Andric 24500b57cec5SDimitry Andric for (const auto &I : Builder.getVBaseOffsetOffsets()) { 24510b57cec5SDimitry Andric // Insert all types. 24520b57cec5SDimitry Andric ClassPairTy ClassPair(RD, I.first); 24530b57cec5SDimitry Andric 24540b57cec5SDimitry Andric VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second)); 24550b57cec5SDimitry Andric } 24560b57cec5SDimitry Andric } 24570b57cec5SDimitry Andric 24580b57cec5SDimitry Andric std::unique_ptr<VTableLayout> 24590b57cec5SDimitry Andric ItaniumVTableContext::createConstructionVTableLayout( 24600b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, 24610b57cec5SDimitry Andric bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) { 24620b57cec5SDimitry Andric ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset, 24630b57cec5SDimitry Andric MostDerivedClassIsVirtual, LayoutClass); 24640b57cec5SDimitry Andric return CreateVTableLayout(Builder); 24650b57cec5SDimitry Andric } 24660b57cec5SDimitry Andric 24670b57cec5SDimitry Andric namespace { 24680b57cec5SDimitry Andric 24690b57cec5SDimitry Andric // Vtables in the Microsoft ABI are different from the Itanium ABI. 24700b57cec5SDimitry Andric // 24710b57cec5SDimitry Andric // The main differences are: 24720b57cec5SDimitry Andric // 1. Separate vftable and vbtable. 24730b57cec5SDimitry Andric // 24740b57cec5SDimitry Andric // 2. Each subobject with a vfptr gets its own vftable rather than an address 24750b57cec5SDimitry Andric // point in a single vtable shared between all the subobjects. 24760b57cec5SDimitry Andric // Each vftable is represented by a separate section and virtual calls 24770b57cec5SDimitry Andric // must be done using the vftable which has a slot for the function to be 24780b57cec5SDimitry Andric // called. 24790b57cec5SDimitry Andric // 24800b57cec5SDimitry Andric // 3. Virtual method definitions expect their 'this' parameter to point to the 24810b57cec5SDimitry Andric // first vfptr whose table provides a compatible overridden method. In many 24820b57cec5SDimitry Andric // cases, this permits the original vf-table entry to directly call 24830b57cec5SDimitry Andric // the method instead of passing through a thunk. 24840b57cec5SDimitry Andric // See example before VFTableBuilder::ComputeThisOffset below. 24850b57cec5SDimitry Andric // 24860b57cec5SDimitry Andric // A compatible overridden method is one which does not have a non-trivial 24870b57cec5SDimitry Andric // covariant-return adjustment. 24880b57cec5SDimitry Andric // 24890b57cec5SDimitry Andric // The first vfptr is the one with the lowest offset in the complete-object 24900b57cec5SDimitry Andric // layout of the defining class, and the method definition will subtract 24910b57cec5SDimitry Andric // that constant offset from the parameter value to get the real 'this' 24920b57cec5SDimitry Andric // value. Therefore, if the offset isn't really constant (e.g. if a virtual 24930b57cec5SDimitry Andric // function defined in a virtual base is overridden in a more derived 24940b57cec5SDimitry Andric // virtual base and these bases have a reverse order in the complete 24950b57cec5SDimitry Andric // object), the vf-table may require a this-adjustment thunk. 24960b57cec5SDimitry Andric // 24970b57cec5SDimitry Andric // 4. vftables do not contain new entries for overrides that merely require 24980b57cec5SDimitry Andric // this-adjustment. Together with #3, this keeps vf-tables smaller and 24990b57cec5SDimitry Andric // eliminates the need for this-adjustment thunks in many cases, at the cost 25000b57cec5SDimitry Andric // of often requiring redundant work to adjust the "this" pointer. 25010b57cec5SDimitry Andric // 25020b57cec5SDimitry Andric // 5. Instead of VTT and constructor vtables, vbtables and vtordisps are used. 25030b57cec5SDimitry Andric // Vtordisps are emitted into the class layout if a class has 25040b57cec5SDimitry Andric // a) a user-defined ctor/dtor 25050b57cec5SDimitry Andric // and 25060b57cec5SDimitry Andric // b) a method overriding a method in a virtual base. 25070b57cec5SDimitry Andric // 25080b57cec5SDimitry Andric // To get a better understanding of this code, 25090b57cec5SDimitry Andric // you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp 25100b57cec5SDimitry Andric 25110b57cec5SDimitry Andric class VFTableBuilder { 25120b57cec5SDimitry Andric public: 25130b57cec5SDimitry Andric typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> 25140b57cec5SDimitry Andric MethodVFTableLocationsTy; 25150b57cec5SDimitry Andric 25160b57cec5SDimitry Andric typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator> 25170b57cec5SDimitry Andric method_locations_range; 25180b57cec5SDimitry Andric 25190b57cec5SDimitry Andric private: 25200b57cec5SDimitry Andric /// VTables - Global vtable information. 25210b57cec5SDimitry Andric MicrosoftVTableContext &VTables; 25220b57cec5SDimitry Andric 25230b57cec5SDimitry Andric /// Context - The ASTContext which we will use for layout information. 25240b57cec5SDimitry Andric ASTContext &Context; 25250b57cec5SDimitry Andric 25260b57cec5SDimitry Andric /// MostDerivedClass - The most derived class for which we're building this 25270b57cec5SDimitry Andric /// vtable. 25280b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass; 25290b57cec5SDimitry Andric 25300b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedClassLayout; 25310b57cec5SDimitry Andric 25320b57cec5SDimitry Andric const VPtrInfo &WhichVFPtr; 25330b57cec5SDimitry Andric 25340b57cec5SDimitry Andric /// FinalOverriders - The final overriders of the most derived class. 25350b57cec5SDimitry Andric const FinalOverriders Overriders; 25360b57cec5SDimitry Andric 25370b57cec5SDimitry Andric /// Components - The components of the vftable being built. 25380b57cec5SDimitry Andric SmallVector<VTableComponent, 64> Components; 25390b57cec5SDimitry Andric 25400b57cec5SDimitry Andric MethodVFTableLocationsTy MethodVFTableLocations; 25410b57cec5SDimitry Andric 25420b57cec5SDimitry Andric /// Does this class have an RTTI component? 25430b57cec5SDimitry Andric bool HasRTTIComponent = false; 25440b57cec5SDimitry Andric 25450b57cec5SDimitry Andric /// MethodInfo - Contains information about a method in a vtable. 25460b57cec5SDimitry Andric /// (Used for computing 'this' pointer adjustment thunks. 25470b57cec5SDimitry Andric struct MethodInfo { 25480b57cec5SDimitry Andric /// VBTableIndex - The nonzero index in the vbtable that 25490b57cec5SDimitry Andric /// this method's base has, or zero. 25500b57cec5SDimitry Andric const uint64_t VBTableIndex; 25510b57cec5SDimitry Andric 25520b57cec5SDimitry Andric /// VFTableIndex - The index in the vftable that this method has. 25530b57cec5SDimitry Andric const uint64_t VFTableIndex; 25540b57cec5SDimitry Andric 25550b57cec5SDimitry Andric /// Shadowed - Indicates if this vftable slot is shadowed by 25560b57cec5SDimitry Andric /// a slot for a covariant-return override. If so, it shouldn't be printed 25570b57cec5SDimitry Andric /// or used for vcalls in the most derived class. 25580b57cec5SDimitry Andric bool Shadowed; 25590b57cec5SDimitry Andric 25600b57cec5SDimitry Andric /// UsesExtraSlot - Indicates if this vftable slot was created because 25610b57cec5SDimitry Andric /// any of the overridden slots required a return adjusting thunk. 25620b57cec5SDimitry Andric bool UsesExtraSlot; 25630b57cec5SDimitry Andric 25640b57cec5SDimitry Andric MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex, 25650b57cec5SDimitry Andric bool UsesExtraSlot = false) 25660b57cec5SDimitry Andric : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), 25670b57cec5SDimitry Andric Shadowed(false), UsesExtraSlot(UsesExtraSlot) {} 25680b57cec5SDimitry Andric 25690b57cec5SDimitry Andric MethodInfo() 25700b57cec5SDimitry Andric : VBTableIndex(0), VFTableIndex(0), Shadowed(false), 25710b57cec5SDimitry Andric UsesExtraSlot(false) {} 25720b57cec5SDimitry Andric }; 25730b57cec5SDimitry Andric 25740b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; 25750b57cec5SDimitry Andric 25760b57cec5SDimitry Andric /// MethodInfoMap - The information for all methods in the vftable we're 25770b57cec5SDimitry Andric /// currently building. 25780b57cec5SDimitry Andric MethodInfoMapTy MethodInfoMap; 25790b57cec5SDimitry Andric 25800b57cec5SDimitry Andric typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; 25810b57cec5SDimitry Andric 25820b57cec5SDimitry Andric /// VTableThunks - The thunks by vftable index in the vftable currently being 25830b57cec5SDimitry Andric /// built. 25840b57cec5SDimitry Andric VTableThunksMapTy VTableThunks; 25850b57cec5SDimitry Andric 25860b57cec5SDimitry Andric typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 25870b57cec5SDimitry Andric typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 25880b57cec5SDimitry Andric 25890b57cec5SDimitry Andric /// Thunks - A map that contains all the thunks needed for all methods in the 25900b57cec5SDimitry Andric /// most derived class for which the vftable is currently being built. 25910b57cec5SDimitry Andric ThunksMapTy Thunks; 25920b57cec5SDimitry Andric 25930b57cec5SDimitry Andric /// AddThunk - Add a thunk for the given method. 25940b57cec5SDimitry Andric void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { 25950b57cec5SDimitry Andric SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; 25960b57cec5SDimitry Andric 25970b57cec5SDimitry Andric // Check if we have this thunk already. 2598349cc55cSDimitry Andric if (llvm::is_contained(ThunksVector, Thunk)) 25990b57cec5SDimitry Andric return; 26000b57cec5SDimitry Andric 26010b57cec5SDimitry Andric ThunksVector.push_back(Thunk); 26020b57cec5SDimitry Andric } 26030b57cec5SDimitry Andric 26040b57cec5SDimitry Andric /// ComputeThisOffset - Returns the 'this' argument offset for the given 26050b57cec5SDimitry Andric /// method, relative to the beginning of the MostDerivedClass. 26060b57cec5SDimitry Andric CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider); 26070b57cec5SDimitry Andric 26080b57cec5SDimitry Andric void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider, 26090b57cec5SDimitry Andric CharUnits ThisOffset, ThisAdjustment &TA); 26100b57cec5SDimitry Andric 26110b57cec5SDimitry Andric /// AddMethod - Add a single virtual member function to the vftable 26120b57cec5SDimitry Andric /// components vector. 26130b57cec5SDimitry Andric void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) { 26140b57cec5SDimitry Andric if (!TI.isEmpty()) { 26150b57cec5SDimitry Andric VTableThunks[Components.size()] = TI; 26160b57cec5SDimitry Andric AddThunk(MD, TI); 26170b57cec5SDimitry Andric } 26180b57cec5SDimitry Andric if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { 26190b57cec5SDimitry Andric assert(TI.Return.isEmpty() && 26200b57cec5SDimitry Andric "Destructor can't have return adjustment!"); 26210b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeDeletingDtor(DD)); 26220b57cec5SDimitry Andric } else { 26230b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeFunction(MD)); 26240b57cec5SDimitry Andric } 26250b57cec5SDimitry Andric } 26260b57cec5SDimitry Andric 26270b57cec5SDimitry Andric /// AddMethods - Add the methods of this base subobject and the relevant 26280b57cec5SDimitry Andric /// subbases to the vftable we're currently laying out. 26290b57cec5SDimitry Andric void AddMethods(BaseSubobject Base, unsigned BaseDepth, 26300b57cec5SDimitry Andric const CXXRecordDecl *LastVBase, 26310b57cec5SDimitry Andric BasesSetVectorTy &VisitedBases); 26320b57cec5SDimitry Andric 26330b57cec5SDimitry Andric void LayoutVFTable() { 26340b57cec5SDimitry Andric // RTTI data goes before all other entries. 26350b57cec5SDimitry Andric if (HasRTTIComponent) 26360b57cec5SDimitry Andric Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); 26370b57cec5SDimitry Andric 26380b57cec5SDimitry Andric BasesSetVectorTy VisitedBases; 26390b57cec5SDimitry Andric AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr, 26400b57cec5SDimitry Andric VisitedBases); 26415ffd83dbSDimitry Andric // Note that it is possible for the vftable to contain only an RTTI 26425ffd83dbSDimitry Andric // pointer, if all virtual functions are constewval. 26435ffd83dbSDimitry Andric assert(!Components.empty() && "vftable can't be empty"); 26440b57cec5SDimitry Andric 26450b57cec5SDimitry Andric assert(MethodVFTableLocations.empty()); 26460b57cec5SDimitry Andric for (const auto &I : MethodInfoMap) { 26470b57cec5SDimitry Andric const CXXMethodDecl *MD = I.first; 26480b57cec5SDimitry Andric const MethodInfo &MI = I.second; 26490b57cec5SDimitry Andric assert(MD == MD->getCanonicalDecl()); 26500b57cec5SDimitry Andric 26510b57cec5SDimitry Andric // Skip the methods that the MostDerivedClass didn't override 26520b57cec5SDimitry Andric // and the entries shadowed by return adjusting thunks. 26530b57cec5SDimitry Andric if (MD->getParent() != MostDerivedClass || MI.Shadowed) 26540b57cec5SDimitry Andric continue; 26550b57cec5SDimitry Andric MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(), 26560b57cec5SDimitry Andric WhichVFPtr.NonVirtualOffset, MI.VFTableIndex); 26570b57cec5SDimitry Andric if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { 26580b57cec5SDimitry Andric MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc; 26590b57cec5SDimitry Andric } else { 26600b57cec5SDimitry Andric MethodVFTableLocations[MD] = Loc; 26610b57cec5SDimitry Andric } 26620b57cec5SDimitry Andric } 26630b57cec5SDimitry Andric } 26640b57cec5SDimitry Andric 26650b57cec5SDimitry Andric public: 26660b57cec5SDimitry Andric VFTableBuilder(MicrosoftVTableContext &VTables, 26670b57cec5SDimitry Andric const CXXRecordDecl *MostDerivedClass, const VPtrInfo &Which) 26680b57cec5SDimitry Andric : VTables(VTables), 26690b57cec5SDimitry Andric Context(MostDerivedClass->getASTContext()), 26700b57cec5SDimitry Andric MostDerivedClass(MostDerivedClass), 26710b57cec5SDimitry Andric MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)), 26720b57cec5SDimitry Andric WhichVFPtr(Which), 26730b57cec5SDimitry Andric Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) { 26740b57cec5SDimitry Andric // Provide the RTTI component if RTTIData is enabled. If the vftable would 26750b57cec5SDimitry Andric // be available externally, we should not provide the RTTI componenent. It 26760b57cec5SDimitry Andric // is currently impossible to get available externally vftables with either 26770b57cec5SDimitry Andric // dllimport or extern template instantiations, but eventually we may add a 26780b57cec5SDimitry Andric // flag to support additional devirtualization that needs this. 26790b57cec5SDimitry Andric if (Context.getLangOpts().RTTIData) 26800b57cec5SDimitry Andric HasRTTIComponent = true; 26810b57cec5SDimitry Andric 26820b57cec5SDimitry Andric LayoutVFTable(); 26830b57cec5SDimitry Andric 26840b57cec5SDimitry Andric if (Context.getLangOpts().DumpVTableLayouts) 26850b57cec5SDimitry Andric dumpLayout(llvm::outs()); 26860b57cec5SDimitry Andric } 26870b57cec5SDimitry Andric 26880b57cec5SDimitry Andric uint64_t getNumThunks() const { return Thunks.size(); } 26890b57cec5SDimitry Andric 26900b57cec5SDimitry Andric ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); } 26910b57cec5SDimitry Andric 26920b57cec5SDimitry Andric ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); } 26930b57cec5SDimitry Andric 26940b57cec5SDimitry Andric method_locations_range vtable_locations() const { 26950b57cec5SDimitry Andric return method_locations_range(MethodVFTableLocations.begin(), 26960b57cec5SDimitry Andric MethodVFTableLocations.end()); 26970b57cec5SDimitry Andric } 26980b57cec5SDimitry Andric 26990b57cec5SDimitry Andric ArrayRef<VTableComponent> vtable_components() const { return Components; } 27000b57cec5SDimitry Andric 27010b57cec5SDimitry Andric VTableThunksMapTy::const_iterator vtable_thunks_begin() const { 27020b57cec5SDimitry Andric return VTableThunks.begin(); 27030b57cec5SDimitry Andric } 27040b57cec5SDimitry Andric 27050b57cec5SDimitry Andric VTableThunksMapTy::const_iterator vtable_thunks_end() const { 27060b57cec5SDimitry Andric return VTableThunks.end(); 27070b57cec5SDimitry Andric } 27080b57cec5SDimitry Andric 27090b57cec5SDimitry Andric void dumpLayout(raw_ostream &); 27100b57cec5SDimitry Andric }; 27110b57cec5SDimitry Andric 27120b57cec5SDimitry Andric } // end namespace 27130b57cec5SDimitry Andric 27140b57cec5SDimitry Andric // Let's study one class hierarchy as an example: 27150b57cec5SDimitry Andric // struct A { 27160b57cec5SDimitry Andric // virtual void f(); 27170b57cec5SDimitry Andric // int x; 27180b57cec5SDimitry Andric // }; 27190b57cec5SDimitry Andric // 27200b57cec5SDimitry Andric // struct B : virtual A { 27210b57cec5SDimitry Andric // virtual void f(); 27220b57cec5SDimitry Andric // }; 27230b57cec5SDimitry Andric // 27240b57cec5SDimitry Andric // Record layouts: 27250b57cec5SDimitry Andric // struct A: 27260b57cec5SDimitry Andric // 0 | (A vftable pointer) 27270b57cec5SDimitry Andric // 4 | int x 27280b57cec5SDimitry Andric // 27290b57cec5SDimitry Andric // struct B: 27300b57cec5SDimitry Andric // 0 | (B vbtable pointer) 27310b57cec5SDimitry Andric // 4 | struct A (virtual base) 27320b57cec5SDimitry Andric // 4 | (A vftable pointer) 27330b57cec5SDimitry Andric // 8 | int x 27340b57cec5SDimitry Andric // 27350b57cec5SDimitry Andric // Let's assume we have a pointer to the A part of an object of dynamic type B: 27360b57cec5SDimitry Andric // B b; 27370b57cec5SDimitry Andric // A *a = (A*)&b; 27380b57cec5SDimitry Andric // a->f(); 27390b57cec5SDimitry Andric // 27400b57cec5SDimitry Andric // In this hierarchy, f() belongs to the vftable of A, so B::f() expects 27410b57cec5SDimitry Andric // "this" parameter to point at the A subobject, which is B+4. 27420b57cec5SDimitry Andric // In the B::f() prologue, it adjusts "this" back to B by subtracting 4, 27430b57cec5SDimitry Andric // performed as a *static* adjustment. 27440b57cec5SDimitry Andric // 27450b57cec5SDimitry Andric // Interesting thing happens when we alter the relative placement of A and B 27460b57cec5SDimitry Andric // subobjects in a class: 27470b57cec5SDimitry Andric // struct C : virtual B { }; 27480b57cec5SDimitry Andric // 27490b57cec5SDimitry Andric // C c; 27500b57cec5SDimitry Andric // A *a = (A*)&c; 27510b57cec5SDimitry Andric // a->f(); 27520b57cec5SDimitry Andric // 27530b57cec5SDimitry Andric // Respective record layout is: 27540b57cec5SDimitry Andric // 0 | (C vbtable pointer) 27550b57cec5SDimitry Andric // 4 | struct A (virtual base) 27560b57cec5SDimitry Andric // 4 | (A vftable pointer) 27570b57cec5SDimitry Andric // 8 | int x 27580b57cec5SDimitry Andric // 12 | struct B (virtual base) 27590b57cec5SDimitry Andric // 12 | (B vbtable pointer) 27600b57cec5SDimitry Andric // 27610b57cec5SDimitry Andric // The final overrider of f() in class C is still B::f(), so B+4 should be 27620b57cec5SDimitry Andric // passed as "this" to that code. However, "a" points at B-8, so the respective 27630b57cec5SDimitry Andric // vftable entry should hold a thunk that adds 12 to the "this" argument before 27640b57cec5SDimitry Andric // performing a tail call to B::f(). 27650b57cec5SDimitry Andric // 27660b57cec5SDimitry Andric // With this example in mind, we can now calculate the 'this' argument offset 27670b57cec5SDimitry Andric // for the given method, relative to the beginning of the MostDerivedClass. 27680b57cec5SDimitry Andric CharUnits 27690b57cec5SDimitry Andric VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) { 27700b57cec5SDimitry Andric BasesSetVectorTy Bases; 27710b57cec5SDimitry Andric 27720b57cec5SDimitry Andric { 27730b57cec5SDimitry Andric // Find the set of least derived bases that define the given method. 27740b57cec5SDimitry Andric OverriddenMethodsSetTy VisitedOverriddenMethods; 27750b57cec5SDimitry Andric auto InitialOverriddenDefinitionCollector = [&]( 27760b57cec5SDimitry Andric const CXXMethodDecl *OverriddenMD) { 27770b57cec5SDimitry Andric if (OverriddenMD->size_overridden_methods() == 0) 27780b57cec5SDimitry Andric Bases.insert(OverriddenMD->getParent()); 27790b57cec5SDimitry Andric // Don't recurse on this method if we've already collected it. 27800b57cec5SDimitry Andric return VisitedOverriddenMethods.insert(OverriddenMD).second; 27810b57cec5SDimitry Andric }; 27820b57cec5SDimitry Andric visitAllOverriddenMethods(Overrider.Method, 27830b57cec5SDimitry Andric InitialOverriddenDefinitionCollector); 27840b57cec5SDimitry Andric } 27850b57cec5SDimitry Andric 27860b57cec5SDimitry Andric // If there are no overrides then 'this' is located 27870b57cec5SDimitry Andric // in the base that defines the method. 27880b57cec5SDimitry Andric if (Bases.size() == 0) 27890b57cec5SDimitry Andric return Overrider.Offset; 27900b57cec5SDimitry Andric 27910b57cec5SDimitry Andric CXXBasePaths Paths; 27920b57cec5SDimitry Andric Overrider.Method->getParent()->lookupInBases( 27930b57cec5SDimitry Andric [&Bases](const CXXBaseSpecifier *Specifier, CXXBasePath &) { 27940b57cec5SDimitry Andric return Bases.count(Specifier->getType()->getAsCXXRecordDecl()); 27950b57cec5SDimitry Andric }, 27960b57cec5SDimitry Andric Paths); 27970b57cec5SDimitry Andric 27980b57cec5SDimitry Andric // This will hold the smallest this offset among overridees of MD. 27990b57cec5SDimitry Andric // This implies that an offset of a non-virtual base will dominate an offset 28000b57cec5SDimitry Andric // of a virtual base to potentially reduce the number of thunks required 28010b57cec5SDimitry Andric // in the derived classes that inherit this method. 28020b57cec5SDimitry Andric CharUnits Ret; 28030b57cec5SDimitry Andric bool First = true; 28040b57cec5SDimitry Andric 28050b57cec5SDimitry Andric const ASTRecordLayout &OverriderRDLayout = 28060b57cec5SDimitry Andric Context.getASTRecordLayout(Overrider.Method->getParent()); 28070b57cec5SDimitry Andric for (const CXXBasePath &Path : Paths) { 28080b57cec5SDimitry Andric CharUnits ThisOffset = Overrider.Offset; 28090b57cec5SDimitry Andric CharUnits LastVBaseOffset; 28100b57cec5SDimitry Andric 28110b57cec5SDimitry Andric // For each path from the overrider to the parents of the overridden 28120b57cec5SDimitry Andric // methods, traverse the path, calculating the this offset in the most 28130b57cec5SDimitry Andric // derived class. 28140b57cec5SDimitry Andric for (const CXXBasePathElement &Element : Path) { 28150b57cec5SDimitry Andric QualType CurTy = Element.Base->getType(); 28160b57cec5SDimitry Andric const CXXRecordDecl *PrevRD = Element.Class, 28170b57cec5SDimitry Andric *CurRD = CurTy->getAsCXXRecordDecl(); 28180b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD); 28190b57cec5SDimitry Andric 28200b57cec5SDimitry Andric if (Element.Base->isVirtual()) { 28210b57cec5SDimitry Andric // The interesting things begin when you have virtual inheritance. 28220b57cec5SDimitry Andric // The final overrider will use a static adjustment equal to the offset 28230b57cec5SDimitry Andric // of the vbase in the final overrider class. 28240b57cec5SDimitry Andric // For example, if the final overrider is in a vbase B of the most 28250b57cec5SDimitry Andric // derived class and it overrides a method of the B's own vbase A, 28260b57cec5SDimitry Andric // it uses A* as "this". In its prologue, it can cast A* to B* with 28270b57cec5SDimitry Andric // a static offset. This offset is used regardless of the actual 28280b57cec5SDimitry Andric // offset of A from B in the most derived class, requiring an 28290b57cec5SDimitry Andric // this-adjusting thunk in the vftable if A and B are laid out 28300b57cec5SDimitry Andric // differently in the most derived class. 28310b57cec5SDimitry Andric LastVBaseOffset = ThisOffset = 28320b57cec5SDimitry Andric Overrider.Offset + OverriderRDLayout.getVBaseClassOffset(CurRD); 28330b57cec5SDimitry Andric } else { 28340b57cec5SDimitry Andric ThisOffset += Layout.getBaseClassOffset(CurRD); 28350b57cec5SDimitry Andric } 28360b57cec5SDimitry Andric } 28370b57cec5SDimitry Andric 28380b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(Overrider.Method)) { 28390b57cec5SDimitry Andric if (LastVBaseOffset.isZero()) { 28400b57cec5SDimitry Andric // If a "Base" class has at least one non-virtual base with a virtual 28410b57cec5SDimitry Andric // destructor, the "Base" virtual destructor will take the address 28420b57cec5SDimitry Andric // of the "Base" subobject as the "this" argument. 28430b57cec5SDimitry Andric ThisOffset = Overrider.Offset; 28440b57cec5SDimitry Andric } else { 28450b57cec5SDimitry Andric // A virtual destructor of a virtual base takes the address of the 28460b57cec5SDimitry Andric // virtual base subobject as the "this" argument. 28470b57cec5SDimitry Andric ThisOffset = LastVBaseOffset; 28480b57cec5SDimitry Andric } 28490b57cec5SDimitry Andric } 28500b57cec5SDimitry Andric 28510b57cec5SDimitry Andric if (Ret > ThisOffset || First) { 28520b57cec5SDimitry Andric First = false; 28530b57cec5SDimitry Andric Ret = ThisOffset; 28540b57cec5SDimitry Andric } 28550b57cec5SDimitry Andric } 28560b57cec5SDimitry Andric 28570b57cec5SDimitry Andric assert(!First && "Method not found in the given subobject?"); 28580b57cec5SDimitry Andric return Ret; 28590b57cec5SDimitry Andric } 28600b57cec5SDimitry Andric 28610b57cec5SDimitry Andric // Things are getting even more complex when the "this" adjustment has to 28620b57cec5SDimitry Andric // use a dynamic offset instead of a static one, or even two dynamic offsets. 28630b57cec5SDimitry Andric // This is sometimes required when a virtual call happens in the middle of 28640b57cec5SDimitry Andric // a non-most-derived class construction or destruction. 28650b57cec5SDimitry Andric // 28660b57cec5SDimitry Andric // Let's take a look at the following example: 28670b57cec5SDimitry Andric // struct A { 28680b57cec5SDimitry Andric // virtual void f(); 28690b57cec5SDimitry Andric // }; 28700b57cec5SDimitry Andric // 28710b57cec5SDimitry Andric // void foo(A *a) { a->f(); } // Knows nothing about siblings of A. 28720b57cec5SDimitry Andric // 28730b57cec5SDimitry Andric // struct B : virtual A { 28740b57cec5SDimitry Andric // virtual void f(); 28750b57cec5SDimitry Andric // B() { 28760b57cec5SDimitry Andric // foo(this); 28770b57cec5SDimitry Andric // } 28780b57cec5SDimitry Andric // }; 28790b57cec5SDimitry Andric // 28800b57cec5SDimitry Andric // struct C : virtual B { 28810b57cec5SDimitry Andric // virtual void f(); 28820b57cec5SDimitry Andric // }; 28830b57cec5SDimitry Andric // 28840b57cec5SDimitry Andric // Record layouts for these classes are: 28850b57cec5SDimitry Andric // struct A 28860b57cec5SDimitry Andric // 0 | (A vftable pointer) 28870b57cec5SDimitry Andric // 28880b57cec5SDimitry Andric // struct B 28890b57cec5SDimitry Andric // 0 | (B vbtable pointer) 28900b57cec5SDimitry Andric // 4 | (vtordisp for vbase A) 28910b57cec5SDimitry Andric // 8 | struct A (virtual base) 28920b57cec5SDimitry Andric // 8 | (A vftable pointer) 28930b57cec5SDimitry Andric // 28940b57cec5SDimitry Andric // struct C 28950b57cec5SDimitry Andric // 0 | (C vbtable pointer) 28960b57cec5SDimitry Andric // 4 | (vtordisp for vbase A) 28970b57cec5SDimitry Andric // 8 | struct A (virtual base) // A precedes B! 28980b57cec5SDimitry Andric // 8 | (A vftable pointer) 28990b57cec5SDimitry Andric // 12 | struct B (virtual base) 29000b57cec5SDimitry Andric // 12 | (B vbtable pointer) 29010b57cec5SDimitry Andric // 29020b57cec5SDimitry Andric // When one creates an object of type C, the C constructor: 29030b57cec5SDimitry Andric // - initializes all the vbptrs, then 29040b57cec5SDimitry Andric // - calls the A subobject constructor 29050b57cec5SDimitry Andric // (initializes A's vfptr with an address of A vftable), then 29060b57cec5SDimitry Andric // - calls the B subobject constructor 29070b57cec5SDimitry Andric // (initializes A's vfptr with an address of B vftable and vtordisp for A), 29080b57cec5SDimitry Andric // that in turn calls foo(), then 29090b57cec5SDimitry Andric // - initializes A's vfptr with an address of C vftable and zeroes out the 29100b57cec5SDimitry Andric // vtordisp 29110b57cec5SDimitry Andric // FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable 29120b57cec5SDimitry Andric // without vtordisp thunks? 29130b57cec5SDimitry Andric // FIXME: how are vtordisp handled in the presence of nooverride/final? 29140b57cec5SDimitry Andric // 29150b57cec5SDimitry Andric // When foo() is called, an object with a layout of class C has a vftable 29160b57cec5SDimitry Andric // referencing B::f() that assumes a B layout, so the "this" adjustments are 29170b57cec5SDimitry Andric // incorrect, unless an extra adjustment is done. This adjustment is called 29180b57cec5SDimitry Andric // "vtordisp adjustment". Vtordisp basically holds the difference between the 29190b57cec5SDimitry Andric // actual location of a vbase in the layout class and the location assumed by 29200b57cec5SDimitry Andric // the vftable of the class being constructed/destructed. Vtordisp is only 29210b57cec5SDimitry Andric // needed if "this" escapes a 29220b57cec5SDimitry Andric // structor (or we can't prove otherwise). 29230b57cec5SDimitry Andric // [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an 29240b57cec5SDimitry Andric // estimation of a dynamic adjustment] 29250b57cec5SDimitry Andric // 29260b57cec5SDimitry Andric // foo() gets a pointer to the A vbase and doesn't know anything about B or C, 29270b57cec5SDimitry Andric // so it just passes that pointer as "this" in a virtual call. 29280b57cec5SDimitry Andric // If there was no vtordisp, that would just dispatch to B::f(). 29290b57cec5SDimitry Andric // However, B::f() assumes B+8 is passed as "this", 29300b57cec5SDimitry Andric // yet the pointer foo() passes along is B-4 (i.e. C+8). 29310b57cec5SDimitry Andric // An extra adjustment is needed, so we emit a thunk into the B vftable. 29320b57cec5SDimitry Andric // This vtordisp thunk subtracts the value of vtordisp 29330b57cec5SDimitry Andric // from the "this" argument (-12) before making a tailcall to B::f(). 29340b57cec5SDimitry Andric // 29350b57cec5SDimitry Andric // Let's consider an even more complex example: 29360b57cec5SDimitry Andric // struct D : virtual B, virtual C { 29370b57cec5SDimitry Andric // D() { 29380b57cec5SDimitry Andric // foo(this); 29390b57cec5SDimitry Andric // } 29400b57cec5SDimitry Andric // }; 29410b57cec5SDimitry Andric // 29420b57cec5SDimitry Andric // struct D 29430b57cec5SDimitry Andric // 0 | (D vbtable pointer) 29440b57cec5SDimitry Andric // 4 | (vtordisp for vbase A) 29450b57cec5SDimitry Andric // 8 | struct A (virtual base) // A precedes both B and C! 29460b57cec5SDimitry Andric // 8 | (A vftable pointer) 29470b57cec5SDimitry Andric // 12 | struct B (virtual base) // B precedes C! 29480b57cec5SDimitry Andric // 12 | (B vbtable pointer) 29490b57cec5SDimitry Andric // 16 | struct C (virtual base) 29500b57cec5SDimitry Andric // 16 | (C vbtable pointer) 29510b57cec5SDimitry Andric // 29520b57cec5SDimitry Andric // When D::D() calls foo(), we find ourselves in a thunk that should tailcall 29530b57cec5SDimitry Andric // to C::f(), which assumes C+8 as its "this" parameter. This time, foo() 29540b57cec5SDimitry Andric // passes along A, which is C-8. The A vtordisp holds 29550b57cec5SDimitry Andric // "D.vbptr[index_of_A] - offset_of_A_in_D" 29560b57cec5SDimitry Andric // and we statically know offset_of_A_in_D, so can get a pointer to D. 29570b57cec5SDimitry Andric // When we know it, we can make an extra vbtable lookup to locate the C vbase 29580b57cec5SDimitry Andric // and one extra static adjustment to calculate the expected value of C+8. 29590b57cec5SDimitry Andric void VFTableBuilder::CalculateVtordispAdjustment( 29600b57cec5SDimitry Andric FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset, 29610b57cec5SDimitry Andric ThisAdjustment &TA) { 29620b57cec5SDimitry Andric const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap = 29630b57cec5SDimitry Andric MostDerivedClassLayout.getVBaseOffsetsMap(); 29640b57cec5SDimitry Andric const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry = 29650b57cec5SDimitry Andric VBaseMap.find(WhichVFPtr.getVBaseWithVPtr()); 29660b57cec5SDimitry Andric assert(VBaseMapEntry != VBaseMap.end()); 29670b57cec5SDimitry Andric 29680b57cec5SDimitry Andric // If there's no vtordisp or the final overrider is defined in the same vbase 29690b57cec5SDimitry Andric // as the initial declaration, we don't need any vtordisp adjustment. 29700b57cec5SDimitry Andric if (!VBaseMapEntry->second.hasVtorDisp() || 29710b57cec5SDimitry Andric Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr()) 29720b57cec5SDimitry Andric return; 29730b57cec5SDimitry Andric 29740b57cec5SDimitry Andric // OK, now we know we need to use a vtordisp thunk. 29750b57cec5SDimitry Andric // The implicit vtordisp field is located right before the vbase. 29760b57cec5SDimitry Andric CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset; 29770b57cec5SDimitry Andric TA.Virtual.Microsoft.VtordispOffset = 29780b57cec5SDimitry Andric (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4; 29790b57cec5SDimitry Andric 29800b57cec5SDimitry Andric // A simple vtordisp thunk will suffice if the final overrider is defined 29810b57cec5SDimitry Andric // in either the most derived class or its non-virtual base. 29820b57cec5SDimitry Andric if (Overrider.Method->getParent() == MostDerivedClass || 29830b57cec5SDimitry Andric !Overrider.VirtualBase) 29840b57cec5SDimitry Andric return; 29850b57cec5SDimitry Andric 29860b57cec5SDimitry Andric // Otherwise, we need to do use the dynamic offset of the final overrider 29870b57cec5SDimitry Andric // in order to get "this" adjustment right. 29880b57cec5SDimitry Andric TA.Virtual.Microsoft.VBPtrOffset = 29890b57cec5SDimitry Andric (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset - 29900b57cec5SDimitry Andric MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); 29910b57cec5SDimitry Andric TA.Virtual.Microsoft.VBOffsetOffset = 29920b57cec5SDimitry Andric Context.getTypeSizeInChars(Context.IntTy).getQuantity() * 29930b57cec5SDimitry Andric VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase); 29940b57cec5SDimitry Andric 29950b57cec5SDimitry Andric TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity(); 29960b57cec5SDimitry Andric } 29970b57cec5SDimitry Andric 29980b57cec5SDimitry Andric static void GroupNewVirtualOverloads( 29990b57cec5SDimitry Andric const CXXRecordDecl *RD, 30000b57cec5SDimitry Andric SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) { 30010b57cec5SDimitry Andric // Put the virtual methods into VirtualMethods in the proper order: 30020b57cec5SDimitry Andric // 1) Group overloads by declaration name. New groups are added to the 30030b57cec5SDimitry Andric // vftable in the order of their first declarations in this class 30040b57cec5SDimitry Andric // (including overrides, non-virtual methods and any other named decl that 30050b57cec5SDimitry Andric // might be nested within the class). 30060b57cec5SDimitry Andric // 2) In each group, new overloads appear in the reverse order of declaration. 30070b57cec5SDimitry Andric typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup; 30080b57cec5SDimitry Andric SmallVector<MethodGroup, 10> Groups; 30090b57cec5SDimitry Andric typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy; 30100b57cec5SDimitry Andric VisitedGroupIndicesTy VisitedGroupIndices; 30110b57cec5SDimitry Andric for (const auto *D : RD->decls()) { 30120b57cec5SDimitry Andric const auto *ND = dyn_cast<NamedDecl>(D); 30130b57cec5SDimitry Andric if (!ND) 30140b57cec5SDimitry Andric continue; 30150b57cec5SDimitry Andric VisitedGroupIndicesTy::iterator J; 30160b57cec5SDimitry Andric bool Inserted; 30170b57cec5SDimitry Andric std::tie(J, Inserted) = VisitedGroupIndices.insert( 30180b57cec5SDimitry Andric std::make_pair(ND->getDeclName(), Groups.size())); 30190b57cec5SDimitry Andric if (Inserted) 30200b57cec5SDimitry Andric Groups.push_back(MethodGroup()); 30210b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) 30225ffd83dbSDimitry Andric if (MicrosoftVTableContext::hasVtableSlot(MD)) 30230b57cec5SDimitry Andric Groups[J->second].push_back(MD->getCanonicalDecl()); 30240b57cec5SDimitry Andric } 30250b57cec5SDimitry Andric 30260b57cec5SDimitry Andric for (const MethodGroup &Group : Groups) 30270b57cec5SDimitry Andric VirtualMethods.append(Group.rbegin(), Group.rend()); 30280b57cec5SDimitry Andric } 30290b57cec5SDimitry Andric 30300b57cec5SDimitry Andric static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) { 30310b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 30320b57cec5SDimitry Andric if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base) 30330b57cec5SDimitry Andric return true; 30340b57cec5SDimitry Andric } 30350b57cec5SDimitry Andric return false; 30360b57cec5SDimitry Andric } 30370b57cec5SDimitry Andric 30380b57cec5SDimitry Andric void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, 30390b57cec5SDimitry Andric const CXXRecordDecl *LastVBase, 30400b57cec5SDimitry Andric BasesSetVectorTy &VisitedBases) { 30410b57cec5SDimitry Andric const CXXRecordDecl *RD = Base.getBase(); 30420b57cec5SDimitry Andric if (!RD->isPolymorphic()) 30430b57cec5SDimitry Andric return; 30440b57cec5SDimitry Andric 30450b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 30460b57cec5SDimitry Andric 30470b57cec5SDimitry Andric // See if this class expands a vftable of the base we look at, which is either 30480b57cec5SDimitry Andric // the one defined by the vfptr base path or the primary base of the current 30490b57cec5SDimitry Andric // class. 30500b57cec5SDimitry Andric const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase; 30510b57cec5SDimitry Andric CharUnits NextBaseOffset; 30520b57cec5SDimitry Andric if (BaseDepth < WhichVFPtr.PathToIntroducingObject.size()) { 30530b57cec5SDimitry Andric NextBase = WhichVFPtr.PathToIntroducingObject[BaseDepth]; 30540b57cec5SDimitry Andric if (isDirectVBase(NextBase, RD)) { 30550b57cec5SDimitry Andric NextLastVBase = NextBase; 30560b57cec5SDimitry Andric NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase); 30570b57cec5SDimitry Andric } else { 30580b57cec5SDimitry Andric NextBaseOffset = 30590b57cec5SDimitry Andric Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase); 30600b57cec5SDimitry Andric } 30610b57cec5SDimitry Andric } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { 30620b57cec5SDimitry Andric assert(!Layout.isPrimaryBaseVirtual() && 30630b57cec5SDimitry Andric "No primary virtual bases in this ABI"); 30640b57cec5SDimitry Andric NextBase = PrimaryBase; 30650b57cec5SDimitry Andric NextBaseOffset = Base.getBaseOffset(); 30660b57cec5SDimitry Andric } 30670b57cec5SDimitry Andric 30680b57cec5SDimitry Andric if (NextBase) { 30690b57cec5SDimitry Andric AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1, 30700b57cec5SDimitry Andric NextLastVBase, VisitedBases); 30710b57cec5SDimitry Andric if (!VisitedBases.insert(NextBase)) 30720b57cec5SDimitry Andric llvm_unreachable("Found a duplicate primary base!"); 30730b57cec5SDimitry Andric } 30740b57cec5SDimitry Andric 30750b57cec5SDimitry Andric SmallVector<const CXXMethodDecl*, 10> VirtualMethods; 30760b57cec5SDimitry Andric // Put virtual methods in the proper order. 30770b57cec5SDimitry Andric GroupNewVirtualOverloads(RD, VirtualMethods); 30780b57cec5SDimitry Andric 30790b57cec5SDimitry Andric // Now go through all virtual member functions and add them to the current 30800b57cec5SDimitry Andric // vftable. This is done by 30810b57cec5SDimitry Andric // - replacing overridden methods in their existing slots, as long as they 30820b57cec5SDimitry Andric // don't require return adjustment; calculating This adjustment if needed. 30830b57cec5SDimitry Andric // - adding new slots for methods of the current base not present in any 30840b57cec5SDimitry Andric // sub-bases; 30850b57cec5SDimitry Andric // - adding new slots for methods that require Return adjustment. 30860b57cec5SDimitry Andric // We keep track of the methods visited in the sub-bases in MethodInfoMap. 30870b57cec5SDimitry Andric for (const CXXMethodDecl *MD : VirtualMethods) { 30880b57cec5SDimitry Andric FinalOverriders::OverriderInfo FinalOverrider = 30890b57cec5SDimitry Andric Overriders.getOverrider(MD, Base.getBaseOffset()); 30900b57cec5SDimitry Andric const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method; 30910b57cec5SDimitry Andric const CXXMethodDecl *OverriddenMD = 30920b57cec5SDimitry Andric FindNearestOverriddenMethod(MD, VisitedBases); 30930b57cec5SDimitry Andric 30940b57cec5SDimitry Andric ThisAdjustment ThisAdjustmentOffset; 30950b57cec5SDimitry Andric bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false; 30960b57cec5SDimitry Andric CharUnits ThisOffset = ComputeThisOffset(FinalOverrider); 30970b57cec5SDimitry Andric ThisAdjustmentOffset.NonVirtual = 30980b57cec5SDimitry Andric (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity(); 30990b57cec5SDimitry Andric if ((OverriddenMD || FinalOverriderMD != MD) && 31000b57cec5SDimitry Andric WhichVFPtr.getVBaseWithVPtr()) 31010b57cec5SDimitry Andric CalculateVtordispAdjustment(FinalOverrider, ThisOffset, 31020b57cec5SDimitry Andric ThisAdjustmentOffset); 31030b57cec5SDimitry Andric 31040b57cec5SDimitry Andric unsigned VBIndex = 31050b57cec5SDimitry Andric LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; 31060b57cec5SDimitry Andric 31070b57cec5SDimitry Andric if (OverriddenMD) { 31080b57cec5SDimitry Andric // If MD overrides anything in this vftable, we need to update the 31090b57cec5SDimitry Andric // entries. 31100b57cec5SDimitry Andric MethodInfoMapTy::iterator OverriddenMDIterator = 31110b57cec5SDimitry Andric MethodInfoMap.find(OverriddenMD); 31120b57cec5SDimitry Andric 31130b57cec5SDimitry Andric // If the overridden method went to a different vftable, skip it. 31140b57cec5SDimitry Andric if (OverriddenMDIterator == MethodInfoMap.end()) 31150b57cec5SDimitry Andric continue; 31160b57cec5SDimitry Andric 31170b57cec5SDimitry Andric MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; 31180b57cec5SDimitry Andric 31190b57cec5SDimitry Andric VBIndex = OverriddenMethodInfo.VBTableIndex; 31200b57cec5SDimitry Andric 31210b57cec5SDimitry Andric // Let's check if the overrider requires any return adjustments. 31220b57cec5SDimitry Andric // We must create a new slot if the MD's return type is not trivially 31230b57cec5SDimitry Andric // convertible to the OverriddenMD's one. 31240b57cec5SDimitry Andric // Once a chain of method overrides adds a return adjusting vftable slot, 31250b57cec5SDimitry Andric // all subsequent overrides will also use an extra method slot. 31260b57cec5SDimitry Andric ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset( 31270b57cec5SDimitry Andric Context, MD, OverriddenMD).isEmpty() || 31280b57cec5SDimitry Andric OverriddenMethodInfo.UsesExtraSlot; 31290b57cec5SDimitry Andric 31300b57cec5SDimitry Andric if (!ReturnAdjustingThunk) { 31310b57cec5SDimitry Andric // No return adjustment needed - just replace the overridden method info 31320b57cec5SDimitry Andric // with the current info. 31330b57cec5SDimitry Andric MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex); 31340b57cec5SDimitry Andric MethodInfoMap.erase(OverriddenMDIterator); 31350b57cec5SDimitry Andric 31360b57cec5SDimitry Andric assert(!MethodInfoMap.count(MD) && 31370b57cec5SDimitry Andric "Should not have method info for this method yet!"); 31380b57cec5SDimitry Andric MethodInfoMap.insert(std::make_pair(MD, MI)); 31390b57cec5SDimitry Andric continue; 31400b57cec5SDimitry Andric } 31410b57cec5SDimitry Andric 31420b57cec5SDimitry Andric // In case we need a return adjustment, we'll add a new slot for 31430b57cec5SDimitry Andric // the overrider. Mark the overridden method as shadowed by the new slot. 31440b57cec5SDimitry Andric OverriddenMethodInfo.Shadowed = true; 31450b57cec5SDimitry Andric 31460b57cec5SDimitry Andric // Force a special name mangling for a return-adjusting thunk 31470b57cec5SDimitry Andric // unless the method is the final overrider without this adjustment. 31480b57cec5SDimitry Andric ForceReturnAdjustmentMangling = 31490b57cec5SDimitry Andric !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty()); 31500b57cec5SDimitry Andric } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC || 31510b57cec5SDimitry Andric MD->size_overridden_methods()) { 31520b57cec5SDimitry Andric // Skip methods that don't belong to the vftable of the current class, 31530b57cec5SDimitry Andric // e.g. each method that wasn't seen in any of the visited sub-bases 31540b57cec5SDimitry Andric // but overrides multiple methods of other sub-bases. 31550b57cec5SDimitry Andric continue; 31560b57cec5SDimitry Andric } 31570b57cec5SDimitry Andric 31580b57cec5SDimitry Andric // If we got here, MD is a method not seen in any of the sub-bases or 31590b57cec5SDimitry Andric // it requires return adjustment. Insert the method info for this method. 31600b57cec5SDimitry Andric MethodInfo MI(VBIndex, 31610b57cec5SDimitry Andric HasRTTIComponent ? Components.size() - 1 : Components.size(), 31620b57cec5SDimitry Andric ReturnAdjustingThunk); 31630b57cec5SDimitry Andric 31640b57cec5SDimitry Andric assert(!MethodInfoMap.count(MD) && 31650b57cec5SDimitry Andric "Should not have method info for this method yet!"); 31660b57cec5SDimitry Andric MethodInfoMap.insert(std::make_pair(MD, MI)); 31670b57cec5SDimitry Andric 31680b57cec5SDimitry Andric // Check if this overrider needs a return adjustment. 31690b57cec5SDimitry Andric // We don't want to do this for pure virtual member functions. 31700b57cec5SDimitry Andric BaseOffset ReturnAdjustmentOffset; 31710b57cec5SDimitry Andric ReturnAdjustment ReturnAdjustment; 31727a6dacacSDimitry Andric if (!FinalOverriderMD->isPureVirtual()) { 31730b57cec5SDimitry Andric ReturnAdjustmentOffset = 31740b57cec5SDimitry Andric ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD); 31750b57cec5SDimitry Andric } 31760b57cec5SDimitry Andric if (!ReturnAdjustmentOffset.isEmpty()) { 31770b57cec5SDimitry Andric ForceReturnAdjustmentMangling = true; 31780b57cec5SDimitry Andric ReturnAdjustment.NonVirtual = 31790b57cec5SDimitry Andric ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); 31800b57cec5SDimitry Andric if (ReturnAdjustmentOffset.VirtualBase) { 31810b57cec5SDimitry Andric const ASTRecordLayout &DerivedLayout = 31820b57cec5SDimitry Andric Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass); 31830b57cec5SDimitry Andric ReturnAdjustment.Virtual.Microsoft.VBPtrOffset = 31840b57cec5SDimitry Andric DerivedLayout.getVBPtrOffset().getQuantity(); 31850b57cec5SDimitry Andric ReturnAdjustment.Virtual.Microsoft.VBIndex = 31860b57cec5SDimitry Andric VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass, 31870b57cec5SDimitry Andric ReturnAdjustmentOffset.VirtualBase); 31880b57cec5SDimitry Andric } 31890b57cec5SDimitry Andric } 3190*0fca6ea1SDimitry Andric auto ThisType = (OverriddenMD ? OverriddenMD : MD)->getThisType().getTypePtr(); 31910b57cec5SDimitry Andric AddMethod(FinalOverriderMD, 3192*0fca6ea1SDimitry Andric ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, ThisType, 31930b57cec5SDimitry Andric ForceReturnAdjustmentMangling ? MD : nullptr)); 31940b57cec5SDimitry Andric } 31950b57cec5SDimitry Andric } 31960b57cec5SDimitry Andric 31970b57cec5SDimitry Andric static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out) { 3198349cc55cSDimitry Andric for (const CXXRecordDecl *Elem : llvm::reverse(Path)) { 31990b57cec5SDimitry Andric Out << "'"; 32000b57cec5SDimitry Andric Elem->printQualifiedName(Out); 32010b57cec5SDimitry Andric Out << "' in "; 32020b57cec5SDimitry Andric } 32030b57cec5SDimitry Andric } 32040b57cec5SDimitry Andric 32050b57cec5SDimitry Andric static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, 32060b57cec5SDimitry Andric bool ContinueFirstLine) { 32070b57cec5SDimitry Andric const ReturnAdjustment &R = TI.Return; 32080b57cec5SDimitry Andric bool Multiline = false; 32090b57cec5SDimitry Andric const char *LinePrefix = "\n "; 32100b57cec5SDimitry Andric if (!R.isEmpty() || TI.Method) { 32110b57cec5SDimitry Andric if (!ContinueFirstLine) 32120b57cec5SDimitry Andric Out << LinePrefix; 32130b57cec5SDimitry Andric Out << "[return adjustment (to type '" 321481ad6265SDimitry Andric << TI.Method->getReturnType().getCanonicalType() << "'): "; 32150b57cec5SDimitry Andric if (R.Virtual.Microsoft.VBPtrOffset) 32160b57cec5SDimitry Andric Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", "; 32170b57cec5SDimitry Andric if (R.Virtual.Microsoft.VBIndex) 32180b57cec5SDimitry Andric Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", "; 32190b57cec5SDimitry Andric Out << R.NonVirtual << " non-virtual]"; 32200b57cec5SDimitry Andric Multiline = true; 32210b57cec5SDimitry Andric } 32220b57cec5SDimitry Andric 32230b57cec5SDimitry Andric const ThisAdjustment &T = TI.This; 32240b57cec5SDimitry Andric if (!T.isEmpty()) { 32250b57cec5SDimitry Andric if (Multiline || !ContinueFirstLine) 32260b57cec5SDimitry Andric Out << LinePrefix; 32270b57cec5SDimitry Andric Out << "[this adjustment: "; 32280b57cec5SDimitry Andric if (!TI.This.Virtual.isEmpty()) { 32290b57cec5SDimitry Andric assert(T.Virtual.Microsoft.VtordispOffset < 0); 32300b57cec5SDimitry Andric Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", "; 32310b57cec5SDimitry Andric if (T.Virtual.Microsoft.VBPtrOffset) { 32320b57cec5SDimitry Andric Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset 32330b57cec5SDimitry Andric << " to the left,"; 32340b57cec5SDimitry Andric assert(T.Virtual.Microsoft.VBOffsetOffset > 0); 32350b57cec5SDimitry Andric Out << LinePrefix << " vboffset at " 32360b57cec5SDimitry Andric << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, "; 32370b57cec5SDimitry Andric } 32380b57cec5SDimitry Andric } 32390b57cec5SDimitry Andric Out << T.NonVirtual << " non-virtual]"; 32400b57cec5SDimitry Andric } 32410b57cec5SDimitry Andric } 32420b57cec5SDimitry Andric 32430b57cec5SDimitry Andric void VFTableBuilder::dumpLayout(raw_ostream &Out) { 32440b57cec5SDimitry Andric Out << "VFTable for "; 32450b57cec5SDimitry Andric PrintBasePath(WhichVFPtr.PathToIntroducingObject, Out); 32460b57cec5SDimitry Andric Out << "'"; 32470b57cec5SDimitry Andric MostDerivedClass->printQualifiedName(Out); 32480b57cec5SDimitry Andric Out << "' (" << Components.size() 32490b57cec5SDimitry Andric << (Components.size() == 1 ? " entry" : " entries") << ").\n"; 32500b57cec5SDimitry Andric 32510b57cec5SDimitry Andric for (unsigned I = 0, E = Components.size(); I != E; ++I) { 32520b57cec5SDimitry Andric Out << llvm::format("%4d | ", I); 32530b57cec5SDimitry Andric 32540b57cec5SDimitry Andric const VTableComponent &Component = Components[I]; 32550b57cec5SDimitry Andric 32560b57cec5SDimitry Andric // Dump the component. 32570b57cec5SDimitry Andric switch (Component.getKind()) { 32580b57cec5SDimitry Andric case VTableComponent::CK_RTTI: 32590b57cec5SDimitry Andric Component.getRTTIDecl()->printQualifiedName(Out); 32600b57cec5SDimitry Andric Out << " RTTI"; 32610b57cec5SDimitry Andric break; 32620b57cec5SDimitry Andric 32630b57cec5SDimitry Andric case VTableComponent::CK_FunctionPointer: { 32640b57cec5SDimitry Andric const CXXMethodDecl *MD = Component.getFunctionDecl(); 32650b57cec5SDimitry Andric 32660b57cec5SDimitry Andric // FIXME: Figure out how to print the real thunk type, since they can 32670b57cec5SDimitry Andric // differ in the return type. 32680b57cec5SDimitry Andric std::string Str = PredefinedExpr::ComputeName( 32695f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 32700b57cec5SDimitry Andric Out << Str; 32717a6dacacSDimitry Andric if (MD->isPureVirtual()) 32720b57cec5SDimitry Andric Out << " [pure]"; 32730b57cec5SDimitry Andric 32740b57cec5SDimitry Andric if (MD->isDeleted()) 32750b57cec5SDimitry Andric Out << " [deleted]"; 32760b57cec5SDimitry Andric 32770b57cec5SDimitry Andric ThunkInfo Thunk = VTableThunks.lookup(I); 32780b57cec5SDimitry Andric if (!Thunk.isEmpty()) 32790b57cec5SDimitry Andric dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); 32800b57cec5SDimitry Andric 32810b57cec5SDimitry Andric break; 32820b57cec5SDimitry Andric } 32830b57cec5SDimitry Andric 32840b57cec5SDimitry Andric case VTableComponent::CK_DeletingDtorPointer: { 32850b57cec5SDimitry Andric const CXXDestructorDecl *DD = Component.getDestructorDecl(); 32860b57cec5SDimitry Andric 32870b57cec5SDimitry Andric DD->printQualifiedName(Out); 32880b57cec5SDimitry Andric Out << "() [scalar deleting]"; 32890b57cec5SDimitry Andric 32907a6dacacSDimitry Andric if (DD->isPureVirtual()) 32910b57cec5SDimitry Andric Out << " [pure]"; 32920b57cec5SDimitry Andric 32930b57cec5SDimitry Andric ThunkInfo Thunk = VTableThunks.lookup(I); 32940b57cec5SDimitry Andric if (!Thunk.isEmpty()) { 32950b57cec5SDimitry Andric assert(Thunk.Return.isEmpty() && 32960b57cec5SDimitry Andric "No return adjustment needed for destructors!"); 32970b57cec5SDimitry Andric dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); 32980b57cec5SDimitry Andric } 32990b57cec5SDimitry Andric 33000b57cec5SDimitry Andric break; 33010b57cec5SDimitry Andric } 33020b57cec5SDimitry Andric 33030b57cec5SDimitry Andric default: 33040b57cec5SDimitry Andric DiagnosticsEngine &Diags = Context.getDiagnostics(); 33050b57cec5SDimitry Andric unsigned DiagID = Diags.getCustomDiagID( 33060b57cec5SDimitry Andric DiagnosticsEngine::Error, 33070b57cec5SDimitry Andric "Unexpected vftable component type %0 for component number %1"); 33080b57cec5SDimitry Andric Diags.Report(MostDerivedClass->getLocation(), DiagID) 33090b57cec5SDimitry Andric << I << Component.getKind(); 33100b57cec5SDimitry Andric } 33110b57cec5SDimitry Andric 33120b57cec5SDimitry Andric Out << '\n'; 33130b57cec5SDimitry Andric } 33140b57cec5SDimitry Andric 33150b57cec5SDimitry Andric Out << '\n'; 33160b57cec5SDimitry Andric 33170b57cec5SDimitry Andric if (!Thunks.empty()) { 33180b57cec5SDimitry Andric // We store the method names in a map to get a stable order. 33190b57cec5SDimitry Andric std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; 33200b57cec5SDimitry Andric 33210b57cec5SDimitry Andric for (const auto &I : Thunks) { 33220b57cec5SDimitry Andric const CXXMethodDecl *MD = I.first; 33230b57cec5SDimitry Andric std::string MethodName = PredefinedExpr::ComputeName( 33245f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 33250b57cec5SDimitry Andric 33260b57cec5SDimitry Andric MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); 33270b57cec5SDimitry Andric } 33280b57cec5SDimitry Andric 33290b57cec5SDimitry Andric for (const auto &MethodNameAndDecl : MethodNamesAndDecls) { 33300b57cec5SDimitry Andric const std::string &MethodName = MethodNameAndDecl.first; 33310b57cec5SDimitry Andric const CXXMethodDecl *MD = MethodNameAndDecl.second; 33320b57cec5SDimitry Andric 33330b57cec5SDimitry Andric ThunkInfoVectorTy ThunksVector = Thunks[MD]; 33340b57cec5SDimitry Andric llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS, 33350b57cec5SDimitry Andric const ThunkInfo &RHS) { 33360b57cec5SDimitry Andric // Keep different thunks with the same adjustments in the order they 33370b57cec5SDimitry Andric // were put into the vector. 33380b57cec5SDimitry Andric return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); 33390b57cec5SDimitry Andric }); 33400b57cec5SDimitry Andric 33410b57cec5SDimitry Andric Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); 33420b57cec5SDimitry Andric Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; 33430b57cec5SDimitry Andric 33440b57cec5SDimitry Andric for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { 33450b57cec5SDimitry Andric const ThunkInfo &Thunk = ThunksVector[I]; 33460b57cec5SDimitry Andric 33470b57cec5SDimitry Andric Out << llvm::format("%4d | ", I); 33480b57cec5SDimitry Andric dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true); 33490b57cec5SDimitry Andric Out << '\n'; 33500b57cec5SDimitry Andric } 33510b57cec5SDimitry Andric 33520b57cec5SDimitry Andric Out << '\n'; 33530b57cec5SDimitry Andric } 33540b57cec5SDimitry Andric } 33550b57cec5SDimitry Andric 33560b57cec5SDimitry Andric Out.flush(); 33570b57cec5SDimitry Andric } 33580b57cec5SDimitry Andric 33590b57cec5SDimitry Andric static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A, 33600b57cec5SDimitry Andric ArrayRef<const CXXRecordDecl *> B) { 33610b57cec5SDimitry Andric for (const CXXRecordDecl *Decl : B) { 33620b57cec5SDimitry Andric if (A.count(Decl)) 33630b57cec5SDimitry Andric return true; 33640b57cec5SDimitry Andric } 33650b57cec5SDimitry Andric return false; 33660b57cec5SDimitry Andric } 33670b57cec5SDimitry Andric 33680b57cec5SDimitry Andric static bool rebucketPaths(VPtrInfoVector &Paths); 33690b57cec5SDimitry Andric 33700b57cec5SDimitry Andric /// Produces MSVC-compatible vbtable data. The symbols produced by this 33710b57cec5SDimitry Andric /// algorithm match those produced by MSVC 2012 and newer, which is different 33720b57cec5SDimitry Andric /// from MSVC 2010. 33730b57cec5SDimitry Andric /// 33740b57cec5SDimitry Andric /// MSVC 2012 appears to minimize the vbtable names using the following 33750b57cec5SDimitry Andric /// algorithm. First, walk the class hierarchy in the usual order, depth first, 33760b57cec5SDimitry Andric /// left to right, to find all of the subobjects which contain a vbptr field. 33770b57cec5SDimitry Andric /// Visiting each class node yields a list of inheritance paths to vbptrs. Each 33780b57cec5SDimitry Andric /// record with a vbptr creates an initially empty path. 33790b57cec5SDimitry Andric /// 33800b57cec5SDimitry Andric /// To combine paths from child nodes, the paths are compared to check for 33810b57cec5SDimitry Andric /// ambiguity. Paths are "ambiguous" if multiple paths have the same set of 33820b57cec5SDimitry Andric /// components in the same order. Each group of ambiguous paths is extended by 33830b57cec5SDimitry Andric /// appending the class of the base from which it came. If the current class 33840b57cec5SDimitry Andric /// node produced an ambiguous path, its path is extended with the current class. 33850b57cec5SDimitry Andric /// After extending paths, MSVC again checks for ambiguity, and extends any 33860b57cec5SDimitry Andric /// ambiguous path which wasn't already extended. Because each node yields an 33870b57cec5SDimitry Andric /// unambiguous set of paths, MSVC doesn't need to extend any path more than once 33880b57cec5SDimitry Andric /// to produce an unambiguous set of paths. 33890b57cec5SDimitry Andric /// 33900b57cec5SDimitry Andric /// TODO: Presumably vftables use the same algorithm. 33910b57cec5SDimitry Andric void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables, 33920b57cec5SDimitry Andric const CXXRecordDecl *RD, 33930b57cec5SDimitry Andric VPtrInfoVector &Paths) { 33940b57cec5SDimitry Andric assert(Paths.empty()); 33950b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 33960b57cec5SDimitry Andric 33970b57cec5SDimitry Andric // Base case: this subobject has its own vptr. 33980b57cec5SDimitry Andric if (ForVBTables ? Layout.hasOwnVBPtr() : Layout.hasOwnVFPtr()) 3399a7dea167SDimitry Andric Paths.push_back(std::make_unique<VPtrInfo>(RD)); 34000b57cec5SDimitry Andric 34010b57cec5SDimitry Andric // Recursive case: get all the vbtables from our bases and remove anything 34020b57cec5SDimitry Andric // that shares a virtual base. 34030b57cec5SDimitry Andric llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen; 34040b57cec5SDimitry Andric for (const auto &B : RD->bases()) { 34050b57cec5SDimitry Andric const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); 34060b57cec5SDimitry Andric if (B.isVirtual() && VBasesSeen.count(Base)) 34070b57cec5SDimitry Andric continue; 34080b57cec5SDimitry Andric 34090b57cec5SDimitry Andric if (!Base->isDynamicClass()) 34100b57cec5SDimitry Andric continue; 34110b57cec5SDimitry Andric 34120b57cec5SDimitry Andric const VPtrInfoVector &BasePaths = 34130b57cec5SDimitry Andric ForVBTables ? enumerateVBTables(Base) : getVFPtrOffsets(Base); 34140b57cec5SDimitry Andric 34150b57cec5SDimitry Andric for (const std::unique_ptr<VPtrInfo> &BaseInfo : BasePaths) { 34160b57cec5SDimitry Andric // Don't include the path if it goes through a virtual base that we've 34170b57cec5SDimitry Andric // already included. 34180b57cec5SDimitry Andric if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases)) 34190b57cec5SDimitry Andric continue; 34200b57cec5SDimitry Andric 34210b57cec5SDimitry Andric // Copy the path and adjust it as necessary. 3422a7dea167SDimitry Andric auto P = std::make_unique<VPtrInfo>(*BaseInfo); 34230b57cec5SDimitry Andric 34240b57cec5SDimitry Andric // We mangle Base into the path if the path would've been ambiguous and it 34250b57cec5SDimitry Andric // wasn't already extended with Base. 34260b57cec5SDimitry Andric if (P->MangledPath.empty() || P->MangledPath.back() != Base) 34270b57cec5SDimitry Andric P->NextBaseToMangle = Base; 34280b57cec5SDimitry Andric 34290b57cec5SDimitry Andric // Keep track of which vtable the derived class is going to extend with 34300b57cec5SDimitry Andric // new methods or bases. We append to either the vftable of our primary 34310b57cec5SDimitry Andric // base, or the first non-virtual base that has a vbtable. 34320b57cec5SDimitry Andric if (P->ObjectWithVPtr == Base && 34330b57cec5SDimitry Andric Base == (ForVBTables ? Layout.getBaseSharingVBPtr() 34340b57cec5SDimitry Andric : Layout.getPrimaryBase())) 34350b57cec5SDimitry Andric P->ObjectWithVPtr = RD; 34360b57cec5SDimitry Andric 34370b57cec5SDimitry Andric // Keep track of the full adjustment from the MDC to this vtable. The 34380b57cec5SDimitry Andric // adjustment is captured by an optional vbase and a non-virtual offset. 34390b57cec5SDimitry Andric if (B.isVirtual()) 34400b57cec5SDimitry Andric P->ContainingVBases.push_back(Base); 34410b57cec5SDimitry Andric else if (P->ContainingVBases.empty()) 34420b57cec5SDimitry Andric P->NonVirtualOffset += Layout.getBaseClassOffset(Base); 34430b57cec5SDimitry Andric 34440b57cec5SDimitry Andric // Update the full offset in the MDC. 34450b57cec5SDimitry Andric P->FullOffsetInMDC = P->NonVirtualOffset; 34460b57cec5SDimitry Andric if (const CXXRecordDecl *VB = P->getVBaseWithVPtr()) 34470b57cec5SDimitry Andric P->FullOffsetInMDC += Layout.getVBaseClassOffset(VB); 34480b57cec5SDimitry Andric 34490b57cec5SDimitry Andric Paths.push_back(std::move(P)); 34500b57cec5SDimitry Andric } 34510b57cec5SDimitry Andric 34520b57cec5SDimitry Andric if (B.isVirtual()) 34530b57cec5SDimitry Andric VBasesSeen.insert(Base); 34540b57cec5SDimitry Andric 34550b57cec5SDimitry Andric // After visiting any direct base, we've transitively visited all of its 34560b57cec5SDimitry Andric // morally virtual bases. 34570b57cec5SDimitry Andric for (const auto &VB : Base->vbases()) 34580b57cec5SDimitry Andric VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl()); 34590b57cec5SDimitry Andric } 34600b57cec5SDimitry Andric 34610b57cec5SDimitry Andric // Sort the paths into buckets, and if any of them are ambiguous, extend all 34620b57cec5SDimitry Andric // paths in ambiguous buckets. 34630b57cec5SDimitry Andric bool Changed = true; 34640b57cec5SDimitry Andric while (Changed) 34650b57cec5SDimitry Andric Changed = rebucketPaths(Paths); 34660b57cec5SDimitry Andric } 34670b57cec5SDimitry Andric 34680b57cec5SDimitry Andric static bool extendPath(VPtrInfo &P) { 34690b57cec5SDimitry Andric if (P.NextBaseToMangle) { 34700b57cec5SDimitry Andric P.MangledPath.push_back(P.NextBaseToMangle); 34710b57cec5SDimitry Andric P.NextBaseToMangle = nullptr;// Prevent the path from being extended twice. 34720b57cec5SDimitry Andric return true; 34730b57cec5SDimitry Andric } 34740b57cec5SDimitry Andric return false; 34750b57cec5SDimitry Andric } 34760b57cec5SDimitry Andric 34770b57cec5SDimitry Andric static bool rebucketPaths(VPtrInfoVector &Paths) { 34780b57cec5SDimitry Andric // What we're essentially doing here is bucketing together ambiguous paths. 34790b57cec5SDimitry Andric // Any bucket with more than one path in it gets extended by NextBase, which 34800b57cec5SDimitry Andric // is usually the direct base of the inherited the vbptr. This code uses a 34810b57cec5SDimitry Andric // sorted vector to implement a multiset to form the buckets. Note that the 34820b57cec5SDimitry Andric // ordering is based on pointers, but it doesn't change our output order. The 34830b57cec5SDimitry Andric // current algorithm is designed to match MSVC 2012's names. 348481ad6265SDimitry Andric llvm::SmallVector<std::reference_wrapper<VPtrInfo>, 2> PathsSorted( 348581ad6265SDimitry Andric llvm::make_pointee_range(Paths)); 34860b57cec5SDimitry Andric llvm::sort(PathsSorted, [](const VPtrInfo &LHS, const VPtrInfo &RHS) { 34870b57cec5SDimitry Andric return LHS.MangledPath < RHS.MangledPath; 34880b57cec5SDimitry Andric }); 34890b57cec5SDimitry Andric bool Changed = false; 34900b57cec5SDimitry Andric for (size_t I = 0, E = PathsSorted.size(); I != E;) { 34910b57cec5SDimitry Andric // Scan forward to find the end of the bucket. 34920b57cec5SDimitry Andric size_t BucketStart = I; 34930b57cec5SDimitry Andric do { 34940b57cec5SDimitry Andric ++I; 34950b57cec5SDimitry Andric } while (I != E && 34960b57cec5SDimitry Andric PathsSorted[BucketStart].get().MangledPath == 34970b57cec5SDimitry Andric PathsSorted[I].get().MangledPath); 34980b57cec5SDimitry Andric 34990b57cec5SDimitry Andric // If this bucket has multiple paths, extend them all. 35000b57cec5SDimitry Andric if (I - BucketStart > 1) { 35010b57cec5SDimitry Andric for (size_t II = BucketStart; II != I; ++II) 35020b57cec5SDimitry Andric Changed |= extendPath(PathsSorted[II]); 35030b57cec5SDimitry Andric assert(Changed && "no paths were extended to fix ambiguity"); 35040b57cec5SDimitry Andric } 35050b57cec5SDimitry Andric } 35060b57cec5SDimitry Andric return Changed; 35070b57cec5SDimitry Andric } 35080b57cec5SDimitry Andric 35090b57cec5SDimitry Andric MicrosoftVTableContext::~MicrosoftVTableContext() {} 35100b57cec5SDimitry Andric 35110b57cec5SDimitry Andric namespace { 35120b57cec5SDimitry Andric typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>, 35130b57cec5SDimitry Andric llvm::DenseSet<BaseSubobject>> FullPathTy; 35140b57cec5SDimitry Andric } 35150b57cec5SDimitry Andric 35160b57cec5SDimitry Andric // This recursive function finds all paths from a subobject centered at 35170b57cec5SDimitry Andric // (RD, Offset) to the subobject located at IntroducingObject. 35180b57cec5SDimitry Andric static void findPathsToSubobject(ASTContext &Context, 35190b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedLayout, 35200b57cec5SDimitry Andric const CXXRecordDecl *RD, CharUnits Offset, 35210b57cec5SDimitry Andric BaseSubobject IntroducingObject, 35220b57cec5SDimitry Andric FullPathTy &FullPath, 35230b57cec5SDimitry Andric std::list<FullPathTy> &Paths) { 35240b57cec5SDimitry Andric if (BaseSubobject(RD, Offset) == IntroducingObject) { 35250b57cec5SDimitry Andric Paths.push_back(FullPath); 35260b57cec5SDimitry Andric return; 35270b57cec5SDimitry Andric } 35280b57cec5SDimitry Andric 35290b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 35300b57cec5SDimitry Andric 35310b57cec5SDimitry Andric for (const CXXBaseSpecifier &BS : RD->bases()) { 35320b57cec5SDimitry Andric const CXXRecordDecl *Base = BS.getType()->getAsCXXRecordDecl(); 35330b57cec5SDimitry Andric CharUnits NewOffset = BS.isVirtual() 35340b57cec5SDimitry Andric ? MostDerivedLayout.getVBaseClassOffset(Base) 35350b57cec5SDimitry Andric : Offset + Layout.getBaseClassOffset(Base); 35360b57cec5SDimitry Andric FullPath.insert(BaseSubobject(Base, NewOffset)); 35370b57cec5SDimitry Andric findPathsToSubobject(Context, MostDerivedLayout, Base, NewOffset, 35380b57cec5SDimitry Andric IntroducingObject, FullPath, Paths); 35390b57cec5SDimitry Andric FullPath.pop_back(); 35400b57cec5SDimitry Andric } 35410b57cec5SDimitry Andric } 35420b57cec5SDimitry Andric 35430b57cec5SDimitry Andric // Return the paths which are not subsets of other paths. 35440b57cec5SDimitry Andric static void removeRedundantPaths(std::list<FullPathTy> &FullPaths) { 35450b57cec5SDimitry Andric FullPaths.remove_if([&](const FullPathTy &SpecificPath) { 35460b57cec5SDimitry Andric for (const FullPathTy &OtherPath : FullPaths) { 35470b57cec5SDimitry Andric if (&SpecificPath == &OtherPath) 35480b57cec5SDimitry Andric continue; 35490b57cec5SDimitry Andric if (llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) { 3550349cc55cSDimitry Andric return OtherPath.contains(BSO); 35510b57cec5SDimitry Andric })) { 35520b57cec5SDimitry Andric return true; 35530b57cec5SDimitry Andric } 35540b57cec5SDimitry Andric } 35550b57cec5SDimitry Andric return false; 35560b57cec5SDimitry Andric }); 35570b57cec5SDimitry Andric } 35580b57cec5SDimitry Andric 35590b57cec5SDimitry Andric static CharUnits getOffsetOfFullPath(ASTContext &Context, 35600b57cec5SDimitry Andric const CXXRecordDecl *RD, 35610b57cec5SDimitry Andric const FullPathTy &FullPath) { 35620b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedLayout = 35630b57cec5SDimitry Andric Context.getASTRecordLayout(RD); 35640b57cec5SDimitry Andric CharUnits Offset = CharUnits::fromQuantity(-1); 35650b57cec5SDimitry Andric for (const BaseSubobject &BSO : FullPath) { 35660b57cec5SDimitry Andric const CXXRecordDecl *Base = BSO.getBase(); 35670b57cec5SDimitry Andric // The first entry in the path is always the most derived record, skip it. 35680b57cec5SDimitry Andric if (Base == RD) { 35690b57cec5SDimitry Andric assert(Offset.getQuantity() == -1); 35700b57cec5SDimitry Andric Offset = CharUnits::Zero(); 35710b57cec5SDimitry Andric continue; 35720b57cec5SDimitry Andric } 35730b57cec5SDimitry Andric assert(Offset.getQuantity() != -1); 35740b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 35750b57cec5SDimitry Andric // While we know which base has to be traversed, we don't know if that base 35760b57cec5SDimitry Andric // was a virtual base. 35770b57cec5SDimitry Andric const CXXBaseSpecifier *BaseBS = std::find_if( 35780b57cec5SDimitry Andric RD->bases_begin(), RD->bases_end(), [&](const CXXBaseSpecifier &BS) { 35790b57cec5SDimitry Andric return BS.getType()->getAsCXXRecordDecl() == Base; 35800b57cec5SDimitry Andric }); 35810b57cec5SDimitry Andric Offset = BaseBS->isVirtual() ? MostDerivedLayout.getVBaseClassOffset(Base) 35820b57cec5SDimitry Andric : Offset + Layout.getBaseClassOffset(Base); 35830b57cec5SDimitry Andric RD = Base; 35840b57cec5SDimitry Andric } 35850b57cec5SDimitry Andric return Offset; 35860b57cec5SDimitry Andric } 35870b57cec5SDimitry Andric 35880b57cec5SDimitry Andric // We want to select the path which introduces the most covariant overrides. If 35890b57cec5SDimitry Andric // two paths introduce overrides which the other path doesn't contain, issue a 35900b57cec5SDimitry Andric // diagnostic. 35910b57cec5SDimitry Andric static const FullPathTy *selectBestPath(ASTContext &Context, 35920b57cec5SDimitry Andric const CXXRecordDecl *RD, 35930b57cec5SDimitry Andric const VPtrInfo &Info, 35940b57cec5SDimitry Andric std::list<FullPathTy> &FullPaths) { 35950b57cec5SDimitry Andric // Handle some easy cases first. 35960b57cec5SDimitry Andric if (FullPaths.empty()) 35970b57cec5SDimitry Andric return nullptr; 35980b57cec5SDimitry Andric if (FullPaths.size() == 1) 35990b57cec5SDimitry Andric return &FullPaths.front(); 36000b57cec5SDimitry Andric 36010b57cec5SDimitry Andric const FullPathTy *BestPath = nullptr; 36020b57cec5SDimitry Andric typedef std::set<const CXXMethodDecl *> OverriderSetTy; 36030b57cec5SDimitry Andric OverriderSetTy LastOverrides; 36040b57cec5SDimitry Andric for (const FullPathTy &SpecificPath : FullPaths) { 36050b57cec5SDimitry Andric assert(!SpecificPath.empty()); 36060b57cec5SDimitry Andric OverriderSetTy CurrentOverrides; 36070b57cec5SDimitry Andric const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase(); 36080b57cec5SDimitry Andric // Find the distance from the start of the path to the subobject with the 36090b57cec5SDimitry Andric // VPtr. 36100b57cec5SDimitry Andric CharUnits BaseOffset = 36110b57cec5SDimitry Andric getOffsetOfFullPath(Context, TopLevelRD, SpecificPath); 36120b57cec5SDimitry Andric FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD); 36130b57cec5SDimitry Andric for (const CXXMethodDecl *MD : Info.IntroducingObject->methods()) { 36145ffd83dbSDimitry Andric if (!MicrosoftVTableContext::hasVtableSlot(MD)) 36150b57cec5SDimitry Andric continue; 36160b57cec5SDimitry Andric FinalOverriders::OverriderInfo OI = 36170b57cec5SDimitry Andric Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset); 36180b57cec5SDimitry Andric const CXXMethodDecl *OverridingMethod = OI.Method; 36190b57cec5SDimitry Andric // Only overriders which have a return adjustment introduce problematic 36200b57cec5SDimitry Andric // thunks. 36210b57cec5SDimitry Andric if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD) 36220b57cec5SDimitry Andric .isEmpty()) 36230b57cec5SDimitry Andric continue; 36240b57cec5SDimitry Andric // It's possible that the overrider isn't in this path. If so, skip it 36250b57cec5SDimitry Andric // because this path didn't introduce it. 36260b57cec5SDimitry Andric const CXXRecordDecl *OverridingParent = OverridingMethod->getParent(); 36270b57cec5SDimitry Andric if (llvm::none_of(SpecificPath, [&](const BaseSubobject &BSO) { 36280b57cec5SDimitry Andric return BSO.getBase() == OverridingParent; 36290b57cec5SDimitry Andric })) 36300b57cec5SDimitry Andric continue; 36310b57cec5SDimitry Andric CurrentOverrides.insert(OverridingMethod); 36320b57cec5SDimitry Andric } 36330b57cec5SDimitry Andric OverriderSetTy NewOverrides = 36340b57cec5SDimitry Andric llvm::set_difference(CurrentOverrides, LastOverrides); 36350b57cec5SDimitry Andric if (NewOverrides.empty()) 36360b57cec5SDimitry Andric continue; 36370b57cec5SDimitry Andric OverriderSetTy MissingOverrides = 36380b57cec5SDimitry Andric llvm::set_difference(LastOverrides, CurrentOverrides); 36390b57cec5SDimitry Andric if (MissingOverrides.empty()) { 36400b57cec5SDimitry Andric // This path is a strict improvement over the last path, let's use it. 36410b57cec5SDimitry Andric BestPath = &SpecificPath; 36420b57cec5SDimitry Andric std::swap(CurrentOverrides, LastOverrides); 36430b57cec5SDimitry Andric } else { 36440b57cec5SDimitry Andric // This path introduces an overrider with a conflicting covariant thunk. 36450b57cec5SDimitry Andric DiagnosticsEngine &Diags = Context.getDiagnostics(); 36460b57cec5SDimitry Andric const CXXMethodDecl *CovariantMD = *NewOverrides.begin(); 36470b57cec5SDimitry Andric const CXXMethodDecl *ConflictMD = *MissingOverrides.begin(); 36480b57cec5SDimitry Andric Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component) 36490b57cec5SDimitry Andric << RD; 36500b57cec5SDimitry Andric Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk) 36510b57cec5SDimitry Andric << CovariantMD; 36520b57cec5SDimitry Andric Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk) 36530b57cec5SDimitry Andric << ConflictMD; 36540b57cec5SDimitry Andric } 36550b57cec5SDimitry Andric } 36560b57cec5SDimitry Andric // Go with the path that introduced the most covariant overrides. If there is 36570b57cec5SDimitry Andric // no such path, pick the first path. 36580b57cec5SDimitry Andric return BestPath ? BestPath : &FullPaths.front(); 36590b57cec5SDimitry Andric } 36600b57cec5SDimitry Andric 36610b57cec5SDimitry Andric static void computeFullPathsForVFTables(ASTContext &Context, 36620b57cec5SDimitry Andric const CXXRecordDecl *RD, 36630b57cec5SDimitry Andric VPtrInfoVector &Paths) { 36640b57cec5SDimitry Andric const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD); 36650b57cec5SDimitry Andric FullPathTy FullPath; 36660b57cec5SDimitry Andric std::list<FullPathTy> FullPaths; 36670b57cec5SDimitry Andric for (const std::unique_ptr<VPtrInfo>& Info : Paths) { 36680b57cec5SDimitry Andric findPathsToSubobject( 36690b57cec5SDimitry Andric Context, MostDerivedLayout, RD, CharUnits::Zero(), 36700b57cec5SDimitry Andric BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath, 36710b57cec5SDimitry Andric FullPaths); 36720b57cec5SDimitry Andric FullPath.clear(); 36730b57cec5SDimitry Andric removeRedundantPaths(FullPaths); 36740b57cec5SDimitry Andric Info->PathToIntroducingObject.clear(); 36750b57cec5SDimitry Andric if (const FullPathTy *BestPath = 36760b57cec5SDimitry Andric selectBestPath(Context, RD, *Info, FullPaths)) 36770b57cec5SDimitry Andric for (const BaseSubobject &BSO : *BestPath) 36780b57cec5SDimitry Andric Info->PathToIntroducingObject.push_back(BSO.getBase()); 36790b57cec5SDimitry Andric FullPaths.clear(); 36800b57cec5SDimitry Andric } 36810b57cec5SDimitry Andric } 36820b57cec5SDimitry Andric 36830b57cec5SDimitry Andric static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, 36840b57cec5SDimitry Andric const MethodVFTableLocation &LHS, 36850b57cec5SDimitry Andric const MethodVFTableLocation &RHS) { 36860b57cec5SDimitry Andric CharUnits L = LHS.VFPtrOffset; 36870b57cec5SDimitry Andric CharUnits R = RHS.VFPtrOffset; 36880b57cec5SDimitry Andric if (LHS.VBase) 36890b57cec5SDimitry Andric L += Layout.getVBaseClassOffset(LHS.VBase); 36900b57cec5SDimitry Andric if (RHS.VBase) 36910b57cec5SDimitry Andric R += Layout.getVBaseClassOffset(RHS.VBase); 36920b57cec5SDimitry Andric return L < R; 36930b57cec5SDimitry Andric } 36940b57cec5SDimitry Andric 36950b57cec5SDimitry Andric void MicrosoftVTableContext::computeVTableRelatedInformation( 36960b57cec5SDimitry Andric const CXXRecordDecl *RD) { 36970b57cec5SDimitry Andric assert(RD->isDynamicClass()); 36980b57cec5SDimitry Andric 36990b57cec5SDimitry Andric // Check if we've computed this information before. 37000b57cec5SDimitry Andric if (VFPtrLocations.count(RD)) 37010b57cec5SDimitry Andric return; 37020b57cec5SDimitry Andric 37030b57cec5SDimitry Andric const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap; 37040b57cec5SDimitry Andric 37050b57cec5SDimitry Andric { 3706a7dea167SDimitry Andric auto VFPtrs = std::make_unique<VPtrInfoVector>(); 37070b57cec5SDimitry Andric computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs); 37080b57cec5SDimitry Andric computeFullPathsForVFTables(Context, RD, *VFPtrs); 37090b57cec5SDimitry Andric VFPtrLocations[RD] = std::move(VFPtrs); 37100b57cec5SDimitry Andric } 37110b57cec5SDimitry Andric 37120b57cec5SDimitry Andric MethodVFTableLocationsTy NewMethodLocations; 37130b57cec5SDimitry Andric for (const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) { 37140b57cec5SDimitry Andric VFTableBuilder Builder(*this, RD, *VFPtr); 37150b57cec5SDimitry Andric 37160b57cec5SDimitry Andric VFTableIdTy id(RD, VFPtr->FullOffsetInMDC); 37170b57cec5SDimitry Andric assert(VFTableLayouts.count(id) == 0); 37180b57cec5SDimitry Andric SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks( 37190b57cec5SDimitry Andric Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); 3720a7dea167SDimitry Andric VFTableLayouts[id] = std::make_unique<VTableLayout>( 37210b57cec5SDimitry Andric ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks, 37220b57cec5SDimitry Andric EmptyAddressPointsMap); 37230b57cec5SDimitry Andric Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); 37240b57cec5SDimitry Andric 37250b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 37260b57cec5SDimitry Andric for (const auto &Loc : Builder.vtable_locations()) { 37270b57cec5SDimitry Andric auto Insert = NewMethodLocations.insert(Loc); 37280b57cec5SDimitry Andric if (!Insert.second) { 37290b57cec5SDimitry Andric const MethodVFTableLocation &NewLoc = Loc.second; 37300b57cec5SDimitry Andric MethodVFTableLocation &OldLoc = Insert.first->second; 37310b57cec5SDimitry Andric if (vfptrIsEarlierInMDC(Layout, NewLoc, OldLoc)) 37320b57cec5SDimitry Andric OldLoc = NewLoc; 37330b57cec5SDimitry Andric } 37340b57cec5SDimitry Andric } 37350b57cec5SDimitry Andric } 37360b57cec5SDimitry Andric 37370b57cec5SDimitry Andric MethodVFTableLocations.insert(NewMethodLocations.begin(), 37380b57cec5SDimitry Andric NewMethodLocations.end()); 37390b57cec5SDimitry Andric if (Context.getLangOpts().DumpVTableLayouts) 37400b57cec5SDimitry Andric dumpMethodLocations(RD, NewMethodLocations, llvm::outs()); 37410b57cec5SDimitry Andric } 37420b57cec5SDimitry Andric 37430b57cec5SDimitry Andric void MicrosoftVTableContext::dumpMethodLocations( 37440b57cec5SDimitry Andric const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods, 37450b57cec5SDimitry Andric raw_ostream &Out) { 37460b57cec5SDimitry Andric // Compute the vtable indices for all the member functions. 37470b57cec5SDimitry Andric // Store them in a map keyed by the location so we'll get a sorted table. 37480b57cec5SDimitry Andric std::map<MethodVFTableLocation, std::string> IndicesMap; 37490b57cec5SDimitry Andric bool HasNonzeroOffset = false; 37500b57cec5SDimitry Andric 37510b57cec5SDimitry Andric for (const auto &I : NewMethods) { 37520b57cec5SDimitry Andric const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl()); 37535ffd83dbSDimitry Andric assert(hasVtableSlot(MD)); 37540b57cec5SDimitry Andric 37550b57cec5SDimitry Andric std::string MethodName = PredefinedExpr::ComputeName( 37565f757f3fSDimitry Andric PredefinedIdentKind::PrettyFunctionNoVirtual, MD); 37570b57cec5SDimitry Andric 37580b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(MD)) { 37590b57cec5SDimitry Andric IndicesMap[I.second] = MethodName + " [scalar deleting]"; 37600b57cec5SDimitry Andric } else { 37610b57cec5SDimitry Andric IndicesMap[I.second] = MethodName; 37620b57cec5SDimitry Andric } 37630b57cec5SDimitry Andric 37640b57cec5SDimitry Andric if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0) 37650b57cec5SDimitry Andric HasNonzeroOffset = true; 37660b57cec5SDimitry Andric } 37670b57cec5SDimitry Andric 37680b57cec5SDimitry Andric // Print the vtable indices for all the member functions. 37690b57cec5SDimitry Andric if (!IndicesMap.empty()) { 37700b57cec5SDimitry Andric Out << "VFTable indices for "; 37710b57cec5SDimitry Andric Out << "'"; 37720b57cec5SDimitry Andric RD->printQualifiedName(Out); 37730b57cec5SDimitry Andric Out << "' (" << IndicesMap.size() 37740b57cec5SDimitry Andric << (IndicesMap.size() == 1 ? " entry" : " entries") << ").\n"; 37750b57cec5SDimitry Andric 37760b57cec5SDimitry Andric CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1); 37770b57cec5SDimitry Andric uint64_t LastVBIndex = 0; 37780b57cec5SDimitry Andric for (const auto &I : IndicesMap) { 37790b57cec5SDimitry Andric CharUnits VFPtrOffset = I.first.VFPtrOffset; 37800b57cec5SDimitry Andric uint64_t VBIndex = I.first.VBTableIndex; 37810b57cec5SDimitry Andric if (HasNonzeroOffset && 37820b57cec5SDimitry Andric (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) { 37830b57cec5SDimitry Andric assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset); 37840b57cec5SDimitry Andric Out << " -- accessible via "; 37850b57cec5SDimitry Andric if (VBIndex) 37860b57cec5SDimitry Andric Out << "vbtable index " << VBIndex << ", "; 37870b57cec5SDimitry Andric Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n"; 37880b57cec5SDimitry Andric LastVFPtrOffset = VFPtrOffset; 37890b57cec5SDimitry Andric LastVBIndex = VBIndex; 37900b57cec5SDimitry Andric } 37910b57cec5SDimitry Andric 37920b57cec5SDimitry Andric uint64_t VTableIndex = I.first.Index; 37930b57cec5SDimitry Andric const std::string &MethodName = I.second; 37940b57cec5SDimitry Andric Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n'; 37950b57cec5SDimitry Andric } 37960b57cec5SDimitry Andric Out << '\n'; 37970b57cec5SDimitry Andric } 37980b57cec5SDimitry Andric 37990b57cec5SDimitry Andric Out.flush(); 38000b57cec5SDimitry Andric } 38010b57cec5SDimitry Andric 38020b57cec5SDimitry Andric const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation( 38030b57cec5SDimitry Andric const CXXRecordDecl *RD) { 38040b57cec5SDimitry Andric VirtualBaseInfo *VBI; 38050b57cec5SDimitry Andric 38060b57cec5SDimitry Andric { 38070b57cec5SDimitry Andric // Get or create a VBI for RD. Don't hold a reference to the DenseMap cell, 38080b57cec5SDimitry Andric // as it may be modified and rehashed under us. 38090b57cec5SDimitry Andric std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD]; 38100b57cec5SDimitry Andric if (Entry) 38110b57cec5SDimitry Andric return *Entry; 3812a7dea167SDimitry Andric Entry = std::make_unique<VirtualBaseInfo>(); 38130b57cec5SDimitry Andric VBI = Entry.get(); 38140b57cec5SDimitry Andric } 38150b57cec5SDimitry Andric 38160b57cec5SDimitry Andric computeVTablePaths(/*ForVBTables=*/true, RD, VBI->VBPtrPaths); 38170b57cec5SDimitry Andric 38180b57cec5SDimitry Andric // First, see if the Derived class shared the vbptr with a non-virtual base. 38190b57cec5SDimitry Andric const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 38200b57cec5SDimitry Andric if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) { 38210b57cec5SDimitry Andric // If the Derived class shares the vbptr with a non-virtual base, the shared 38220b57cec5SDimitry Andric // virtual bases come first so that the layout is the same. 38230b57cec5SDimitry Andric const VirtualBaseInfo &BaseInfo = 38240b57cec5SDimitry Andric computeVBTableRelatedInformation(VBPtrBase); 38250b57cec5SDimitry Andric VBI->VBTableIndices.insert(BaseInfo.VBTableIndices.begin(), 38260b57cec5SDimitry Andric BaseInfo.VBTableIndices.end()); 38270b57cec5SDimitry Andric } 38280b57cec5SDimitry Andric 38290b57cec5SDimitry Andric // New vbases are added to the end of the vbtable. 38300b57cec5SDimitry Andric // Skip the self entry and vbases visited in the non-virtual base, if any. 38310b57cec5SDimitry Andric unsigned VBTableIndex = 1 + VBI->VBTableIndices.size(); 38320b57cec5SDimitry Andric for (const auto &VB : RD->vbases()) { 38330b57cec5SDimitry Andric const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl(); 38340b57cec5SDimitry Andric if (!VBI->VBTableIndices.count(CurVBase)) 38350b57cec5SDimitry Andric VBI->VBTableIndices[CurVBase] = VBTableIndex++; 38360b57cec5SDimitry Andric } 38370b57cec5SDimitry Andric 38380b57cec5SDimitry Andric return *VBI; 38390b57cec5SDimitry Andric } 38400b57cec5SDimitry Andric 38410b57cec5SDimitry Andric unsigned MicrosoftVTableContext::getVBTableIndex(const CXXRecordDecl *Derived, 38420b57cec5SDimitry Andric const CXXRecordDecl *VBase) { 38430b57cec5SDimitry Andric const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived); 38440b57cec5SDimitry Andric assert(VBInfo.VBTableIndices.count(VBase)); 38450b57cec5SDimitry Andric return VBInfo.VBTableIndices.find(VBase)->second; 38460b57cec5SDimitry Andric } 38470b57cec5SDimitry Andric 38480b57cec5SDimitry Andric const VPtrInfoVector & 38490b57cec5SDimitry Andric MicrosoftVTableContext::enumerateVBTables(const CXXRecordDecl *RD) { 38500b57cec5SDimitry Andric return computeVBTableRelatedInformation(RD).VBPtrPaths; 38510b57cec5SDimitry Andric } 38520b57cec5SDimitry Andric 38530b57cec5SDimitry Andric const VPtrInfoVector & 38540b57cec5SDimitry Andric MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { 38550b57cec5SDimitry Andric computeVTableRelatedInformation(RD); 38560b57cec5SDimitry Andric 38570b57cec5SDimitry Andric assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations"); 38580b57cec5SDimitry Andric return *VFPtrLocations[RD]; 38590b57cec5SDimitry Andric } 38600b57cec5SDimitry Andric 38610b57cec5SDimitry Andric const VTableLayout & 38620b57cec5SDimitry Andric MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD, 38630b57cec5SDimitry Andric CharUnits VFPtrOffset) { 38640b57cec5SDimitry Andric computeVTableRelatedInformation(RD); 38650b57cec5SDimitry Andric 38660b57cec5SDimitry Andric VFTableIdTy id(RD, VFPtrOffset); 38670b57cec5SDimitry Andric assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset"); 38680b57cec5SDimitry Andric return *VFTableLayouts[id]; 38690b57cec5SDimitry Andric } 38700b57cec5SDimitry Andric 38710b57cec5SDimitry Andric MethodVFTableLocation 38720b57cec5SDimitry Andric MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) { 38735ffd83dbSDimitry Andric assert(hasVtableSlot(cast<CXXMethodDecl>(GD.getDecl())) && 38740b57cec5SDimitry Andric "Only use this method for virtual methods or dtors"); 38750b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(GD.getDecl())) 38760b57cec5SDimitry Andric assert(GD.getDtorType() == Dtor_Deleting); 38770b57cec5SDimitry Andric 38780b57cec5SDimitry Andric GD = GD.getCanonicalDecl(); 38790b57cec5SDimitry Andric 38800b57cec5SDimitry Andric MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD); 38810b57cec5SDimitry Andric if (I != MethodVFTableLocations.end()) 38820b57cec5SDimitry Andric return I->second; 38830b57cec5SDimitry Andric 38840b57cec5SDimitry Andric const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); 38850b57cec5SDimitry Andric 38860b57cec5SDimitry Andric computeVTableRelatedInformation(RD); 38870b57cec5SDimitry Andric 38880b57cec5SDimitry Andric I = MethodVFTableLocations.find(GD); 38890b57cec5SDimitry Andric assert(I != MethodVFTableLocations.end() && "Did not find index!"); 38900b57cec5SDimitry Andric return I->second; 38910b57cec5SDimitry Andric } 3892