From dbfa453e4138bb977644929c69d1c71e5e8b4bee Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 20 Jul 2018 17:10:32 +0000 Subject: [CodeGen][ObjC] Make copying and disposing of a non-escaping block no-ops. A non-escaping block on the stack will never be called after its lifetime ends, so it doesn't have to be copied to the heap. To prevent a non-escaping block from being copied to the heap, this patch sets field 'isa' of the block object to NSConcreteGlobalBlock and sets the BLOCK_IS_GLOBAL bit of field 'flags', which causes the runtime to treat the block as if it were a global block (calling _Block_copy on the block just returns the original block and calling _Block_release is a no-op). Also, a new flag bit 'BLOCK_IS_NOESCAPE' is added, which allows the runtime or tools to distinguish between true global blocks and non-escaping blocks. rdar://problem/39352313 Differential Revision: https://reviews.llvm.org/D49303 llvm-svn: 337580 --- clang/lib/CodeGen/CGBlocks.cpp | 16 ++++++++++++---- clang/lib/CodeGen/CGBlocks.h | 9 ++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'clang/lib/CodeGen') diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 926683db93c..352a02db2b9 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -104,7 +104,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, elements.addInt(ulong, blockInfo.BlockSize.getQuantity()); // Optional copy/dispose helpers. - if (blockInfo.NeedsCopyDispose) { + if (blockInfo.needsCopyDisposeHelpers()) { // copy_func_helper_decl elements.add(buildCopyHelper(CGM, blockInfo)); @@ -159,6 +159,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, /// These are the flags (with corresponding bit number) that the /// compiler is actually supposed to know about. + /// 23. BLOCK_IS_NOESCAPE - indicates that the block is non-escaping /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block /// descriptor provides copy and dispose helper functions /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured @@ -778,8 +779,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { llvm::Constant *descriptor; BlockFlags flags; if (!IsOpenCL) { - isa = llvm::ConstantExpr::getBitCast(CGM.getNSConcreteStackBlock(), - VoidPtrTy); + // If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock + // and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping + // block just returns the original block and releasing it is a no-op. + llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape() + ? CGM.getNSConcreteGlobalBlock() + : CGM.getNSConcreteStackBlock(); + isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy); // Build the block descriptor. descriptor = buildBlockDescriptor(CGM, blockInfo); @@ -788,12 +794,14 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { flags = BLOCK_HAS_SIGNATURE; if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; - if (blockInfo.NeedsCopyDispose) + if (blockInfo.needsCopyDisposeHelpers()) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; + if (blockInfo.getBlockDecl()->doesNotEscape()) + flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL; } auto projectField = diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h index 80e255f7541..5a8e960ffcc 100644 --- a/clang/lib/CodeGen/CGBlocks.h +++ b/clang/lib/CodeGen/CGBlocks.h @@ -54,6 +54,7 @@ enum BlockByrefFlags { }; enum BlockLiteralFlags { + BLOCK_IS_NOESCAPE = (1 << 23), BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CXX_OBJ = (1 << 26), BLOCK_IS_GLOBAL = (1 << 28), @@ -214,7 +215,8 @@ public: /// no non-constant captures. bool CanBeGlobal : 1; - /// True if the block needs a custom copy or dispose function. + /// True if the block has captures that would necessitate custom copy or + /// dispose helper functions if the block were escaping. bool NeedsCopyDispose : 1; /// HasCXXObject - True if the block's custom copy/dispose functions @@ -276,6 +278,11 @@ public: } CGBlockInfo(const BlockDecl *blockDecl, StringRef Name); + + // Indicates whether the block needs a custom copy or dispose function. + bool needsCopyDisposeHelpers() const { + return NeedsCopyDispose && !Block->doesNotEscape(); + } }; } // end namespace CodeGen -- cgit v1.2.1