diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 246 | ||||
-rw-r--r-- | lib/CodeGen/CGVtable.h | 13 |
4 files changed, 251 insertions, 19 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index a848b1269b..9cd72fe215 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -1055,7 +1055,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, return VBaseOffset; } -static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex, +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -1071,7 +1071,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); return ::BuildVirtualCall(*this, VtableIndex, This, Ty); } @@ -1080,7 +1080,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); - int64_t VtableIndex = + uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VtableIndex, This, Ty); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index d0475dd8df..54e3fa4744 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -413,9 +413,10 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); - Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1); + // The pointer is 1 + the virtual table offset in bytes. + Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); } else { llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD); diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index fb3e6be3e6..4669515a4e 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -14,6 +14,7 @@ #include "CodeGenModule.h" #include "CodeGenFunction.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "llvm/ADT/DenseSet.h" #include <cstdio> @@ -781,24 +782,243 @@ VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D, return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); } -int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { +/// TypeConversionRequiresAdjustment - Returns whether conversion from a +/// derived type to a base type requires adjustment. +static bool +TypeConversionRequiresAdjustment(ASTContext &Ctx, + const CXXRecordDecl *DerivedDecl, + const CXXRecordDecl *BaseDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + if (!const_cast<CXXRecordDecl *>(DerivedDecl)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return false; + } + + const CXXBasePath &Path = Paths.front(); + + size_t Start = 0, End = Path.size(); + + // Check if we have a virtual base. + if (const RecordType *RT = Paths.getDetectedVirtual()) { + const CXXRecordDecl *VirtualBase = cast<CXXRecordDecl>(RT->getDecl()); + assert(VirtualBase->isCanonicalDecl() && "Must have canonical decl!"); + + // Check the virtual base class offset. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(DerivedDecl); + + if (Layout.getVBaseClassOffset(VirtualBase) != 0) { + // This requires an adjustment. + return true; + } + + // Now ignore all the path elements up to the virtual base. + // FIXME: It would be nice if CXXBasePaths could return an index to the + // CXXElementSpecifier that corresponded to the virtual base. + for (; Start != End; ++Start) { + const CXXBasePathElement& Element = Path[Start]; + + if (Element.Class == VirtualBase) + break; + } + } + + for (; Start != End; ++Start) { + const CXXBasePathElement &Element = Path[Start]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); + const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); + + if (Layout.getBaseClassOffset(Base) != 0) { + // This requires an adjustment. + return true; + } + } + + return false; +} + +static bool +TypeConversionRequiresAdjustment(ASTContext &Ctx, + QualType DerivedType, QualType BaseType) { + // Canonicalize the types. + QualType CanDerivedType = Ctx.getCanonicalType(DerivedType); + QualType CanBaseType = Ctx.getCanonicalType(BaseType); + + assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedType == CanBaseType) { + // No adjustment needed. + return false; + } + + if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) { + CanDerivedType = RT->getPointeeType(); + CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType(); + } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) { + CanDerivedType = PT->getPointeeType(); + CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType(); + } else { + assert(false && "Unexpected return type!"); + } + + if (CanDerivedType == CanBaseType) { + // No adjustment needed. + return false; + } + + const CXXRecordDecl *DerivedDecl = + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); + + return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); +} + +void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { + + // Itanium C++ ABI 2.5.2: + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. + // + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. + + int64_t CurrentIndex = 0; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (PrimaryBase) { + assert(PrimaryBase->isCanonicalDecl() && + "Should have the canonical decl of the primary base!"); + + // Since the record decl shares its vtable pointer with the primary base + // we need to start counting at the end of the primary base's vtable. + CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); + } + + const CXXDestructorDecl *ImplicitVirtualDtor = 0; + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + const CXXMethodDecl *MD = *i; + + // We only want virtual methods. + if (!MD->isVirtual()) + continue; + + bool ShouldAddEntryForMethod = true; + + // Check if this method overrides a method in the primary base. + for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); i != e; ++i) { + const CXXMethodDecl *OverriddenMD = *i; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + assert(OverriddenMD->isCanonicalDecl() && + "Should have the canonical decl of the overridden RD!"); + + if (OverriddenRD == PrimaryBase) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + QualType OverriddenReturnType = + OverriddenMD->getType()->getAs<FunctionType>()->getResultType(); + + if (!TypeConversionRequiresAdjustment(CGM.getContext(), + ReturnType, OverriddenReturnType)) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + const CXXDestructorDecl *OverriddenDD = + cast<CXXDestructorDecl>(OverriddenMD); + + // Add both the complete and deleting entries. + MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + } else { + MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD); + } + + // We don't need to add an entry for this method. + ShouldAddEntryForMethod = false; + break; + } + } + } + + if (!ShouldAddEntryForMethod) + continue; + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + if (MD->isImplicit()) { + assert(!ImplicitVirtualDtor && + "Did already see an implicit virtual dtor!"); + ImplicitVirtualDtor = DD; + continue; + } + + // Add the complete dtor. + MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + + // Add the deleting dtor. + MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + } else { + // Add the entry. + MethodVtableIndices[MD] = CurrentIndex++; + } + } + + if (ImplicitVirtualDtor) { + // Itanium C++ ABI 2.5.2: + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. + + // Add the complete dtor. + MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = + CurrentIndex++; + + // Add the deleting dtor. + MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = + CurrentIndex++; + } + + NumVirtualFunctionPointers[RD] = CurrentIndex; +} + +uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { + llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + NumVirtualFunctionPointers.find(RD); + if (I != NumVirtualFunctionPointers.end()) + return I->second; + + ComputeMethodVtableIndices(RD); + + I = NumVirtualFunctionPointers.find(RD); + assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); + return I->second; +} + +uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); if (I != MethodVtableIndices.end()) return I->second; const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - - std::vector<llvm::Constant *> methods; - // FIXME: This seems expensive. Can we do a partial job to get - // just this data. - VtableBuilder b(methods, RD, RD, 0, CGM); - D1(printf("vtable %s\n", RD->getNameAsCString())); - b.GenerateVtableForBase(RD); - b.GenerateVtableForVBases(RD); - - MethodVtableIndices.insert(b.getIndex().begin(), - b.getIndex().end()); - + + ComputeMethodVtableIndices(RD); + I = MethodVtableIndices.find(GD); assert(I != MethodVtableIndices.end() && "Did not find index!"); return I->second; diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index daf49d31b3..ac3cdee63b 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -80,6 +80,17 @@ class CGVtableInfo { VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables; + + /// NumVirtualFunctionPointers - Contains the number of virtual function + /// pointers in the vtable for a given record decl. + llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; + + /// getNumVirtualFunctionPointers - Return the number of virtual function + /// pointers in the vtable for a given record decl. + uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); + + void ComputeMethodVtableIndices(const CXXRecordDecl *RD); + public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -87,7 +98,7 @@ public: /// getMethodVtableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. - int64_t getMethodVtableIndex(GlobalDecl GD); + uint64_t getMethodVtableIndex(GlobalDecl GD); /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable /// address point) where the offset of the virtual base that contains the |