| //===--- MicrosoftVBTables.cpp - Virtual Base Table Emission --------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This class generates data about MSVC virtual base tables. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MicrosoftVBTables.h" |
| #include "CodeGenModule.h" |
| #include "CGCXXABI.h" |
| |
| namespace clang { |
| namespace CodeGen { |
| |
| /// Holds intermediate data about a path to a vbptr inside a base subobject. |
| struct VBTablePath { |
| VBTablePath(const VBTableInfo &VBInfo) |
| : VBInfo(VBInfo), NextBase(VBInfo.VBPtrSubobject.getBase()) { } |
| |
| /// All the data needed to build a vbtable, minus the GlobalVariable whose |
| /// name we haven't computed yet. |
| VBTableInfo VBInfo; |
| |
| /// Next base to use for disambiguation. Can be null if we've already |
| /// disambiguated this path once. |
| const CXXRecordDecl *NextBase; |
| |
| /// Path is not really a full path like a CXXBasePath. It holds the subset of |
| /// records that need to be mangled into the vbtable symbol name in order to get |
| /// a unique name. |
| llvm::SmallVector<const CXXRecordDecl *, 1> Path; |
| }; |
| |
| VBTableBuilder::VBTableBuilder(CodeGenModule &CGM, |
| const CXXRecordDecl *MostDerived) |
| : CGM(CGM), MostDerived(MostDerived), |
| DerivedLayout(CGM.getContext().getASTRecordLayout(MostDerived)) {} |
| |
| void VBTableBuilder::enumerateVBTables(VBTableVector &VBTables) { |
| VBTablePathVector Paths; |
| findUnambiguousPaths(MostDerived, BaseSubobject(MostDerived, |
| CharUnits::Zero()), Paths); |
| for (VBTablePathVector::iterator I = Paths.begin(), E = Paths.end(); |
| I != E; ++I) { |
| VBTablePath *P = *I; |
| P->VBInfo.GV = getAddrOfVBTable(P->VBInfo.ReusingBase, P->Path); |
| VBTables.push_back(P->VBInfo); |
| } |
| } |
| |
| bool VBTableBuilder::hasVBPtr(const CXXRecordDecl *RD) { |
| const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); |
| return Layout.getVBPtrOffset().getQuantity() != -1; |
| } |
| |
| void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase, |
| BaseSubobject CurSubobject, |
| VBTablePathVector &Paths) { |
| size_t PathsStart = Paths.size(); |
| bool ReuseVBPtrFromBase = true; |
| const CXXRecordDecl *CurBase = CurSubobject.getBase(); |
| |
| // If this base has a vbptr, then we've found a path. These are not full |
| // paths, so we don't use CXXBasePath. |
| if (hasVBPtr(CurBase)) { |
| ReuseVBPtrFromBase = false; |
| VBTablePath *Info = new VBTablePath( |
| VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0)); |
| Paths.push_back(Info); |
| } |
| |
| // Recurse onto any bases which themselves have virtual bases. |
| const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase); |
| for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(), |
| E = CurBase->bases_end(); I != E; ++I) { |
| const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); |
| if (!Base->getNumVBases()) |
| continue; // Bases without virtual bases have no vbptrs. |
| CharUnits NextOffset; |
| const CXXRecordDecl *NextReusingBase = Base; |
| if (I->isVirtual()) { |
| if (!VBasesSeen.insert(Base)) |
| continue; // Don't visit virtual bases twice. |
| NextOffset = DerivedLayout.getVBaseClassOffset(Base); |
| } else { |
| NextOffset = (CurSubobject.getBaseOffset() + |
| Layout.getBaseClassOffset(Base)); |
| |
| // If CurBase didn't have a vbptr, then ReusingBase will reuse the vbptr |
| // from the first non-virtual base with vbases for its vbptr. |
| if (ReuseVBPtrFromBase) { |
| NextReusingBase = ReusingBase; |
| ReuseVBPtrFromBase = false; |
| } |
| } |
| |
| size_t NumPaths = Paths.size(); |
| findUnambiguousPaths(NextReusingBase, BaseSubobject(Base, NextOffset), |
| Paths); |
| |
| // Tag paths through this base with the base itself. We might use it to |
| // disambiguate. |
| for (size_t I = NumPaths, E = Paths.size(); I != E; ++I) |
| Paths[I]->NextBase = Base; |
| } |
| |
| bool AmbiguousPaths = rebucketPaths(Paths, PathsStart); |
| if (AmbiguousPaths) |
| rebucketPaths(Paths, PathsStart, /*SecondPass=*/true); |
| |
| #ifndef NDEBUG |
| // Check that the paths are in fact unique. |
| for (size_t I = PathsStart + 1, E = Paths.size(); I != E; ++I) { |
| assert(Paths[I]->Path != Paths[I - 1]->Path && "vbtable paths are not unique"); |
| } |
| #endif |
| } |
| |
| static bool pathCompare(VBTablePath *LHS, VBTablePath *RHS) { |
| return LHS->Path < RHS->Path; |
| } |
| |
| void VBTableBuilder::extendPath(VBTablePath *P, bool SecondPass) { |
| assert(P->NextBase || SecondPass); |
| if (P->NextBase) { |
| P->Path.push_back(P->NextBase); |
| P->NextBase = 0; // Prevent the path from being extended twice. |
| } |
| } |
| |
| bool VBTableBuilder::rebucketPaths(VBTablePathVector &Paths, size_t PathsStart, |
| bool SecondPass) { |
| // What we're essentially doing here is bucketing together ambiguous paths. |
| // Any bucket with more than one path in it gets extended by NextBase, which |
| // is usually the direct base of the inherited the vbptr. This code uses a |
| // sorted vector to implement a multiset to form the buckets. Note that the |
| // ordering is based on pointers, but it doesn't change our output order. The |
| // current algorithm is designed to match MSVC 2012's names. |
| // TODO: Implement MSVC 2010 or earlier names to avoid extra vbtable cruft. |
| VBTablePathVector PathsSorted(&Paths[PathsStart], &Paths.back() + 1); |
| std::sort(PathsSorted.begin(), PathsSorted.end(), pathCompare); |
| bool AmbiguousPaths = false; |
| for (size_t I = 0, E = PathsSorted.size(); I != E;) { |
| // Scan forward to find the end of the bucket. |
| size_t BucketStart = I; |
| do { |
| ++I; |
| } while (I != E && PathsSorted[BucketStart]->Path == PathsSorted[I]->Path); |
| |
| // If this bucket has multiple paths, extend them all. |
| if (I - BucketStart > 1) { |
| AmbiguousPaths = true; |
| for (size_t II = BucketStart; II != I; ++II) |
| extendPath(PathsSorted[II], SecondPass); |
| } |
| } |
| return AmbiguousPaths; |
| } |
| |
| llvm::GlobalVariable * |
| VBTableBuilder::getAddrOfVBTable(const CXXRecordDecl *ReusingBase, |
| ArrayRef<const CXXRecordDecl *> BasePath) { |
| // Caching at this layer is redundant with the caching in EnumerateVBTables(). |
| |
| SmallString<256> OutName; |
| llvm::raw_svector_ostream Out(OutName); |
| MangleContext &Mangler = CGM.getCXXABI().getMangleContext(); |
| Mangler.mangleCXXVBTable(MostDerived, BasePath, Out); |
| Out.flush(); |
| StringRef Name = OutName.str(); |
| |
| llvm::ArrayType *VBTableType = |
| llvm::ArrayType::get(CGM.IntTy, 1 + ReusingBase->getNumVBases()); |
| |
| assert(!CGM.getModule().getNamedGlobal(Name) && |
| "vbtable with this name already exists: mangling bug?"); |
| llvm::GlobalVariable *VBTable = |
| CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType, |
| llvm::GlobalValue::ExternalLinkage); |
| VBTable->setUnnamedAddr(true); |
| return VBTable; |
| } |
| |
| void VBTableInfo::EmitVBTableDefinition( |
| CodeGenModule &CGM, const CXXRecordDecl *RD, |
| llvm::GlobalVariable::LinkageTypes Linkage) const { |
| assert(RD->getNumVBases() && ReusingBase->getNumVBases() && |
| "should only emit vbtables for classes with vbtables"); |
| |
| const ASTRecordLayout &BaseLayout = |
| CGM.getContext().getASTRecordLayout(VBPtrSubobject.getBase()); |
| const ASTRecordLayout &DerivedLayout = |
| CGM.getContext().getASTRecordLayout(RD); |
| |
| SmallVector<llvm::Constant *, 4> Offsets; |
| |
| // The offset from ReusingBase's vbptr to itself always leads. |
| CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset(); |
| Offsets.push_back( |
| llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity())); |
| |
| // These are laid out in the same order as in Itanium, which is the same as |
| // the order of the vbase iterator. |
| for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(), |
| E = ReusingBase->vbases_end(); I != E; ++I) { |
| const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl(); |
| CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase); |
| assert(!Offset.isNegative()); |
| // Make it relative to the subobject vbptr. |
| Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset; |
| Offsets.push_back(llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity())); |
| } |
| |
| assert(Offsets.size() == |
| cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType()) |
| ->getElementType())->getNumElements()); |
| llvm::ArrayType *VBTableType = |
| llvm::ArrayType::get(CGM.IntTy, Offsets.size()); |
| llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets); |
| GV->setInitializer(Init); |
| |
| // Set the correct linkage. |
| GV->setLinkage(Linkage); |
| |
| // Set the right visibility. |
| CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForVTable); |
| } |
| |
| } // namespace CodeGen |
| } // namespace clang |