xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/AST/VTableBuilder.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This contains code dealing with generation of the layout of virtual tables.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "clang/AST/VTableBuilder.h"
147330f729Sjoerg #include "clang/AST/ASTContext.h"
157330f729Sjoerg #include "clang/AST/ASTDiagnostic.h"
167330f729Sjoerg #include "clang/AST/CXXInheritance.h"
177330f729Sjoerg #include "clang/AST/RecordLayout.h"
187330f729Sjoerg #include "clang/Basic/TargetInfo.h"
197330f729Sjoerg #include "llvm/ADT/SetOperations.h"
207330f729Sjoerg #include "llvm/ADT/SmallPtrSet.h"
217330f729Sjoerg #include "llvm/Support/Format.h"
227330f729Sjoerg #include "llvm/Support/raw_ostream.h"
237330f729Sjoerg #include <algorithm>
247330f729Sjoerg #include <cstdio>
257330f729Sjoerg 
267330f729Sjoerg using namespace clang;
277330f729Sjoerg 
287330f729Sjoerg #define DUMP_OVERRIDERS 0
297330f729Sjoerg 
307330f729Sjoerg namespace {
317330f729Sjoerg 
327330f729Sjoerg /// BaseOffset - Represents an offset from a derived class to a direct or
337330f729Sjoerg /// indirect base class.
347330f729Sjoerg struct BaseOffset {
357330f729Sjoerg   /// DerivedClass - The derived class.
367330f729Sjoerg   const CXXRecordDecl *DerivedClass;
377330f729Sjoerg 
387330f729Sjoerg   /// VirtualBase - If the path from the derived class to the base class
397330f729Sjoerg   /// involves virtual base classes, this holds the declaration of the last
407330f729Sjoerg   /// virtual base in this path (i.e. closest to the base class).
417330f729Sjoerg   const CXXRecordDecl *VirtualBase;
427330f729Sjoerg 
437330f729Sjoerg   /// NonVirtualOffset - The offset from the derived class to the base class.
447330f729Sjoerg   /// (Or the offset from the virtual base class to the base class, if the
457330f729Sjoerg   /// path from the derived class to the base class involves a virtual base
467330f729Sjoerg   /// class.
477330f729Sjoerg   CharUnits NonVirtualOffset;
487330f729Sjoerg 
BaseOffset__anon6f3b34010111::BaseOffset497330f729Sjoerg   BaseOffset() : DerivedClass(nullptr), VirtualBase(nullptr),
507330f729Sjoerg                  NonVirtualOffset(CharUnits::Zero()) { }
BaseOffset__anon6f3b34010111::BaseOffset517330f729Sjoerg   BaseOffset(const CXXRecordDecl *DerivedClass,
527330f729Sjoerg              const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset)
537330f729Sjoerg     : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
547330f729Sjoerg     NonVirtualOffset(NonVirtualOffset) { }
557330f729Sjoerg 
isEmpty__anon6f3b34010111::BaseOffset567330f729Sjoerg   bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; }
577330f729Sjoerg };
587330f729Sjoerg 
597330f729Sjoerg /// FinalOverriders - Contains the final overrider member functions for all
607330f729Sjoerg /// member functions in the base subobjects of a class.
617330f729Sjoerg class FinalOverriders {
627330f729Sjoerg public:
637330f729Sjoerg   /// OverriderInfo - Information about a final overrider.
647330f729Sjoerg   struct OverriderInfo {
657330f729Sjoerg     /// Method - The method decl of the overrider.
667330f729Sjoerg     const CXXMethodDecl *Method;
677330f729Sjoerg 
687330f729Sjoerg     /// VirtualBase - The virtual base class subobject of this overrider.
697330f729Sjoerg     /// Note that this records the closest derived virtual base class subobject.
707330f729Sjoerg     const CXXRecordDecl *VirtualBase;
717330f729Sjoerg 
727330f729Sjoerg     /// Offset - the base offset of the overrider's parent in the layout class.
737330f729Sjoerg     CharUnits Offset;
747330f729Sjoerg 
OverriderInfo__anon6f3b34010111::FinalOverriders::OverriderInfo757330f729Sjoerg     OverriderInfo() : Method(nullptr), VirtualBase(nullptr),
767330f729Sjoerg                       Offset(CharUnits::Zero()) { }
777330f729Sjoerg   };
787330f729Sjoerg 
797330f729Sjoerg private:
807330f729Sjoerg   /// MostDerivedClass - The most derived class for which the final overriders
817330f729Sjoerg   /// are stored.
827330f729Sjoerg   const CXXRecordDecl *MostDerivedClass;
837330f729Sjoerg 
847330f729Sjoerg   /// MostDerivedClassOffset - If we're building final overriders for a
857330f729Sjoerg   /// construction vtable, this holds the offset from the layout class to the
867330f729Sjoerg   /// most derived class.
877330f729Sjoerg   const CharUnits MostDerivedClassOffset;
887330f729Sjoerg 
897330f729Sjoerg   /// LayoutClass - The class we're using for layout information. Will be
907330f729Sjoerg   /// different than the most derived class if the final overriders are for a
917330f729Sjoerg   /// construction vtable.
927330f729Sjoerg   const CXXRecordDecl *LayoutClass;
937330f729Sjoerg 
947330f729Sjoerg   ASTContext &Context;
957330f729Sjoerg 
967330f729Sjoerg   /// MostDerivedClassLayout - the AST record layout of the most derived class.
977330f729Sjoerg   const ASTRecordLayout &MostDerivedClassLayout;
987330f729Sjoerg 
997330f729Sjoerg   /// MethodBaseOffsetPairTy - Uniquely identifies a member function
1007330f729Sjoerg   /// in a base subobject.
1017330f729Sjoerg   typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
1027330f729Sjoerg 
1037330f729Sjoerg   typedef llvm::DenseMap<MethodBaseOffsetPairTy,
1047330f729Sjoerg                          OverriderInfo> OverridersMapTy;
1057330f729Sjoerg 
1067330f729Sjoerg   /// OverridersMap - The final overriders for all virtual member functions of
1077330f729Sjoerg   /// all the base subobjects of the most derived class.
1087330f729Sjoerg   OverridersMapTy OverridersMap;
1097330f729Sjoerg 
1107330f729Sjoerg   /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented
1117330f729Sjoerg   /// as a record decl and a subobject number) and its offsets in the most
1127330f729Sjoerg   /// derived class as well as the layout class.
1137330f729Sjoerg   typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
1147330f729Sjoerg                          CharUnits> SubobjectOffsetMapTy;
1157330f729Sjoerg 
1167330f729Sjoerg   typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
1177330f729Sjoerg 
1187330f729Sjoerg   /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the
1197330f729Sjoerg   /// given base.
1207330f729Sjoerg   void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
1217330f729Sjoerg                           CharUnits OffsetInLayoutClass,
1227330f729Sjoerg                           SubobjectOffsetMapTy &SubobjectOffsets,
1237330f729Sjoerg                           SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
1247330f729Sjoerg                           SubobjectCountMapTy &SubobjectCounts);
1257330f729Sjoerg 
1267330f729Sjoerg   typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
1277330f729Sjoerg 
1287330f729Sjoerg   /// dump - dump the final overriders for a base subobject, and all its direct
1297330f729Sjoerg   /// and indirect base subobjects.
1307330f729Sjoerg   void dump(raw_ostream &Out, BaseSubobject Base,
1317330f729Sjoerg             VisitedVirtualBasesSetTy& VisitedVirtualBases);
1327330f729Sjoerg 
1337330f729Sjoerg public:
1347330f729Sjoerg   FinalOverriders(const CXXRecordDecl *MostDerivedClass,
1357330f729Sjoerg                   CharUnits MostDerivedClassOffset,
1367330f729Sjoerg                   const CXXRecordDecl *LayoutClass);
1377330f729Sjoerg 
1387330f729Sjoerg   /// getOverrider - Get the final overrider for the given method declaration in
1397330f729Sjoerg   /// the subobject with the given base offset.
getOverrider(const CXXMethodDecl * MD,CharUnits BaseOffset) const1407330f729Sjoerg   OverriderInfo getOverrider(const CXXMethodDecl *MD,
1417330f729Sjoerg                              CharUnits BaseOffset) const {
1427330f729Sjoerg     assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
1437330f729Sjoerg            "Did not find overrider!");
1447330f729Sjoerg 
1457330f729Sjoerg     return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
1467330f729Sjoerg   }
1477330f729Sjoerg 
1487330f729Sjoerg   /// dump - dump the final overriders.
dump()1497330f729Sjoerg   void dump() {
1507330f729Sjoerg     VisitedVirtualBasesSetTy VisitedVirtualBases;
1517330f729Sjoerg     dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()),
1527330f729Sjoerg          VisitedVirtualBases);
1537330f729Sjoerg   }
1547330f729Sjoerg 
1557330f729Sjoerg };
1567330f729Sjoerg 
FinalOverriders(const CXXRecordDecl * MostDerivedClass,CharUnits MostDerivedClassOffset,const CXXRecordDecl * LayoutClass)1577330f729Sjoerg FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
1587330f729Sjoerg                                  CharUnits MostDerivedClassOffset,
1597330f729Sjoerg                                  const CXXRecordDecl *LayoutClass)
1607330f729Sjoerg   : MostDerivedClass(MostDerivedClass),
1617330f729Sjoerg   MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
1627330f729Sjoerg   Context(MostDerivedClass->getASTContext()),
1637330f729Sjoerg   MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
1647330f729Sjoerg 
1657330f729Sjoerg   // Compute base offsets.
1667330f729Sjoerg   SubobjectOffsetMapTy SubobjectOffsets;
1677330f729Sjoerg   SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
1687330f729Sjoerg   SubobjectCountMapTy SubobjectCounts;
1697330f729Sjoerg   ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
1707330f729Sjoerg                      /*IsVirtual=*/false,
1717330f729Sjoerg                      MostDerivedClassOffset,
1727330f729Sjoerg                      SubobjectOffsets, SubobjectLayoutClassOffsets,
1737330f729Sjoerg                      SubobjectCounts);
1747330f729Sjoerg 
1757330f729Sjoerg   // Get the final overriders.
1767330f729Sjoerg   CXXFinalOverriderMap FinalOverriders;
1777330f729Sjoerg   MostDerivedClass->getFinalOverriders(FinalOverriders);
1787330f729Sjoerg 
1797330f729Sjoerg   for (const auto &Overrider : FinalOverriders) {
1807330f729Sjoerg     const CXXMethodDecl *MD = Overrider.first;
1817330f729Sjoerg     const OverridingMethods &Methods = Overrider.second;
1827330f729Sjoerg 
1837330f729Sjoerg     for (const auto &M : Methods) {
1847330f729Sjoerg       unsigned SubobjectNumber = M.first;
1857330f729Sjoerg       assert(SubobjectOffsets.count(std::make_pair(MD->getParent(),
1867330f729Sjoerg                                                    SubobjectNumber)) &&
1877330f729Sjoerg              "Did not find subobject offset!");
1887330f729Sjoerg 
1897330f729Sjoerg       CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
1907330f729Sjoerg                                                             SubobjectNumber)];
1917330f729Sjoerg 
1927330f729Sjoerg       assert(M.second.size() == 1 && "Final overrider is not unique!");
1937330f729Sjoerg       const UniqueVirtualMethod &Method = M.second.front();
1947330f729Sjoerg 
1957330f729Sjoerg       const CXXRecordDecl *OverriderRD = Method.Method->getParent();
1967330f729Sjoerg       assert(SubobjectLayoutClassOffsets.count(
1977330f729Sjoerg              std::make_pair(OverriderRD, Method.Subobject))
1987330f729Sjoerg              && "Did not find subobject offset!");
1997330f729Sjoerg       CharUnits OverriderOffset =
2007330f729Sjoerg         SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
2017330f729Sjoerg                                                    Method.Subobject)];
2027330f729Sjoerg 
2037330f729Sjoerg       OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
2047330f729Sjoerg       assert(!Overrider.Method && "Overrider should not exist yet!");
2057330f729Sjoerg 
2067330f729Sjoerg       Overrider.Offset = OverriderOffset;
2077330f729Sjoerg       Overrider.Method = Method.Method;
2087330f729Sjoerg       Overrider.VirtualBase = Method.InVirtualSubobject;
2097330f729Sjoerg     }
2107330f729Sjoerg   }
2117330f729Sjoerg 
2127330f729Sjoerg #if DUMP_OVERRIDERS
2137330f729Sjoerg   // And dump them (for now).
2147330f729Sjoerg   dump();
2157330f729Sjoerg #endif
2167330f729Sjoerg }
2177330f729Sjoerg 
ComputeBaseOffset(const ASTContext & Context,const CXXRecordDecl * DerivedRD,const CXXBasePath & Path)2187330f729Sjoerg static BaseOffset ComputeBaseOffset(const ASTContext &Context,
2197330f729Sjoerg                                     const CXXRecordDecl *DerivedRD,
2207330f729Sjoerg                                     const CXXBasePath &Path) {
2217330f729Sjoerg   CharUnits NonVirtualOffset = CharUnits::Zero();
2227330f729Sjoerg 
2237330f729Sjoerg   unsigned NonVirtualStart = 0;
2247330f729Sjoerg   const CXXRecordDecl *VirtualBase = nullptr;
2257330f729Sjoerg 
2267330f729Sjoerg   // First, look for the virtual base class.
2277330f729Sjoerg   for (int I = Path.size(), E = 0; I != E; --I) {
2287330f729Sjoerg     const CXXBasePathElement &Element = Path[I - 1];
2297330f729Sjoerg 
2307330f729Sjoerg     if (Element.Base->isVirtual()) {
2317330f729Sjoerg       NonVirtualStart = I;
2327330f729Sjoerg       QualType VBaseType = Element.Base->getType();
2337330f729Sjoerg       VirtualBase = VBaseType->getAsCXXRecordDecl();
2347330f729Sjoerg       break;
2357330f729Sjoerg     }
2367330f729Sjoerg   }
2377330f729Sjoerg 
2387330f729Sjoerg   // Now compute the non-virtual offset.
2397330f729Sjoerg   for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
2407330f729Sjoerg     const CXXBasePathElement &Element = Path[I];
2417330f729Sjoerg 
2427330f729Sjoerg     // Check the base class offset.
2437330f729Sjoerg     const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
2447330f729Sjoerg 
2457330f729Sjoerg     const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl();
2467330f729Sjoerg 
2477330f729Sjoerg     NonVirtualOffset += Layout.getBaseClassOffset(Base);
2487330f729Sjoerg   }
2497330f729Sjoerg 
2507330f729Sjoerg   // FIXME: This should probably use CharUnits or something. Maybe we should
2517330f729Sjoerg   // even change the base offsets in ASTRecordLayout to be specified in
2527330f729Sjoerg   // CharUnits.
2537330f729Sjoerg   return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
2547330f729Sjoerg 
2557330f729Sjoerg }
2567330f729Sjoerg 
ComputeBaseOffset(const ASTContext & Context,const CXXRecordDecl * BaseRD,const CXXRecordDecl * DerivedRD)2577330f729Sjoerg static BaseOffset ComputeBaseOffset(const ASTContext &Context,
2587330f729Sjoerg                                     const CXXRecordDecl *BaseRD,
2597330f729Sjoerg                                     const CXXRecordDecl *DerivedRD) {
2607330f729Sjoerg   CXXBasePaths Paths(/*FindAmbiguities=*/false,
2617330f729Sjoerg                      /*RecordPaths=*/true, /*DetectVirtual=*/false);
2627330f729Sjoerg 
2637330f729Sjoerg   if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
2647330f729Sjoerg     llvm_unreachable("Class must be derived from the passed in base class!");
2657330f729Sjoerg 
2667330f729Sjoerg   return ComputeBaseOffset(Context, DerivedRD, Paths.front());
2677330f729Sjoerg }
2687330f729Sjoerg 
2697330f729Sjoerg static BaseOffset
ComputeReturnAdjustmentBaseOffset(ASTContext & Context,const CXXMethodDecl * DerivedMD,const CXXMethodDecl * BaseMD)2707330f729Sjoerg ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
2717330f729Sjoerg                                   const CXXMethodDecl *DerivedMD,
2727330f729Sjoerg                                   const CXXMethodDecl *BaseMD) {
273*e038c9c4Sjoerg   const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>();
274*e038c9c4Sjoerg   const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>();
2757330f729Sjoerg 
2767330f729Sjoerg   // Canonicalize the return types.
2777330f729Sjoerg   CanQualType CanDerivedReturnType =
2787330f729Sjoerg       Context.getCanonicalType(DerivedFT->getReturnType());
2797330f729Sjoerg   CanQualType CanBaseReturnType =
2807330f729Sjoerg       Context.getCanonicalType(BaseFT->getReturnType());
2817330f729Sjoerg 
2827330f729Sjoerg   assert(CanDerivedReturnType->getTypeClass() ==
2837330f729Sjoerg          CanBaseReturnType->getTypeClass() &&
2847330f729Sjoerg          "Types must have same type class!");
2857330f729Sjoerg 
2867330f729Sjoerg   if (CanDerivedReturnType == CanBaseReturnType) {
2877330f729Sjoerg     // No adjustment needed.
2887330f729Sjoerg     return BaseOffset();
2897330f729Sjoerg   }
2907330f729Sjoerg 
2917330f729Sjoerg   if (isa<ReferenceType>(CanDerivedReturnType)) {
2927330f729Sjoerg     CanDerivedReturnType =
2937330f729Sjoerg       CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
2947330f729Sjoerg     CanBaseReturnType =
2957330f729Sjoerg       CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
2967330f729Sjoerg   } else if (isa<PointerType>(CanDerivedReturnType)) {
2977330f729Sjoerg     CanDerivedReturnType =
2987330f729Sjoerg       CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
2997330f729Sjoerg     CanBaseReturnType =
3007330f729Sjoerg       CanBaseReturnType->getAs<PointerType>()->getPointeeType();
3017330f729Sjoerg   } else {
3027330f729Sjoerg     llvm_unreachable("Unexpected return type!");
3037330f729Sjoerg   }
3047330f729Sjoerg 
3057330f729Sjoerg   // We need to compare unqualified types here; consider
3067330f729Sjoerg   //   const T *Base::foo();
3077330f729Sjoerg   //   T *Derived::foo();
3087330f729Sjoerg   if (CanDerivedReturnType.getUnqualifiedType() ==
3097330f729Sjoerg       CanBaseReturnType.getUnqualifiedType()) {
3107330f729Sjoerg     // No adjustment needed.
3117330f729Sjoerg     return BaseOffset();
3127330f729Sjoerg   }
3137330f729Sjoerg 
3147330f729Sjoerg   const CXXRecordDecl *DerivedRD =
3157330f729Sjoerg     cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
3167330f729Sjoerg 
3177330f729Sjoerg   const CXXRecordDecl *BaseRD =
3187330f729Sjoerg     cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
3197330f729Sjoerg 
3207330f729Sjoerg   return ComputeBaseOffset(Context, BaseRD, DerivedRD);
3217330f729Sjoerg }
3227330f729Sjoerg 
3237330f729Sjoerg void
ComputeBaseOffsets(BaseSubobject Base,bool IsVirtual,CharUnits OffsetInLayoutClass,SubobjectOffsetMapTy & SubobjectOffsets,SubobjectOffsetMapTy & SubobjectLayoutClassOffsets,SubobjectCountMapTy & SubobjectCounts)3247330f729Sjoerg FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
3257330f729Sjoerg                               CharUnits OffsetInLayoutClass,
3267330f729Sjoerg                               SubobjectOffsetMapTy &SubobjectOffsets,
3277330f729Sjoerg                               SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
3287330f729Sjoerg                               SubobjectCountMapTy &SubobjectCounts) {
3297330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
3307330f729Sjoerg 
3317330f729Sjoerg   unsigned SubobjectNumber = 0;
3327330f729Sjoerg   if (!IsVirtual)
3337330f729Sjoerg     SubobjectNumber = ++SubobjectCounts[RD];
3347330f729Sjoerg 
3357330f729Sjoerg   // Set up the subobject to offset mapping.
3367330f729Sjoerg   assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
3377330f729Sjoerg          && "Subobject offset already exists!");
3387330f729Sjoerg   assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
3397330f729Sjoerg          && "Subobject offset already exists!");
3407330f729Sjoerg 
3417330f729Sjoerg   SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
3427330f729Sjoerg   SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
3437330f729Sjoerg     OffsetInLayoutClass;
3447330f729Sjoerg 
3457330f729Sjoerg   // Traverse our bases.
3467330f729Sjoerg   for (const auto &B : RD->bases()) {
3477330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
3487330f729Sjoerg 
3497330f729Sjoerg     CharUnits BaseOffset;
3507330f729Sjoerg     CharUnits BaseOffsetInLayoutClass;
3517330f729Sjoerg     if (B.isVirtual()) {
3527330f729Sjoerg       // Check if we've visited this virtual base before.
3537330f729Sjoerg       if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
3547330f729Sjoerg         continue;
3557330f729Sjoerg 
3567330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
3577330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
3587330f729Sjoerg 
3597330f729Sjoerg       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
3607330f729Sjoerg       BaseOffsetInLayoutClass =
3617330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(BaseDecl);
3627330f729Sjoerg     } else {
3637330f729Sjoerg       const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3647330f729Sjoerg       CharUnits Offset = Layout.getBaseClassOffset(BaseDecl);
3657330f729Sjoerg 
3667330f729Sjoerg       BaseOffset = Base.getBaseOffset() + Offset;
3677330f729Sjoerg       BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
3687330f729Sjoerg     }
3697330f729Sjoerg 
3707330f729Sjoerg     ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
3717330f729Sjoerg                        B.isVirtual(), BaseOffsetInLayoutClass,
3727330f729Sjoerg                        SubobjectOffsets, SubobjectLayoutClassOffsets,
3737330f729Sjoerg                        SubobjectCounts);
3747330f729Sjoerg   }
3757330f729Sjoerg }
3767330f729Sjoerg 
dump(raw_ostream & Out,BaseSubobject Base,VisitedVirtualBasesSetTy & VisitedVirtualBases)3777330f729Sjoerg void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
3787330f729Sjoerg                            VisitedVirtualBasesSetTy &VisitedVirtualBases) {
3797330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
3807330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3817330f729Sjoerg 
3827330f729Sjoerg   for (const auto &B : RD->bases()) {
3837330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
3847330f729Sjoerg 
3857330f729Sjoerg     // Ignore bases that don't have any virtual member functions.
3867330f729Sjoerg     if (!BaseDecl->isPolymorphic())
3877330f729Sjoerg       continue;
3887330f729Sjoerg 
3897330f729Sjoerg     CharUnits BaseOffset;
3907330f729Sjoerg     if (B.isVirtual()) {
3917330f729Sjoerg       if (!VisitedVirtualBases.insert(BaseDecl).second) {
3927330f729Sjoerg         // We've visited this base before.
3937330f729Sjoerg         continue;
3947330f729Sjoerg       }
3957330f729Sjoerg 
3967330f729Sjoerg       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
3977330f729Sjoerg     } else {
3987330f729Sjoerg       BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
3997330f729Sjoerg     }
4007330f729Sjoerg 
4017330f729Sjoerg     dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
4027330f729Sjoerg   }
4037330f729Sjoerg 
4047330f729Sjoerg   Out << "Final overriders for (";
4057330f729Sjoerg   RD->printQualifiedName(Out);
4067330f729Sjoerg   Out << ", ";
4077330f729Sjoerg   Out << Base.getBaseOffset().getQuantity() << ")\n";
4087330f729Sjoerg 
4097330f729Sjoerg   // Now dump the overriders for this base subobject.
4107330f729Sjoerg   for (const auto *MD : RD->methods()) {
411*e038c9c4Sjoerg     if (!VTableContextBase::hasVtableSlot(MD))
4127330f729Sjoerg       continue;
4137330f729Sjoerg     MD = MD->getCanonicalDecl();
4147330f729Sjoerg 
4157330f729Sjoerg     OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
4167330f729Sjoerg 
4177330f729Sjoerg     Out << "  ";
4187330f729Sjoerg     MD->printQualifiedName(Out);
4197330f729Sjoerg     Out << " - (";
4207330f729Sjoerg     Overrider.Method->printQualifiedName(Out);
4217330f729Sjoerg     Out << ", " << Overrider.Offset.getQuantity() << ')';
4227330f729Sjoerg 
4237330f729Sjoerg     BaseOffset Offset;
4247330f729Sjoerg     if (!Overrider.Method->isPure())
4257330f729Sjoerg       Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
4267330f729Sjoerg 
4277330f729Sjoerg     if (!Offset.isEmpty()) {
4287330f729Sjoerg       Out << " [ret-adj: ";
4297330f729Sjoerg       if (Offset.VirtualBase) {
4307330f729Sjoerg         Offset.VirtualBase->printQualifiedName(Out);
4317330f729Sjoerg         Out << " vbase, ";
4327330f729Sjoerg       }
4337330f729Sjoerg 
4347330f729Sjoerg       Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
4357330f729Sjoerg     }
4367330f729Sjoerg 
4377330f729Sjoerg     Out << "\n";
4387330f729Sjoerg   }
4397330f729Sjoerg }
4407330f729Sjoerg 
4417330f729Sjoerg /// VCallOffsetMap - Keeps track of vcall offsets when building a vtable.
4427330f729Sjoerg struct VCallOffsetMap {
4437330f729Sjoerg 
4447330f729Sjoerg   typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
4457330f729Sjoerg 
4467330f729Sjoerg   /// Offsets - Keeps track of methods and their offsets.
4477330f729Sjoerg   // FIXME: This should be a real map and not a vector.
4487330f729Sjoerg   SmallVector<MethodAndOffsetPairTy, 16> Offsets;
4497330f729Sjoerg 
4507330f729Sjoerg   /// MethodsCanShareVCallOffset - Returns whether two virtual member functions
4517330f729Sjoerg   /// can share the same vcall offset.
4527330f729Sjoerg   static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
4537330f729Sjoerg                                          const CXXMethodDecl *RHS);
4547330f729Sjoerg 
4557330f729Sjoerg public:
4567330f729Sjoerg   /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the
4577330f729Sjoerg   /// add was successful, or false if there was already a member function with
4587330f729Sjoerg   /// the same signature in the map.
4597330f729Sjoerg   bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset);
4607330f729Sjoerg 
4617330f729Sjoerg   /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the
4627330f729Sjoerg   /// vtable address point) for the given virtual member function.
4637330f729Sjoerg   CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD);
4647330f729Sjoerg 
4657330f729Sjoerg   // empty - Return whether the offset map is empty or not.
empty__anon6f3b34010111::VCallOffsetMap4667330f729Sjoerg   bool empty() const { return Offsets.empty(); }
4677330f729Sjoerg };
4687330f729Sjoerg 
HasSameVirtualSignature(const CXXMethodDecl * LHS,const CXXMethodDecl * RHS)4697330f729Sjoerg static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
4707330f729Sjoerg                                     const CXXMethodDecl *RHS) {
4717330f729Sjoerg   const FunctionProtoType *LT =
4727330f729Sjoerg     cast<FunctionProtoType>(LHS->getType().getCanonicalType());
4737330f729Sjoerg   const FunctionProtoType *RT =
4747330f729Sjoerg     cast<FunctionProtoType>(RHS->getType().getCanonicalType());
4757330f729Sjoerg 
4767330f729Sjoerg   // Fast-path matches in the canonical types.
4777330f729Sjoerg   if (LT == RT) return true;
4787330f729Sjoerg 
4797330f729Sjoerg   // Force the signatures to match.  We can't rely on the overrides
4807330f729Sjoerg   // list here because there isn't necessarily an inheritance
4817330f729Sjoerg   // relationship between the two methods.
4827330f729Sjoerg   if (LT->getMethodQuals() != RT->getMethodQuals())
4837330f729Sjoerg     return false;
4847330f729Sjoerg   return LT->getParamTypes() == RT->getParamTypes();
4857330f729Sjoerg }
4867330f729Sjoerg 
MethodsCanShareVCallOffset(const CXXMethodDecl * LHS,const CXXMethodDecl * RHS)4877330f729Sjoerg bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
4887330f729Sjoerg                                                 const CXXMethodDecl *RHS) {
489*e038c9c4Sjoerg   assert(VTableContextBase::hasVtableSlot(LHS) && "LHS must be virtual!");
490*e038c9c4Sjoerg   assert(VTableContextBase::hasVtableSlot(RHS) && "RHS must be virtual!");
4917330f729Sjoerg 
4927330f729Sjoerg   // A destructor can share a vcall offset with another destructor.
4937330f729Sjoerg   if (isa<CXXDestructorDecl>(LHS))
4947330f729Sjoerg     return isa<CXXDestructorDecl>(RHS);
4957330f729Sjoerg 
4967330f729Sjoerg   // FIXME: We need to check more things here.
4977330f729Sjoerg 
4987330f729Sjoerg   // The methods must have the same name.
4997330f729Sjoerg   DeclarationName LHSName = LHS->getDeclName();
5007330f729Sjoerg   DeclarationName RHSName = RHS->getDeclName();
5017330f729Sjoerg   if (LHSName != RHSName)
5027330f729Sjoerg     return false;
5037330f729Sjoerg 
5047330f729Sjoerg   // And the same signatures.
5057330f729Sjoerg   return HasSameVirtualSignature(LHS, RHS);
5067330f729Sjoerg }
5077330f729Sjoerg 
AddVCallOffset(const CXXMethodDecl * MD,CharUnits OffsetOffset)5087330f729Sjoerg bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
5097330f729Sjoerg                                     CharUnits OffsetOffset) {
5107330f729Sjoerg   // Check if we can reuse an offset.
5117330f729Sjoerg   for (const auto &OffsetPair : Offsets) {
5127330f729Sjoerg     if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
5137330f729Sjoerg       return false;
5147330f729Sjoerg   }
5157330f729Sjoerg 
5167330f729Sjoerg   // Add the offset.
5177330f729Sjoerg   Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
5187330f729Sjoerg   return true;
5197330f729Sjoerg }
5207330f729Sjoerg 
getVCallOffsetOffset(const CXXMethodDecl * MD)5217330f729Sjoerg CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
5227330f729Sjoerg   // Look for an offset.
5237330f729Sjoerg   for (const auto &OffsetPair : Offsets) {
5247330f729Sjoerg     if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
5257330f729Sjoerg       return OffsetPair.second;
5267330f729Sjoerg   }
5277330f729Sjoerg 
5287330f729Sjoerg   llvm_unreachable("Should always find a vcall offset offset!");
5297330f729Sjoerg }
5307330f729Sjoerg 
5317330f729Sjoerg /// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets.
5327330f729Sjoerg class VCallAndVBaseOffsetBuilder {
5337330f729Sjoerg public:
5347330f729Sjoerg   typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
5357330f729Sjoerg     VBaseOffsetOffsetsMapTy;
5367330f729Sjoerg 
5377330f729Sjoerg private:
538*e038c9c4Sjoerg   const ItaniumVTableContext &VTables;
539*e038c9c4Sjoerg 
5407330f729Sjoerg   /// MostDerivedClass - The most derived class for which we're building vcall
5417330f729Sjoerg   /// and vbase offsets.
5427330f729Sjoerg   const CXXRecordDecl *MostDerivedClass;
5437330f729Sjoerg 
5447330f729Sjoerg   /// LayoutClass - The class we're using for layout information. Will be
5457330f729Sjoerg   /// different than the most derived class if we're building a construction
5467330f729Sjoerg   /// vtable.
5477330f729Sjoerg   const CXXRecordDecl *LayoutClass;
5487330f729Sjoerg 
5497330f729Sjoerg   /// Context - The ASTContext which we will use for layout information.
5507330f729Sjoerg   ASTContext &Context;
5517330f729Sjoerg 
5527330f729Sjoerg   /// Components - vcall and vbase offset components
5537330f729Sjoerg   typedef SmallVector<VTableComponent, 64> VTableComponentVectorTy;
5547330f729Sjoerg   VTableComponentVectorTy Components;
5557330f729Sjoerg 
5567330f729Sjoerg   /// VisitedVirtualBases - Visited virtual bases.
5577330f729Sjoerg   llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
5587330f729Sjoerg 
5597330f729Sjoerg   /// VCallOffsets - Keeps track of vcall offsets.
5607330f729Sjoerg   VCallOffsetMap VCallOffsets;
5617330f729Sjoerg 
5627330f729Sjoerg 
5637330f729Sjoerg   /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets,
5647330f729Sjoerg   /// relative to the address point.
5657330f729Sjoerg   VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
5667330f729Sjoerg 
5677330f729Sjoerg   /// FinalOverriders - The final overriders of the most derived class.
5687330f729Sjoerg   /// (Can be null when we're not building a vtable of the most derived class).
5697330f729Sjoerg   const FinalOverriders *Overriders;
5707330f729Sjoerg 
5717330f729Sjoerg   /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
5727330f729Sjoerg   /// given base subobject.
5737330f729Sjoerg   void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
5747330f729Sjoerg                                CharUnits RealBaseOffset);
5757330f729Sjoerg 
5767330f729Sjoerg   /// AddVCallOffsets - Add vcall offsets for the given base subobject.
5777330f729Sjoerg   void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset);
5787330f729Sjoerg 
5797330f729Sjoerg   /// AddVBaseOffsets - Add vbase offsets for the given class.
5807330f729Sjoerg   void AddVBaseOffsets(const CXXRecordDecl *Base,
5817330f729Sjoerg                        CharUnits OffsetInLayoutClass);
5827330f729Sjoerg 
5837330f729Sjoerg   /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in
5847330f729Sjoerg   /// chars, relative to the vtable address point.
5857330f729Sjoerg   CharUnits getCurrentOffsetOffset() const;
5867330f729Sjoerg 
5877330f729Sjoerg public:
VCallAndVBaseOffsetBuilder(const ItaniumVTableContext & VTables,const CXXRecordDecl * MostDerivedClass,const CXXRecordDecl * LayoutClass,const FinalOverriders * Overriders,BaseSubobject Base,bool BaseIsVirtual,CharUnits OffsetInLayoutClass)588*e038c9c4Sjoerg   VCallAndVBaseOffsetBuilder(const ItaniumVTableContext &VTables,
589*e038c9c4Sjoerg                              const CXXRecordDecl *MostDerivedClass,
5907330f729Sjoerg                              const CXXRecordDecl *LayoutClass,
5917330f729Sjoerg                              const FinalOverriders *Overriders,
5927330f729Sjoerg                              BaseSubobject Base, bool BaseIsVirtual,
5937330f729Sjoerg                              CharUnits OffsetInLayoutClass)
594*e038c9c4Sjoerg       : VTables(VTables), MostDerivedClass(MostDerivedClass),
595*e038c9c4Sjoerg         LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
596*e038c9c4Sjoerg         Overriders(Overriders) {
5977330f729Sjoerg 
5987330f729Sjoerg     // Add vcall and vbase offsets.
5997330f729Sjoerg     AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
6007330f729Sjoerg   }
6017330f729Sjoerg 
6027330f729Sjoerg   /// Methods for iterating over the components.
6037330f729Sjoerg   typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
components_begin() const6047330f729Sjoerg   const_iterator components_begin() const { return Components.rbegin(); }
components_end() const6057330f729Sjoerg   const_iterator components_end() const { return Components.rend(); }
6067330f729Sjoerg 
getVCallOffsets() const6077330f729Sjoerg   const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
getVBaseOffsetOffsets() const6087330f729Sjoerg   const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
6097330f729Sjoerg     return VBaseOffsetOffsets;
6107330f729Sjoerg   }
6117330f729Sjoerg };
6127330f729Sjoerg 
6137330f729Sjoerg void
AddVCallAndVBaseOffsets(BaseSubobject Base,bool BaseIsVirtual,CharUnits RealBaseOffset)6147330f729Sjoerg VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
6157330f729Sjoerg                                                     bool BaseIsVirtual,
6167330f729Sjoerg                                                     CharUnits RealBaseOffset) {
6177330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
6187330f729Sjoerg 
6197330f729Sjoerg   // Itanium C++ ABI 2.5.2:
6207330f729Sjoerg   //   ..in classes sharing a virtual table with a primary base class, the vcall
6217330f729Sjoerg   //   and vbase offsets added by the derived class all come before the vcall
6227330f729Sjoerg   //   and vbase offsets required by the base class, so that the latter may be
6237330f729Sjoerg   //   laid out as required by the base class without regard to additions from
6247330f729Sjoerg   //   the derived class(es).
6257330f729Sjoerg 
6267330f729Sjoerg   // (Since we're emitting the vcall and vbase offsets in reverse order, we'll
6277330f729Sjoerg   // emit them for the primary base first).
6287330f729Sjoerg   if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
6297330f729Sjoerg     bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
6307330f729Sjoerg 
6317330f729Sjoerg     CharUnits PrimaryBaseOffset;
6327330f729Sjoerg 
6337330f729Sjoerg     // Get the base offset of the primary base.
6347330f729Sjoerg     if (PrimaryBaseIsVirtual) {
6357330f729Sjoerg       assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() &&
6367330f729Sjoerg              "Primary vbase should have a zero offset!");
6377330f729Sjoerg 
6387330f729Sjoerg       const ASTRecordLayout &MostDerivedClassLayout =
6397330f729Sjoerg         Context.getASTRecordLayout(MostDerivedClass);
6407330f729Sjoerg 
6417330f729Sjoerg       PrimaryBaseOffset =
6427330f729Sjoerg         MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
6437330f729Sjoerg     } else {
6447330f729Sjoerg       assert(Layout.getBaseClassOffset(PrimaryBase).isZero() &&
6457330f729Sjoerg              "Primary base should have a zero offset!");
6467330f729Sjoerg 
6477330f729Sjoerg       PrimaryBaseOffset = Base.getBaseOffset();
6487330f729Sjoerg     }
6497330f729Sjoerg 
6507330f729Sjoerg     AddVCallAndVBaseOffsets(
6517330f729Sjoerg       BaseSubobject(PrimaryBase,PrimaryBaseOffset),
6527330f729Sjoerg       PrimaryBaseIsVirtual, RealBaseOffset);
6537330f729Sjoerg   }
6547330f729Sjoerg 
6557330f729Sjoerg   AddVBaseOffsets(Base.getBase(), RealBaseOffset);
6567330f729Sjoerg 
6577330f729Sjoerg   // We only want to add vcall offsets for virtual bases.
6587330f729Sjoerg   if (BaseIsVirtual)
6597330f729Sjoerg     AddVCallOffsets(Base, RealBaseOffset);
6607330f729Sjoerg }
6617330f729Sjoerg 
getCurrentOffsetOffset() const6627330f729Sjoerg CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
6637330f729Sjoerg   // OffsetIndex is the index of this vcall or vbase offset, relative to the
6647330f729Sjoerg   // vtable address point. (We subtract 3 to account for the information just
6657330f729Sjoerg   // above the address point, the RTTI info, the offset to top, and the
6667330f729Sjoerg   // vcall offset itself).
6677330f729Sjoerg   int64_t OffsetIndex = -(int64_t)(3 + Components.size());
6687330f729Sjoerg 
669*e038c9c4Sjoerg   // Under the relative ABI, the offset widths are 32-bit ints instead of
670*e038c9c4Sjoerg   // pointer widths.
671*e038c9c4Sjoerg   CharUnits OffsetWidth = Context.toCharUnitsFromBits(
672*e038c9c4Sjoerg       VTables.isRelativeLayout() ? 32
673*e038c9c4Sjoerg                                  : Context.getTargetInfo().getPointerWidth(0));
674*e038c9c4Sjoerg   CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
675*e038c9c4Sjoerg 
6767330f729Sjoerg   return OffsetOffset;
6777330f729Sjoerg }
6787330f729Sjoerg 
AddVCallOffsets(BaseSubobject Base,CharUnits VBaseOffset)6797330f729Sjoerg void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
6807330f729Sjoerg                                                  CharUnits VBaseOffset) {
6817330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
6827330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
6837330f729Sjoerg 
6847330f729Sjoerg   const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
6857330f729Sjoerg 
6867330f729Sjoerg   // Handle the primary base first.
6877330f729Sjoerg   // We only want to add vcall offsets if the base is non-virtual; a virtual
6887330f729Sjoerg   // primary base will have its vcall and vbase offsets emitted already.
6897330f729Sjoerg   if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) {
6907330f729Sjoerg     // Get the base offset of the primary base.
6917330f729Sjoerg     assert(Layout.getBaseClassOffset(PrimaryBase).isZero() &&
6927330f729Sjoerg            "Primary base should have a zero offset!");
6937330f729Sjoerg 
6947330f729Sjoerg     AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
6957330f729Sjoerg                     VBaseOffset);
6967330f729Sjoerg   }
6977330f729Sjoerg 
6987330f729Sjoerg   // Add the vcall offsets.
6997330f729Sjoerg   for (const auto *MD : RD->methods()) {
700*e038c9c4Sjoerg     if (!VTableContextBase::hasVtableSlot(MD))
7017330f729Sjoerg       continue;
7027330f729Sjoerg     MD = MD->getCanonicalDecl();
7037330f729Sjoerg 
7047330f729Sjoerg     CharUnits OffsetOffset = getCurrentOffsetOffset();
7057330f729Sjoerg 
7067330f729Sjoerg     // Don't add a vcall offset if we already have one for this member function
7077330f729Sjoerg     // signature.
7087330f729Sjoerg     if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
7097330f729Sjoerg       continue;
7107330f729Sjoerg 
7117330f729Sjoerg     CharUnits Offset = CharUnits::Zero();
7127330f729Sjoerg 
7137330f729Sjoerg     if (Overriders) {
7147330f729Sjoerg       // Get the final overrider.
7157330f729Sjoerg       FinalOverriders::OverriderInfo Overrider =
7167330f729Sjoerg         Overriders->getOverrider(MD, Base.getBaseOffset());
7177330f729Sjoerg 
7187330f729Sjoerg       /// The vcall offset is the offset from the virtual base to the object
7197330f729Sjoerg       /// where the function was overridden.
7207330f729Sjoerg       Offset = Overrider.Offset - VBaseOffset;
7217330f729Sjoerg     }
7227330f729Sjoerg 
7237330f729Sjoerg     Components.push_back(
7247330f729Sjoerg       VTableComponent::MakeVCallOffset(Offset));
7257330f729Sjoerg   }
7267330f729Sjoerg 
7277330f729Sjoerg   // And iterate over all non-virtual bases (ignoring the primary base).
7287330f729Sjoerg   for (const auto &B : RD->bases()) {
7297330f729Sjoerg     if (B.isVirtual())
7307330f729Sjoerg       continue;
7317330f729Sjoerg 
7327330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
7337330f729Sjoerg     if (BaseDecl == PrimaryBase)
7347330f729Sjoerg       continue;
7357330f729Sjoerg 
7367330f729Sjoerg     // Get the base offset of this base.
7377330f729Sjoerg     CharUnits BaseOffset = Base.getBaseOffset() +
7387330f729Sjoerg       Layout.getBaseClassOffset(BaseDecl);
7397330f729Sjoerg 
7407330f729Sjoerg     AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
7417330f729Sjoerg                     VBaseOffset);
7427330f729Sjoerg   }
7437330f729Sjoerg }
7447330f729Sjoerg 
7457330f729Sjoerg void
AddVBaseOffsets(const CXXRecordDecl * RD,CharUnits OffsetInLayoutClass)7467330f729Sjoerg VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
7477330f729Sjoerg                                             CharUnits OffsetInLayoutClass) {
7487330f729Sjoerg   const ASTRecordLayout &LayoutClassLayout =
7497330f729Sjoerg     Context.getASTRecordLayout(LayoutClass);
7507330f729Sjoerg 
7517330f729Sjoerg   // Add vbase offsets.
7527330f729Sjoerg   for (const auto &B : RD->bases()) {
7537330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
7547330f729Sjoerg 
7557330f729Sjoerg     // Check if this is a virtual base that we haven't visited before.
7567330f729Sjoerg     if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
7577330f729Sjoerg       CharUnits Offset =
7587330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
7597330f729Sjoerg 
7607330f729Sjoerg       // Add the vbase offset offset.
7617330f729Sjoerg       assert(!VBaseOffsetOffsets.count(BaseDecl) &&
7627330f729Sjoerg              "vbase offset offset already exists!");
7637330f729Sjoerg 
7647330f729Sjoerg       CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
7657330f729Sjoerg       VBaseOffsetOffsets.insert(
7667330f729Sjoerg           std::make_pair(BaseDecl, VBaseOffsetOffset));
7677330f729Sjoerg 
7687330f729Sjoerg       Components.push_back(
7697330f729Sjoerg           VTableComponent::MakeVBaseOffset(Offset));
7707330f729Sjoerg     }
7717330f729Sjoerg 
7727330f729Sjoerg     // Check the base class looking for more vbase offsets.
7737330f729Sjoerg     AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
7747330f729Sjoerg   }
7757330f729Sjoerg }
7767330f729Sjoerg 
7777330f729Sjoerg /// ItaniumVTableBuilder - Class for building vtable layout information.
7787330f729Sjoerg class ItaniumVTableBuilder {
7797330f729Sjoerg public:
7807330f729Sjoerg   /// PrimaryBasesSetVectorTy - A set vector of direct and indirect
7817330f729Sjoerg   /// primary bases.
7827330f729Sjoerg   typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
7837330f729Sjoerg     PrimaryBasesSetVectorTy;
7847330f729Sjoerg 
7857330f729Sjoerg   typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
7867330f729Sjoerg     VBaseOffsetOffsetsMapTy;
7877330f729Sjoerg 
7887330f729Sjoerg   typedef VTableLayout::AddressPointsMapTy AddressPointsMapTy;
7897330f729Sjoerg 
7907330f729Sjoerg   typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
7917330f729Sjoerg 
7927330f729Sjoerg private:
7937330f729Sjoerg   /// VTables - Global vtable information.
7947330f729Sjoerg   ItaniumVTableContext &VTables;
7957330f729Sjoerg 
7967330f729Sjoerg   /// MostDerivedClass - The most derived class for which we're building this
7977330f729Sjoerg   /// vtable.
7987330f729Sjoerg   const CXXRecordDecl *MostDerivedClass;
7997330f729Sjoerg 
8007330f729Sjoerg   /// MostDerivedClassOffset - If we're building a construction vtable, this
8017330f729Sjoerg   /// holds the offset from the layout class to the most derived class.
8027330f729Sjoerg   const CharUnits MostDerivedClassOffset;
8037330f729Sjoerg 
8047330f729Sjoerg   /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual
8057330f729Sjoerg   /// base. (This only makes sense when building a construction vtable).
8067330f729Sjoerg   bool MostDerivedClassIsVirtual;
8077330f729Sjoerg 
8087330f729Sjoerg   /// LayoutClass - The class we're using for layout information. Will be
8097330f729Sjoerg   /// different than the most derived class if we're building a construction
8107330f729Sjoerg   /// vtable.
8117330f729Sjoerg   const CXXRecordDecl *LayoutClass;
8127330f729Sjoerg 
8137330f729Sjoerg   /// Context - The ASTContext which we will use for layout information.
8147330f729Sjoerg   ASTContext &Context;
8157330f729Sjoerg 
8167330f729Sjoerg   /// FinalOverriders - The final overriders of the most derived class.
8177330f729Sjoerg   const FinalOverriders Overriders;
8187330f729Sjoerg 
8197330f729Sjoerg   /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual
8207330f729Sjoerg   /// bases in this vtable.
8217330f729Sjoerg   llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
8227330f729Sjoerg 
8237330f729Sjoerg   /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
8247330f729Sjoerg   /// the most derived class.
8257330f729Sjoerg   VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
8267330f729Sjoerg 
8277330f729Sjoerg   /// Components - The components of the vtable being built.
8287330f729Sjoerg   SmallVector<VTableComponent, 64> Components;
8297330f729Sjoerg 
8307330f729Sjoerg   /// AddressPoints - Address points for the vtable being built.
8317330f729Sjoerg   AddressPointsMapTy AddressPoints;
8327330f729Sjoerg 
8337330f729Sjoerg   /// MethodInfo - Contains information about a method in a vtable.
8347330f729Sjoerg   /// (Used for computing 'this' pointer adjustment thunks.
8357330f729Sjoerg   struct MethodInfo {
8367330f729Sjoerg     /// BaseOffset - The base offset of this method.
8377330f729Sjoerg     const CharUnits BaseOffset;
8387330f729Sjoerg 
8397330f729Sjoerg     /// BaseOffsetInLayoutClass - The base offset in the layout class of this
8407330f729Sjoerg     /// method.
8417330f729Sjoerg     const CharUnits BaseOffsetInLayoutClass;
8427330f729Sjoerg 
8437330f729Sjoerg     /// VTableIndex - The index in the vtable that this method has.
8447330f729Sjoerg     /// (For destructors, this is the index of the complete destructor).
8457330f729Sjoerg     const uint64_t VTableIndex;
8467330f729Sjoerg 
MethodInfo__anon6f3b34010111::ItaniumVTableBuilder::MethodInfo8477330f729Sjoerg     MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass,
8487330f729Sjoerg                uint64_t VTableIndex)
8497330f729Sjoerg       : BaseOffset(BaseOffset),
8507330f729Sjoerg       BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
8517330f729Sjoerg       VTableIndex(VTableIndex) { }
8527330f729Sjoerg 
MethodInfo__anon6f3b34010111::ItaniumVTableBuilder::MethodInfo8537330f729Sjoerg     MethodInfo()
8547330f729Sjoerg       : BaseOffset(CharUnits::Zero()),
8557330f729Sjoerg       BaseOffsetInLayoutClass(CharUnits::Zero()),
8567330f729Sjoerg       VTableIndex(0) { }
8577330f729Sjoerg 
8587330f729Sjoerg     MethodInfo(MethodInfo const&) = default;
8597330f729Sjoerg   };
8607330f729Sjoerg 
8617330f729Sjoerg   typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
8627330f729Sjoerg 
8637330f729Sjoerg   /// MethodInfoMap - The information for all methods in the vtable we're
8647330f729Sjoerg   /// currently building.
8657330f729Sjoerg   MethodInfoMapTy MethodInfoMap;
8667330f729Sjoerg 
8677330f729Sjoerg   /// MethodVTableIndices - Contains the index (relative to the vtable address
8687330f729Sjoerg   /// point) where the function pointer for a virtual function is stored.
8697330f729Sjoerg   MethodVTableIndicesTy MethodVTableIndices;
8707330f729Sjoerg 
8717330f729Sjoerg   typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
8727330f729Sjoerg 
8737330f729Sjoerg   /// VTableThunks - The thunks by vtable index in the vtable currently being
8747330f729Sjoerg   /// built.
8757330f729Sjoerg   VTableThunksMapTy VTableThunks;
8767330f729Sjoerg 
8777330f729Sjoerg   typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
8787330f729Sjoerg   typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
8797330f729Sjoerg 
8807330f729Sjoerg   /// Thunks - A map that contains all the thunks needed for all methods in the
8817330f729Sjoerg   /// most derived class for which the vtable is currently being built.
8827330f729Sjoerg   ThunksMapTy Thunks;
8837330f729Sjoerg 
8847330f729Sjoerg   /// AddThunk - Add a thunk for the given method.
8857330f729Sjoerg   void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk);
8867330f729Sjoerg 
8877330f729Sjoerg   /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
8887330f729Sjoerg   /// part of the vtable we're currently building.
8897330f729Sjoerg   void ComputeThisAdjustments();
8907330f729Sjoerg 
8917330f729Sjoerg   typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
8927330f729Sjoerg 
8937330f729Sjoerg   /// PrimaryVirtualBases - All known virtual bases who are a primary base of
8947330f729Sjoerg   /// some other base.
8957330f729Sjoerg   VisitedVirtualBasesSetTy PrimaryVirtualBases;
8967330f729Sjoerg 
8977330f729Sjoerg   /// ComputeReturnAdjustment - Compute the return adjustment given a return
8987330f729Sjoerg   /// adjustment base offset.
8997330f729Sjoerg   ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset);
9007330f729Sjoerg 
9017330f729Sjoerg   /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
9027330f729Sjoerg   /// the 'this' pointer from the base subobject to the derived subobject.
9037330f729Sjoerg   BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
9047330f729Sjoerg                                              BaseSubobject Derived) const;
9057330f729Sjoerg 
9067330f729Sjoerg   /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the
9077330f729Sjoerg   /// given virtual member function, its offset in the layout class and its
9087330f729Sjoerg   /// final overrider.
9097330f729Sjoerg   ThisAdjustment
9107330f729Sjoerg   ComputeThisAdjustment(const CXXMethodDecl *MD,
9117330f729Sjoerg                         CharUnits BaseOffsetInLayoutClass,
9127330f729Sjoerg                         FinalOverriders::OverriderInfo Overrider);
9137330f729Sjoerg 
9147330f729Sjoerg   /// AddMethod - Add a single virtual member function to the vtable
9157330f729Sjoerg   /// components vector.
9167330f729Sjoerg   void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
9177330f729Sjoerg 
9187330f729Sjoerg   /// IsOverriderUsed - Returns whether the overrider will ever be used in this
9197330f729Sjoerg   /// part of the vtable.
9207330f729Sjoerg   ///
9217330f729Sjoerg   /// Itanium C++ ABI 2.5.2:
9227330f729Sjoerg   ///
9237330f729Sjoerg   ///   struct A { virtual void f(); };
9247330f729Sjoerg   ///   struct B : virtual public A { int i; };
9257330f729Sjoerg   ///   struct C : virtual public A { int j; };
9267330f729Sjoerg   ///   struct D : public B, public C {};
9277330f729Sjoerg   ///
9287330f729Sjoerg   ///   When B and C are declared, A is a primary base in each case, so although
9297330f729Sjoerg   ///   vcall offsets are allocated in the A-in-B and A-in-C vtables, no this
9307330f729Sjoerg   ///   adjustment is required and no thunk is generated. However, inside D
9317330f729Sjoerg   ///   objects, A is no longer a primary base of C, so if we allowed calls to
9327330f729Sjoerg   ///   C::f() to use the copy of A's vtable in the C subobject, we would need
9337330f729Sjoerg   ///   to adjust this from C* to B::A*, which would require a third-party
9347330f729Sjoerg   ///   thunk. Since we require that a call to C::f() first convert to A*,
9357330f729Sjoerg   ///   C-in-D's copy of A's vtable is never referenced, so this is not
9367330f729Sjoerg   ///   necessary.
9377330f729Sjoerg   bool IsOverriderUsed(const CXXMethodDecl *Overrider,
9387330f729Sjoerg                        CharUnits BaseOffsetInLayoutClass,
9397330f729Sjoerg                        const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
9407330f729Sjoerg                        CharUnits FirstBaseOffsetInLayoutClass) const;
9417330f729Sjoerg 
9427330f729Sjoerg 
9437330f729Sjoerg   /// AddMethods - Add the methods of this base subobject and all its
9447330f729Sjoerg   /// primary bases to the vtable components vector.
9457330f729Sjoerg   void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
9467330f729Sjoerg                   const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
9477330f729Sjoerg                   CharUnits FirstBaseOffsetInLayoutClass,
9487330f729Sjoerg                   PrimaryBasesSetVectorTy &PrimaryBases);
9497330f729Sjoerg 
9507330f729Sjoerg   // LayoutVTable - Layout the vtable for the given base class, including its
9517330f729Sjoerg   // secondary vtables and any vtables for virtual bases.
9527330f729Sjoerg   void LayoutVTable();
9537330f729Sjoerg 
9547330f729Sjoerg   /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the
9557330f729Sjoerg   /// given base subobject, as well as all its secondary vtables.
9567330f729Sjoerg   ///
9577330f729Sjoerg   /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
9587330f729Sjoerg   /// or a direct or indirect base of a virtual base.
9597330f729Sjoerg   ///
9607330f729Sjoerg   /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual
9617330f729Sjoerg   /// in the layout class.
9627330f729Sjoerg   void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
9637330f729Sjoerg                                         bool BaseIsMorallyVirtual,
9647330f729Sjoerg                                         bool BaseIsVirtualInLayoutClass,
9657330f729Sjoerg                                         CharUnits OffsetInLayoutClass);
9667330f729Sjoerg 
9677330f729Sjoerg   /// LayoutSecondaryVTables - Layout the secondary vtables for the given base
9687330f729Sjoerg   /// subobject.
9697330f729Sjoerg   ///
9707330f729Sjoerg   /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
9717330f729Sjoerg   /// or a direct or indirect base of a virtual base.
9727330f729Sjoerg   void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
9737330f729Sjoerg                               CharUnits OffsetInLayoutClass);
9747330f729Sjoerg 
9757330f729Sjoerg   /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
9767330f729Sjoerg   /// class hierarchy.
9777330f729Sjoerg   void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
9787330f729Sjoerg                                     CharUnits OffsetInLayoutClass,
9797330f729Sjoerg                                     VisitedVirtualBasesSetTy &VBases);
9807330f729Sjoerg 
9817330f729Sjoerg   /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
9827330f729Sjoerg   /// given base (excluding any primary bases).
9837330f729Sjoerg   void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
9847330f729Sjoerg                                     VisitedVirtualBasesSetTy &VBases);
9857330f729Sjoerg 
9867330f729Sjoerg   /// isBuildingConstructionVTable - Return whether this vtable builder is
9877330f729Sjoerg   /// building a construction vtable.
isBuildingConstructorVTable() const9887330f729Sjoerg   bool isBuildingConstructorVTable() const {
9897330f729Sjoerg     return MostDerivedClass != LayoutClass;
9907330f729Sjoerg   }
9917330f729Sjoerg 
9927330f729Sjoerg public:
9937330f729Sjoerg   /// Component indices of the first component of each of the vtables in the
9947330f729Sjoerg   /// vtable group.
9957330f729Sjoerg   SmallVector<size_t, 4> VTableIndices;
9967330f729Sjoerg 
ItaniumVTableBuilder(ItaniumVTableContext & VTables,const CXXRecordDecl * MostDerivedClass,CharUnits MostDerivedClassOffset,bool MostDerivedClassIsVirtual,const CXXRecordDecl * LayoutClass)9977330f729Sjoerg   ItaniumVTableBuilder(ItaniumVTableContext &VTables,
9987330f729Sjoerg                        const CXXRecordDecl *MostDerivedClass,
9997330f729Sjoerg                        CharUnits MostDerivedClassOffset,
10007330f729Sjoerg                        bool MostDerivedClassIsVirtual,
10017330f729Sjoerg                        const CXXRecordDecl *LayoutClass)
10027330f729Sjoerg       : VTables(VTables), MostDerivedClass(MostDerivedClass),
10037330f729Sjoerg         MostDerivedClassOffset(MostDerivedClassOffset),
10047330f729Sjoerg         MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
10057330f729Sjoerg         LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
10067330f729Sjoerg         Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
10077330f729Sjoerg     assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
10087330f729Sjoerg 
10097330f729Sjoerg     LayoutVTable();
10107330f729Sjoerg 
10117330f729Sjoerg     if (Context.getLangOpts().DumpVTableLayouts)
10127330f729Sjoerg       dumpLayout(llvm::outs());
10137330f729Sjoerg   }
10147330f729Sjoerg 
getNumThunks() const10157330f729Sjoerg   uint64_t getNumThunks() const {
10167330f729Sjoerg     return Thunks.size();
10177330f729Sjoerg   }
10187330f729Sjoerg 
thunks_begin() const10197330f729Sjoerg   ThunksMapTy::const_iterator thunks_begin() const {
10207330f729Sjoerg     return Thunks.begin();
10217330f729Sjoerg   }
10227330f729Sjoerg 
thunks_end() const10237330f729Sjoerg   ThunksMapTy::const_iterator thunks_end() const {
10247330f729Sjoerg     return Thunks.end();
10257330f729Sjoerg   }
10267330f729Sjoerg 
getVBaseOffsetOffsets() const10277330f729Sjoerg   const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
10287330f729Sjoerg     return VBaseOffsetOffsets;
10297330f729Sjoerg   }
10307330f729Sjoerg 
getAddressPoints() const10317330f729Sjoerg   const AddressPointsMapTy &getAddressPoints() const {
10327330f729Sjoerg     return AddressPoints;
10337330f729Sjoerg   }
10347330f729Sjoerg 
vtable_indices_begin() const10357330f729Sjoerg   MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
10367330f729Sjoerg     return MethodVTableIndices.begin();
10377330f729Sjoerg   }
10387330f729Sjoerg 
vtable_indices_end() const10397330f729Sjoerg   MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
10407330f729Sjoerg     return MethodVTableIndices.end();
10417330f729Sjoerg   }
10427330f729Sjoerg 
vtable_components() const10437330f729Sjoerg   ArrayRef<VTableComponent> vtable_components() const { return Components; }
10447330f729Sjoerg 
address_points_begin() const10457330f729Sjoerg   AddressPointsMapTy::const_iterator address_points_begin() const {
10467330f729Sjoerg     return AddressPoints.begin();
10477330f729Sjoerg   }
10487330f729Sjoerg 
address_points_end() const10497330f729Sjoerg   AddressPointsMapTy::const_iterator address_points_end() const {
10507330f729Sjoerg     return AddressPoints.end();
10517330f729Sjoerg   }
10527330f729Sjoerg 
vtable_thunks_begin() const10537330f729Sjoerg   VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
10547330f729Sjoerg     return VTableThunks.begin();
10557330f729Sjoerg   }
10567330f729Sjoerg 
vtable_thunks_end() const10577330f729Sjoerg   VTableThunksMapTy::const_iterator vtable_thunks_end() const {
10587330f729Sjoerg     return VTableThunks.end();
10597330f729Sjoerg   }
10607330f729Sjoerg 
10617330f729Sjoerg   /// dumpLayout - Dump the vtable layout.
10627330f729Sjoerg   void dumpLayout(raw_ostream&);
10637330f729Sjoerg };
10647330f729Sjoerg 
AddThunk(const CXXMethodDecl * MD,const ThunkInfo & Thunk)10657330f729Sjoerg void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
10667330f729Sjoerg                                     const ThunkInfo &Thunk) {
10677330f729Sjoerg   assert(!isBuildingConstructorVTable() &&
10687330f729Sjoerg          "Can't add thunks for construction vtable");
10697330f729Sjoerg 
10707330f729Sjoerg   SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD];
10717330f729Sjoerg 
10727330f729Sjoerg   // Check if we have this thunk already.
10737330f729Sjoerg   if (llvm::find(ThunksVector, Thunk) != ThunksVector.end())
10747330f729Sjoerg     return;
10757330f729Sjoerg 
10767330f729Sjoerg   ThunksVector.push_back(Thunk);
10777330f729Sjoerg }
10787330f729Sjoerg 
10797330f729Sjoerg typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
10807330f729Sjoerg 
10817330f729Sjoerg /// Visit all the methods overridden by the given method recursively,
10827330f729Sjoerg /// in a depth-first pre-order. The Visitor's visitor method returns a bool
10837330f729Sjoerg /// indicating whether to continue the recursion for the given overridden
10847330f729Sjoerg /// method (i.e. returning false stops the iteration).
10857330f729Sjoerg template <class VisitorTy>
10867330f729Sjoerg static void
visitAllOverriddenMethods(const CXXMethodDecl * MD,VisitorTy & Visitor)10877330f729Sjoerg visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
1088*e038c9c4Sjoerg   assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!");
10897330f729Sjoerg 
10907330f729Sjoerg   for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) {
10917330f729Sjoerg     if (!Visitor(OverriddenMD))
10927330f729Sjoerg       continue;
10937330f729Sjoerg     visitAllOverriddenMethods(OverriddenMD, Visitor);
10947330f729Sjoerg   }
10957330f729Sjoerg }
10967330f729Sjoerg 
10977330f729Sjoerg /// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
10987330f729Sjoerg /// the overridden methods that the function decl overrides.
10997330f729Sjoerg static void
ComputeAllOverriddenMethods(const CXXMethodDecl * MD,OverriddenMethodsSetTy & OverriddenMethods)11007330f729Sjoerg ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
11017330f729Sjoerg                             OverriddenMethodsSetTy& OverriddenMethods) {
11027330f729Sjoerg   auto OverriddenMethodsCollector = [&](const CXXMethodDecl *MD) {
11037330f729Sjoerg     // Don't recurse on this method if we've already collected it.
11047330f729Sjoerg     return OverriddenMethods.insert(MD).second;
11057330f729Sjoerg   };
11067330f729Sjoerg   visitAllOverriddenMethods(MD, OverriddenMethodsCollector);
11077330f729Sjoerg }
11087330f729Sjoerg 
ComputeThisAdjustments()11097330f729Sjoerg void ItaniumVTableBuilder::ComputeThisAdjustments() {
11107330f729Sjoerg   // Now go through the method info map and see if any of the methods need
11117330f729Sjoerg   // 'this' pointer adjustments.
11127330f729Sjoerg   for (const auto &MI : MethodInfoMap) {
11137330f729Sjoerg     const CXXMethodDecl *MD = MI.first;
11147330f729Sjoerg     const MethodInfo &MethodInfo = MI.second;
11157330f729Sjoerg 
11167330f729Sjoerg     // Ignore adjustments for unused function pointers.
11177330f729Sjoerg     uint64_t VTableIndex = MethodInfo.VTableIndex;
11187330f729Sjoerg     if (Components[VTableIndex].getKind() ==
11197330f729Sjoerg         VTableComponent::CK_UnusedFunctionPointer)
11207330f729Sjoerg       continue;
11217330f729Sjoerg 
11227330f729Sjoerg     // Get the final overrider for this method.
11237330f729Sjoerg     FinalOverriders::OverriderInfo Overrider =
11247330f729Sjoerg       Overriders.getOverrider(MD, MethodInfo.BaseOffset);
11257330f729Sjoerg 
11267330f729Sjoerg     // Check if we need an adjustment at all.
11277330f729Sjoerg     if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
11287330f729Sjoerg       // When a return thunk is needed by a derived class that overrides a
11297330f729Sjoerg       // virtual base, gcc uses a virtual 'this' adjustment as well.
11307330f729Sjoerg       // While the thunk itself might be needed by vtables in subclasses or
11317330f729Sjoerg       // in construction vtables, there doesn't seem to be a reason for using
11327330f729Sjoerg       // the thunk in this vtable. Still, we do so to match gcc.
11337330f729Sjoerg       if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
11347330f729Sjoerg         continue;
11357330f729Sjoerg     }
11367330f729Sjoerg 
11377330f729Sjoerg     ThisAdjustment ThisAdjustment =
11387330f729Sjoerg       ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
11397330f729Sjoerg 
11407330f729Sjoerg     if (ThisAdjustment.isEmpty())
11417330f729Sjoerg       continue;
11427330f729Sjoerg 
11437330f729Sjoerg     // Add it.
11447330f729Sjoerg     VTableThunks[VTableIndex].This = ThisAdjustment;
11457330f729Sjoerg 
11467330f729Sjoerg     if (isa<CXXDestructorDecl>(MD)) {
11477330f729Sjoerg       // Add an adjustment for the deleting destructor as well.
11487330f729Sjoerg       VTableThunks[VTableIndex + 1].This = ThisAdjustment;
11497330f729Sjoerg     }
11507330f729Sjoerg   }
11517330f729Sjoerg 
11527330f729Sjoerg   /// Clear the method info map.
11537330f729Sjoerg   MethodInfoMap.clear();
11547330f729Sjoerg 
11557330f729Sjoerg   if (isBuildingConstructorVTable()) {
11567330f729Sjoerg     // We don't need to store thunk information for construction vtables.
11577330f729Sjoerg     return;
11587330f729Sjoerg   }
11597330f729Sjoerg 
11607330f729Sjoerg   for (const auto &TI : VTableThunks) {
11617330f729Sjoerg     const VTableComponent &Component = Components[TI.first];
11627330f729Sjoerg     const ThunkInfo &Thunk = TI.second;
11637330f729Sjoerg     const CXXMethodDecl *MD;
11647330f729Sjoerg 
11657330f729Sjoerg     switch (Component.getKind()) {
11667330f729Sjoerg     default:
11677330f729Sjoerg       llvm_unreachable("Unexpected vtable component kind!");
11687330f729Sjoerg     case VTableComponent::CK_FunctionPointer:
11697330f729Sjoerg       MD = Component.getFunctionDecl();
11707330f729Sjoerg       break;
11717330f729Sjoerg     case VTableComponent::CK_CompleteDtorPointer:
11727330f729Sjoerg       MD = Component.getDestructorDecl();
11737330f729Sjoerg       break;
11747330f729Sjoerg     case VTableComponent::CK_DeletingDtorPointer:
11757330f729Sjoerg       // We've already added the thunk when we saw the complete dtor pointer.
11767330f729Sjoerg       continue;
11777330f729Sjoerg     }
11787330f729Sjoerg 
11797330f729Sjoerg     if (MD->getParent() == MostDerivedClass)
11807330f729Sjoerg       AddThunk(MD, Thunk);
11817330f729Sjoerg   }
11827330f729Sjoerg }
11837330f729Sjoerg 
11847330f729Sjoerg ReturnAdjustment
ComputeReturnAdjustment(BaseOffset Offset)11857330f729Sjoerg ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
11867330f729Sjoerg   ReturnAdjustment Adjustment;
11877330f729Sjoerg 
11887330f729Sjoerg   if (!Offset.isEmpty()) {
11897330f729Sjoerg     if (Offset.VirtualBase) {
11907330f729Sjoerg       // Get the virtual base offset offset.
11917330f729Sjoerg       if (Offset.DerivedClass == MostDerivedClass) {
11927330f729Sjoerg         // We can get the offset offset directly from our map.
11937330f729Sjoerg         Adjustment.Virtual.Itanium.VBaseOffsetOffset =
11947330f729Sjoerg           VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
11957330f729Sjoerg       } else {
11967330f729Sjoerg         Adjustment.Virtual.Itanium.VBaseOffsetOffset =
11977330f729Sjoerg           VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
11987330f729Sjoerg                                              Offset.VirtualBase).getQuantity();
11997330f729Sjoerg       }
12007330f729Sjoerg     }
12017330f729Sjoerg 
12027330f729Sjoerg     Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
12037330f729Sjoerg   }
12047330f729Sjoerg 
12057330f729Sjoerg   return Adjustment;
12067330f729Sjoerg }
12077330f729Sjoerg 
ComputeThisAdjustmentBaseOffset(BaseSubobject Base,BaseSubobject Derived) const12087330f729Sjoerg BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
12097330f729Sjoerg     BaseSubobject Base, BaseSubobject Derived) const {
12107330f729Sjoerg   const CXXRecordDecl *BaseRD = Base.getBase();
12117330f729Sjoerg   const CXXRecordDecl *DerivedRD = Derived.getBase();
12127330f729Sjoerg 
12137330f729Sjoerg   CXXBasePaths Paths(/*FindAmbiguities=*/true,
12147330f729Sjoerg                      /*RecordPaths=*/true, /*DetectVirtual=*/true);
12157330f729Sjoerg 
12167330f729Sjoerg   if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
12177330f729Sjoerg     llvm_unreachable("Class must be derived from the passed in base class!");
12187330f729Sjoerg 
12197330f729Sjoerg   // We have to go through all the paths, and see which one leads us to the
12207330f729Sjoerg   // right base subobject.
12217330f729Sjoerg   for (const CXXBasePath &Path : Paths) {
12227330f729Sjoerg     BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path);
12237330f729Sjoerg 
12247330f729Sjoerg     CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
12257330f729Sjoerg 
12267330f729Sjoerg     if (Offset.VirtualBase) {
12277330f729Sjoerg       // If we have a virtual base class, the non-virtual offset is relative
12287330f729Sjoerg       // to the virtual base class offset.
12297330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
12307330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
12317330f729Sjoerg 
12327330f729Sjoerg       /// Get the virtual base offset, relative to the most derived class
12337330f729Sjoerg       /// layout.
12347330f729Sjoerg       OffsetToBaseSubobject +=
12357330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase);
12367330f729Sjoerg     } else {
12377330f729Sjoerg       // Otherwise, the non-virtual offset is relative to the derived class
12387330f729Sjoerg       // offset.
12397330f729Sjoerg       OffsetToBaseSubobject += Derived.getBaseOffset();
12407330f729Sjoerg     }
12417330f729Sjoerg 
12427330f729Sjoerg     // Check if this path gives us the right base subobject.
12437330f729Sjoerg     if (OffsetToBaseSubobject == Base.getBaseOffset()) {
12447330f729Sjoerg       // Since we're going from the base class _to_ the derived class, we'll
12457330f729Sjoerg       // invert the non-virtual offset here.
12467330f729Sjoerg       Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
12477330f729Sjoerg       return Offset;
12487330f729Sjoerg     }
12497330f729Sjoerg   }
12507330f729Sjoerg 
12517330f729Sjoerg   return BaseOffset();
12527330f729Sjoerg }
12537330f729Sjoerg 
ComputeThisAdjustment(const CXXMethodDecl * MD,CharUnits BaseOffsetInLayoutClass,FinalOverriders::OverriderInfo Overrider)12547330f729Sjoerg ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
12557330f729Sjoerg     const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass,
12567330f729Sjoerg     FinalOverriders::OverriderInfo Overrider) {
12577330f729Sjoerg   // Ignore adjustments for pure virtual member functions.
12587330f729Sjoerg   if (Overrider.Method->isPure())
12597330f729Sjoerg     return ThisAdjustment();
12607330f729Sjoerg 
12617330f729Sjoerg   BaseSubobject OverriddenBaseSubobject(MD->getParent(),
12627330f729Sjoerg                                         BaseOffsetInLayoutClass);
12637330f729Sjoerg 
12647330f729Sjoerg   BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
12657330f729Sjoerg                                        Overrider.Offset);
12667330f729Sjoerg 
12677330f729Sjoerg   // Compute the adjustment offset.
12687330f729Sjoerg   BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
12697330f729Sjoerg                                                       OverriderBaseSubobject);
12707330f729Sjoerg   if (Offset.isEmpty())
12717330f729Sjoerg     return ThisAdjustment();
12727330f729Sjoerg 
12737330f729Sjoerg   ThisAdjustment Adjustment;
12747330f729Sjoerg 
12757330f729Sjoerg   if (Offset.VirtualBase) {
12767330f729Sjoerg     // Get the vcall offset map for this virtual base.
12777330f729Sjoerg     VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
12787330f729Sjoerg 
12797330f729Sjoerg     if (VCallOffsets.empty()) {
12807330f729Sjoerg       // We don't have vcall offsets for this virtual base, go ahead and
12817330f729Sjoerg       // build them.
1282*e038c9c4Sjoerg       VCallAndVBaseOffsetBuilder Builder(
1283*e038c9c4Sjoerg           VTables, MostDerivedClass, MostDerivedClass,
12847330f729Sjoerg           /*Overriders=*/nullptr,
1285*e038c9c4Sjoerg           BaseSubobject(Offset.VirtualBase, CharUnits::Zero()),
12867330f729Sjoerg           /*BaseIsVirtual=*/true,
12877330f729Sjoerg           /*OffsetInLayoutClass=*/
12887330f729Sjoerg           CharUnits::Zero());
12897330f729Sjoerg 
12907330f729Sjoerg       VCallOffsets = Builder.getVCallOffsets();
12917330f729Sjoerg     }
12927330f729Sjoerg 
12937330f729Sjoerg     Adjustment.Virtual.Itanium.VCallOffsetOffset =
12947330f729Sjoerg       VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
12957330f729Sjoerg   }
12967330f729Sjoerg 
12977330f729Sjoerg   // Set the non-virtual part of the adjustment.
12987330f729Sjoerg   Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
12997330f729Sjoerg 
13007330f729Sjoerg   return Adjustment;
13017330f729Sjoerg }
13027330f729Sjoerg 
AddMethod(const CXXMethodDecl * MD,ReturnAdjustment ReturnAdjustment)13037330f729Sjoerg void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
13047330f729Sjoerg                                      ReturnAdjustment ReturnAdjustment) {
13057330f729Sjoerg   if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
13067330f729Sjoerg     assert(ReturnAdjustment.isEmpty() &&
13077330f729Sjoerg            "Destructor can't have return adjustment!");
13087330f729Sjoerg 
13097330f729Sjoerg     // Add both the complete destructor and the deleting destructor.
13107330f729Sjoerg     Components.push_back(VTableComponent::MakeCompleteDtor(DD));
13117330f729Sjoerg     Components.push_back(VTableComponent::MakeDeletingDtor(DD));
13127330f729Sjoerg   } else {
13137330f729Sjoerg     // Add the return adjustment if necessary.
13147330f729Sjoerg     if (!ReturnAdjustment.isEmpty())
13157330f729Sjoerg       VTableThunks[Components.size()].Return = ReturnAdjustment;
13167330f729Sjoerg 
13177330f729Sjoerg     // Add the function.
13187330f729Sjoerg     Components.push_back(VTableComponent::MakeFunction(MD));
13197330f729Sjoerg   }
13207330f729Sjoerg }
13217330f729Sjoerg 
13227330f729Sjoerg /// OverridesIndirectMethodInBase - Return whether the given member function
13237330f729Sjoerg /// overrides any methods in the set of given bases.
13247330f729Sjoerg /// Unlike OverridesMethodInBase, this checks "overriders of overriders".
13257330f729Sjoerg /// For example, if we have:
13267330f729Sjoerg ///
13277330f729Sjoerg /// struct A { virtual void f(); }
13287330f729Sjoerg /// struct B : A { virtual void f(); }
13297330f729Sjoerg /// struct C : B { virtual void f(); }
13307330f729Sjoerg ///
13317330f729Sjoerg /// OverridesIndirectMethodInBase will return true if given C::f as the method
13327330f729Sjoerg /// and { A } as the set of bases.
OverridesIndirectMethodInBases(const CXXMethodDecl * MD,ItaniumVTableBuilder::PrimaryBasesSetVectorTy & Bases)13337330f729Sjoerg static bool OverridesIndirectMethodInBases(
13347330f729Sjoerg     const CXXMethodDecl *MD,
13357330f729Sjoerg     ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) {
13367330f729Sjoerg   if (Bases.count(MD->getParent()))
13377330f729Sjoerg     return true;
13387330f729Sjoerg 
13397330f729Sjoerg   for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) {
13407330f729Sjoerg     // Check "indirect overriders".
13417330f729Sjoerg     if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
13427330f729Sjoerg       return true;
13437330f729Sjoerg   }
13447330f729Sjoerg 
13457330f729Sjoerg   return false;
13467330f729Sjoerg }
13477330f729Sjoerg 
IsOverriderUsed(const CXXMethodDecl * Overrider,CharUnits BaseOffsetInLayoutClass,const CXXRecordDecl * FirstBaseInPrimaryBaseChain,CharUnits FirstBaseOffsetInLayoutClass) const13487330f729Sjoerg bool ItaniumVTableBuilder::IsOverriderUsed(
13497330f729Sjoerg     const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass,
13507330f729Sjoerg     const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
13517330f729Sjoerg     CharUnits FirstBaseOffsetInLayoutClass) const {
13527330f729Sjoerg   // If the base and the first base in the primary base chain have the same
13537330f729Sjoerg   // offsets, then this overrider will be used.
13547330f729Sjoerg   if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
13557330f729Sjoerg    return true;
13567330f729Sjoerg 
13577330f729Sjoerg   // We know now that Base (or a direct or indirect base of it) is a primary
13587330f729Sjoerg   // base in part of the class hierarchy, but not a primary base in the most
13597330f729Sjoerg   // derived class.
13607330f729Sjoerg 
13617330f729Sjoerg   // If the overrider is the first base in the primary base chain, we know
13627330f729Sjoerg   // that the overrider will be used.
13637330f729Sjoerg   if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
13647330f729Sjoerg     return true;
13657330f729Sjoerg 
13667330f729Sjoerg   ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
13677330f729Sjoerg 
13687330f729Sjoerg   const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
13697330f729Sjoerg   PrimaryBases.insert(RD);
13707330f729Sjoerg 
13717330f729Sjoerg   // Now traverse the base chain, starting with the first base, until we find
13727330f729Sjoerg   // the base that is no longer a primary base.
13737330f729Sjoerg   while (true) {
13747330f729Sjoerg     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
13757330f729Sjoerg     const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
13767330f729Sjoerg 
13777330f729Sjoerg     if (!PrimaryBase)
13787330f729Sjoerg       break;
13797330f729Sjoerg 
13807330f729Sjoerg     if (Layout.isPrimaryBaseVirtual()) {
13817330f729Sjoerg       assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() &&
13827330f729Sjoerg              "Primary base should always be at offset 0!");
13837330f729Sjoerg 
13847330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
13857330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
13867330f729Sjoerg 
13877330f729Sjoerg       // Now check if this is the primary base that is not a primary base in the
13887330f729Sjoerg       // most derived class.
13897330f729Sjoerg       if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
13907330f729Sjoerg           FirstBaseOffsetInLayoutClass) {
13917330f729Sjoerg         // We found it, stop walking the chain.
13927330f729Sjoerg         break;
13937330f729Sjoerg       }
13947330f729Sjoerg     } else {
13957330f729Sjoerg       assert(Layout.getBaseClassOffset(PrimaryBase).isZero() &&
13967330f729Sjoerg              "Primary base should always be at offset 0!");
13977330f729Sjoerg     }
13987330f729Sjoerg 
13997330f729Sjoerg     if (!PrimaryBases.insert(PrimaryBase))
14007330f729Sjoerg       llvm_unreachable("Found a duplicate primary base!");
14017330f729Sjoerg 
14027330f729Sjoerg     RD = PrimaryBase;
14037330f729Sjoerg   }
14047330f729Sjoerg 
14057330f729Sjoerg   // If the final overrider is an override of one of the primary bases,
14067330f729Sjoerg   // then we know that it will be used.
14077330f729Sjoerg   return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
14087330f729Sjoerg }
14097330f729Sjoerg 
14107330f729Sjoerg typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy;
14117330f729Sjoerg 
14127330f729Sjoerg /// FindNearestOverriddenMethod - Given a method, returns the overridden method
14137330f729Sjoerg /// from the nearest base. Returns null if no method was found.
14147330f729Sjoerg /// The Bases are expected to be sorted in a base-to-derived order.
14157330f729Sjoerg static const CXXMethodDecl *
FindNearestOverriddenMethod(const CXXMethodDecl * MD,BasesSetVectorTy & Bases)14167330f729Sjoerg FindNearestOverriddenMethod(const CXXMethodDecl *MD,
14177330f729Sjoerg                             BasesSetVectorTy &Bases) {
14187330f729Sjoerg   OverriddenMethodsSetTy OverriddenMethods;
14197330f729Sjoerg   ComputeAllOverriddenMethods(MD, OverriddenMethods);
14207330f729Sjoerg 
14217330f729Sjoerg   for (const CXXRecordDecl *PrimaryBase :
14227330f729Sjoerg        llvm::make_range(Bases.rbegin(), Bases.rend())) {
14237330f729Sjoerg     // Now check the overridden methods.
14247330f729Sjoerg     for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) {
14257330f729Sjoerg       // We found our overridden method.
14267330f729Sjoerg       if (OverriddenMD->getParent() == PrimaryBase)
14277330f729Sjoerg         return OverriddenMD;
14287330f729Sjoerg     }
14297330f729Sjoerg   }
14307330f729Sjoerg 
14317330f729Sjoerg   return nullptr;
14327330f729Sjoerg }
14337330f729Sjoerg 
AddMethods(BaseSubobject Base,CharUnits BaseOffsetInLayoutClass,const CXXRecordDecl * FirstBaseInPrimaryBaseChain,CharUnits FirstBaseOffsetInLayoutClass,PrimaryBasesSetVectorTy & PrimaryBases)14347330f729Sjoerg void ItaniumVTableBuilder::AddMethods(
14357330f729Sjoerg     BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
14367330f729Sjoerg     const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
14377330f729Sjoerg     CharUnits FirstBaseOffsetInLayoutClass,
14387330f729Sjoerg     PrimaryBasesSetVectorTy &PrimaryBases) {
14397330f729Sjoerg   // Itanium C++ ABI 2.5.2:
14407330f729Sjoerg   //   The order of the virtual function pointers in a virtual table is the
14417330f729Sjoerg   //   order of declaration of the corresponding member functions in the class.
14427330f729Sjoerg   //
14437330f729Sjoerg   //   There is an entry for any virtual function declared in a class,
14447330f729Sjoerg   //   whether it is a new function or overrides a base class function,
14457330f729Sjoerg   //   unless it overrides a function from the primary base, and conversion
14467330f729Sjoerg   //   between their return types does not require an adjustment.
14477330f729Sjoerg 
14487330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
14497330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
14507330f729Sjoerg 
14517330f729Sjoerg   if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
14527330f729Sjoerg     CharUnits PrimaryBaseOffset;
14537330f729Sjoerg     CharUnits PrimaryBaseOffsetInLayoutClass;
14547330f729Sjoerg     if (Layout.isPrimaryBaseVirtual()) {
14557330f729Sjoerg       assert(Layout.getVBaseClassOffset(PrimaryBase).isZero() &&
14567330f729Sjoerg              "Primary vbase should have a zero offset!");
14577330f729Sjoerg 
14587330f729Sjoerg       const ASTRecordLayout &MostDerivedClassLayout =
14597330f729Sjoerg         Context.getASTRecordLayout(MostDerivedClass);
14607330f729Sjoerg 
14617330f729Sjoerg       PrimaryBaseOffset =
14627330f729Sjoerg         MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
14637330f729Sjoerg 
14647330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
14657330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
14667330f729Sjoerg 
14677330f729Sjoerg       PrimaryBaseOffsetInLayoutClass =
14687330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
14697330f729Sjoerg     } else {
14707330f729Sjoerg       assert(Layout.getBaseClassOffset(PrimaryBase).isZero() &&
14717330f729Sjoerg              "Primary base should have a zero offset!");
14727330f729Sjoerg 
14737330f729Sjoerg       PrimaryBaseOffset = Base.getBaseOffset();
14747330f729Sjoerg       PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
14757330f729Sjoerg     }
14767330f729Sjoerg 
14777330f729Sjoerg     AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
14787330f729Sjoerg                PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
14797330f729Sjoerg                FirstBaseOffsetInLayoutClass, PrimaryBases);
14807330f729Sjoerg 
14817330f729Sjoerg     if (!PrimaryBases.insert(PrimaryBase))
14827330f729Sjoerg       llvm_unreachable("Found a duplicate primary base!");
14837330f729Sjoerg   }
14847330f729Sjoerg 
14857330f729Sjoerg   typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
14867330f729Sjoerg   NewVirtualFunctionsTy NewVirtualFunctions;
14877330f729Sjoerg 
1488*e038c9c4Sjoerg   llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions;
1489*e038c9c4Sjoerg 
14907330f729Sjoerg   // Now go through all virtual member functions and add them.
14917330f729Sjoerg   for (const auto *MD : RD->methods()) {
1492*e038c9c4Sjoerg     if (!ItaniumVTableContext::hasVtableSlot(MD))
14937330f729Sjoerg       continue;
14947330f729Sjoerg     MD = MD->getCanonicalDecl();
14957330f729Sjoerg 
14967330f729Sjoerg     // Get the final overrider.
14977330f729Sjoerg     FinalOverriders::OverriderInfo Overrider =
14987330f729Sjoerg       Overriders.getOverrider(MD, Base.getBaseOffset());
14997330f729Sjoerg 
15007330f729Sjoerg     // Check if this virtual member function overrides a method in a primary
15017330f729Sjoerg     // base. If this is the case, and the return type doesn't require adjustment
15027330f729Sjoerg     // then we can just use the member function from the primary base.
15037330f729Sjoerg     if (const CXXMethodDecl *OverriddenMD =
15047330f729Sjoerg           FindNearestOverriddenMethod(MD, PrimaryBases)) {
15057330f729Sjoerg       if (ComputeReturnAdjustmentBaseOffset(Context, MD,
15067330f729Sjoerg                                             OverriddenMD).isEmpty()) {
15077330f729Sjoerg         // Replace the method info of the overridden method with our own
15087330f729Sjoerg         // method.
15097330f729Sjoerg         assert(MethodInfoMap.count(OverriddenMD) &&
15107330f729Sjoerg                "Did not find the overridden method!");
15117330f729Sjoerg         MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
15127330f729Sjoerg 
15137330f729Sjoerg         MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
15147330f729Sjoerg                               OverriddenMethodInfo.VTableIndex);
15157330f729Sjoerg 
15167330f729Sjoerg         assert(!MethodInfoMap.count(MD) &&
15177330f729Sjoerg                "Should not have method info for this method yet!");
15187330f729Sjoerg 
15197330f729Sjoerg         MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
15207330f729Sjoerg         MethodInfoMap.erase(OverriddenMD);
15217330f729Sjoerg 
15227330f729Sjoerg         // If the overridden method exists in a virtual base class or a direct
15237330f729Sjoerg         // or indirect base class of a virtual base class, we need to emit a
15247330f729Sjoerg         // thunk if we ever have a class hierarchy where the base class is not
15257330f729Sjoerg         // a primary base in the complete object.
15267330f729Sjoerg         if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
15277330f729Sjoerg           // Compute the this adjustment.
15287330f729Sjoerg           ThisAdjustment ThisAdjustment =
15297330f729Sjoerg             ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
15307330f729Sjoerg                                   Overrider);
15317330f729Sjoerg 
15327330f729Sjoerg           if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset &&
15337330f729Sjoerg               Overrider.Method->getParent() == MostDerivedClass) {
15347330f729Sjoerg 
15357330f729Sjoerg             // There's no return adjustment from OverriddenMD and MD,
15367330f729Sjoerg             // but that doesn't mean there isn't one between MD and
15377330f729Sjoerg             // the final overrider.
15387330f729Sjoerg             BaseOffset ReturnAdjustmentOffset =
15397330f729Sjoerg               ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
15407330f729Sjoerg             ReturnAdjustment ReturnAdjustment =
15417330f729Sjoerg               ComputeReturnAdjustment(ReturnAdjustmentOffset);
15427330f729Sjoerg 
15437330f729Sjoerg             // This is a virtual thunk for the most derived class, add it.
15447330f729Sjoerg             AddThunk(Overrider.Method,
15457330f729Sjoerg                      ThunkInfo(ThisAdjustment, ReturnAdjustment));
15467330f729Sjoerg           }
15477330f729Sjoerg         }
15487330f729Sjoerg 
15497330f729Sjoerg         continue;
15507330f729Sjoerg       }
15517330f729Sjoerg     }
15527330f729Sjoerg 
1553*e038c9c4Sjoerg     if (MD->isImplicit())
1554*e038c9c4Sjoerg       NewImplicitVirtualFunctions.push_back(MD);
1555*e038c9c4Sjoerg     else
15567330f729Sjoerg       NewVirtualFunctions.push_back(MD);
15577330f729Sjoerg   }
15587330f729Sjoerg 
1559*e038c9c4Sjoerg   std::stable_sort(
1560*e038c9c4Sjoerg       NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
1561*e038c9c4Sjoerg       [](const CXXMethodDecl *A, const CXXMethodDecl *B) {
1562*e038c9c4Sjoerg         if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
1563*e038c9c4Sjoerg           return A->isCopyAssignmentOperator();
1564*e038c9c4Sjoerg         if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
1565*e038c9c4Sjoerg           return A->isMoveAssignmentOperator();
1566*e038c9c4Sjoerg         if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
1567*e038c9c4Sjoerg           return isa<CXXDestructorDecl>(A);
1568*e038c9c4Sjoerg         assert(A->getOverloadedOperator() == OO_EqualEqual &&
1569*e038c9c4Sjoerg                B->getOverloadedOperator() == OO_EqualEqual &&
1570*e038c9c4Sjoerg                "unexpected or duplicate implicit virtual function");
1571*e038c9c4Sjoerg         // We rely on Sema to have declared the operator== members in the
1572*e038c9c4Sjoerg         // same order as the corresponding operator<=> members.
1573*e038c9c4Sjoerg         return false;
1574*e038c9c4Sjoerg       });
1575*e038c9c4Sjoerg   NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1576*e038c9c4Sjoerg                              NewImplicitVirtualFunctions.end());
15777330f729Sjoerg 
15787330f729Sjoerg   for (const CXXMethodDecl *MD : NewVirtualFunctions) {
15797330f729Sjoerg     // Get the final overrider.
15807330f729Sjoerg     FinalOverriders::OverriderInfo Overrider =
15817330f729Sjoerg       Overriders.getOverrider(MD, Base.getBaseOffset());
15827330f729Sjoerg 
15837330f729Sjoerg     // Insert the method info for this method.
15847330f729Sjoerg     MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
15857330f729Sjoerg                           Components.size());
15867330f729Sjoerg 
15877330f729Sjoerg     assert(!MethodInfoMap.count(MD) &&
15887330f729Sjoerg            "Should not have method info for this method yet!");
15897330f729Sjoerg     MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
15907330f729Sjoerg 
15917330f729Sjoerg     // Check if this overrider is going to be used.
15927330f729Sjoerg     const CXXMethodDecl *OverriderMD = Overrider.Method;
15937330f729Sjoerg     if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
15947330f729Sjoerg                          FirstBaseInPrimaryBaseChain,
15957330f729Sjoerg                          FirstBaseOffsetInLayoutClass)) {
15967330f729Sjoerg       Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
15977330f729Sjoerg       continue;
15987330f729Sjoerg     }
15997330f729Sjoerg 
16007330f729Sjoerg     // Check if this overrider needs a return adjustment.
16017330f729Sjoerg     // We don't want to do this for pure virtual member functions.
16027330f729Sjoerg     BaseOffset ReturnAdjustmentOffset;
16037330f729Sjoerg     if (!OverriderMD->isPure()) {
16047330f729Sjoerg       ReturnAdjustmentOffset =
16057330f729Sjoerg         ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
16067330f729Sjoerg     }
16077330f729Sjoerg 
16087330f729Sjoerg     ReturnAdjustment ReturnAdjustment =
16097330f729Sjoerg       ComputeReturnAdjustment(ReturnAdjustmentOffset);
16107330f729Sjoerg 
16117330f729Sjoerg     AddMethod(Overrider.Method, ReturnAdjustment);
16127330f729Sjoerg   }
16137330f729Sjoerg }
16147330f729Sjoerg 
LayoutVTable()16157330f729Sjoerg void ItaniumVTableBuilder::LayoutVTable() {
16167330f729Sjoerg   LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
16177330f729Sjoerg                                                  CharUnits::Zero()),
16187330f729Sjoerg                                    /*BaseIsMorallyVirtual=*/false,
16197330f729Sjoerg                                    MostDerivedClassIsVirtual,
16207330f729Sjoerg                                    MostDerivedClassOffset);
16217330f729Sjoerg 
16227330f729Sjoerg   VisitedVirtualBasesSetTy VBases;
16237330f729Sjoerg 
16247330f729Sjoerg   // Determine the primary virtual bases.
16257330f729Sjoerg   DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
16267330f729Sjoerg                                VBases);
16277330f729Sjoerg   VBases.clear();
16287330f729Sjoerg 
16297330f729Sjoerg   LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
16307330f729Sjoerg 
16317330f729Sjoerg   // -fapple-kext adds an extra entry at end of vtbl.
16327330f729Sjoerg   bool IsAppleKext = Context.getLangOpts().AppleKext;
16337330f729Sjoerg   if (IsAppleKext)
16347330f729Sjoerg     Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero()));
16357330f729Sjoerg }
16367330f729Sjoerg 
LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,bool BaseIsMorallyVirtual,bool BaseIsVirtualInLayoutClass,CharUnits OffsetInLayoutClass)16377330f729Sjoerg void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
16387330f729Sjoerg     BaseSubobject Base, bool BaseIsMorallyVirtual,
16397330f729Sjoerg     bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) {
16407330f729Sjoerg   assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
16417330f729Sjoerg 
16427330f729Sjoerg   unsigned VTableIndex = Components.size();
16437330f729Sjoerg   VTableIndices.push_back(VTableIndex);
16447330f729Sjoerg 
16457330f729Sjoerg   // Add vcall and vbase offsets for this vtable.
1646*e038c9c4Sjoerg   VCallAndVBaseOffsetBuilder Builder(
1647*e038c9c4Sjoerg       VTables, MostDerivedClass, LayoutClass, &Overriders, Base,
1648*e038c9c4Sjoerg       BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
16497330f729Sjoerg   Components.append(Builder.components_begin(), Builder.components_end());
16507330f729Sjoerg 
16517330f729Sjoerg   // Check if we need to add these vcall offsets.
16527330f729Sjoerg   if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
16537330f729Sjoerg     VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
16547330f729Sjoerg 
16557330f729Sjoerg     if (VCallOffsets.empty())
16567330f729Sjoerg       VCallOffsets = Builder.getVCallOffsets();
16577330f729Sjoerg   }
16587330f729Sjoerg 
16597330f729Sjoerg   // If we're laying out the most derived class we want to keep track of the
16607330f729Sjoerg   // virtual base class offset offsets.
16617330f729Sjoerg   if (Base.getBase() == MostDerivedClass)
16627330f729Sjoerg     VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
16637330f729Sjoerg 
16647330f729Sjoerg   // Add the offset to top.
16657330f729Sjoerg   CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
16667330f729Sjoerg   Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
16677330f729Sjoerg 
16687330f729Sjoerg   // Next, add the RTTI.
16697330f729Sjoerg   Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
16707330f729Sjoerg 
16717330f729Sjoerg   uint64_t AddressPoint = Components.size();
16727330f729Sjoerg 
16737330f729Sjoerg   // Now go through all virtual member functions and add them.
16747330f729Sjoerg   PrimaryBasesSetVectorTy PrimaryBases;
16757330f729Sjoerg   AddMethods(Base, OffsetInLayoutClass,
16767330f729Sjoerg              Base.getBase(), OffsetInLayoutClass,
16777330f729Sjoerg              PrimaryBases);
16787330f729Sjoerg 
16797330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
16807330f729Sjoerg   if (RD == MostDerivedClass) {
16817330f729Sjoerg     assert(MethodVTableIndices.empty());
16827330f729Sjoerg     for (const auto &I : MethodInfoMap) {
16837330f729Sjoerg       const CXXMethodDecl *MD = I.first;
16847330f729Sjoerg       const MethodInfo &MI = I.second;
16857330f729Sjoerg       if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
16867330f729Sjoerg         MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
16877330f729Sjoerg             = MI.VTableIndex - AddressPoint;
16887330f729Sjoerg         MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
16897330f729Sjoerg             = MI.VTableIndex + 1 - AddressPoint;
16907330f729Sjoerg       } else {
16917330f729Sjoerg         MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
16927330f729Sjoerg       }
16937330f729Sjoerg     }
16947330f729Sjoerg   }
16957330f729Sjoerg 
16967330f729Sjoerg   // Compute 'this' pointer adjustments.
16977330f729Sjoerg   ComputeThisAdjustments();
16987330f729Sjoerg 
16997330f729Sjoerg   // Add all address points.
17007330f729Sjoerg   while (true) {
17017330f729Sjoerg     AddressPoints.insert(
17027330f729Sjoerg         std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
17037330f729Sjoerg                        VTableLayout::AddressPointLocation{
17047330f729Sjoerg                            unsigned(VTableIndices.size() - 1),
17057330f729Sjoerg                            unsigned(AddressPoint - VTableIndex)}));
17067330f729Sjoerg 
17077330f729Sjoerg     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
17087330f729Sjoerg     const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
17097330f729Sjoerg 
17107330f729Sjoerg     if (!PrimaryBase)
17117330f729Sjoerg       break;
17127330f729Sjoerg 
17137330f729Sjoerg     if (Layout.isPrimaryBaseVirtual()) {
17147330f729Sjoerg       // Check if this virtual primary base is a primary base in the layout
17157330f729Sjoerg       // class. If it's not, we don't want to add it.
17167330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
17177330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
17187330f729Sjoerg 
17197330f729Sjoerg       if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
17207330f729Sjoerg           OffsetInLayoutClass) {
17217330f729Sjoerg         // We don't want to add this class (or any of its primary bases).
17227330f729Sjoerg         break;
17237330f729Sjoerg       }
17247330f729Sjoerg     }
17257330f729Sjoerg 
17267330f729Sjoerg     RD = PrimaryBase;
17277330f729Sjoerg   }
17287330f729Sjoerg 
17297330f729Sjoerg   // Layout secondary vtables.
17307330f729Sjoerg   LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
17317330f729Sjoerg }
17327330f729Sjoerg 
17337330f729Sjoerg void
LayoutSecondaryVTables(BaseSubobject Base,bool BaseIsMorallyVirtual,CharUnits OffsetInLayoutClass)17347330f729Sjoerg ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
17357330f729Sjoerg                                              bool BaseIsMorallyVirtual,
17367330f729Sjoerg                                              CharUnits OffsetInLayoutClass) {
17377330f729Sjoerg   // Itanium C++ ABI 2.5.2:
17387330f729Sjoerg   //   Following the primary virtual table of a derived class are secondary
17397330f729Sjoerg   //   virtual tables for each of its proper base classes, except any primary
17407330f729Sjoerg   //   base(s) with which it shares its primary virtual table.
17417330f729Sjoerg 
17427330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
17437330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
17447330f729Sjoerg   const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
17457330f729Sjoerg 
17467330f729Sjoerg   for (const auto &B : RD->bases()) {
17477330f729Sjoerg     // Ignore virtual bases, we'll emit them later.
17487330f729Sjoerg     if (B.isVirtual())
17497330f729Sjoerg       continue;
17507330f729Sjoerg 
17517330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
17527330f729Sjoerg 
17537330f729Sjoerg     // Ignore bases that don't have a vtable.
17547330f729Sjoerg     if (!BaseDecl->isDynamicClass())
17557330f729Sjoerg       continue;
17567330f729Sjoerg 
17577330f729Sjoerg     if (isBuildingConstructorVTable()) {
17587330f729Sjoerg       // Itanium C++ ABI 2.6.4:
17597330f729Sjoerg       //   Some of the base class subobjects may not need construction virtual
17607330f729Sjoerg       //   tables, which will therefore not be present in the construction
17617330f729Sjoerg       //   virtual table group, even though the subobject virtual tables are
17627330f729Sjoerg       //   present in the main virtual table group for the complete object.
17637330f729Sjoerg       if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
17647330f729Sjoerg         continue;
17657330f729Sjoerg     }
17667330f729Sjoerg 
17677330f729Sjoerg     // Get the base offset of this base.
17687330f729Sjoerg     CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl);
17697330f729Sjoerg     CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
17707330f729Sjoerg 
17717330f729Sjoerg     CharUnits BaseOffsetInLayoutClass =
17727330f729Sjoerg       OffsetInLayoutClass + RelativeBaseOffset;
17737330f729Sjoerg 
17747330f729Sjoerg     // Don't emit a secondary vtable for a primary base. We might however want
17757330f729Sjoerg     // to emit secondary vtables for other bases of this base.
17767330f729Sjoerg     if (BaseDecl == PrimaryBase) {
17777330f729Sjoerg       LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
17787330f729Sjoerg                              BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
17797330f729Sjoerg       continue;
17807330f729Sjoerg     }
17817330f729Sjoerg 
17827330f729Sjoerg     // Layout the primary vtable (and any secondary vtables) for this base.
17837330f729Sjoerg     LayoutPrimaryAndSecondaryVTables(
17847330f729Sjoerg       BaseSubobject(BaseDecl, BaseOffset),
17857330f729Sjoerg       BaseIsMorallyVirtual,
17867330f729Sjoerg       /*BaseIsVirtualInLayoutClass=*/false,
17877330f729Sjoerg       BaseOffsetInLayoutClass);
17887330f729Sjoerg   }
17897330f729Sjoerg }
17907330f729Sjoerg 
DeterminePrimaryVirtualBases(const CXXRecordDecl * RD,CharUnits OffsetInLayoutClass,VisitedVirtualBasesSetTy & VBases)17917330f729Sjoerg void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
17927330f729Sjoerg     const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass,
17937330f729Sjoerg     VisitedVirtualBasesSetTy &VBases) {
17947330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
17957330f729Sjoerg 
17967330f729Sjoerg   // Check if this base has a primary base.
17977330f729Sjoerg   if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
17987330f729Sjoerg 
17997330f729Sjoerg     // Check if it's virtual.
18007330f729Sjoerg     if (Layout.isPrimaryBaseVirtual()) {
18017330f729Sjoerg       bool IsPrimaryVirtualBase = true;
18027330f729Sjoerg 
18037330f729Sjoerg       if (isBuildingConstructorVTable()) {
18047330f729Sjoerg         // Check if the base is actually a primary base in the class we use for
18057330f729Sjoerg         // layout.
18067330f729Sjoerg         const ASTRecordLayout &LayoutClassLayout =
18077330f729Sjoerg           Context.getASTRecordLayout(LayoutClass);
18087330f729Sjoerg 
18097330f729Sjoerg         CharUnits PrimaryBaseOffsetInLayoutClass =
18107330f729Sjoerg           LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
18117330f729Sjoerg 
18127330f729Sjoerg         // We know that the base is not a primary base in the layout class if
18137330f729Sjoerg         // the base offsets are different.
18147330f729Sjoerg         if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
18157330f729Sjoerg           IsPrimaryVirtualBase = false;
18167330f729Sjoerg       }
18177330f729Sjoerg 
18187330f729Sjoerg       if (IsPrimaryVirtualBase)
18197330f729Sjoerg         PrimaryVirtualBases.insert(PrimaryBase);
18207330f729Sjoerg     }
18217330f729Sjoerg   }
18227330f729Sjoerg 
18237330f729Sjoerg   // Traverse bases, looking for more primary virtual bases.
18247330f729Sjoerg   for (const auto &B : RD->bases()) {
18257330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
18267330f729Sjoerg 
18277330f729Sjoerg     CharUnits BaseOffsetInLayoutClass;
18287330f729Sjoerg 
18297330f729Sjoerg     if (B.isVirtual()) {
18307330f729Sjoerg       if (!VBases.insert(BaseDecl).second)
18317330f729Sjoerg         continue;
18327330f729Sjoerg 
18337330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
18347330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
18357330f729Sjoerg 
18367330f729Sjoerg       BaseOffsetInLayoutClass =
18377330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(BaseDecl);
18387330f729Sjoerg     } else {
18397330f729Sjoerg       BaseOffsetInLayoutClass =
18407330f729Sjoerg         OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl);
18417330f729Sjoerg     }
18427330f729Sjoerg 
18437330f729Sjoerg     DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
18447330f729Sjoerg   }
18457330f729Sjoerg }
18467330f729Sjoerg 
LayoutVTablesForVirtualBases(const CXXRecordDecl * RD,VisitedVirtualBasesSetTy & VBases)18477330f729Sjoerg void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
18487330f729Sjoerg     const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
18497330f729Sjoerg   // Itanium C++ ABI 2.5.2:
18507330f729Sjoerg   //   Then come the virtual base virtual tables, also in inheritance graph
18517330f729Sjoerg   //   order, and again excluding primary bases (which share virtual tables with
18527330f729Sjoerg   //   the classes for which they are primary).
18537330f729Sjoerg   for (const auto &B : RD->bases()) {
18547330f729Sjoerg     const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
18557330f729Sjoerg 
18567330f729Sjoerg     // Check if this base needs a vtable. (If it's virtual, not a primary base
18577330f729Sjoerg     // of some other class, and we haven't visited it before).
18587330f729Sjoerg     if (B.isVirtual() && BaseDecl->isDynamicClass() &&
18597330f729Sjoerg         !PrimaryVirtualBases.count(BaseDecl) &&
18607330f729Sjoerg         VBases.insert(BaseDecl).second) {
18617330f729Sjoerg       const ASTRecordLayout &MostDerivedClassLayout =
18627330f729Sjoerg         Context.getASTRecordLayout(MostDerivedClass);
18637330f729Sjoerg       CharUnits BaseOffset =
18647330f729Sjoerg         MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
18657330f729Sjoerg 
18667330f729Sjoerg       const ASTRecordLayout &LayoutClassLayout =
18677330f729Sjoerg         Context.getASTRecordLayout(LayoutClass);
18687330f729Sjoerg       CharUnits BaseOffsetInLayoutClass =
18697330f729Sjoerg         LayoutClassLayout.getVBaseClassOffset(BaseDecl);
18707330f729Sjoerg 
18717330f729Sjoerg       LayoutPrimaryAndSecondaryVTables(
18727330f729Sjoerg         BaseSubobject(BaseDecl, BaseOffset),
18737330f729Sjoerg         /*BaseIsMorallyVirtual=*/true,
18747330f729Sjoerg         /*BaseIsVirtualInLayoutClass=*/true,
18757330f729Sjoerg         BaseOffsetInLayoutClass);
18767330f729Sjoerg     }
18777330f729Sjoerg 
18787330f729Sjoerg     // We only need to check the base for virtual base vtables if it actually
18797330f729Sjoerg     // has virtual bases.
18807330f729Sjoerg     if (BaseDecl->getNumVBases())
18817330f729Sjoerg       LayoutVTablesForVirtualBases(BaseDecl, VBases);
18827330f729Sjoerg   }
18837330f729Sjoerg }
18847330f729Sjoerg 
18857330f729Sjoerg /// dumpLayout - Dump the vtable layout.
dumpLayout(raw_ostream & Out)18867330f729Sjoerg void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
18877330f729Sjoerg   // FIXME: write more tests that actually use the dumpLayout output to prevent
18887330f729Sjoerg   // ItaniumVTableBuilder regressions.
18897330f729Sjoerg 
18907330f729Sjoerg   if (isBuildingConstructorVTable()) {
18917330f729Sjoerg     Out << "Construction vtable for ('";
18927330f729Sjoerg     MostDerivedClass->printQualifiedName(Out);
18937330f729Sjoerg     Out << "', ";
18947330f729Sjoerg     Out << MostDerivedClassOffset.getQuantity() << ") in '";
18957330f729Sjoerg     LayoutClass->printQualifiedName(Out);
18967330f729Sjoerg   } else {
18977330f729Sjoerg     Out << "Vtable for '";
18987330f729Sjoerg     MostDerivedClass->printQualifiedName(Out);
18997330f729Sjoerg   }
19007330f729Sjoerg   Out << "' (" << Components.size() << " entries).\n";
19017330f729Sjoerg 
19027330f729Sjoerg   // Iterate through the address points and insert them into a new map where
19037330f729Sjoerg   // they are keyed by the index and not the base object.
19047330f729Sjoerg   // Since an address point can be shared by multiple subobjects, we use an
19057330f729Sjoerg   // STL multimap.
19067330f729Sjoerg   std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
19077330f729Sjoerg   for (const auto &AP : AddressPoints) {
19087330f729Sjoerg     const BaseSubobject &Base = AP.first;
19097330f729Sjoerg     uint64_t Index =
19107330f729Sjoerg         VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex;
19117330f729Sjoerg 
19127330f729Sjoerg     AddressPointsByIndex.insert(std::make_pair(Index, Base));
19137330f729Sjoerg   }
19147330f729Sjoerg 
19157330f729Sjoerg   for (unsigned I = 0, E = Components.size(); I != E; ++I) {
19167330f729Sjoerg     uint64_t Index = I;
19177330f729Sjoerg 
19187330f729Sjoerg     Out << llvm::format("%4d | ", I);
19197330f729Sjoerg 
19207330f729Sjoerg     const VTableComponent &Component = Components[I];
19217330f729Sjoerg 
19227330f729Sjoerg     // Dump the component.
19237330f729Sjoerg     switch (Component.getKind()) {
19247330f729Sjoerg 
19257330f729Sjoerg     case VTableComponent::CK_VCallOffset:
19267330f729Sjoerg       Out << "vcall_offset ("
19277330f729Sjoerg           << Component.getVCallOffset().getQuantity()
19287330f729Sjoerg           << ")";
19297330f729Sjoerg       break;
19307330f729Sjoerg 
19317330f729Sjoerg     case VTableComponent::CK_VBaseOffset:
19327330f729Sjoerg       Out << "vbase_offset ("
19337330f729Sjoerg           << Component.getVBaseOffset().getQuantity()
19347330f729Sjoerg           << ")";
19357330f729Sjoerg       break;
19367330f729Sjoerg 
19377330f729Sjoerg     case VTableComponent::CK_OffsetToTop:
19387330f729Sjoerg       Out << "offset_to_top ("
19397330f729Sjoerg           << Component.getOffsetToTop().getQuantity()
19407330f729Sjoerg           << ")";
19417330f729Sjoerg       break;
19427330f729Sjoerg 
19437330f729Sjoerg     case VTableComponent::CK_RTTI:
19447330f729Sjoerg       Component.getRTTIDecl()->printQualifiedName(Out);
19457330f729Sjoerg       Out << " RTTI";
19467330f729Sjoerg       break;
19477330f729Sjoerg 
19487330f729Sjoerg     case VTableComponent::CK_FunctionPointer: {
19497330f729Sjoerg       const CXXMethodDecl *MD = Component.getFunctionDecl();
19507330f729Sjoerg 
19517330f729Sjoerg       std::string Str =
19527330f729Sjoerg         PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
19537330f729Sjoerg                                     MD);
19547330f729Sjoerg       Out << Str;
19557330f729Sjoerg       if (MD->isPure())
19567330f729Sjoerg         Out << " [pure]";
19577330f729Sjoerg 
19587330f729Sjoerg       if (MD->isDeleted())
19597330f729Sjoerg         Out << " [deleted]";
19607330f729Sjoerg 
19617330f729Sjoerg       ThunkInfo Thunk = VTableThunks.lookup(I);
19627330f729Sjoerg       if (!Thunk.isEmpty()) {
19637330f729Sjoerg         // If this function pointer has a return adjustment, dump it.
19647330f729Sjoerg         if (!Thunk.Return.isEmpty()) {
19657330f729Sjoerg           Out << "\n       [return adjustment: ";
19667330f729Sjoerg           Out << Thunk.Return.NonVirtual << " non-virtual";
19677330f729Sjoerg 
19687330f729Sjoerg           if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
19697330f729Sjoerg             Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
19707330f729Sjoerg             Out << " vbase offset offset";
19717330f729Sjoerg           }
19727330f729Sjoerg 
19737330f729Sjoerg           Out << ']';
19747330f729Sjoerg         }
19757330f729Sjoerg 
19767330f729Sjoerg         // If this function pointer has a 'this' pointer adjustment, dump it.
19777330f729Sjoerg         if (!Thunk.This.isEmpty()) {
19787330f729Sjoerg           Out << "\n       [this adjustment: ";
19797330f729Sjoerg           Out << Thunk.This.NonVirtual << " non-virtual";
19807330f729Sjoerg 
19817330f729Sjoerg           if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
19827330f729Sjoerg             Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
19837330f729Sjoerg             Out << " vcall offset offset";
19847330f729Sjoerg           }
19857330f729Sjoerg 
19867330f729Sjoerg           Out << ']';
19877330f729Sjoerg         }
19887330f729Sjoerg       }
19897330f729Sjoerg 
19907330f729Sjoerg       break;
19917330f729Sjoerg     }
19927330f729Sjoerg 
19937330f729Sjoerg     case VTableComponent::CK_CompleteDtorPointer:
19947330f729Sjoerg     case VTableComponent::CK_DeletingDtorPointer: {
19957330f729Sjoerg       bool IsComplete =
19967330f729Sjoerg         Component.getKind() == VTableComponent::CK_CompleteDtorPointer;
19977330f729Sjoerg 
19987330f729Sjoerg       const CXXDestructorDecl *DD = Component.getDestructorDecl();
19997330f729Sjoerg 
20007330f729Sjoerg       DD->printQualifiedName(Out);
20017330f729Sjoerg       if (IsComplete)
20027330f729Sjoerg         Out << "() [complete]";
20037330f729Sjoerg       else
20047330f729Sjoerg         Out << "() [deleting]";
20057330f729Sjoerg 
20067330f729Sjoerg       if (DD->isPure())
20077330f729Sjoerg         Out << " [pure]";
20087330f729Sjoerg 
20097330f729Sjoerg       ThunkInfo Thunk = VTableThunks.lookup(I);
20107330f729Sjoerg       if (!Thunk.isEmpty()) {
20117330f729Sjoerg         // If this destructor has a 'this' pointer adjustment, dump it.
20127330f729Sjoerg         if (!Thunk.This.isEmpty()) {
20137330f729Sjoerg           Out << "\n       [this adjustment: ";
20147330f729Sjoerg           Out << Thunk.This.NonVirtual << " non-virtual";
20157330f729Sjoerg 
20167330f729Sjoerg           if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
20177330f729Sjoerg             Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
20187330f729Sjoerg             Out << " vcall offset offset";
20197330f729Sjoerg           }
20207330f729Sjoerg 
20217330f729Sjoerg           Out << ']';
20227330f729Sjoerg         }
20237330f729Sjoerg       }
20247330f729Sjoerg 
20257330f729Sjoerg       break;
20267330f729Sjoerg     }
20277330f729Sjoerg 
20287330f729Sjoerg     case VTableComponent::CK_UnusedFunctionPointer: {
20297330f729Sjoerg       const CXXMethodDecl *MD = Component.getUnusedFunctionDecl();
20307330f729Sjoerg 
20317330f729Sjoerg       std::string Str =
20327330f729Sjoerg         PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
20337330f729Sjoerg                                     MD);
20347330f729Sjoerg       Out << "[unused] " << Str;
20357330f729Sjoerg       if (MD->isPure())
20367330f729Sjoerg         Out << " [pure]";
20377330f729Sjoerg     }
20387330f729Sjoerg 
20397330f729Sjoerg     }
20407330f729Sjoerg 
20417330f729Sjoerg     Out << '\n';
20427330f729Sjoerg 
20437330f729Sjoerg     // Dump the next address point.
20447330f729Sjoerg     uint64_t NextIndex = Index + 1;
20457330f729Sjoerg     if (AddressPointsByIndex.count(NextIndex)) {
20467330f729Sjoerg       if (AddressPointsByIndex.count(NextIndex) == 1) {
20477330f729Sjoerg         const BaseSubobject &Base =
20487330f729Sjoerg           AddressPointsByIndex.find(NextIndex)->second;
20497330f729Sjoerg 
20507330f729Sjoerg         Out << "       -- (";
20517330f729Sjoerg         Base.getBase()->printQualifiedName(Out);
20527330f729Sjoerg         Out << ", " << Base.getBaseOffset().getQuantity();
20537330f729Sjoerg         Out << ") vtable address --\n";
20547330f729Sjoerg       } else {
20557330f729Sjoerg         CharUnits BaseOffset =
20567330f729Sjoerg           AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
20577330f729Sjoerg 
20587330f729Sjoerg         // We store the class names in a set to get a stable order.
20597330f729Sjoerg         std::set<std::string> ClassNames;
20607330f729Sjoerg         for (const auto &I :
20617330f729Sjoerg              llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) {
20627330f729Sjoerg           assert(I.second.getBaseOffset() == BaseOffset &&
20637330f729Sjoerg                  "Invalid base offset!");
20647330f729Sjoerg           const CXXRecordDecl *RD = I.second.getBase();
20657330f729Sjoerg           ClassNames.insert(RD->getQualifiedNameAsString());
20667330f729Sjoerg         }
20677330f729Sjoerg 
20687330f729Sjoerg         for (const std::string &Name : ClassNames) {
20697330f729Sjoerg           Out << "       -- (" << Name;
20707330f729Sjoerg           Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
20717330f729Sjoerg         }
20727330f729Sjoerg       }
20737330f729Sjoerg     }
20747330f729Sjoerg   }
20757330f729Sjoerg 
20767330f729Sjoerg   Out << '\n';
20777330f729Sjoerg 
20787330f729Sjoerg   if (isBuildingConstructorVTable())
20797330f729Sjoerg     return;
20807330f729Sjoerg 
20817330f729Sjoerg   if (MostDerivedClass->getNumVBases()) {
20827330f729Sjoerg     // We store the virtual base class names and their offsets in a map to get
20837330f729Sjoerg     // a stable order.
20847330f729Sjoerg 
20857330f729Sjoerg     std::map<std::string, CharUnits> ClassNamesAndOffsets;
20867330f729Sjoerg     for (const auto &I : VBaseOffsetOffsets) {
20877330f729Sjoerg       std::string ClassName = I.first->getQualifiedNameAsString();
20887330f729Sjoerg       CharUnits OffsetOffset = I.second;
20897330f729Sjoerg       ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
20907330f729Sjoerg     }
20917330f729Sjoerg 
20927330f729Sjoerg     Out << "Virtual base offset offsets for '";
20937330f729Sjoerg     MostDerivedClass->printQualifiedName(Out);
20947330f729Sjoerg     Out << "' (";
20957330f729Sjoerg     Out << ClassNamesAndOffsets.size();
20967330f729Sjoerg     Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
20977330f729Sjoerg 
20987330f729Sjoerg     for (const auto &I : ClassNamesAndOffsets)
20997330f729Sjoerg       Out << "   " << I.first << " | " << I.second.getQuantity() << '\n';
21007330f729Sjoerg 
21017330f729Sjoerg     Out << "\n";
21027330f729Sjoerg   }
21037330f729Sjoerg 
21047330f729Sjoerg   if (!Thunks.empty()) {
21057330f729Sjoerg     // We store the method names in a map to get a stable order.
21067330f729Sjoerg     std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
21077330f729Sjoerg 
21087330f729Sjoerg     for (const auto &I : Thunks) {
21097330f729Sjoerg       const CXXMethodDecl *MD = I.first;
21107330f729Sjoerg       std::string MethodName =
21117330f729Sjoerg         PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
21127330f729Sjoerg                                     MD);
21137330f729Sjoerg 
21147330f729Sjoerg       MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
21157330f729Sjoerg     }
21167330f729Sjoerg 
21177330f729Sjoerg     for (const auto &I : MethodNamesAndDecls) {
21187330f729Sjoerg       const std::string &MethodName = I.first;
21197330f729Sjoerg       const CXXMethodDecl *MD = I.second;
21207330f729Sjoerg 
21217330f729Sjoerg       ThunkInfoVectorTy ThunksVector = Thunks[MD];
21227330f729Sjoerg       llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
21237330f729Sjoerg         assert(LHS.Method == nullptr && RHS.Method == nullptr);
21247330f729Sjoerg         return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);
21257330f729Sjoerg       });
21267330f729Sjoerg 
21277330f729Sjoerg       Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
21287330f729Sjoerg       Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
21297330f729Sjoerg 
21307330f729Sjoerg       for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
21317330f729Sjoerg         const ThunkInfo &Thunk = ThunksVector[I];
21327330f729Sjoerg 
21337330f729Sjoerg         Out << llvm::format("%4d | ", I);
21347330f729Sjoerg 
21357330f729Sjoerg         // If this function pointer has a return pointer adjustment, dump it.
21367330f729Sjoerg         if (!Thunk.Return.isEmpty()) {
21377330f729Sjoerg           Out << "return adjustment: " << Thunk.Return.NonVirtual;
21387330f729Sjoerg           Out << " non-virtual";
21397330f729Sjoerg           if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
21407330f729Sjoerg             Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
21417330f729Sjoerg             Out << " vbase offset offset";
21427330f729Sjoerg           }
21437330f729Sjoerg 
21447330f729Sjoerg           if (!Thunk.This.isEmpty())
21457330f729Sjoerg             Out << "\n       ";
21467330f729Sjoerg         }
21477330f729Sjoerg 
21487330f729Sjoerg         // If this function pointer has a 'this' pointer adjustment, dump it.
21497330f729Sjoerg         if (!Thunk.This.isEmpty()) {
21507330f729Sjoerg           Out << "this adjustment: ";
21517330f729Sjoerg           Out << Thunk.This.NonVirtual << " non-virtual";
21527330f729Sjoerg 
21537330f729Sjoerg           if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
21547330f729Sjoerg             Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
21557330f729Sjoerg             Out << " vcall offset offset";
21567330f729Sjoerg           }
21577330f729Sjoerg         }
21587330f729Sjoerg 
21597330f729Sjoerg         Out << '\n';
21607330f729Sjoerg       }
21617330f729Sjoerg 
21627330f729Sjoerg       Out << '\n';
21637330f729Sjoerg     }
21647330f729Sjoerg   }
21657330f729Sjoerg 
21667330f729Sjoerg   // Compute the vtable indices for all the member functions.
21677330f729Sjoerg   // Store them in a map keyed by the index so we'll get a sorted table.
21687330f729Sjoerg   std::map<uint64_t, std::string> IndicesMap;
21697330f729Sjoerg 
21707330f729Sjoerg   for (const auto *MD : MostDerivedClass->methods()) {
21717330f729Sjoerg     // We only want virtual member functions.
2172*e038c9c4Sjoerg     if (!ItaniumVTableContext::hasVtableSlot(MD))
21737330f729Sjoerg       continue;
21747330f729Sjoerg     MD = MD->getCanonicalDecl();
21757330f729Sjoerg 
21767330f729Sjoerg     std::string MethodName =
21777330f729Sjoerg       PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
21787330f729Sjoerg                                   MD);
21797330f729Sjoerg 
21807330f729Sjoerg     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
21817330f729Sjoerg       GlobalDecl GD(DD, Dtor_Complete);
21827330f729Sjoerg       assert(MethodVTableIndices.count(GD));
21837330f729Sjoerg       uint64_t VTableIndex = MethodVTableIndices[GD];
21847330f729Sjoerg       IndicesMap[VTableIndex] = MethodName + " [complete]";
21857330f729Sjoerg       IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
21867330f729Sjoerg     } else {
21877330f729Sjoerg       assert(MethodVTableIndices.count(MD));
21887330f729Sjoerg       IndicesMap[MethodVTableIndices[MD]] = MethodName;
21897330f729Sjoerg     }
21907330f729Sjoerg   }
21917330f729Sjoerg 
21927330f729Sjoerg   // Print the vtable indices for all the member functions.
21937330f729Sjoerg   if (!IndicesMap.empty()) {
21947330f729Sjoerg     Out << "VTable indices for '";
21957330f729Sjoerg     MostDerivedClass->printQualifiedName(Out);
21967330f729Sjoerg     Out << "' (" << IndicesMap.size() << " entries).\n";
21977330f729Sjoerg 
21987330f729Sjoerg     for (const auto &I : IndicesMap) {
21997330f729Sjoerg       uint64_t VTableIndex = I.first;
22007330f729Sjoerg       const std::string &MethodName = I.second;
22017330f729Sjoerg 
22027330f729Sjoerg       Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
22037330f729Sjoerg           << '\n';
22047330f729Sjoerg     }
22057330f729Sjoerg   }
22067330f729Sjoerg 
22077330f729Sjoerg   Out << '\n';
22087330f729Sjoerg }
22097330f729Sjoerg }
22107330f729Sjoerg 
2211*e038c9c4Sjoerg static VTableLayout::AddressPointsIndexMapTy
MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy & addressPoints,unsigned numVTables)2212*e038c9c4Sjoerg MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints,
2213*e038c9c4Sjoerg                         unsigned numVTables) {
2214*e038c9c4Sjoerg   VTableLayout::AddressPointsIndexMapTy indexMap(numVTables);
2215*e038c9c4Sjoerg 
2216*e038c9c4Sjoerg   for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
2217*e038c9c4Sjoerg     const auto &addressPointLoc = it->second;
2218*e038c9c4Sjoerg     unsigned vtableIndex = addressPointLoc.VTableIndex;
2219*e038c9c4Sjoerg     unsigned addressPoint = addressPointLoc.AddressPointIndex;
2220*e038c9c4Sjoerg     if (indexMap[vtableIndex]) {
2221*e038c9c4Sjoerg       // Multiple BaseSubobjects can map to the same AddressPointLocation, but
2222*e038c9c4Sjoerg       // every vtable index should have a unique address point.
2223*e038c9c4Sjoerg       assert(indexMap[vtableIndex] == addressPoint &&
2224*e038c9c4Sjoerg              "Every vtable index should have a unique address point. Found a "
2225*e038c9c4Sjoerg              "vtable that has two different address points.");
2226*e038c9c4Sjoerg     } else {
2227*e038c9c4Sjoerg       indexMap[vtableIndex] = addressPoint;
2228*e038c9c4Sjoerg     }
2229*e038c9c4Sjoerg   }
2230*e038c9c4Sjoerg 
2231*e038c9c4Sjoerg   // Note that by this point, not all the address may be initialized if the
2232*e038c9c4Sjoerg   // AddressPoints map is empty. This is ok if the map isn't needed. See
2233*e038c9c4Sjoerg   // MicrosoftVTableContext::computeVTableRelatedInformation() which uses an
2234*e038c9c4Sjoerg   // emprt map.
2235*e038c9c4Sjoerg   return indexMap;
2236*e038c9c4Sjoerg }
2237*e038c9c4Sjoerg 
VTableLayout(ArrayRef<size_t> VTableIndices,ArrayRef<VTableComponent> VTableComponents,ArrayRef<VTableThunkTy> VTableThunks,const AddressPointsMapTy & AddressPoints)22387330f729Sjoerg VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices,
22397330f729Sjoerg                            ArrayRef<VTableComponent> VTableComponents,
22407330f729Sjoerg                            ArrayRef<VTableThunkTy> VTableThunks,
22417330f729Sjoerg                            const AddressPointsMapTy &AddressPoints)
22427330f729Sjoerg     : VTableComponents(VTableComponents), VTableThunks(VTableThunks),
2243*e038c9c4Sjoerg       AddressPoints(AddressPoints), AddressPointIndices(MakeAddressPointIndices(
2244*e038c9c4Sjoerg                                         AddressPoints, VTableIndices.size())) {
22457330f729Sjoerg   if (VTableIndices.size() <= 1)
22467330f729Sjoerg     assert(VTableIndices.size() == 1 && VTableIndices[0] == 0);
22477330f729Sjoerg   else
22487330f729Sjoerg     this->VTableIndices = OwningArrayRef<size_t>(VTableIndices);
22497330f729Sjoerg 
22507330f729Sjoerg   llvm::sort(this->VTableThunks, [](const VTableLayout::VTableThunkTy &LHS,
22517330f729Sjoerg                                     const VTableLayout::VTableThunkTy &RHS) {
22527330f729Sjoerg     assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
22537330f729Sjoerg            "Different thunks should have unique indices!");
22547330f729Sjoerg     return LHS.first < RHS.first;
22557330f729Sjoerg   });
22567330f729Sjoerg }
22577330f729Sjoerg 
~VTableLayout()22587330f729Sjoerg VTableLayout::~VTableLayout() { }
22597330f729Sjoerg 
hasVtableSlot(const CXXMethodDecl * MD)2260*e038c9c4Sjoerg bool VTableContextBase::hasVtableSlot(const CXXMethodDecl *MD) {
2261*e038c9c4Sjoerg   return MD->isVirtual() && !MD->isConsteval();
2262*e038c9c4Sjoerg }
2263*e038c9c4Sjoerg 
ItaniumVTableContext(ASTContext & Context,VTableComponentLayout ComponentLayout)2264*e038c9c4Sjoerg ItaniumVTableContext::ItaniumVTableContext(
2265*e038c9c4Sjoerg     ASTContext &Context, VTableComponentLayout ComponentLayout)
2266*e038c9c4Sjoerg     : VTableContextBase(/*MS=*/false), ComponentLayout(ComponentLayout) {}
22677330f729Sjoerg 
~ItaniumVTableContext()22687330f729Sjoerg ItaniumVTableContext::~ItaniumVTableContext() {}
22697330f729Sjoerg 
getMethodVTableIndex(GlobalDecl GD)22707330f729Sjoerg uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) {
22717330f729Sjoerg   GD = GD.getCanonicalDecl();
22727330f729Sjoerg   MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
22737330f729Sjoerg   if (I != MethodVTableIndices.end())
22747330f729Sjoerg     return I->second;
22757330f729Sjoerg 
22767330f729Sjoerg   const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
22777330f729Sjoerg 
22787330f729Sjoerg   computeVTableRelatedInformation(RD);
22797330f729Sjoerg 
22807330f729Sjoerg   I = MethodVTableIndices.find(GD);
22817330f729Sjoerg   assert(I != MethodVTableIndices.end() && "Did not find index!");
22827330f729Sjoerg   return I->second;
22837330f729Sjoerg }
22847330f729Sjoerg 
22857330f729Sjoerg CharUnits
getVirtualBaseOffsetOffset(const CXXRecordDecl * RD,const CXXRecordDecl * VBase)22867330f729Sjoerg ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
22877330f729Sjoerg                                                  const CXXRecordDecl *VBase) {
22887330f729Sjoerg   ClassPairTy ClassPair(RD, VBase);
22897330f729Sjoerg 
22907330f729Sjoerg   VirtualBaseClassOffsetOffsetsMapTy::iterator I =
22917330f729Sjoerg     VirtualBaseClassOffsetOffsets.find(ClassPair);
22927330f729Sjoerg   if (I != VirtualBaseClassOffsetOffsets.end())
22937330f729Sjoerg     return I->second;
22947330f729Sjoerg 
2295*e038c9c4Sjoerg   VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, /*Overriders=*/nullptr,
22967330f729Sjoerg                                      BaseSubobject(RD, CharUnits::Zero()),
22977330f729Sjoerg                                      /*BaseIsVirtual=*/false,
22987330f729Sjoerg                                      /*OffsetInLayoutClass=*/CharUnits::Zero());
22997330f729Sjoerg 
23007330f729Sjoerg   for (const auto &I : Builder.getVBaseOffsetOffsets()) {
23017330f729Sjoerg     // Insert all types.
23027330f729Sjoerg     ClassPairTy ClassPair(RD, I.first);
23037330f729Sjoerg 
23047330f729Sjoerg     VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
23057330f729Sjoerg   }
23067330f729Sjoerg 
23077330f729Sjoerg   I = VirtualBaseClassOffsetOffsets.find(ClassPair);
23087330f729Sjoerg   assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
23097330f729Sjoerg 
23107330f729Sjoerg   return I->second;
23117330f729Sjoerg }
23127330f729Sjoerg 
23137330f729Sjoerg static std::unique_ptr<VTableLayout>
CreateVTableLayout(const ItaniumVTableBuilder & Builder)23147330f729Sjoerg CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
23157330f729Sjoerg   SmallVector<VTableLayout::VTableThunkTy, 1>
23167330f729Sjoerg     VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
23177330f729Sjoerg 
23187330f729Sjoerg   return std::make_unique<VTableLayout>(
23197330f729Sjoerg       Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
23207330f729Sjoerg       Builder.getAddressPoints());
23217330f729Sjoerg }
23227330f729Sjoerg 
23237330f729Sjoerg void
computeVTableRelatedInformation(const CXXRecordDecl * RD)23247330f729Sjoerg ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
23257330f729Sjoerg   std::unique_ptr<const VTableLayout> &Entry = VTableLayouts[RD];
23267330f729Sjoerg 
23277330f729Sjoerg   // Check if we've computed this information before.
23287330f729Sjoerg   if (Entry)
23297330f729Sjoerg     return;
23307330f729Sjoerg 
23317330f729Sjoerg   ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
23327330f729Sjoerg                                /*MostDerivedClassIsVirtual=*/0, RD);
23337330f729Sjoerg   Entry = CreateVTableLayout(Builder);
23347330f729Sjoerg 
23357330f729Sjoerg   MethodVTableIndices.insert(Builder.vtable_indices_begin(),
23367330f729Sjoerg                              Builder.vtable_indices_end());
23377330f729Sjoerg 
23387330f729Sjoerg   // Add the known thunks.
23397330f729Sjoerg   Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
23407330f729Sjoerg 
23417330f729Sjoerg   // If we don't have the vbase information for this class, insert it.
23427330f729Sjoerg   // getVirtualBaseOffsetOffset will compute it separately without computing
23437330f729Sjoerg   // the rest of the vtable related information.
23447330f729Sjoerg   if (!RD->getNumVBases())
23457330f729Sjoerg     return;
23467330f729Sjoerg 
23477330f729Sjoerg   const CXXRecordDecl *VBase =
23487330f729Sjoerg     RD->vbases_begin()->getType()->getAsCXXRecordDecl();
23497330f729Sjoerg 
23507330f729Sjoerg   if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
23517330f729Sjoerg     return;
23527330f729Sjoerg 
23537330f729Sjoerg   for (const auto &I : Builder.getVBaseOffsetOffsets()) {
23547330f729Sjoerg     // Insert all types.
23557330f729Sjoerg     ClassPairTy ClassPair(RD, I.first);
23567330f729Sjoerg 
23577330f729Sjoerg     VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
23587330f729Sjoerg   }
23597330f729Sjoerg }
23607330f729Sjoerg 
23617330f729Sjoerg std::unique_ptr<VTableLayout>
createConstructionVTableLayout(const CXXRecordDecl * MostDerivedClass,CharUnits MostDerivedClassOffset,bool MostDerivedClassIsVirtual,const CXXRecordDecl * LayoutClass)23627330f729Sjoerg ItaniumVTableContext::createConstructionVTableLayout(
23637330f729Sjoerg     const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset,
23647330f729Sjoerg     bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) {
23657330f729Sjoerg   ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
23667330f729Sjoerg                                MostDerivedClassIsVirtual, LayoutClass);
23677330f729Sjoerg   return CreateVTableLayout(Builder);
23687330f729Sjoerg }
23697330f729Sjoerg 
23707330f729Sjoerg namespace {
23717330f729Sjoerg 
23727330f729Sjoerg // Vtables in the Microsoft ABI are different from the Itanium ABI.
23737330f729Sjoerg //
23747330f729Sjoerg // The main differences are:
23757330f729Sjoerg //  1. Separate vftable and vbtable.
23767330f729Sjoerg //
23777330f729Sjoerg //  2. Each subobject with a vfptr gets its own vftable rather than an address
23787330f729Sjoerg //     point in a single vtable shared between all the subobjects.
23797330f729Sjoerg //     Each vftable is represented by a separate section and virtual calls
23807330f729Sjoerg //     must be done using the vftable which has a slot for the function to be
23817330f729Sjoerg //     called.
23827330f729Sjoerg //
23837330f729Sjoerg //  3. Virtual method definitions expect their 'this' parameter to point to the
23847330f729Sjoerg //     first vfptr whose table provides a compatible overridden method.  In many
23857330f729Sjoerg //     cases, this permits the original vf-table entry to directly call
23867330f729Sjoerg //     the method instead of passing through a thunk.
23877330f729Sjoerg //     See example before VFTableBuilder::ComputeThisOffset below.
23887330f729Sjoerg //
23897330f729Sjoerg //     A compatible overridden method is one which does not have a non-trivial
23907330f729Sjoerg //     covariant-return adjustment.
23917330f729Sjoerg //
23927330f729Sjoerg //     The first vfptr is the one with the lowest offset in the complete-object
23937330f729Sjoerg //     layout of the defining class, and the method definition will subtract
23947330f729Sjoerg //     that constant offset from the parameter value to get the real 'this'
23957330f729Sjoerg //     value.  Therefore, if the offset isn't really constant (e.g. if a virtual
23967330f729Sjoerg //     function defined in a virtual base is overridden in a more derived
23977330f729Sjoerg //     virtual base and these bases have a reverse order in the complete
23987330f729Sjoerg //     object), the vf-table may require a this-adjustment thunk.
23997330f729Sjoerg //
24007330f729Sjoerg //  4. vftables do not contain new entries for overrides that merely require
24017330f729Sjoerg //     this-adjustment.  Together with #3, this keeps vf-tables smaller and
24027330f729Sjoerg //     eliminates the need for this-adjustment thunks in many cases, at the cost
24037330f729Sjoerg //     of often requiring redundant work to adjust the "this" pointer.
24047330f729Sjoerg //
24057330f729Sjoerg //  5. Instead of VTT and constructor vtables, vbtables and vtordisps are used.
24067330f729Sjoerg //     Vtordisps are emitted into the class layout if a class has
24077330f729Sjoerg //      a) a user-defined ctor/dtor
24087330f729Sjoerg //     and
24097330f729Sjoerg //      b) a method overriding a method in a virtual base.
24107330f729Sjoerg //
24117330f729Sjoerg //  To get a better understanding of this code,
24127330f729Sjoerg //  you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp
24137330f729Sjoerg 
24147330f729Sjoerg class VFTableBuilder {
24157330f729Sjoerg public:
24167330f729Sjoerg   typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
24177330f729Sjoerg     MethodVFTableLocationsTy;
24187330f729Sjoerg 
24197330f729Sjoerg   typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator>
24207330f729Sjoerg     method_locations_range;
24217330f729Sjoerg 
24227330f729Sjoerg private:
24237330f729Sjoerg   /// VTables - Global vtable information.
24247330f729Sjoerg   MicrosoftVTableContext &VTables;
24257330f729Sjoerg 
24267330f729Sjoerg   /// Context - The ASTContext which we will use for layout information.
24277330f729Sjoerg   ASTContext &Context;
24287330f729Sjoerg 
24297330f729Sjoerg   /// MostDerivedClass - The most derived class for which we're building this
24307330f729Sjoerg   /// vtable.
24317330f729Sjoerg   const CXXRecordDecl *MostDerivedClass;
24327330f729Sjoerg 
24337330f729Sjoerg   const ASTRecordLayout &MostDerivedClassLayout;
24347330f729Sjoerg 
24357330f729Sjoerg   const VPtrInfo &WhichVFPtr;
24367330f729Sjoerg 
24377330f729Sjoerg   /// FinalOverriders - The final overriders of the most derived class.
24387330f729Sjoerg   const FinalOverriders Overriders;
24397330f729Sjoerg 
24407330f729Sjoerg   /// Components - The components of the vftable being built.
24417330f729Sjoerg   SmallVector<VTableComponent, 64> Components;
24427330f729Sjoerg 
24437330f729Sjoerg   MethodVFTableLocationsTy MethodVFTableLocations;
24447330f729Sjoerg 
24457330f729Sjoerg   /// Does this class have an RTTI component?
24467330f729Sjoerg   bool HasRTTIComponent = false;
24477330f729Sjoerg 
24487330f729Sjoerg   /// MethodInfo - Contains information about a method in a vtable.
24497330f729Sjoerg   /// (Used for computing 'this' pointer adjustment thunks.
24507330f729Sjoerg   struct MethodInfo {
24517330f729Sjoerg     /// VBTableIndex - The nonzero index in the vbtable that
24527330f729Sjoerg     /// this method's base has, or zero.
24537330f729Sjoerg     const uint64_t VBTableIndex;
24547330f729Sjoerg 
24557330f729Sjoerg     /// VFTableIndex - The index in the vftable that this method has.
24567330f729Sjoerg     const uint64_t VFTableIndex;
24577330f729Sjoerg 
24587330f729Sjoerg     /// Shadowed - Indicates if this vftable slot is shadowed by
24597330f729Sjoerg     /// a slot for a covariant-return override. If so, it shouldn't be printed
24607330f729Sjoerg     /// or used for vcalls in the most derived class.
24617330f729Sjoerg     bool Shadowed;
24627330f729Sjoerg 
24637330f729Sjoerg     /// UsesExtraSlot - Indicates if this vftable slot was created because
24647330f729Sjoerg     /// any of the overridden slots required a return adjusting thunk.
24657330f729Sjoerg     bool UsesExtraSlot;
24667330f729Sjoerg 
MethodInfo__anon6f3b34010611::VFTableBuilder::MethodInfo24677330f729Sjoerg     MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
24687330f729Sjoerg                bool UsesExtraSlot = false)
24697330f729Sjoerg         : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
24707330f729Sjoerg           Shadowed(false), UsesExtraSlot(UsesExtraSlot) {}
24717330f729Sjoerg 
MethodInfo__anon6f3b34010611::VFTableBuilder::MethodInfo24727330f729Sjoerg     MethodInfo()
24737330f729Sjoerg         : VBTableIndex(0), VFTableIndex(0), Shadowed(false),
24747330f729Sjoerg           UsesExtraSlot(false) {}
24757330f729Sjoerg   };
24767330f729Sjoerg 
24777330f729Sjoerg   typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
24787330f729Sjoerg 
24797330f729Sjoerg   /// MethodInfoMap - The information for all methods in the vftable we're
24807330f729Sjoerg   /// currently building.
24817330f729Sjoerg   MethodInfoMapTy MethodInfoMap;
24827330f729Sjoerg 
24837330f729Sjoerg   typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
24847330f729Sjoerg 
24857330f729Sjoerg   /// VTableThunks - The thunks by vftable index in the vftable currently being
24867330f729Sjoerg   /// built.
24877330f729Sjoerg   VTableThunksMapTy VTableThunks;
24887330f729Sjoerg 
24897330f729Sjoerg   typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
24907330f729Sjoerg   typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
24917330f729Sjoerg 
24927330f729Sjoerg   /// Thunks - A map that contains all the thunks needed for all methods in the
24937330f729Sjoerg   /// most derived class for which the vftable is currently being built.
24947330f729Sjoerg   ThunksMapTy Thunks;
24957330f729Sjoerg 
24967330f729Sjoerg   /// AddThunk - Add a thunk for the given method.
AddThunk(const CXXMethodDecl * MD,const ThunkInfo & Thunk)24977330f729Sjoerg   void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
24987330f729Sjoerg     SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
24997330f729Sjoerg 
25007330f729Sjoerg     // Check if we have this thunk already.
25017330f729Sjoerg     if (llvm::find(ThunksVector, Thunk) != ThunksVector.end())
25027330f729Sjoerg       return;
25037330f729Sjoerg 
25047330f729Sjoerg     ThunksVector.push_back(Thunk);
25057330f729Sjoerg   }
25067330f729Sjoerg 
25077330f729Sjoerg   /// ComputeThisOffset - Returns the 'this' argument offset for the given
25087330f729Sjoerg   /// method, relative to the beginning of the MostDerivedClass.
25097330f729Sjoerg   CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
25107330f729Sjoerg 
25117330f729Sjoerg   void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
25127330f729Sjoerg                                    CharUnits ThisOffset, ThisAdjustment &TA);
25137330f729Sjoerg 
25147330f729Sjoerg   /// AddMethod - Add a single virtual member function to the vftable
25157330f729Sjoerg   /// components vector.
AddMethod(const CXXMethodDecl * MD,ThunkInfo TI)25167330f729Sjoerg   void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
25177330f729Sjoerg     if (!TI.isEmpty()) {
25187330f729Sjoerg       VTableThunks[Components.size()] = TI;
25197330f729Sjoerg       AddThunk(MD, TI);
25207330f729Sjoerg     }
25217330f729Sjoerg     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
25227330f729Sjoerg       assert(TI.Return.isEmpty() &&
25237330f729Sjoerg              "Destructor can't have return adjustment!");
25247330f729Sjoerg       Components.push_back(VTableComponent::MakeDeletingDtor(DD));
25257330f729Sjoerg     } else {
25267330f729Sjoerg       Components.push_back(VTableComponent::MakeFunction(MD));
25277330f729Sjoerg     }
25287330f729Sjoerg   }
25297330f729Sjoerg 
25307330f729Sjoerg   /// AddMethods - Add the methods of this base subobject and the relevant
25317330f729Sjoerg   /// subbases to the vftable we're currently laying out.
25327330f729Sjoerg   void AddMethods(BaseSubobject Base, unsigned BaseDepth,
25337330f729Sjoerg                   const CXXRecordDecl *LastVBase,
25347330f729Sjoerg                   BasesSetVectorTy &VisitedBases);
25357330f729Sjoerg 
LayoutVFTable()25367330f729Sjoerg   void LayoutVFTable() {
25377330f729Sjoerg     // RTTI data goes before all other entries.
25387330f729Sjoerg     if (HasRTTIComponent)
25397330f729Sjoerg       Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
25407330f729Sjoerg 
25417330f729Sjoerg     BasesSetVectorTy VisitedBases;
25427330f729Sjoerg     AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
25437330f729Sjoerg                VisitedBases);
2544*e038c9c4Sjoerg     // Note that it is possible for the vftable to contain only an RTTI
2545*e038c9c4Sjoerg     // pointer, if all virtual functions are constewval.
2546*e038c9c4Sjoerg     assert(!Components.empty() && "vftable can't be empty");
25477330f729Sjoerg 
25487330f729Sjoerg     assert(MethodVFTableLocations.empty());
25497330f729Sjoerg     for (const auto &I : MethodInfoMap) {
25507330f729Sjoerg       const CXXMethodDecl *MD = I.first;
25517330f729Sjoerg       const MethodInfo &MI = I.second;
25527330f729Sjoerg       assert(MD == MD->getCanonicalDecl());
25537330f729Sjoerg 
25547330f729Sjoerg       // Skip the methods that the MostDerivedClass didn't override
25557330f729Sjoerg       // and the entries shadowed by return adjusting thunks.
25567330f729Sjoerg       if (MD->getParent() != MostDerivedClass || MI.Shadowed)
25577330f729Sjoerg         continue;
25587330f729Sjoerg       MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(),
25597330f729Sjoerg                                 WhichVFPtr.NonVirtualOffset, MI.VFTableIndex);
25607330f729Sjoerg       if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
25617330f729Sjoerg         MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
25627330f729Sjoerg       } else {
25637330f729Sjoerg         MethodVFTableLocations[MD] = Loc;
25647330f729Sjoerg       }
25657330f729Sjoerg     }
25667330f729Sjoerg   }
25677330f729Sjoerg 
25687330f729Sjoerg public:
VFTableBuilder(MicrosoftVTableContext & VTables,const CXXRecordDecl * MostDerivedClass,const VPtrInfo & Which)25697330f729Sjoerg   VFTableBuilder(MicrosoftVTableContext &VTables,
25707330f729Sjoerg                  const CXXRecordDecl *MostDerivedClass, const VPtrInfo &Which)
25717330f729Sjoerg       : VTables(VTables),
25727330f729Sjoerg         Context(MostDerivedClass->getASTContext()),
25737330f729Sjoerg         MostDerivedClass(MostDerivedClass),
25747330f729Sjoerg         MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
25757330f729Sjoerg         WhichVFPtr(Which),
25767330f729Sjoerg         Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
25777330f729Sjoerg     // Provide the RTTI component if RTTIData is enabled. If the vftable would
25787330f729Sjoerg     // be available externally, we should not provide the RTTI componenent. It
25797330f729Sjoerg     // is currently impossible to get available externally vftables with either
25807330f729Sjoerg     // dllimport or extern template instantiations, but eventually we may add a
25817330f729Sjoerg     // flag to support additional devirtualization that needs this.
25827330f729Sjoerg     if (Context.getLangOpts().RTTIData)
25837330f729Sjoerg       HasRTTIComponent = true;
25847330f729Sjoerg 
25857330f729Sjoerg     LayoutVFTable();
25867330f729Sjoerg 
25877330f729Sjoerg     if (Context.getLangOpts().DumpVTableLayouts)
25887330f729Sjoerg       dumpLayout(llvm::outs());
25897330f729Sjoerg   }
25907330f729Sjoerg 
getNumThunks() const25917330f729Sjoerg   uint64_t getNumThunks() const { return Thunks.size(); }
25927330f729Sjoerg 
thunks_begin() const25937330f729Sjoerg   ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); }
25947330f729Sjoerg 
thunks_end() const25957330f729Sjoerg   ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
25967330f729Sjoerg 
vtable_locations() const25977330f729Sjoerg   method_locations_range vtable_locations() const {
25987330f729Sjoerg     return method_locations_range(MethodVFTableLocations.begin(),
25997330f729Sjoerg                                   MethodVFTableLocations.end());
26007330f729Sjoerg   }
26017330f729Sjoerg 
vtable_components() const26027330f729Sjoerg   ArrayRef<VTableComponent> vtable_components() const { return Components; }
26037330f729Sjoerg 
vtable_thunks_begin() const26047330f729Sjoerg   VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
26057330f729Sjoerg     return VTableThunks.begin();
26067330f729Sjoerg   }
26077330f729Sjoerg 
vtable_thunks_end() const26087330f729Sjoerg   VTableThunksMapTy::const_iterator vtable_thunks_end() const {
26097330f729Sjoerg     return VTableThunks.end();
26107330f729Sjoerg   }
26117330f729Sjoerg 
26127330f729Sjoerg   void dumpLayout(raw_ostream &);
26137330f729Sjoerg };
26147330f729Sjoerg 
26157330f729Sjoerg } // end namespace
26167330f729Sjoerg 
26177330f729Sjoerg // Let's study one class hierarchy as an example:
26187330f729Sjoerg //   struct A {
26197330f729Sjoerg //     virtual void f();
26207330f729Sjoerg //     int x;
26217330f729Sjoerg //   };
26227330f729Sjoerg //
26237330f729Sjoerg //   struct B : virtual A {
26247330f729Sjoerg //     virtual void f();
26257330f729Sjoerg //   };
26267330f729Sjoerg //
26277330f729Sjoerg // Record layouts:
26287330f729Sjoerg //   struct A:
26297330f729Sjoerg //   0 |   (A vftable pointer)
26307330f729Sjoerg //   4 |   int x
26317330f729Sjoerg //
26327330f729Sjoerg //   struct B:
26337330f729Sjoerg //   0 |   (B vbtable pointer)
26347330f729Sjoerg //   4 |   struct A (virtual base)
26357330f729Sjoerg //   4 |     (A vftable pointer)
26367330f729Sjoerg //   8 |     int x
26377330f729Sjoerg //
26387330f729Sjoerg // Let's assume we have a pointer to the A part of an object of dynamic type B:
26397330f729Sjoerg //   B b;
26407330f729Sjoerg //   A *a = (A*)&b;
26417330f729Sjoerg //   a->f();
26427330f729Sjoerg //
26437330f729Sjoerg // In this hierarchy, f() belongs to the vftable of A, so B::f() expects
26447330f729Sjoerg // "this" parameter to point at the A subobject, which is B+4.
26457330f729Sjoerg // In the B::f() prologue, it adjusts "this" back to B by subtracting 4,
26467330f729Sjoerg // performed as a *static* adjustment.
26477330f729Sjoerg //
26487330f729Sjoerg // Interesting thing happens when we alter the relative placement of A and B
26497330f729Sjoerg // subobjects in a class:
26507330f729Sjoerg //   struct C : virtual B { };
26517330f729Sjoerg //
26527330f729Sjoerg //   C c;
26537330f729Sjoerg //   A *a = (A*)&c;
26547330f729Sjoerg //   a->f();
26557330f729Sjoerg //
26567330f729Sjoerg // Respective record layout is:
26577330f729Sjoerg //   0 |   (C vbtable pointer)
26587330f729Sjoerg //   4 |   struct A (virtual base)
26597330f729Sjoerg //   4 |     (A vftable pointer)
26607330f729Sjoerg //   8 |     int x
26617330f729Sjoerg //  12 |   struct B (virtual base)
26627330f729Sjoerg //  12 |     (B vbtable pointer)
26637330f729Sjoerg //
26647330f729Sjoerg // The final overrider of f() in class C is still B::f(), so B+4 should be
26657330f729Sjoerg // passed as "this" to that code.  However, "a" points at B-8, so the respective
26667330f729Sjoerg // vftable entry should hold a thunk that adds 12 to the "this" argument before
26677330f729Sjoerg // performing a tail call to B::f().
26687330f729Sjoerg //
26697330f729Sjoerg // With this example in mind, we can now calculate the 'this' argument offset
26707330f729Sjoerg // for the given method, relative to the beginning of the MostDerivedClass.
26717330f729Sjoerg CharUnits
ComputeThisOffset(FinalOverriders::OverriderInfo Overrider)26727330f729Sjoerg VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
26737330f729Sjoerg   BasesSetVectorTy Bases;
26747330f729Sjoerg 
26757330f729Sjoerg   {
26767330f729Sjoerg     // Find the set of least derived bases that define the given method.
26777330f729Sjoerg     OverriddenMethodsSetTy VisitedOverriddenMethods;
26787330f729Sjoerg     auto InitialOverriddenDefinitionCollector = [&](
26797330f729Sjoerg         const CXXMethodDecl *OverriddenMD) {
26807330f729Sjoerg       if (OverriddenMD->size_overridden_methods() == 0)
26817330f729Sjoerg         Bases.insert(OverriddenMD->getParent());
26827330f729Sjoerg       // Don't recurse on this method if we've already collected it.
26837330f729Sjoerg       return VisitedOverriddenMethods.insert(OverriddenMD).second;
26847330f729Sjoerg     };
26857330f729Sjoerg     visitAllOverriddenMethods(Overrider.Method,
26867330f729Sjoerg                               InitialOverriddenDefinitionCollector);
26877330f729Sjoerg   }
26887330f729Sjoerg 
26897330f729Sjoerg   // If there are no overrides then 'this' is located
26907330f729Sjoerg   // in the base that defines the method.
26917330f729Sjoerg   if (Bases.size() == 0)
26927330f729Sjoerg     return Overrider.Offset;
26937330f729Sjoerg 
26947330f729Sjoerg   CXXBasePaths Paths;
26957330f729Sjoerg   Overrider.Method->getParent()->lookupInBases(
26967330f729Sjoerg       [&Bases](const CXXBaseSpecifier *Specifier, CXXBasePath &) {
26977330f729Sjoerg         return Bases.count(Specifier->getType()->getAsCXXRecordDecl());
26987330f729Sjoerg       },
26997330f729Sjoerg       Paths);
27007330f729Sjoerg 
27017330f729Sjoerg   // This will hold the smallest this offset among overridees of MD.
27027330f729Sjoerg   // This implies that an offset of a non-virtual base will dominate an offset
27037330f729Sjoerg   // of a virtual base to potentially reduce the number of thunks required
27047330f729Sjoerg   // in the derived classes that inherit this method.
27057330f729Sjoerg   CharUnits Ret;
27067330f729Sjoerg   bool First = true;
27077330f729Sjoerg 
27087330f729Sjoerg   const ASTRecordLayout &OverriderRDLayout =
27097330f729Sjoerg       Context.getASTRecordLayout(Overrider.Method->getParent());
27107330f729Sjoerg   for (const CXXBasePath &Path : Paths) {
27117330f729Sjoerg     CharUnits ThisOffset = Overrider.Offset;
27127330f729Sjoerg     CharUnits LastVBaseOffset;
27137330f729Sjoerg 
27147330f729Sjoerg     // For each path from the overrider to the parents of the overridden
27157330f729Sjoerg     // methods, traverse the path, calculating the this offset in the most
27167330f729Sjoerg     // derived class.
27177330f729Sjoerg     for (const CXXBasePathElement &Element : Path) {
27187330f729Sjoerg       QualType CurTy = Element.Base->getType();
27197330f729Sjoerg       const CXXRecordDecl *PrevRD = Element.Class,
27207330f729Sjoerg                           *CurRD = CurTy->getAsCXXRecordDecl();
27217330f729Sjoerg       const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
27227330f729Sjoerg 
27237330f729Sjoerg       if (Element.Base->isVirtual()) {
27247330f729Sjoerg         // The interesting things begin when you have virtual inheritance.
27257330f729Sjoerg         // The final overrider will use a static adjustment equal to the offset
27267330f729Sjoerg         // of the vbase in the final overrider class.
27277330f729Sjoerg         // For example, if the final overrider is in a vbase B of the most
27287330f729Sjoerg         // derived class and it overrides a method of the B's own vbase A,
27297330f729Sjoerg         // it uses A* as "this".  In its prologue, it can cast A* to B* with
27307330f729Sjoerg         // a static offset.  This offset is used regardless of the actual
27317330f729Sjoerg         // offset of A from B in the most derived class, requiring an
27327330f729Sjoerg         // this-adjusting thunk in the vftable if A and B are laid out
27337330f729Sjoerg         // differently in the most derived class.
27347330f729Sjoerg         LastVBaseOffset = ThisOffset =
27357330f729Sjoerg             Overrider.Offset + OverriderRDLayout.getVBaseClassOffset(CurRD);
27367330f729Sjoerg       } else {
27377330f729Sjoerg         ThisOffset += Layout.getBaseClassOffset(CurRD);
27387330f729Sjoerg       }
27397330f729Sjoerg     }
27407330f729Sjoerg 
27417330f729Sjoerg     if (isa<CXXDestructorDecl>(Overrider.Method)) {
27427330f729Sjoerg       if (LastVBaseOffset.isZero()) {
27437330f729Sjoerg         // If a "Base" class has at least one non-virtual base with a virtual
27447330f729Sjoerg         // destructor, the "Base" virtual destructor will take the address
27457330f729Sjoerg         // of the "Base" subobject as the "this" argument.
27467330f729Sjoerg         ThisOffset = Overrider.Offset;
27477330f729Sjoerg       } else {
27487330f729Sjoerg         // A virtual destructor of a virtual base takes the address of the
27497330f729Sjoerg         // virtual base subobject as the "this" argument.
27507330f729Sjoerg         ThisOffset = LastVBaseOffset;
27517330f729Sjoerg       }
27527330f729Sjoerg     }
27537330f729Sjoerg 
27547330f729Sjoerg     if (Ret > ThisOffset || First) {
27557330f729Sjoerg       First = false;
27567330f729Sjoerg       Ret = ThisOffset;
27577330f729Sjoerg     }
27587330f729Sjoerg   }
27597330f729Sjoerg 
27607330f729Sjoerg   assert(!First && "Method not found in the given subobject?");
27617330f729Sjoerg   return Ret;
27627330f729Sjoerg }
27637330f729Sjoerg 
27647330f729Sjoerg // Things are getting even more complex when the "this" adjustment has to
27657330f729Sjoerg // use a dynamic offset instead of a static one, or even two dynamic offsets.
27667330f729Sjoerg // This is sometimes required when a virtual call happens in the middle of
27677330f729Sjoerg // a non-most-derived class construction or destruction.
27687330f729Sjoerg //
27697330f729Sjoerg // Let's take a look at the following example:
27707330f729Sjoerg //   struct A {
27717330f729Sjoerg //     virtual void f();
27727330f729Sjoerg //   };
27737330f729Sjoerg //
27747330f729Sjoerg //   void foo(A *a) { a->f(); }  // Knows nothing about siblings of A.
27757330f729Sjoerg //
27767330f729Sjoerg //   struct B : virtual A {
27777330f729Sjoerg //     virtual void f();
27787330f729Sjoerg //     B() {
27797330f729Sjoerg //       foo(this);
27807330f729Sjoerg //     }
27817330f729Sjoerg //   };
27827330f729Sjoerg //
27837330f729Sjoerg //   struct C : virtual B {
27847330f729Sjoerg //     virtual void f();
27857330f729Sjoerg //   };
27867330f729Sjoerg //
27877330f729Sjoerg // Record layouts for these classes are:
27887330f729Sjoerg //   struct A
27897330f729Sjoerg //   0 |   (A vftable pointer)
27907330f729Sjoerg //
27917330f729Sjoerg //   struct B
27927330f729Sjoerg //   0 |   (B vbtable pointer)
27937330f729Sjoerg //   4 |   (vtordisp for vbase A)
27947330f729Sjoerg //   8 |   struct A (virtual base)
27957330f729Sjoerg //   8 |     (A vftable pointer)
27967330f729Sjoerg //
27977330f729Sjoerg //   struct C
27987330f729Sjoerg //   0 |   (C vbtable pointer)
27997330f729Sjoerg //   4 |   (vtordisp for vbase A)
28007330f729Sjoerg //   8 |   struct A (virtual base)  // A precedes B!
28017330f729Sjoerg //   8 |     (A vftable pointer)
28027330f729Sjoerg //  12 |   struct B (virtual base)
28037330f729Sjoerg //  12 |     (B vbtable pointer)
28047330f729Sjoerg //
28057330f729Sjoerg // When one creates an object of type C, the C constructor:
28067330f729Sjoerg // - initializes all the vbptrs, then
28077330f729Sjoerg // - calls the A subobject constructor
28087330f729Sjoerg //   (initializes A's vfptr with an address of A vftable), then
28097330f729Sjoerg // - calls the B subobject constructor
28107330f729Sjoerg //   (initializes A's vfptr with an address of B vftable and vtordisp for A),
28117330f729Sjoerg //   that in turn calls foo(), then
28127330f729Sjoerg // - initializes A's vfptr with an address of C vftable and zeroes out the
28137330f729Sjoerg //   vtordisp
28147330f729Sjoerg //   FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable
28157330f729Sjoerg //   without vtordisp thunks?
28167330f729Sjoerg //   FIXME: how are vtordisp handled in the presence of nooverride/final?
28177330f729Sjoerg //
28187330f729Sjoerg // When foo() is called, an object with a layout of class C has a vftable
28197330f729Sjoerg // referencing B::f() that assumes a B layout, so the "this" adjustments are
28207330f729Sjoerg // incorrect, unless an extra adjustment is done.  This adjustment is called
28217330f729Sjoerg // "vtordisp adjustment".  Vtordisp basically holds the difference between the
28227330f729Sjoerg // actual location of a vbase in the layout class and the location assumed by
28237330f729Sjoerg // the vftable of the class being constructed/destructed.  Vtordisp is only
28247330f729Sjoerg // needed if "this" escapes a
28257330f729Sjoerg // structor (or we can't prove otherwise).
28267330f729Sjoerg // [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an
28277330f729Sjoerg // estimation of a dynamic adjustment]
28287330f729Sjoerg //
28297330f729Sjoerg // foo() gets a pointer to the A vbase and doesn't know anything about B or C,
28307330f729Sjoerg // so it just passes that pointer as "this" in a virtual call.
28317330f729Sjoerg // If there was no vtordisp, that would just dispatch to B::f().
28327330f729Sjoerg // However, B::f() assumes B+8 is passed as "this",
28337330f729Sjoerg // yet the pointer foo() passes along is B-4 (i.e. C+8).
28347330f729Sjoerg // An extra adjustment is needed, so we emit a thunk into the B vftable.
28357330f729Sjoerg // This vtordisp thunk subtracts the value of vtordisp
28367330f729Sjoerg // from the "this" argument (-12) before making a tailcall to B::f().
28377330f729Sjoerg //
28387330f729Sjoerg // Let's consider an even more complex example:
28397330f729Sjoerg //   struct D : virtual B, virtual C {
28407330f729Sjoerg //     D() {
28417330f729Sjoerg //       foo(this);
28427330f729Sjoerg //     }
28437330f729Sjoerg //   };
28447330f729Sjoerg //
28457330f729Sjoerg //   struct D
28467330f729Sjoerg //   0 |   (D vbtable pointer)
28477330f729Sjoerg //   4 |   (vtordisp for vbase A)
28487330f729Sjoerg //   8 |   struct A (virtual base)  // A precedes both B and C!
28497330f729Sjoerg //   8 |     (A vftable pointer)
28507330f729Sjoerg //  12 |   struct B (virtual base)  // B precedes C!
28517330f729Sjoerg //  12 |     (B vbtable pointer)
28527330f729Sjoerg //  16 |   struct C (virtual base)
28537330f729Sjoerg //  16 |     (C vbtable pointer)
28547330f729Sjoerg //
28557330f729Sjoerg // When D::D() calls foo(), we find ourselves in a thunk that should tailcall
28567330f729Sjoerg // to C::f(), which assumes C+8 as its "this" parameter.  This time, foo()
28577330f729Sjoerg // passes along A, which is C-8.  The A vtordisp holds
28587330f729Sjoerg //   "D.vbptr[index_of_A] - offset_of_A_in_D"
28597330f729Sjoerg // and we statically know offset_of_A_in_D, so can get a pointer to D.
28607330f729Sjoerg // When we know it, we can make an extra vbtable lookup to locate the C vbase
28617330f729Sjoerg // and one extra static adjustment to calculate the expected value of C+8.
CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,CharUnits ThisOffset,ThisAdjustment & TA)28627330f729Sjoerg void VFTableBuilder::CalculateVtordispAdjustment(
28637330f729Sjoerg     FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
28647330f729Sjoerg     ThisAdjustment &TA) {
28657330f729Sjoerg   const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap =
28667330f729Sjoerg       MostDerivedClassLayout.getVBaseOffsetsMap();
28677330f729Sjoerg   const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
28687330f729Sjoerg       VBaseMap.find(WhichVFPtr.getVBaseWithVPtr());
28697330f729Sjoerg   assert(VBaseMapEntry != VBaseMap.end());
28707330f729Sjoerg 
28717330f729Sjoerg   // If there's no vtordisp or the final overrider is defined in the same vbase
28727330f729Sjoerg   // as the initial declaration, we don't need any vtordisp adjustment.
28737330f729Sjoerg   if (!VBaseMapEntry->second.hasVtorDisp() ||
28747330f729Sjoerg       Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr())
28757330f729Sjoerg     return;
28767330f729Sjoerg 
28777330f729Sjoerg   // OK, now we know we need to use a vtordisp thunk.
28787330f729Sjoerg   // The implicit vtordisp field is located right before the vbase.
28797330f729Sjoerg   CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
28807330f729Sjoerg   TA.Virtual.Microsoft.VtordispOffset =
28817330f729Sjoerg       (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
28827330f729Sjoerg 
28837330f729Sjoerg   // A simple vtordisp thunk will suffice if the final overrider is defined
28847330f729Sjoerg   // in either the most derived class or its non-virtual base.
28857330f729Sjoerg   if (Overrider.Method->getParent() == MostDerivedClass ||
28867330f729Sjoerg       !Overrider.VirtualBase)
28877330f729Sjoerg     return;
28887330f729Sjoerg 
28897330f729Sjoerg   // Otherwise, we need to do use the dynamic offset of the final overrider
28907330f729Sjoerg   // in order to get "this" adjustment right.
28917330f729Sjoerg   TA.Virtual.Microsoft.VBPtrOffset =
28927330f729Sjoerg       (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset -
28937330f729Sjoerg        MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
28947330f729Sjoerg   TA.Virtual.Microsoft.VBOffsetOffset =
28957330f729Sjoerg       Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
28967330f729Sjoerg       VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase);
28977330f729Sjoerg 
28987330f729Sjoerg   TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
28997330f729Sjoerg }
29007330f729Sjoerg 
GroupNewVirtualOverloads(const CXXRecordDecl * RD,SmallVector<const CXXMethodDecl *,10> & VirtualMethods)29017330f729Sjoerg static void GroupNewVirtualOverloads(
29027330f729Sjoerg     const CXXRecordDecl *RD,
29037330f729Sjoerg     SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) {
29047330f729Sjoerg   // Put the virtual methods into VirtualMethods in the proper order:
29057330f729Sjoerg   // 1) Group overloads by declaration name. New groups are added to the
29067330f729Sjoerg   //    vftable in the order of their first declarations in this class
29077330f729Sjoerg   //    (including overrides, non-virtual methods and any other named decl that
29087330f729Sjoerg   //    might be nested within the class).
29097330f729Sjoerg   // 2) In each group, new overloads appear in the reverse order of declaration.
29107330f729Sjoerg   typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
29117330f729Sjoerg   SmallVector<MethodGroup, 10> Groups;
29127330f729Sjoerg   typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
29137330f729Sjoerg   VisitedGroupIndicesTy VisitedGroupIndices;
29147330f729Sjoerg   for (const auto *D : RD->decls()) {
29157330f729Sjoerg     const auto *ND = dyn_cast<NamedDecl>(D);
29167330f729Sjoerg     if (!ND)
29177330f729Sjoerg       continue;
29187330f729Sjoerg     VisitedGroupIndicesTy::iterator J;
29197330f729Sjoerg     bool Inserted;
29207330f729Sjoerg     std::tie(J, Inserted) = VisitedGroupIndices.insert(
29217330f729Sjoerg         std::make_pair(ND->getDeclName(), Groups.size()));
29227330f729Sjoerg     if (Inserted)
29237330f729Sjoerg       Groups.push_back(MethodGroup());
29247330f729Sjoerg     if (const auto *MD = dyn_cast<CXXMethodDecl>(ND))
2925*e038c9c4Sjoerg       if (MicrosoftVTableContext::hasVtableSlot(MD))
29267330f729Sjoerg         Groups[J->second].push_back(MD->getCanonicalDecl());
29277330f729Sjoerg   }
29287330f729Sjoerg 
29297330f729Sjoerg   for (const MethodGroup &Group : Groups)
29307330f729Sjoerg     VirtualMethods.append(Group.rbegin(), Group.rend());
29317330f729Sjoerg }
29327330f729Sjoerg 
isDirectVBase(const CXXRecordDecl * Base,const CXXRecordDecl * RD)29337330f729Sjoerg static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) {
29347330f729Sjoerg   for (const auto &B : RD->bases()) {
29357330f729Sjoerg     if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
29367330f729Sjoerg       return true;
29377330f729Sjoerg   }
29387330f729Sjoerg   return false;
29397330f729Sjoerg }
29407330f729Sjoerg 
AddMethods(BaseSubobject Base,unsigned BaseDepth,const CXXRecordDecl * LastVBase,BasesSetVectorTy & VisitedBases)29417330f729Sjoerg void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
29427330f729Sjoerg                                 const CXXRecordDecl *LastVBase,
29437330f729Sjoerg                                 BasesSetVectorTy &VisitedBases) {
29447330f729Sjoerg   const CXXRecordDecl *RD = Base.getBase();
29457330f729Sjoerg   if (!RD->isPolymorphic())
29467330f729Sjoerg     return;
29477330f729Sjoerg 
29487330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
29497330f729Sjoerg 
29507330f729Sjoerg   // See if this class expands a vftable of the base we look at, which is either
29517330f729Sjoerg   // the one defined by the vfptr base path or the primary base of the current
29527330f729Sjoerg   // class.
29537330f729Sjoerg   const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase;
29547330f729Sjoerg   CharUnits NextBaseOffset;
29557330f729Sjoerg   if (BaseDepth < WhichVFPtr.PathToIntroducingObject.size()) {
29567330f729Sjoerg     NextBase = WhichVFPtr.PathToIntroducingObject[BaseDepth];
29577330f729Sjoerg     if (isDirectVBase(NextBase, RD)) {
29587330f729Sjoerg       NextLastVBase = NextBase;
29597330f729Sjoerg       NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase);
29607330f729Sjoerg     } else {
29617330f729Sjoerg       NextBaseOffset =
29627330f729Sjoerg           Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase);
29637330f729Sjoerg     }
29647330f729Sjoerg   } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
29657330f729Sjoerg     assert(!Layout.isPrimaryBaseVirtual() &&
29667330f729Sjoerg            "No primary virtual bases in this ABI");
29677330f729Sjoerg     NextBase = PrimaryBase;
29687330f729Sjoerg     NextBaseOffset = Base.getBaseOffset();
29697330f729Sjoerg   }
29707330f729Sjoerg 
29717330f729Sjoerg   if (NextBase) {
29727330f729Sjoerg     AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
29737330f729Sjoerg                NextLastVBase, VisitedBases);
29747330f729Sjoerg     if (!VisitedBases.insert(NextBase))
29757330f729Sjoerg       llvm_unreachable("Found a duplicate primary base!");
29767330f729Sjoerg   }
29777330f729Sjoerg 
29787330f729Sjoerg   SmallVector<const CXXMethodDecl*, 10> VirtualMethods;
29797330f729Sjoerg   // Put virtual methods in the proper order.
29807330f729Sjoerg   GroupNewVirtualOverloads(RD, VirtualMethods);
29817330f729Sjoerg 
29827330f729Sjoerg   // Now go through all virtual member functions and add them to the current
29837330f729Sjoerg   // vftable. This is done by
29847330f729Sjoerg   //  - replacing overridden methods in their existing slots, as long as they
29857330f729Sjoerg   //    don't require return adjustment; calculating This adjustment if needed.
29867330f729Sjoerg   //  - adding new slots for methods of the current base not present in any
29877330f729Sjoerg   //    sub-bases;
29887330f729Sjoerg   //  - adding new slots for methods that require Return adjustment.
29897330f729Sjoerg   // We keep track of the methods visited in the sub-bases in MethodInfoMap.
29907330f729Sjoerg   for (const CXXMethodDecl *MD : VirtualMethods) {
29917330f729Sjoerg     FinalOverriders::OverriderInfo FinalOverrider =
29927330f729Sjoerg         Overriders.getOverrider(MD, Base.getBaseOffset());
29937330f729Sjoerg     const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
29947330f729Sjoerg     const CXXMethodDecl *OverriddenMD =
29957330f729Sjoerg         FindNearestOverriddenMethod(MD, VisitedBases);
29967330f729Sjoerg 
29977330f729Sjoerg     ThisAdjustment ThisAdjustmentOffset;
29987330f729Sjoerg     bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false;
29997330f729Sjoerg     CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
30007330f729Sjoerg     ThisAdjustmentOffset.NonVirtual =
30017330f729Sjoerg         (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
30027330f729Sjoerg     if ((OverriddenMD || FinalOverriderMD != MD) &&
30037330f729Sjoerg         WhichVFPtr.getVBaseWithVPtr())
30047330f729Sjoerg       CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
30057330f729Sjoerg                                   ThisAdjustmentOffset);
30067330f729Sjoerg 
30077330f729Sjoerg     unsigned VBIndex =
30087330f729Sjoerg         LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
30097330f729Sjoerg 
30107330f729Sjoerg     if (OverriddenMD) {
30117330f729Sjoerg       // If MD overrides anything in this vftable, we need to update the
30127330f729Sjoerg       // entries.
30137330f729Sjoerg       MethodInfoMapTy::iterator OverriddenMDIterator =
30147330f729Sjoerg           MethodInfoMap.find(OverriddenMD);
30157330f729Sjoerg 
30167330f729Sjoerg       // If the overridden method went to a different vftable, skip it.
30177330f729Sjoerg       if (OverriddenMDIterator == MethodInfoMap.end())
30187330f729Sjoerg         continue;
30197330f729Sjoerg 
30207330f729Sjoerg       MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
30217330f729Sjoerg 
30227330f729Sjoerg       VBIndex = OverriddenMethodInfo.VBTableIndex;
30237330f729Sjoerg 
30247330f729Sjoerg       // Let's check if the overrider requires any return adjustments.
30257330f729Sjoerg       // We must create a new slot if the MD's return type is not trivially
30267330f729Sjoerg       // convertible to the OverriddenMD's one.
30277330f729Sjoerg       // Once a chain of method overrides adds a return adjusting vftable slot,
30287330f729Sjoerg       // all subsequent overrides will also use an extra method slot.
30297330f729Sjoerg       ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
30307330f729Sjoerg                                   Context, MD, OverriddenMD).isEmpty() ||
30317330f729Sjoerg                              OverriddenMethodInfo.UsesExtraSlot;
30327330f729Sjoerg 
30337330f729Sjoerg       if (!ReturnAdjustingThunk) {
30347330f729Sjoerg         // No return adjustment needed - just replace the overridden method info
30357330f729Sjoerg         // with the current info.
30367330f729Sjoerg         MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
30377330f729Sjoerg         MethodInfoMap.erase(OverriddenMDIterator);
30387330f729Sjoerg 
30397330f729Sjoerg         assert(!MethodInfoMap.count(MD) &&
30407330f729Sjoerg                "Should not have method info for this method yet!");
30417330f729Sjoerg         MethodInfoMap.insert(std::make_pair(MD, MI));
30427330f729Sjoerg         continue;
30437330f729Sjoerg       }
30447330f729Sjoerg 
30457330f729Sjoerg       // In case we need a return adjustment, we'll add a new slot for
30467330f729Sjoerg       // the overrider. Mark the overridden method as shadowed by the new slot.
30477330f729Sjoerg       OverriddenMethodInfo.Shadowed = true;
30487330f729Sjoerg 
30497330f729Sjoerg       // Force a special name mangling for a return-adjusting thunk
30507330f729Sjoerg       // unless the method is the final overrider without this adjustment.
30517330f729Sjoerg       ForceReturnAdjustmentMangling =
30527330f729Sjoerg           !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty());
30537330f729Sjoerg     } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC ||
30547330f729Sjoerg                MD->size_overridden_methods()) {
30557330f729Sjoerg       // Skip methods that don't belong to the vftable of the current class,
30567330f729Sjoerg       // e.g. each method that wasn't seen in any of the visited sub-bases
30577330f729Sjoerg       // but overrides multiple methods of other sub-bases.
30587330f729Sjoerg       continue;
30597330f729Sjoerg     }
30607330f729Sjoerg 
30617330f729Sjoerg     // If we got here, MD is a method not seen in any of the sub-bases or
30627330f729Sjoerg     // it requires return adjustment. Insert the method info for this method.
30637330f729Sjoerg     MethodInfo MI(VBIndex,
30647330f729Sjoerg                   HasRTTIComponent ? Components.size() - 1 : Components.size(),
30657330f729Sjoerg                   ReturnAdjustingThunk);
30667330f729Sjoerg 
30677330f729Sjoerg     assert(!MethodInfoMap.count(MD) &&
30687330f729Sjoerg            "Should not have method info for this method yet!");
30697330f729Sjoerg     MethodInfoMap.insert(std::make_pair(MD, MI));
30707330f729Sjoerg 
30717330f729Sjoerg     // Check if this overrider needs a return adjustment.
30727330f729Sjoerg     // We don't want to do this for pure virtual member functions.
30737330f729Sjoerg     BaseOffset ReturnAdjustmentOffset;
30747330f729Sjoerg     ReturnAdjustment ReturnAdjustment;
30757330f729Sjoerg     if (!FinalOverriderMD->isPure()) {
30767330f729Sjoerg       ReturnAdjustmentOffset =
30777330f729Sjoerg           ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
30787330f729Sjoerg     }
30797330f729Sjoerg     if (!ReturnAdjustmentOffset.isEmpty()) {
30807330f729Sjoerg       ForceReturnAdjustmentMangling = true;
30817330f729Sjoerg       ReturnAdjustment.NonVirtual =
30827330f729Sjoerg           ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
30837330f729Sjoerg       if (ReturnAdjustmentOffset.VirtualBase) {
30847330f729Sjoerg         const ASTRecordLayout &DerivedLayout =
30857330f729Sjoerg             Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass);
30867330f729Sjoerg         ReturnAdjustment.Virtual.Microsoft.VBPtrOffset =
30877330f729Sjoerg             DerivedLayout.getVBPtrOffset().getQuantity();
30887330f729Sjoerg         ReturnAdjustment.Virtual.Microsoft.VBIndex =
30897330f729Sjoerg             VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
30907330f729Sjoerg                                     ReturnAdjustmentOffset.VirtualBase);
30917330f729Sjoerg       }
30927330f729Sjoerg     }
30937330f729Sjoerg 
30947330f729Sjoerg     AddMethod(FinalOverriderMD,
30957330f729Sjoerg               ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
30967330f729Sjoerg                         ForceReturnAdjustmentMangling ? MD : nullptr));
30977330f729Sjoerg   }
30987330f729Sjoerg }
30997330f729Sjoerg 
PrintBasePath(const VPtrInfo::BasePath & Path,raw_ostream & Out)31007330f729Sjoerg static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out) {
31017330f729Sjoerg   for (const CXXRecordDecl *Elem :
31027330f729Sjoerg        llvm::make_range(Path.rbegin(), Path.rend())) {
31037330f729Sjoerg     Out << "'";
31047330f729Sjoerg     Elem->printQualifiedName(Out);
31057330f729Sjoerg     Out << "' in ";
31067330f729Sjoerg   }
31077330f729Sjoerg }
31087330f729Sjoerg 
dumpMicrosoftThunkAdjustment(const ThunkInfo & TI,raw_ostream & Out,bool ContinueFirstLine)31097330f729Sjoerg static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
31107330f729Sjoerg                                          bool ContinueFirstLine) {
31117330f729Sjoerg   const ReturnAdjustment &R = TI.Return;
31127330f729Sjoerg   bool Multiline = false;
31137330f729Sjoerg   const char *LinePrefix = "\n       ";
31147330f729Sjoerg   if (!R.isEmpty() || TI.Method) {
31157330f729Sjoerg     if (!ContinueFirstLine)
31167330f729Sjoerg       Out << LinePrefix;
31177330f729Sjoerg     Out << "[return adjustment (to type '"
31187330f729Sjoerg         << TI.Method->getReturnType().getCanonicalType().getAsString()
31197330f729Sjoerg         << "'): ";
31207330f729Sjoerg     if (R.Virtual.Microsoft.VBPtrOffset)
31217330f729Sjoerg       Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
31227330f729Sjoerg     if (R.Virtual.Microsoft.VBIndex)
31237330f729Sjoerg       Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", ";
31247330f729Sjoerg     Out << R.NonVirtual << " non-virtual]";
31257330f729Sjoerg     Multiline = true;
31267330f729Sjoerg   }
31277330f729Sjoerg 
31287330f729Sjoerg   const ThisAdjustment &T = TI.This;
31297330f729Sjoerg   if (!T.isEmpty()) {
31307330f729Sjoerg     if (Multiline || !ContinueFirstLine)
31317330f729Sjoerg       Out << LinePrefix;
31327330f729Sjoerg     Out << "[this adjustment: ";
31337330f729Sjoerg     if (!TI.This.Virtual.isEmpty()) {
31347330f729Sjoerg       assert(T.Virtual.Microsoft.VtordispOffset < 0);
31357330f729Sjoerg       Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
31367330f729Sjoerg       if (T.Virtual.Microsoft.VBPtrOffset) {
31377330f729Sjoerg         Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
31387330f729Sjoerg             << " to the left,";
31397330f729Sjoerg         assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
31407330f729Sjoerg         Out << LinePrefix << " vboffset at "
31417330f729Sjoerg             << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
31427330f729Sjoerg       }
31437330f729Sjoerg     }
31447330f729Sjoerg     Out << T.NonVirtual << " non-virtual]";
31457330f729Sjoerg   }
31467330f729Sjoerg }
31477330f729Sjoerg 
dumpLayout(raw_ostream & Out)31487330f729Sjoerg void VFTableBuilder::dumpLayout(raw_ostream &Out) {
31497330f729Sjoerg   Out << "VFTable for ";
31507330f729Sjoerg   PrintBasePath(WhichVFPtr.PathToIntroducingObject, Out);
31517330f729Sjoerg   Out << "'";
31527330f729Sjoerg   MostDerivedClass->printQualifiedName(Out);
31537330f729Sjoerg   Out << "' (" << Components.size()
31547330f729Sjoerg       << (Components.size() == 1 ? " entry" : " entries") << ").\n";
31557330f729Sjoerg 
31567330f729Sjoerg   for (unsigned I = 0, E = Components.size(); I != E; ++I) {
31577330f729Sjoerg     Out << llvm::format("%4d | ", I);
31587330f729Sjoerg 
31597330f729Sjoerg     const VTableComponent &Component = Components[I];
31607330f729Sjoerg 
31617330f729Sjoerg     // Dump the component.
31627330f729Sjoerg     switch (Component.getKind()) {
31637330f729Sjoerg     case VTableComponent::CK_RTTI:
31647330f729Sjoerg       Component.getRTTIDecl()->printQualifiedName(Out);
31657330f729Sjoerg       Out << " RTTI";
31667330f729Sjoerg       break;
31677330f729Sjoerg 
31687330f729Sjoerg     case VTableComponent::CK_FunctionPointer: {
31697330f729Sjoerg       const CXXMethodDecl *MD = Component.getFunctionDecl();
31707330f729Sjoerg 
31717330f729Sjoerg       // FIXME: Figure out how to print the real thunk type, since they can
31727330f729Sjoerg       // differ in the return type.
31737330f729Sjoerg       std::string Str = PredefinedExpr::ComputeName(
31747330f729Sjoerg           PredefinedExpr::PrettyFunctionNoVirtual, MD);
31757330f729Sjoerg       Out << Str;
31767330f729Sjoerg       if (MD->isPure())
31777330f729Sjoerg         Out << " [pure]";
31787330f729Sjoerg 
31797330f729Sjoerg       if (MD->isDeleted())
31807330f729Sjoerg         Out << " [deleted]";
31817330f729Sjoerg 
31827330f729Sjoerg       ThunkInfo Thunk = VTableThunks.lookup(I);
31837330f729Sjoerg       if (!Thunk.isEmpty())
31847330f729Sjoerg         dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
31857330f729Sjoerg 
31867330f729Sjoerg       break;
31877330f729Sjoerg     }
31887330f729Sjoerg 
31897330f729Sjoerg     case VTableComponent::CK_DeletingDtorPointer: {
31907330f729Sjoerg       const CXXDestructorDecl *DD = Component.getDestructorDecl();
31917330f729Sjoerg 
31927330f729Sjoerg       DD->printQualifiedName(Out);
31937330f729Sjoerg       Out << "() [scalar deleting]";
31947330f729Sjoerg 
31957330f729Sjoerg       if (DD->isPure())
31967330f729Sjoerg         Out << " [pure]";
31977330f729Sjoerg 
31987330f729Sjoerg       ThunkInfo Thunk = VTableThunks.lookup(I);
31997330f729Sjoerg       if (!Thunk.isEmpty()) {
32007330f729Sjoerg         assert(Thunk.Return.isEmpty() &&
32017330f729Sjoerg                "No return adjustment needed for destructors!");
32027330f729Sjoerg         dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
32037330f729Sjoerg       }
32047330f729Sjoerg 
32057330f729Sjoerg       break;
32067330f729Sjoerg     }
32077330f729Sjoerg 
32087330f729Sjoerg     default:
32097330f729Sjoerg       DiagnosticsEngine &Diags = Context.getDiagnostics();
32107330f729Sjoerg       unsigned DiagID = Diags.getCustomDiagID(
32117330f729Sjoerg           DiagnosticsEngine::Error,
32127330f729Sjoerg           "Unexpected vftable component type %0 for component number %1");
32137330f729Sjoerg       Diags.Report(MostDerivedClass->getLocation(), DiagID)
32147330f729Sjoerg           << I << Component.getKind();
32157330f729Sjoerg     }
32167330f729Sjoerg 
32177330f729Sjoerg     Out << '\n';
32187330f729Sjoerg   }
32197330f729Sjoerg 
32207330f729Sjoerg   Out << '\n';
32217330f729Sjoerg 
32227330f729Sjoerg   if (!Thunks.empty()) {
32237330f729Sjoerg     // We store the method names in a map to get a stable order.
32247330f729Sjoerg     std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
32257330f729Sjoerg 
32267330f729Sjoerg     for (const auto &I : Thunks) {
32277330f729Sjoerg       const CXXMethodDecl *MD = I.first;
32287330f729Sjoerg       std::string MethodName = PredefinedExpr::ComputeName(
32297330f729Sjoerg           PredefinedExpr::PrettyFunctionNoVirtual, MD);
32307330f729Sjoerg 
32317330f729Sjoerg       MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
32327330f729Sjoerg     }
32337330f729Sjoerg 
32347330f729Sjoerg     for (const auto &MethodNameAndDecl : MethodNamesAndDecls) {
32357330f729Sjoerg       const std::string &MethodName = MethodNameAndDecl.first;
32367330f729Sjoerg       const CXXMethodDecl *MD = MethodNameAndDecl.second;
32377330f729Sjoerg 
32387330f729Sjoerg       ThunkInfoVectorTy ThunksVector = Thunks[MD];
32397330f729Sjoerg       llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS,
32407330f729Sjoerg                                          const ThunkInfo &RHS) {
32417330f729Sjoerg         // Keep different thunks with the same adjustments in the order they
32427330f729Sjoerg         // were put into the vector.
32437330f729Sjoerg         return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);
32447330f729Sjoerg       });
32457330f729Sjoerg 
32467330f729Sjoerg       Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
32477330f729Sjoerg       Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
32487330f729Sjoerg 
32497330f729Sjoerg       for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
32507330f729Sjoerg         const ThunkInfo &Thunk = ThunksVector[I];
32517330f729Sjoerg 
32527330f729Sjoerg         Out << llvm::format("%4d | ", I);
32537330f729Sjoerg         dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true);
32547330f729Sjoerg         Out << '\n';
32557330f729Sjoerg       }
32567330f729Sjoerg 
32577330f729Sjoerg       Out << '\n';
32587330f729Sjoerg     }
32597330f729Sjoerg   }
32607330f729Sjoerg 
32617330f729Sjoerg   Out.flush();
32627330f729Sjoerg }
32637330f729Sjoerg 
setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *,4> & A,ArrayRef<const CXXRecordDecl * > B)32647330f729Sjoerg static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A,
32657330f729Sjoerg                           ArrayRef<const CXXRecordDecl *> B) {
32667330f729Sjoerg   for (const CXXRecordDecl *Decl : B) {
32677330f729Sjoerg     if (A.count(Decl))
32687330f729Sjoerg       return true;
32697330f729Sjoerg   }
32707330f729Sjoerg   return false;
32717330f729Sjoerg }
32727330f729Sjoerg 
32737330f729Sjoerg static bool rebucketPaths(VPtrInfoVector &Paths);
32747330f729Sjoerg 
32757330f729Sjoerg /// Produces MSVC-compatible vbtable data.  The symbols produced by this
32767330f729Sjoerg /// algorithm match those produced by MSVC 2012 and newer, which is different
32777330f729Sjoerg /// from MSVC 2010.
32787330f729Sjoerg ///
32797330f729Sjoerg /// MSVC 2012 appears to minimize the vbtable names using the following
32807330f729Sjoerg /// algorithm.  First, walk the class hierarchy in the usual order, depth first,
32817330f729Sjoerg /// left to right, to find all of the subobjects which contain a vbptr field.
32827330f729Sjoerg /// Visiting each class node yields a list of inheritance paths to vbptrs.  Each
32837330f729Sjoerg /// record with a vbptr creates an initially empty path.
32847330f729Sjoerg ///
32857330f729Sjoerg /// To combine paths from child nodes, the paths are compared to check for
32867330f729Sjoerg /// ambiguity.  Paths are "ambiguous" if multiple paths have the same set of
32877330f729Sjoerg /// components in the same order.  Each group of ambiguous paths is extended by
32887330f729Sjoerg /// appending the class of the base from which it came.  If the current class
32897330f729Sjoerg /// node produced an ambiguous path, its path is extended with the current class.
32907330f729Sjoerg /// After extending paths, MSVC again checks for ambiguity, and extends any
32917330f729Sjoerg /// ambiguous path which wasn't already extended.  Because each node yields an
32927330f729Sjoerg /// unambiguous set of paths, MSVC doesn't need to extend any path more than once
32937330f729Sjoerg /// to produce an unambiguous set of paths.
32947330f729Sjoerg ///
32957330f729Sjoerg /// TODO: Presumably vftables use the same algorithm.
computeVTablePaths(bool ForVBTables,const CXXRecordDecl * RD,VPtrInfoVector & Paths)32967330f729Sjoerg void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
32977330f729Sjoerg                                                 const CXXRecordDecl *RD,
32987330f729Sjoerg                                                 VPtrInfoVector &Paths) {
32997330f729Sjoerg   assert(Paths.empty());
33007330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
33017330f729Sjoerg 
33027330f729Sjoerg   // Base case: this subobject has its own vptr.
33037330f729Sjoerg   if (ForVBTables ? Layout.hasOwnVBPtr() : Layout.hasOwnVFPtr())
33047330f729Sjoerg     Paths.push_back(std::make_unique<VPtrInfo>(RD));
33057330f729Sjoerg 
33067330f729Sjoerg   // Recursive case: get all the vbtables from our bases and remove anything
33077330f729Sjoerg   // that shares a virtual base.
33087330f729Sjoerg   llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
33097330f729Sjoerg   for (const auto &B : RD->bases()) {
33107330f729Sjoerg     const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
33117330f729Sjoerg     if (B.isVirtual() && VBasesSeen.count(Base))
33127330f729Sjoerg       continue;
33137330f729Sjoerg 
33147330f729Sjoerg     if (!Base->isDynamicClass())
33157330f729Sjoerg       continue;
33167330f729Sjoerg 
33177330f729Sjoerg     const VPtrInfoVector &BasePaths =
33187330f729Sjoerg         ForVBTables ? enumerateVBTables(Base) : getVFPtrOffsets(Base);
33197330f729Sjoerg 
33207330f729Sjoerg     for (const std::unique_ptr<VPtrInfo> &BaseInfo : BasePaths) {
33217330f729Sjoerg       // Don't include the path if it goes through a virtual base that we've
33227330f729Sjoerg       // already included.
33237330f729Sjoerg       if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases))
33247330f729Sjoerg         continue;
33257330f729Sjoerg 
33267330f729Sjoerg       // Copy the path and adjust it as necessary.
33277330f729Sjoerg       auto P = std::make_unique<VPtrInfo>(*BaseInfo);
33287330f729Sjoerg 
33297330f729Sjoerg       // We mangle Base into the path if the path would've been ambiguous and it
33307330f729Sjoerg       // wasn't already extended with Base.
33317330f729Sjoerg       if (P->MangledPath.empty() || P->MangledPath.back() != Base)
33327330f729Sjoerg         P->NextBaseToMangle = Base;
33337330f729Sjoerg 
33347330f729Sjoerg       // Keep track of which vtable the derived class is going to extend with
33357330f729Sjoerg       // new methods or bases.  We append to either the vftable of our primary
33367330f729Sjoerg       // base, or the first non-virtual base that has a vbtable.
33377330f729Sjoerg       if (P->ObjectWithVPtr == Base &&
33387330f729Sjoerg           Base == (ForVBTables ? Layout.getBaseSharingVBPtr()
33397330f729Sjoerg                                : Layout.getPrimaryBase()))
33407330f729Sjoerg         P->ObjectWithVPtr = RD;
33417330f729Sjoerg 
33427330f729Sjoerg       // Keep track of the full adjustment from the MDC to this vtable.  The
33437330f729Sjoerg       // adjustment is captured by an optional vbase and a non-virtual offset.
33447330f729Sjoerg       if (B.isVirtual())
33457330f729Sjoerg         P->ContainingVBases.push_back(Base);
33467330f729Sjoerg       else if (P->ContainingVBases.empty())
33477330f729Sjoerg         P->NonVirtualOffset += Layout.getBaseClassOffset(Base);
33487330f729Sjoerg 
33497330f729Sjoerg       // Update the full offset in the MDC.
33507330f729Sjoerg       P->FullOffsetInMDC = P->NonVirtualOffset;
33517330f729Sjoerg       if (const CXXRecordDecl *VB = P->getVBaseWithVPtr())
33527330f729Sjoerg         P->FullOffsetInMDC += Layout.getVBaseClassOffset(VB);
33537330f729Sjoerg 
33547330f729Sjoerg       Paths.push_back(std::move(P));
33557330f729Sjoerg     }
33567330f729Sjoerg 
33577330f729Sjoerg     if (B.isVirtual())
33587330f729Sjoerg       VBasesSeen.insert(Base);
33597330f729Sjoerg 
33607330f729Sjoerg     // After visiting any direct base, we've transitively visited all of its
33617330f729Sjoerg     // morally virtual bases.
33627330f729Sjoerg     for (const auto &VB : Base->vbases())
33637330f729Sjoerg       VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
33647330f729Sjoerg   }
33657330f729Sjoerg 
33667330f729Sjoerg   // Sort the paths into buckets, and if any of them are ambiguous, extend all
33677330f729Sjoerg   // paths in ambiguous buckets.
33687330f729Sjoerg   bool Changed = true;
33697330f729Sjoerg   while (Changed)
33707330f729Sjoerg     Changed = rebucketPaths(Paths);
33717330f729Sjoerg }
33727330f729Sjoerg 
extendPath(VPtrInfo & P)33737330f729Sjoerg static bool extendPath(VPtrInfo &P) {
33747330f729Sjoerg   if (P.NextBaseToMangle) {
33757330f729Sjoerg     P.MangledPath.push_back(P.NextBaseToMangle);
33767330f729Sjoerg     P.NextBaseToMangle = nullptr;// Prevent the path from being extended twice.
33777330f729Sjoerg     return true;
33787330f729Sjoerg   }
33797330f729Sjoerg   return false;
33807330f729Sjoerg }
33817330f729Sjoerg 
rebucketPaths(VPtrInfoVector & Paths)33827330f729Sjoerg static bool rebucketPaths(VPtrInfoVector &Paths) {
33837330f729Sjoerg   // What we're essentially doing here is bucketing together ambiguous paths.
33847330f729Sjoerg   // Any bucket with more than one path in it gets extended by NextBase, which
33857330f729Sjoerg   // is usually the direct base of the inherited the vbptr.  This code uses a
33867330f729Sjoerg   // sorted vector to implement a multiset to form the buckets.  Note that the
33877330f729Sjoerg   // ordering is based on pointers, but it doesn't change our output order.  The
33887330f729Sjoerg   // current algorithm is designed to match MSVC 2012's names.
33897330f729Sjoerg   llvm::SmallVector<std::reference_wrapper<VPtrInfo>, 2> PathsSorted;
33907330f729Sjoerg   PathsSorted.reserve(Paths.size());
33917330f729Sjoerg   for (auto& P : Paths)
33927330f729Sjoerg     PathsSorted.push_back(*P);
33937330f729Sjoerg   llvm::sort(PathsSorted, [](const VPtrInfo &LHS, const VPtrInfo &RHS) {
33947330f729Sjoerg     return LHS.MangledPath < RHS.MangledPath;
33957330f729Sjoerg   });
33967330f729Sjoerg   bool Changed = false;
33977330f729Sjoerg   for (size_t I = 0, E = PathsSorted.size(); I != E;) {
33987330f729Sjoerg     // Scan forward to find the end of the bucket.
33997330f729Sjoerg     size_t BucketStart = I;
34007330f729Sjoerg     do {
34017330f729Sjoerg       ++I;
34027330f729Sjoerg     } while (I != E &&
34037330f729Sjoerg              PathsSorted[BucketStart].get().MangledPath ==
34047330f729Sjoerg                  PathsSorted[I].get().MangledPath);
34057330f729Sjoerg 
34067330f729Sjoerg     // If this bucket has multiple paths, extend them all.
34077330f729Sjoerg     if (I - BucketStart > 1) {
34087330f729Sjoerg       for (size_t II = BucketStart; II != I; ++II)
34097330f729Sjoerg         Changed |= extendPath(PathsSorted[II]);
34107330f729Sjoerg       assert(Changed && "no paths were extended to fix ambiguity");
34117330f729Sjoerg     }
34127330f729Sjoerg   }
34137330f729Sjoerg   return Changed;
34147330f729Sjoerg }
34157330f729Sjoerg 
~MicrosoftVTableContext()34167330f729Sjoerg MicrosoftVTableContext::~MicrosoftVTableContext() {}
34177330f729Sjoerg 
34187330f729Sjoerg namespace {
34197330f729Sjoerg typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>,
34207330f729Sjoerg                         llvm::DenseSet<BaseSubobject>> FullPathTy;
34217330f729Sjoerg }
34227330f729Sjoerg 
34237330f729Sjoerg // This recursive function finds all paths from a subobject centered at
34247330f729Sjoerg // (RD, Offset) to the subobject located at IntroducingObject.
findPathsToSubobject(ASTContext & Context,const ASTRecordLayout & MostDerivedLayout,const CXXRecordDecl * RD,CharUnits Offset,BaseSubobject IntroducingObject,FullPathTy & FullPath,std::list<FullPathTy> & Paths)34257330f729Sjoerg static void findPathsToSubobject(ASTContext &Context,
34267330f729Sjoerg                                  const ASTRecordLayout &MostDerivedLayout,
34277330f729Sjoerg                                  const CXXRecordDecl *RD, CharUnits Offset,
34287330f729Sjoerg                                  BaseSubobject IntroducingObject,
34297330f729Sjoerg                                  FullPathTy &FullPath,
34307330f729Sjoerg                                  std::list<FullPathTy> &Paths) {
34317330f729Sjoerg   if (BaseSubobject(RD, Offset) == IntroducingObject) {
34327330f729Sjoerg     Paths.push_back(FullPath);
34337330f729Sjoerg     return;
34347330f729Sjoerg   }
34357330f729Sjoerg 
34367330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
34377330f729Sjoerg 
34387330f729Sjoerg   for (const CXXBaseSpecifier &BS : RD->bases()) {
34397330f729Sjoerg     const CXXRecordDecl *Base = BS.getType()->getAsCXXRecordDecl();
34407330f729Sjoerg     CharUnits NewOffset = BS.isVirtual()
34417330f729Sjoerg                               ? MostDerivedLayout.getVBaseClassOffset(Base)
34427330f729Sjoerg                               : Offset + Layout.getBaseClassOffset(Base);
34437330f729Sjoerg     FullPath.insert(BaseSubobject(Base, NewOffset));
34447330f729Sjoerg     findPathsToSubobject(Context, MostDerivedLayout, Base, NewOffset,
34457330f729Sjoerg                          IntroducingObject, FullPath, Paths);
34467330f729Sjoerg     FullPath.pop_back();
34477330f729Sjoerg   }
34487330f729Sjoerg }
34497330f729Sjoerg 
34507330f729Sjoerg // Return the paths which are not subsets of other paths.
removeRedundantPaths(std::list<FullPathTy> & FullPaths)34517330f729Sjoerg static void removeRedundantPaths(std::list<FullPathTy> &FullPaths) {
34527330f729Sjoerg   FullPaths.remove_if([&](const FullPathTy &SpecificPath) {
34537330f729Sjoerg     for (const FullPathTy &OtherPath : FullPaths) {
34547330f729Sjoerg       if (&SpecificPath == &OtherPath)
34557330f729Sjoerg         continue;
34567330f729Sjoerg       if (llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) {
34577330f729Sjoerg             return OtherPath.count(BSO) != 0;
34587330f729Sjoerg           })) {
34597330f729Sjoerg         return true;
34607330f729Sjoerg       }
34617330f729Sjoerg     }
34627330f729Sjoerg     return false;
34637330f729Sjoerg   });
34647330f729Sjoerg }
34657330f729Sjoerg 
getOffsetOfFullPath(ASTContext & Context,const CXXRecordDecl * RD,const FullPathTy & FullPath)34667330f729Sjoerg static CharUnits getOffsetOfFullPath(ASTContext &Context,
34677330f729Sjoerg                                      const CXXRecordDecl *RD,
34687330f729Sjoerg                                      const FullPathTy &FullPath) {
34697330f729Sjoerg   const ASTRecordLayout &MostDerivedLayout =
34707330f729Sjoerg       Context.getASTRecordLayout(RD);
34717330f729Sjoerg   CharUnits Offset = CharUnits::fromQuantity(-1);
34727330f729Sjoerg   for (const BaseSubobject &BSO : FullPath) {
34737330f729Sjoerg     const CXXRecordDecl *Base = BSO.getBase();
34747330f729Sjoerg     // The first entry in the path is always the most derived record, skip it.
34757330f729Sjoerg     if (Base == RD) {
34767330f729Sjoerg       assert(Offset.getQuantity() == -1);
34777330f729Sjoerg       Offset = CharUnits::Zero();
34787330f729Sjoerg       continue;
34797330f729Sjoerg     }
34807330f729Sjoerg     assert(Offset.getQuantity() != -1);
34817330f729Sjoerg     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
34827330f729Sjoerg     // While we know which base has to be traversed, we don't know if that base
34837330f729Sjoerg     // was a virtual base.
34847330f729Sjoerg     const CXXBaseSpecifier *BaseBS = std::find_if(
34857330f729Sjoerg         RD->bases_begin(), RD->bases_end(), [&](const CXXBaseSpecifier &BS) {
34867330f729Sjoerg           return BS.getType()->getAsCXXRecordDecl() == Base;
34877330f729Sjoerg         });
34887330f729Sjoerg     Offset = BaseBS->isVirtual() ? MostDerivedLayout.getVBaseClassOffset(Base)
34897330f729Sjoerg                                  : Offset + Layout.getBaseClassOffset(Base);
34907330f729Sjoerg     RD = Base;
34917330f729Sjoerg   }
34927330f729Sjoerg   return Offset;
34937330f729Sjoerg }
34947330f729Sjoerg 
34957330f729Sjoerg // We want to select the path which introduces the most covariant overrides.  If
34967330f729Sjoerg // two paths introduce overrides which the other path doesn't contain, issue a
34977330f729Sjoerg // diagnostic.
selectBestPath(ASTContext & Context,const CXXRecordDecl * RD,const VPtrInfo & Info,std::list<FullPathTy> & FullPaths)34987330f729Sjoerg static const FullPathTy *selectBestPath(ASTContext &Context,
34997330f729Sjoerg                                         const CXXRecordDecl *RD,
35007330f729Sjoerg                                         const VPtrInfo &Info,
35017330f729Sjoerg                                         std::list<FullPathTy> &FullPaths) {
35027330f729Sjoerg   // Handle some easy cases first.
35037330f729Sjoerg   if (FullPaths.empty())
35047330f729Sjoerg     return nullptr;
35057330f729Sjoerg   if (FullPaths.size() == 1)
35067330f729Sjoerg     return &FullPaths.front();
35077330f729Sjoerg 
35087330f729Sjoerg   const FullPathTy *BestPath = nullptr;
35097330f729Sjoerg   typedef std::set<const CXXMethodDecl *> OverriderSetTy;
35107330f729Sjoerg   OverriderSetTy LastOverrides;
35117330f729Sjoerg   for (const FullPathTy &SpecificPath : FullPaths) {
35127330f729Sjoerg     assert(!SpecificPath.empty());
35137330f729Sjoerg     OverriderSetTy CurrentOverrides;
35147330f729Sjoerg     const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase();
35157330f729Sjoerg     // Find the distance from the start of the path to the subobject with the
35167330f729Sjoerg     // VPtr.
35177330f729Sjoerg     CharUnits BaseOffset =
35187330f729Sjoerg         getOffsetOfFullPath(Context, TopLevelRD, SpecificPath);
35197330f729Sjoerg     FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD);
35207330f729Sjoerg     for (const CXXMethodDecl *MD : Info.IntroducingObject->methods()) {
3521*e038c9c4Sjoerg       if (!MicrosoftVTableContext::hasVtableSlot(MD))
35227330f729Sjoerg         continue;
35237330f729Sjoerg       FinalOverriders::OverriderInfo OI =
35247330f729Sjoerg           Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset);
35257330f729Sjoerg       const CXXMethodDecl *OverridingMethod = OI.Method;
35267330f729Sjoerg       // Only overriders which have a return adjustment introduce problematic
35277330f729Sjoerg       // thunks.
35287330f729Sjoerg       if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD)
35297330f729Sjoerg               .isEmpty())
35307330f729Sjoerg         continue;
35317330f729Sjoerg       // It's possible that the overrider isn't in this path.  If so, skip it
35327330f729Sjoerg       // because this path didn't introduce it.
35337330f729Sjoerg       const CXXRecordDecl *OverridingParent = OverridingMethod->getParent();
35347330f729Sjoerg       if (llvm::none_of(SpecificPath, [&](const BaseSubobject &BSO) {
35357330f729Sjoerg             return BSO.getBase() == OverridingParent;
35367330f729Sjoerg           }))
35377330f729Sjoerg         continue;
35387330f729Sjoerg       CurrentOverrides.insert(OverridingMethod);
35397330f729Sjoerg     }
35407330f729Sjoerg     OverriderSetTy NewOverrides =
35417330f729Sjoerg         llvm::set_difference(CurrentOverrides, LastOverrides);
35427330f729Sjoerg     if (NewOverrides.empty())
35437330f729Sjoerg       continue;
35447330f729Sjoerg     OverriderSetTy MissingOverrides =
35457330f729Sjoerg         llvm::set_difference(LastOverrides, CurrentOverrides);
35467330f729Sjoerg     if (MissingOverrides.empty()) {
35477330f729Sjoerg       // This path is a strict improvement over the last path, let's use it.
35487330f729Sjoerg       BestPath = &SpecificPath;
35497330f729Sjoerg       std::swap(CurrentOverrides, LastOverrides);
35507330f729Sjoerg     } else {
35517330f729Sjoerg       // This path introduces an overrider with a conflicting covariant thunk.
35527330f729Sjoerg       DiagnosticsEngine &Diags = Context.getDiagnostics();
35537330f729Sjoerg       const CXXMethodDecl *CovariantMD = *NewOverrides.begin();
35547330f729Sjoerg       const CXXMethodDecl *ConflictMD = *MissingOverrides.begin();
35557330f729Sjoerg       Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component)
35567330f729Sjoerg           << RD;
35577330f729Sjoerg       Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk)
35587330f729Sjoerg           << CovariantMD;
35597330f729Sjoerg       Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk)
35607330f729Sjoerg           << ConflictMD;
35617330f729Sjoerg     }
35627330f729Sjoerg   }
35637330f729Sjoerg   // Go with the path that introduced the most covariant overrides.  If there is
35647330f729Sjoerg   // no such path, pick the first path.
35657330f729Sjoerg   return BestPath ? BestPath : &FullPaths.front();
35667330f729Sjoerg }
35677330f729Sjoerg 
computeFullPathsForVFTables(ASTContext & Context,const CXXRecordDecl * RD,VPtrInfoVector & Paths)35687330f729Sjoerg static void computeFullPathsForVFTables(ASTContext &Context,
35697330f729Sjoerg                                         const CXXRecordDecl *RD,
35707330f729Sjoerg                                         VPtrInfoVector &Paths) {
35717330f729Sjoerg   const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD);
35727330f729Sjoerg   FullPathTy FullPath;
35737330f729Sjoerg   std::list<FullPathTy> FullPaths;
35747330f729Sjoerg   for (const std::unique_ptr<VPtrInfo>& Info : Paths) {
35757330f729Sjoerg     findPathsToSubobject(
35767330f729Sjoerg         Context, MostDerivedLayout, RD, CharUnits::Zero(),
35777330f729Sjoerg         BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath,
35787330f729Sjoerg         FullPaths);
35797330f729Sjoerg     FullPath.clear();
35807330f729Sjoerg     removeRedundantPaths(FullPaths);
35817330f729Sjoerg     Info->PathToIntroducingObject.clear();
35827330f729Sjoerg     if (const FullPathTy *BestPath =
35837330f729Sjoerg             selectBestPath(Context, RD, *Info, FullPaths))
35847330f729Sjoerg       for (const BaseSubobject &BSO : *BestPath)
35857330f729Sjoerg         Info->PathToIntroducingObject.push_back(BSO.getBase());
35867330f729Sjoerg     FullPaths.clear();
35877330f729Sjoerg   }
35887330f729Sjoerg }
35897330f729Sjoerg 
vfptrIsEarlierInMDC(const ASTRecordLayout & Layout,const MethodVFTableLocation & LHS,const MethodVFTableLocation & RHS)35907330f729Sjoerg static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout,
35917330f729Sjoerg                                 const MethodVFTableLocation &LHS,
35927330f729Sjoerg                                 const MethodVFTableLocation &RHS) {
35937330f729Sjoerg   CharUnits L = LHS.VFPtrOffset;
35947330f729Sjoerg   CharUnits R = RHS.VFPtrOffset;
35957330f729Sjoerg   if (LHS.VBase)
35967330f729Sjoerg     L += Layout.getVBaseClassOffset(LHS.VBase);
35977330f729Sjoerg   if (RHS.VBase)
35987330f729Sjoerg     R += Layout.getVBaseClassOffset(RHS.VBase);
35997330f729Sjoerg   return L < R;
36007330f729Sjoerg }
36017330f729Sjoerg 
computeVTableRelatedInformation(const CXXRecordDecl * RD)36027330f729Sjoerg void MicrosoftVTableContext::computeVTableRelatedInformation(
36037330f729Sjoerg     const CXXRecordDecl *RD) {
36047330f729Sjoerg   assert(RD->isDynamicClass());
36057330f729Sjoerg 
36067330f729Sjoerg   // Check if we've computed this information before.
36077330f729Sjoerg   if (VFPtrLocations.count(RD))
36087330f729Sjoerg     return;
36097330f729Sjoerg 
36107330f729Sjoerg   const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
36117330f729Sjoerg 
36127330f729Sjoerg   {
36137330f729Sjoerg     auto VFPtrs = std::make_unique<VPtrInfoVector>();
36147330f729Sjoerg     computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
36157330f729Sjoerg     computeFullPathsForVFTables(Context, RD, *VFPtrs);
36167330f729Sjoerg     VFPtrLocations[RD] = std::move(VFPtrs);
36177330f729Sjoerg   }
36187330f729Sjoerg 
36197330f729Sjoerg   MethodVFTableLocationsTy NewMethodLocations;
36207330f729Sjoerg   for (const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) {
36217330f729Sjoerg     VFTableBuilder Builder(*this, RD, *VFPtr);
36227330f729Sjoerg 
36237330f729Sjoerg     VFTableIdTy id(RD, VFPtr->FullOffsetInMDC);
36247330f729Sjoerg     assert(VFTableLayouts.count(id) == 0);
36257330f729Sjoerg     SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
36267330f729Sjoerg         Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
36277330f729Sjoerg     VFTableLayouts[id] = std::make_unique<VTableLayout>(
36287330f729Sjoerg         ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks,
36297330f729Sjoerg         EmptyAddressPointsMap);
36307330f729Sjoerg     Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
36317330f729Sjoerg 
36327330f729Sjoerg     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
36337330f729Sjoerg     for (const auto &Loc : Builder.vtable_locations()) {
36347330f729Sjoerg       auto Insert = NewMethodLocations.insert(Loc);
36357330f729Sjoerg       if (!Insert.second) {
36367330f729Sjoerg         const MethodVFTableLocation &NewLoc = Loc.second;
36377330f729Sjoerg         MethodVFTableLocation &OldLoc = Insert.first->second;
36387330f729Sjoerg         if (vfptrIsEarlierInMDC(Layout, NewLoc, OldLoc))
36397330f729Sjoerg           OldLoc = NewLoc;
36407330f729Sjoerg       }
36417330f729Sjoerg     }
36427330f729Sjoerg   }
36437330f729Sjoerg 
36447330f729Sjoerg   MethodVFTableLocations.insert(NewMethodLocations.begin(),
36457330f729Sjoerg                                 NewMethodLocations.end());
36467330f729Sjoerg   if (Context.getLangOpts().DumpVTableLayouts)
36477330f729Sjoerg     dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
36487330f729Sjoerg }
36497330f729Sjoerg 
dumpMethodLocations(const CXXRecordDecl * RD,const MethodVFTableLocationsTy & NewMethods,raw_ostream & Out)36507330f729Sjoerg void MicrosoftVTableContext::dumpMethodLocations(
36517330f729Sjoerg     const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods,
36527330f729Sjoerg     raw_ostream &Out) {
36537330f729Sjoerg   // Compute the vtable indices for all the member functions.
36547330f729Sjoerg   // Store them in a map keyed by the location so we'll get a sorted table.
36557330f729Sjoerg   std::map<MethodVFTableLocation, std::string> IndicesMap;
36567330f729Sjoerg   bool HasNonzeroOffset = false;
36577330f729Sjoerg 
36587330f729Sjoerg   for (const auto &I : NewMethods) {
36597330f729Sjoerg     const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl());
3660*e038c9c4Sjoerg     assert(hasVtableSlot(MD));
36617330f729Sjoerg 
36627330f729Sjoerg     std::string MethodName = PredefinedExpr::ComputeName(
36637330f729Sjoerg         PredefinedExpr::PrettyFunctionNoVirtual, MD);
36647330f729Sjoerg 
36657330f729Sjoerg     if (isa<CXXDestructorDecl>(MD)) {
36667330f729Sjoerg       IndicesMap[I.second] = MethodName + " [scalar deleting]";
36677330f729Sjoerg     } else {
36687330f729Sjoerg       IndicesMap[I.second] = MethodName;
36697330f729Sjoerg     }
36707330f729Sjoerg 
36717330f729Sjoerg     if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0)
36727330f729Sjoerg       HasNonzeroOffset = true;
36737330f729Sjoerg   }
36747330f729Sjoerg 
36757330f729Sjoerg   // Print the vtable indices for all the member functions.
36767330f729Sjoerg   if (!IndicesMap.empty()) {
36777330f729Sjoerg     Out << "VFTable indices for ";
36787330f729Sjoerg     Out << "'";
36797330f729Sjoerg     RD->printQualifiedName(Out);
36807330f729Sjoerg     Out << "' (" << IndicesMap.size()
36817330f729Sjoerg         << (IndicesMap.size() == 1 ? " entry" : " entries") << ").\n";
36827330f729Sjoerg 
36837330f729Sjoerg     CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1);
36847330f729Sjoerg     uint64_t LastVBIndex = 0;
36857330f729Sjoerg     for (const auto &I : IndicesMap) {
36867330f729Sjoerg       CharUnits VFPtrOffset = I.first.VFPtrOffset;
36877330f729Sjoerg       uint64_t VBIndex = I.first.VBTableIndex;
36887330f729Sjoerg       if (HasNonzeroOffset &&
36897330f729Sjoerg           (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
36907330f729Sjoerg         assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
36917330f729Sjoerg         Out << " -- accessible via ";
36927330f729Sjoerg         if (VBIndex)
36937330f729Sjoerg           Out << "vbtable index " << VBIndex << ", ";
36947330f729Sjoerg         Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n";
36957330f729Sjoerg         LastVFPtrOffset = VFPtrOffset;
36967330f729Sjoerg         LastVBIndex = VBIndex;
36977330f729Sjoerg       }
36987330f729Sjoerg 
36997330f729Sjoerg       uint64_t VTableIndex = I.first.Index;
37007330f729Sjoerg       const std::string &MethodName = I.second;
37017330f729Sjoerg       Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n';
37027330f729Sjoerg     }
37037330f729Sjoerg     Out << '\n';
37047330f729Sjoerg   }
37057330f729Sjoerg 
37067330f729Sjoerg   Out.flush();
37077330f729Sjoerg }
37087330f729Sjoerg 
computeVBTableRelatedInformation(const CXXRecordDecl * RD)37097330f729Sjoerg const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
37107330f729Sjoerg     const CXXRecordDecl *RD) {
37117330f729Sjoerg   VirtualBaseInfo *VBI;
37127330f729Sjoerg 
37137330f729Sjoerg   {
37147330f729Sjoerg     // Get or create a VBI for RD.  Don't hold a reference to the DenseMap cell,
37157330f729Sjoerg     // as it may be modified and rehashed under us.
37167330f729Sjoerg     std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD];
37177330f729Sjoerg     if (Entry)
37187330f729Sjoerg       return *Entry;
37197330f729Sjoerg     Entry = std::make_unique<VirtualBaseInfo>();
37207330f729Sjoerg     VBI = Entry.get();
37217330f729Sjoerg   }
37227330f729Sjoerg 
37237330f729Sjoerg   computeVTablePaths(/*ForVBTables=*/true, RD, VBI->VBPtrPaths);
37247330f729Sjoerg 
37257330f729Sjoerg   // First, see if the Derived class shared the vbptr with a non-virtual base.
37267330f729Sjoerg   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
37277330f729Sjoerg   if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) {
37287330f729Sjoerg     // If the Derived class shares the vbptr with a non-virtual base, the shared
37297330f729Sjoerg     // virtual bases come first so that the layout is the same.
37307330f729Sjoerg     const VirtualBaseInfo &BaseInfo =
37317330f729Sjoerg         computeVBTableRelatedInformation(VBPtrBase);
37327330f729Sjoerg     VBI->VBTableIndices.insert(BaseInfo.VBTableIndices.begin(),
37337330f729Sjoerg                                BaseInfo.VBTableIndices.end());
37347330f729Sjoerg   }
37357330f729Sjoerg 
37367330f729Sjoerg   // New vbases are added to the end of the vbtable.
37377330f729Sjoerg   // Skip the self entry and vbases visited in the non-virtual base, if any.
37387330f729Sjoerg   unsigned VBTableIndex = 1 + VBI->VBTableIndices.size();
37397330f729Sjoerg   for (const auto &VB : RD->vbases()) {
37407330f729Sjoerg     const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
37417330f729Sjoerg     if (!VBI->VBTableIndices.count(CurVBase))
37427330f729Sjoerg       VBI->VBTableIndices[CurVBase] = VBTableIndex++;
37437330f729Sjoerg   }
37447330f729Sjoerg 
37457330f729Sjoerg   return *VBI;
37467330f729Sjoerg }
37477330f729Sjoerg 
getVBTableIndex(const CXXRecordDecl * Derived,const CXXRecordDecl * VBase)37487330f729Sjoerg unsigned MicrosoftVTableContext::getVBTableIndex(const CXXRecordDecl *Derived,
37497330f729Sjoerg                                                  const CXXRecordDecl *VBase) {
37507330f729Sjoerg   const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived);
37517330f729Sjoerg   assert(VBInfo.VBTableIndices.count(VBase));
37527330f729Sjoerg   return VBInfo.VBTableIndices.find(VBase)->second;
37537330f729Sjoerg }
37547330f729Sjoerg 
37557330f729Sjoerg const VPtrInfoVector &
enumerateVBTables(const CXXRecordDecl * RD)37567330f729Sjoerg MicrosoftVTableContext::enumerateVBTables(const CXXRecordDecl *RD) {
37577330f729Sjoerg   return computeVBTableRelatedInformation(RD).VBPtrPaths;
37587330f729Sjoerg }
37597330f729Sjoerg 
37607330f729Sjoerg const VPtrInfoVector &
getVFPtrOffsets(const CXXRecordDecl * RD)37617330f729Sjoerg MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) {
37627330f729Sjoerg   computeVTableRelatedInformation(RD);
37637330f729Sjoerg 
37647330f729Sjoerg   assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
37657330f729Sjoerg   return *VFPtrLocations[RD];
37667330f729Sjoerg }
37677330f729Sjoerg 
37687330f729Sjoerg const VTableLayout &
getVFTableLayout(const CXXRecordDecl * RD,CharUnits VFPtrOffset)37697330f729Sjoerg MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD,
37707330f729Sjoerg                                          CharUnits VFPtrOffset) {
37717330f729Sjoerg   computeVTableRelatedInformation(RD);
37727330f729Sjoerg 
37737330f729Sjoerg   VFTableIdTy id(RD, VFPtrOffset);
37747330f729Sjoerg   assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset");
37757330f729Sjoerg   return *VFTableLayouts[id];
37767330f729Sjoerg }
37777330f729Sjoerg 
37787330f729Sjoerg MethodVFTableLocation
getMethodVFTableLocation(GlobalDecl GD)37797330f729Sjoerg MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) {
3780*e038c9c4Sjoerg   assert(hasVtableSlot(cast<CXXMethodDecl>(GD.getDecl())) &&
37817330f729Sjoerg          "Only use this method for virtual methods or dtors");
37827330f729Sjoerg   if (isa<CXXDestructorDecl>(GD.getDecl()))
37837330f729Sjoerg     assert(GD.getDtorType() == Dtor_Deleting);
37847330f729Sjoerg 
37857330f729Sjoerg   GD = GD.getCanonicalDecl();
37867330f729Sjoerg 
37877330f729Sjoerg   MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
37887330f729Sjoerg   if (I != MethodVFTableLocations.end())
37897330f729Sjoerg     return I->second;
37907330f729Sjoerg 
37917330f729Sjoerg   const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
37927330f729Sjoerg 
37937330f729Sjoerg   computeVTableRelatedInformation(RD);
37947330f729Sjoerg 
37957330f729Sjoerg   I = MethodVFTableLocations.find(GD);
37967330f729Sjoerg   assert(I != MethodVFTableLocations.end() && "Did not find index!");
37977330f729Sjoerg   return I->second;
37987330f729Sjoerg }
3799