diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCXX.cpp | 96 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGVtable.cpp | 74 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGVtable.h | 8 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 7 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 7 |
5 files changed, 183 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index a2674b82d1b..77bee48b58b 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -994,6 +994,102 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, } llvm::Constant * +CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, + OutName); + else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +llvm::Constant * +CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { + BuildThunksForVirtualRecursive(GD, GD); +} + +void +CodeGenModule::BuildThunksForVirtualRecursive(GlobalDecl GD, + GlobalDecl BaseOGD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + const CXXMethodDecl *BaseOMD = cast<CXXMethodDecl>(BaseOGD.getDecl()); + for (CXXMethodDecl::method_iterator mi = BaseOMD->begin_overridden_methods(), + e = BaseOMD->end_overridden_methods(); + mi != e; ++mi) { + GlobalDecl OGD; + const CXXMethodDecl *OMD = *mi; + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD)) + OGD = GlobalDecl(DD, GD.getDtorType()); + else + OGD = GlobalDecl(OMD); + QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType oret = getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType ret = getContext().getCanonicalType(nc_ret); + ThunkAdjustment ReturnAdjustment; + if (oret != ret) { + QualType qD = nc_ret->getPointeeType(); + QualType qB = nc_oret->getPointeeType(); + CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); + CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); + ReturnAdjustment = ComputeThunkAdjustment(D, B); + } + ThunkAdjustment ThisAdjustment = + getVtableInfo().getThisAdjustment(GD, OGD); + bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace(); + if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { + CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); + llvm::Constant *FnConst; + if (!ReturnAdjustment.isEmpty()) + FnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + FnConst = GetAddrOfThunk(GD, ThisAdjustment); + if (!isa<llvm::Function>(FnConst)) { + assert(0 && "Figure out how to handle incomplete-type cases!"); + } + llvm::Function *Fn = cast<llvm::Function>(FnConst); + if (Fn->isDeclaration()) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + Fn->setLinkage(linktype); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) + Fn->addFnAttr(llvm::Attribute::NoUnwind); + Fn->setAlignment(2); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); + } + } + BuildThunksForVirtualRecursive(GD, OGD); + } +} + +llvm::Constant * CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp index 65c412e0b03..857e661254b 100644 --- a/clang/lib/CodeGen/CGVtable.cpp +++ b/clang/lib/CodeGen/CGVtable.cpp @@ -73,6 +73,7 @@ private: /// Methods - The methods, in vtable order. typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy; MethodsVectorTy Methods; + MethodsVectorTy OrigMethods; public: /// AddMethod - Add a method to the vtable methods. @@ -82,6 +83,7 @@ private: MethodToIndexMap[GD] = Methods.size(); Methods.push_back(GD); + OrigMethods.push_back(GD); } /// OverrideMethod - Replace a method with another. @@ -113,6 +115,10 @@ private: return true; } + GlobalDecl getOrigMethod(uint64_t Index) const { + return OrigMethods[Index]; + } + MethodsVectorTy::size_type size() const { return Methods.size(); } @@ -120,6 +126,7 @@ private: void clear() { MethodToIndexMap.clear(); Methods.clear(); + OrigMethods.clear(); } GlobalDecl operator[](uint64_t Index) const { @@ -135,6 +142,10 @@ private: typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy; ThisAdjustmentsMapTy ThisAdjustments; + typedef std::vector<std::pair<std::pair<GlobalDecl, GlobalDecl>, + ThunkAdjustment> > SavedThisAdjustmentsVectorTy; + SavedThisAdjustmentsVectorTy SavedThisAdjustments; + /// BaseReturnTypes - Contains the base return types of methods who have been /// overridden with methods whose return types require adjustment. Used for /// generating covariant thunk information. @@ -202,6 +213,9 @@ public: llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex() { return VBIndex; } + SavedThisAdjustmentsVectorTy &getSavedThisAdjustments() + { return SavedThisAdjustments; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -762,11 +776,17 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, else OGD = OMD; - // FIXME: Explain why this is necessary! + // Check whether this is the method being overridden in this section of + // the vtable. uint64_t Index; if (!Methods.getIndex(OGD, Index)) continue; + // Get the original method, which we should be computing thunks, etc, + // against. + OGD = Methods.getOrigMethod(Index); + OMD = cast<CXXMethodDecl>(OGD.getDecl()); + QualType ReturnType = MD->getType()->getAs<FunctionType>()->getResultType(); QualType OverriddenReturnType = @@ -777,10 +797,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, OverriddenReturnType)) { CanQualType &BaseReturnType = BaseReturnTypes[Index]; - // Get the canonical return type. - CanQualType CanReturnType = - CGM.getContext().getCanonicalType(ReturnType); - // Insert the base return type. if (BaseReturnType.isNull()) BaseReturnType = @@ -820,8 +836,12 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, VirtualAdjustment); - if (!isPure && !ThisAdjustment.isEmpty()) + if (!isPure && !ThisAdjustment.isEmpty()) { ThisAdjustments[Index] = ThisAdjustment; + // FIXME: Might this end up inserting some false adjustments? + SavedThisAdjustments.push_back(std::make_pair(std::make_pair(GD, OGD), + ThisAdjustment)); + } return true; } @@ -882,10 +902,10 @@ void VtableBuilder::AppendMethodsToVtable() { if (!ReturnAdjustment.isEmpty()) { // Build a covariant thunk. CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); - Method = CGM.BuildCovariantThunk(MD, Extern, Adjustment); + Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); } else if (!ThisAdjustment.isEmpty()) { // Build a "regular" thunk. - Method = CGM.BuildThunk(GD, Extern, ThisAdjustment); + Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); } else if (MD->isPure()) { // We have a pure virtual method. Method = getPureVirtualFn(); @@ -1048,6 +1068,32 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } +ThunkAdjustment CGVtableInfo::getThisAdjustment(GlobalDecl GD, + GlobalDecl OGD) { + SavedThisAdjustmentsTy::iterator I = + SavedThisAdjustments.find(std::make_pair(GD, OGD)); + if (I != SavedThisAdjustments.end()) + return I->second; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext()); + if (!SavedThisAdjustmentRecords.insert(RD).second) + return ThunkAdjustment(); + + VtableBuilder b(RD, RD, 0, CGM, false); + D1(printf("vtable %s\n", RD->getNameAsCString())); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + SavedThisAdjustments.insert(b.getSavedThisAdjustments().begin(), + b.getSavedThisAdjustments().end()); + + I = SavedThisAdjustments.find(std::make_pair(GD, OGD)); + if (I != SavedThisAdjustments.end()) + return I->second; + + return ThunkAdjustment(); +} + int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); @@ -1416,5 +1462,17 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { // Emit the data. GenerateClassData(Linkage, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if ((*i)->isVirtual() && (*i)->hasInlineBody()) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } + } } diff --git a/clang/lib/CodeGen/CGVtable.h b/clang/lib/CodeGen/CGVtable.h index fd7a4865b64..1507725f0fb 100644 --- a/clang/lib/CodeGen/CGVtable.h +++ b/clang/lib/CodeGen/CGVtable.h @@ -15,6 +15,7 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/GlobalVariable.h" #include "GlobalDecl.h" @@ -83,6 +84,11 @@ class CGVtableInfo { /// pointers in the vtable for a given record decl. llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; + typedef llvm::DenseMap<std::pair<GlobalDecl, GlobalDecl>, + ThunkAdjustment> SavedThisAdjustmentsTy; + SavedThisAdjustmentsTy SavedThisAdjustments; + llvm::DenseSet<const CXXRecordDecl*> SavedThisAdjustmentRecords; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -122,6 +128,8 @@ public: int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); + ThunkAdjustment getThisAdjustment(GlobalDecl GD, GlobalDecl OGD); + /// getVtableAddressPoint - returns the address point of the vtable for the /// given record decl. /// FIXME: This should return a list of address points. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8fb03b2d19c..5f822f509f8 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -621,8 +621,13 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa<CXXMethodDecl>(D)) + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { getVtableInfo().MaybeEmitVtable(GD); + if (MD->isVirtual() && MD->isOutOfLine() && + (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) { + BuildThunksForVirtual(GD); + } + } if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index cf36bcf9a02..466aaa67cc0 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -223,6 +223,13 @@ public: /// non-class type. llvm::Constant *GenerateRTTI(QualType Ty); + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &ThisAdjustment); + void BuildThunksForVirtual(GlobalDecl GD); + void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); + /// BuildThunk - Build a thunk for the given method. llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); |