diff options
Diffstat (limited to 'clang/lib/CodeGen/CGVtable.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGVtable.cpp | 74 |
1 files changed, 66 insertions, 8 deletions
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)); + } + } + } } |