parent
28a42c7706
commit
4a6f190e19
|
@ -1874,57 +1874,65 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
|
||||||
Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset());
|
Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset());
|
||||||
Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset());
|
Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset());
|
||||||
|
|
||||||
// If there's an explicit copy expression, we do that.
|
switch (CopiedCapture.Kind) {
|
||||||
if (CI.getCopyExpr()) {
|
case BlockCaptureEntityKind::CXXRecord:
|
||||||
assert(CopiedCapture.Kind == BlockCaptureEntityKind::CXXRecord);
|
// If there's an explicit copy expression, we do that.
|
||||||
|
assert(CI.getCopyExpr() && "copy expression for variable is missing");
|
||||||
EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
|
EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
|
||||||
} else if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCWeak) {
|
break;
|
||||||
|
case BlockCaptureEntityKind::ARCWeak:
|
||||||
EmitARCCopyWeak(dstField, srcField);
|
EmitARCCopyWeak(dstField, srcField);
|
||||||
// If this is a C struct that requires non-trivial copy construction, emit a
|
break;
|
||||||
// call to its copy constructor.
|
case BlockCaptureEntityKind::NonTrivialCStruct: {
|
||||||
} else if (CopiedCapture.Kind ==
|
// If this is a C struct that requires non-trivial copy construction,
|
||||||
BlockCaptureEntityKind::NonTrivialCStruct) {
|
// emit a call to its copy constructor.
|
||||||
QualType varType = CI.getVariable()->getType();
|
QualType varType = CI.getVariable()->getType();
|
||||||
callCStructCopyConstructor(MakeAddrLValue(dstField, varType),
|
callCStructCopyConstructor(MakeAddrLValue(dstField, varType),
|
||||||
MakeAddrLValue(srcField, varType));
|
MakeAddrLValue(srcField, varType));
|
||||||
} else {
|
break;
|
||||||
|
}
|
||||||
|
case BlockCaptureEntityKind::ARCStrong: {
|
||||||
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
|
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
|
||||||
if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCStrong) {
|
// At -O0, store null into the destination field (so that the
|
||||||
// At -O0, store null into the destination field (so that the
|
// storeStrong doesn't over-release) and then call storeStrong.
|
||||||
// storeStrong doesn't over-release) and then call storeStrong.
|
// This is a workaround to not having an initStrong call.
|
||||||
// This is a workaround to not having an initStrong call.
|
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
|
||||||
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
|
auto *ty = cast<llvm::PointerType>(srcValue->getType());
|
||||||
auto *ty = cast<llvm::PointerType>(srcValue->getType());
|
llvm::Value *null = llvm::ConstantPointerNull::get(ty);
|
||||||
llvm::Value *null = llvm::ConstantPointerNull::get(ty);
|
Builder.CreateStore(null, dstField);
|
||||||
Builder.CreateStore(null, dstField);
|
EmitARCStoreStrongCall(dstField, srcValue, true);
|
||||||
EmitARCStoreStrongCall(dstField, srcValue, true);
|
|
||||||
|
|
||||||
// With optimization enabled, take advantage of the fact that
|
// With optimization enabled, take advantage of the fact that
|
||||||
// the blocks runtime guarantees a memcpy of the block data, and
|
// the blocks runtime guarantees a memcpy of the block data, and
|
||||||
// just emit a retain of the src field.
|
// just emit a retain of the src field.
|
||||||
} else {
|
|
||||||
EmitARCRetainNonBlock(srcValue);
|
|
||||||
|
|
||||||
// Unless EH cleanup is required, we don't need this anymore, so kill
|
|
||||||
// it. It's not quite worth the annoyance to avoid creating it in the
|
|
||||||
// first place.
|
|
||||||
if (!needsEHCleanup(captureType.isDestructedType()))
|
|
||||||
cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
assert(CopiedCapture.Kind == BlockCaptureEntityKind::BlockObject);
|
EmitARCRetainNonBlock(srcValue);
|
||||||
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
|
|
||||||
llvm::Value *dstAddr =
|
|
||||||
Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy);
|
|
||||||
llvm::Value *args[] = {
|
|
||||||
dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
|
|
||||||
};
|
|
||||||
|
|
||||||
if (CI.isByRef() && C.getBlockVarCopyInit(CI.getVariable()).canThrow())
|
// Unless EH cleanup is required, we don't need this anymore, so kill
|
||||||
EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
|
// it. It's not quite worth the annoyance to avoid creating it in the
|
||||||
else
|
// first place.
|
||||||
EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
|
if (!needsEHCleanup(captureType.isDestructedType()))
|
||||||
|
cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BlockCaptureEntityKind::BlockObject: {
|
||||||
|
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
|
||||||
|
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
|
||||||
|
llvm::Value *dstAddr =
|
||||||
|
Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy);
|
||||||
|
llvm::Value *args[] = {
|
||||||
|
dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
|
||||||
|
};
|
||||||
|
|
||||||
|
if (CI.isByRef() && C.getBlockVarCopyInit(CI.getVariable()).canThrow())
|
||||||
|
EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
|
||||||
|
else
|
||||||
|
EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BlockCaptureEntityKind::None:
|
||||||
|
llvm_unreachable("unexpected BlockCaptureEntityKind");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that we destroy the copied object if an exception is thrown later
|
// Ensure that we destroy the copied object if an exception is thrown later
|
||||||
|
|
Loading…
Reference in New Issue