diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGVTables.cpp | 42 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 33 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 4 |
4 files changed, 70 insertions, 12 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 436b96a615e..5ef409ecdee 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -218,6 +218,9 @@ public: virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0; virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; } + virtual bool canEmitAvailableExternallyVTable( + const CXXRecordDecl *RD) const = 0; + virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0; virtual llvm::CallInst * diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 7321dbfe340..c6d7e0632c7 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -679,6 +679,12 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, return VTable; } +static bool shouldEmitAvailableExternallyVTable(const CodeGenModule &CGM, + const CXXRecordDecl *RD) { + return CGM.getCodeGenOpts().OptimizationLevel > 0 && + CGM.getCXXABI().canEmitAvailableExternallyVTable(RD); +} + /// Compute the required linkage of the v-table for the given class. /// /// Note that we only call this at the end of the translation unit. @@ -700,7 +706,12 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { switch (keyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - assert(def && "Should not have been asked to emit this"); + assert((def || CodeGenOpts.OptimizationLevel > 0) && + "Shouldn't query vtable linkage without key function or " + "optimizations"); + if (!def && CodeGenOpts.OptimizationLevel > 0) + return llvm::GlobalVariable::AvailableExternallyLinkage; + if (keyFunction->isInlined()) return !Context.getLangOpts().AppleKext ? llvm::GlobalVariable::LinkOnceODRLinkage : @@ -742,16 +753,18 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { } switch (RD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - case TSK_ImplicitInstantiation: - return DiscardableODRLinkage; - - case TSK_ExplicitInstantiationDeclaration: - return llvm::GlobalVariable::ExternalLinkage; - - case TSK_ExplicitInstantiationDefinition: - return NonDiscardableODRLinkage; + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ImplicitInstantiation: + return DiscardableODRLinkage; + + case TSK_ExplicitInstantiationDeclaration: + return shouldEmitAvailableExternallyVTable(*this, RD) + ? llvm::GlobalVariable::AvailableExternallyLinkage + : llvm::GlobalVariable::ExternalLinkage; + + case TSK_ExplicitInstantiationDefinition: + return NonDiscardableODRLinkage; } llvm_unreachable("Invalid TemplateSpecializationKind!"); @@ -819,7 +832,12 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) { /// we define that v-table? static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM, const CXXRecordDecl *RD) { - return !CGM.getVTables().isVTableExternal(RD); + // If vtable is internal then it has to be done + if (!CGM.getVTables().isVTableExternal(RD)) + return true; + + // If it's external then maybe we will need it as available_externally + return shouldEmitAvailableExternallyVTable(CGM, RD); } /// Given that at some point we emitted a reference to one or more diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 70af69b7645..eb85413a5de 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -215,6 +215,8 @@ public: void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override; + bool canEmitAvailableExternallyVTable(const CXXRecordDecl *RD) const override; + void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD, bool ReturnAdjustment) override { // Allow inlining of thunks by emitting them with available_externally @@ -302,6 +304,24 @@ public: friend class ItaniumRTTIBuilder; void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override; + + private: + /// Checks if function has any virtual inline function. + bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const { + const auto &VtableLayout = + CGM.getItaniumVTableContext().getVTableLayout(RD); + + for (const auto &VtableComponent : VtableLayout.vtable_components()) { + if (VtableComponent.getKind() != + VTableComponent::Kind::CK_FunctionPointer) + continue; + + const auto &Method = VtableComponent.getFunctionDecl(); + if (Method->getCanonicalDecl()->isInlined()) + return true; + } + return false; + } }; class ARMCXXABI : public ItaniumCXXABI { @@ -1481,6 +1501,19 @@ void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) { VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD); } +bool ItaniumCXXABI::canEmitAvailableExternallyVTable( + const CXXRecordDecl *RD) const { + // We don't emit available_externally vtables if we are in -fapple-kext mode + // because kext mode does not permit devirtualization. + if (CGM.getLangOpts().AppleKext) + return false; + + // If we don't have any inline virtual functions, + // then we are safe to emit available_externally copy of vtable. + // FIXME we can still emit a copy of the vtable if we + // can emit definition of the inline functions. + return !hasAnyVirtualInlineFunction(RD); +} static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, llvm::Value *Ptr, int64_t NonVirtualAdjustment, diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index f864213566a..613d29a63cd 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -106,6 +106,10 @@ public: QualType DestTy) override; bool EmitBadCastCall(CodeGenFunction &CGF) override; + bool canEmitAvailableExternallyVTable( + const CXXRecordDecl *RD) const override { + return false; + } llvm::Value * GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This, |