summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGBlocks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGBlocks.cpp')
-rw-r--r--clang/lib/CodeGen/CGBlocks.cpp254
1 files changed, 198 insertions, 56 deletions
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index 5d03477e9bd..b1dbb505b5d 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CGBlocks.h"
+#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
@@ -25,6 +26,7 @@
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/ScopedPrinter.h"
#include <algorithm>
#include <cstdio>
@@ -34,8 +36,8 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
- LocalAddress(Address::invalid()), StructureType(nullptr), Block(block),
- DominatingIP(nullptr) {
+ CapturesNonExternalType(false), LocalAddress(Address::invalid()),
+ StructureType(nullptr), Block(block), DominatingIP(nullptr) {
// Skip asm prefix, if any. 'name' is usually taken directly from
// the mangled name of the enclosing function.
@@ -464,6 +466,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
} else if (CI.hasCopyExpr()) {
info.NeedsCopyDispose = true;
info.HasCXXObject = true;
+ if (!variable->getType()->getAsCXXRecordDecl()->isExternallyVisible())
+ info.CapturesNonExternalType = true;
// So do C structs that require non-trivial copy construction or
// destruction.
@@ -480,6 +484,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
if (!record->hasTrivialDestructor()) {
info.HasCXXObject = true;
info.NeedsCopyDispose = true;
+ if (!record->isExternallyVisible())
+ info.CapturesNonExternalType = true;
}
}
}
@@ -1522,13 +1528,17 @@ enum class BlockCaptureEntityKind {
struct BlockCaptureManagedEntity {
BlockCaptureEntityKind Kind;
BlockFieldFlags Flags;
- const BlockDecl::Capture &CI;
- const CGBlockInfo::Capture &Capture;
+ const BlockDecl::Capture *CI;
+ const CGBlockInfo::Capture *Capture;
BlockCaptureManagedEntity(BlockCaptureEntityKind Type, BlockFieldFlags Flags,
const BlockDecl::Capture &CI,
const CGBlockInfo::Capture &Capture)
- : Kind(Type), Flags(Flags), CI(CI), Capture(Capture) {}
+ : Kind(Type), Flags(Flags), CI(&CI), Capture(&Capture) {}
+
+ bool operator<(const BlockCaptureManagedEntity &Other) const {
+ return Capture->getOffset() < Other.Capture->getOffset();
+ }
};
} // end anonymous namespace
@@ -1607,6 +1617,9 @@ static void findBlockCapturedManagedEntities(
if (Info.first != BlockCaptureEntityKind::None)
ManagedCaptures.emplace_back(Info.first, Info.second, CI, Capture);
}
+
+ // Sort the captures by offset.
+ llvm::sort(ManagedCaptures.begin(), ManagedCaptures.end());
}
namespace {
@@ -1614,10 +1627,12 @@ namespace {
struct CallBlockRelease final : EHScopeStack::Cleanup {
Address Addr;
BlockFieldFlags FieldFlags;
- bool LoadBlockVarAddr;
+ bool LoadBlockVarAddr, CanThrow;
- CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue)
- : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue) {}
+ CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue,
+ bool CT)
+ : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue),
+ CanThrow(CT) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::Value *BlockVarAddr;
@@ -1628,15 +1643,112 @@ struct CallBlockRelease final : EHScopeStack::Cleanup {
BlockVarAddr = Addr.getPointer();
}
- CGF.BuildBlockRelease(BlockVarAddr, FieldFlags);
+ CGF.BuildBlockRelease(BlockVarAddr, FieldFlags, CanThrow);
}
};
} // end anonymous namespace
+/// Check if \p T is a C++ class that has a destructor that can throw.
+bool CodeGenFunction::cxxDestructorCanThrow(QualType T) {
+ if (const auto *RD = T->getAsCXXRecordDecl())
+ if (const CXXDestructorDecl *DD = RD->getDestructor())
+ return DD->getType()->getAs<FunctionProtoType>()->canThrow();
+ return false;
+}
+
+static std::string getCopyDestroyHelperFuncName(
+ const SmallVectorImpl<BlockCaptureManagedEntity> &Captures,
+ CharUnits BlockAlignment, bool IsCopyHelper, CodeGenModule &CGM) {
+ ASTContext &Ctx = CGM.getContext();
+ std::unique_ptr<ItaniumMangleContext> MC(
+ ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics()));
+
+ std::string Name =
+ IsCopyHelper ? "__copy_helper_block_" : "__destroy_helper_block_";
+ if (CGM.getLangOpts().Exceptions)
+ Name += "e";
+ if (CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
+ Name += "a";
+ Name += llvm::to_string(BlockAlignment.getQuantity()) + "_";
+
+ for (const BlockCaptureManagedEntity &E : Captures) {
+ const BlockDecl::Capture &CI = *E.CI;
+ BlockFieldFlags Flags = E.Flags;
+ QualType CaptureTy = CI.getVariable()->getType();
+ Name += llvm::to_string(E.Capture->getOffset().getQuantity());
+
+ switch (E.Kind) {
+ case BlockCaptureEntityKind::CXXRecord: {
+ Name += "c";
+ SmallString<256> Str;
+ llvm::raw_svector_ostream Out(Str);
+ MC->mangleTypeName(CaptureTy, Out);
+ Name += llvm::to_string(Str.size()) + Str.c_str();
+ break;
+ }
+ case BlockCaptureEntityKind::ARCWeak:
+ Name += "w";
+ break;
+ case BlockCaptureEntityKind::ARCStrong:
+ Name += "s";
+ break;
+ case BlockCaptureEntityKind::BlockObject: {
+ const VarDecl *Var = CI.getVariable();
+ unsigned F = Flags.getBitMask();
+ if (F & BLOCK_FIELD_IS_BYREF) {
+ Name += "r";
+ if (F & BLOCK_FIELD_IS_WEAK)
+ Name += "w";
+ else {
+ if (IsCopyHelper) {
+ if (Ctx.getBlockVarCopyInit(Var).canThrow())
+ Name += "c";
+ } else {
+ if (CodeGenFunction::cxxDestructorCanThrow(CaptureTy))
+ Name += "d";
+ }
+ }
+ } else {
+ assert((F & BLOCK_FIELD_IS_OBJECT) && "unexpected flag value");
+ if (F == BLOCK_FIELD_IS_BLOCK)
+ Name += "b";
+ else
+ Name += "o";
+ }
+ break;
+ }
+ case BlockCaptureEntityKind::NonTrivialCStruct: {
+ bool IsVolatile = CaptureTy.isVolatileQualified();
+ CharUnits Alignment =
+ BlockAlignment.alignmentAtOffset(E.Capture->getOffset());
+
+ Name += "n";
+ std::string Str;
+ if (IsCopyHelper)
+ Str = CodeGenFunction::getNonTrivialCopyConstructorStr(
+ CaptureTy, Alignment, IsVolatile, Ctx);
+ else
+ Str = CodeGenFunction::getNonTrivialDestructorStr(CaptureTy, Alignment,
+ IsVolatile, Ctx);
+ // The underscore is necessary here because non-trivial copy constructor
+ // and destructor strings can start with a number.
+ Name += llvm::to_string(Str.size()) + "_" + Str;
+ break;
+ }
+ case BlockCaptureEntityKind::None:
+ llvm_unreachable("unexpected block capture kind");
+ }
+ }
+
+ return Name;
+}
+
static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
Address Field, QualType CaptureType,
- BlockFieldFlags Flags, bool EHOnly,
- CodeGenFunction &CGF) {
+ BlockFieldFlags Flags, bool ForCopyHelper,
+ VarDecl *Var, CodeGenFunction &CGF) {
+ bool EHOnly = ForCopyHelper;
+
switch (CaptureKind) {
case BlockCaptureEntityKind::CXXRecord:
case BlockCaptureEntityKind::ARCWeak:
@@ -1658,7 +1770,13 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
case BlockCaptureEntityKind::BlockObject: {
if (!EHOnly || CGF.getLangOpts().Exceptions) {
CleanupKind Kind = EHOnly ? EHCleanup : NormalAndEHCleanup;
- CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true);
+ // Calls to _Block_object_dispose along the EH path in the copy helper
+ // function don't throw as newly-copied __block variables always have a
+ // reference count of 2.
+ bool CanThrow =
+ !ForCopyHelper && CGF.cxxDestructorCanThrow(CaptureType);
+ CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true,
+ CanThrow);
}
break;
}
@@ -1667,6 +1785,19 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
}
}
+static void setBlockHelperAttributesVisibility(bool CapturesNonExternalType,
+ llvm::Function *Fn,
+ const CGFunctionInfo &FI,
+ CodeGenModule &CGM) {
+ if (CapturesNonExternalType) {
+ CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
+ } else {
+ Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ Fn->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+ CGM.SetLLVMFunctionAttributes(nullptr, FI, Fn);
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn);
+ }
+}
/// Generate the copy-helper function for a block closure object:
/// static void block_copy_helper(block_t *dst, block_t *src);
/// The runtime will have previously initialized 'dst' by doing a
@@ -1677,6 +1808,16 @@ static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind,
/// the contents of an individual __block variable to the heap.
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
+ SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
+ computeCopyInfoForBlockCapture);
+ std::string FuncName =
+ getCopyDestroyHelperFuncName(CopiedCaptures, blockInfo.BlockAlign,
+ /*IsCopyHelper*/ true, CGM);
+
+ if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
+ return Func;
+
ASTContext &C = getContext();
FunctionArgList args;
@@ -1695,11 +1836,11 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__copy_helper_block_", &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
+ FuncName, &CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__copy_helper_block_");
+ = &CGM.getContext().Idents.get(FuncName);
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
@@ -1709,8 +1850,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
false,
false);
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
+ setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
+ CGM);
StartFunction(FD, C.VoidTy, Fn, FI, args);
ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getBeginLoc()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1723,13 +1864,9 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
- SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
- computeCopyInfoForBlockCapture);
-
for (const auto &CopiedCapture : CopiedCaptures) {
- const BlockDecl::Capture &CI = CopiedCapture.CI;
- const CGBlockInfo::Capture &capture = CopiedCapture.Capture;
+ const BlockDecl::Capture &CI = *CopiedCapture.CI;
+ const CGBlockInfo::Capture &capture = *CopiedCapture.Capture;
QualType captureType = CI.getVariable()->getType();
BlockFieldFlags flags = CopiedCapture.Flags;
@@ -1783,28 +1920,17 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
};
- const VarDecl *variable = CI.getVariable();
- bool copyCanThrow = false;
- if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) {
- const Expr *copyExpr =
- CGM.getContext().getBlockVarCopyInits(variable);
- if (copyExpr) {
- copyCanThrow = true; // FIXME: reuse the noexcept logic
- }
- }
-
- if (copyCanThrow) {
+ if (CI.isByRef() && C.getBlockVarCopyInit(CI.getVariable()).canThrow())
EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
- } else {
+ else
EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
- }
}
}
// Ensure that we destroy the copied object if an exception is thrown later
// in the helper function.
- pushCaptureCleanup(CopiedCapture.Kind, dstField, captureType, flags, /*EHOnly*/ true,
- *this);
+ pushCaptureCleanup(CopiedCapture.Kind, dstField, captureType, flags,
+ /*ForCopyHelper*/ true, CI.getVariable(), *this);
}
FinishFunction();
@@ -1868,6 +1994,16 @@ computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
/// variable.
llvm::Constant *
CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
+ SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
+ computeDestroyInfoForBlockCapture);
+ std::string FuncName =
+ getCopyDestroyHelperFuncName(DestroyedCaptures, blockInfo.BlockAlign,
+ /*IsCopyHelper*/ false, CGM);
+
+ if (llvm::GlobalValue *Func = CGM.getModule().getNamedValue(FuncName))
+ return Func;
+
ASTContext &C = getContext();
FunctionArgList args;
@@ -1883,11 +2019,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__destroy_helper_block_", &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::LinkOnceODRLinkage,
+ FuncName, &CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__destroy_helper_block_");
+ = &CGM.getContext().Idents.get(FuncName);
FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(),
SourceLocation(),
@@ -1895,9 +2031,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
nullptr, SC_Static,
false, false);
- CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
-
+ setBlockHelperAttributesVisibility(blockInfo.CapturesNonExternalType, Fn, FI,
+ CGM);
StartFunction(FD, C.VoidTy, Fn, FI, args);
+ markAsIgnoreThreadCheckingAtRuntime(Fn);
+
ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getBeginLoc()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1908,20 +2046,17 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
CodeGenFunction::RunCleanupsScope cleanups(*this);
- SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
- findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
- computeDestroyInfoForBlockCapture);
-
for (const auto &DestroyedCapture : DestroyedCaptures) {
- const BlockDecl::Capture &CI = DestroyedCapture.CI;
- const CGBlockInfo::Capture &capture = DestroyedCapture.Capture;
+ const BlockDecl::Capture &CI = *DestroyedCapture.CI;
+ const CGBlockInfo::Capture &capture = *DestroyedCapture.Capture;
BlockFieldFlags flags = DestroyedCapture.Flags;
Address srcField =
Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset());
pushCaptureCleanup(DestroyedCapture.Kind, srcField,
- CI.getVariable()->getType(), flags, /*EHOnly*/ false, *this);
+ CI.getVariable()->getType(), flags,
+ /*ForCopyHelper*/ false, CI.getVariable(), *this);
}
cleanups.ForceCleanup();
@@ -1961,7 +2096,7 @@ public:
field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
llvm::Value *value = CGF.Builder.CreateLoad(field);
- CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
+ CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER, false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const override {
@@ -2288,7 +2423,8 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
byrefInfo.ByrefAlignment.alignmentAtOffset(byrefInfo.FieldOffset);
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
- const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
+ const Expr *copyExpr =
+ CGM.getContext().getBlockVarCopyInit(&var).getCopyExpr();
if (!copyExpr && record->hasTrivialDestructor()) return nullptr;
return ::buildByrefHelpers(
@@ -2591,19 +2727,25 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
}
}
-void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
+void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags,
+ bool CanThrow) {
llvm::Value *F = CGM.getBlockObjectDispose();
llvm::Value *args[] = {
Builder.CreateBitCast(V, Int8PtrTy),
llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
};
- EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors?
+
+ if (CanThrow)
+ EmitRuntimeCallOrInvoke(F, args);
+ else
+ EmitNounwindRuntimeCall(F, args);
}
void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr,
BlockFieldFlags Flags,
- bool LoadBlockVarAddr) {
- EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr);
+ bool LoadBlockVarAddr, bool CanThrow) {
+ EHStack.pushCleanup<CallBlockRelease>(Kind, Addr, Flags, LoadBlockVarAddr,
+ CanThrow);
}
/// Adjust the declaration of something from the blocks API.
OpenPOWER on IntegriCloud