Skip to content

Commit ea6ed2f

Browse files
authored
Merge pull request #82537 from eeckstein/fix-closure-specializer
ClosureSpecializer: don't specialize captures of stack-allocated Objective-C blocks
2 parents 81d22c8 + 1a009f5 commit ea6ed2f

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,19 @@ static bool isSupportedClosure(const SILInstruction *Closure) {
694694
return false;
695695
}
696696

697+
// Bail if it's an ObjectiveC block which might _not_ be copied onto the heap, i.e
698+
// optimized by SimplifyCopyBlock. We can't do this because the optimization inserts
699+
// retains+releases for captured arguments. That's not possible for stack-allocated blocks.
700+
// TODO: avoid inserting retains+releases at all for captures of `partial_apply [on_stack]`
701+
if (ArgTy.is<SILFunctionType>() &&
702+
ArgTy.getFunctionRepresentation() == SILFunctionTypeRepresentation::Block &&
703+
// A `copy_block` ensures that the block is copied onto the heap.
704+
!isa<CopyBlockInst>(Arg) &&
705+
// SimplifyCopyBlock only works for `partial_apply [on_stack]`.
706+
PAI->isOnStack()) {
707+
return false;
708+
}
709+
697710
// Only @inout/@inout_aliasable addresses are (currently) supported.
698711
// If our argument is an object, continue...
699712
if (ArgTy.isObject()) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend -parse-as-library -O %s -emit-sil | %FileCheck %s
2+
3+
func callClosure<R>(_ body: () -> R) -> R {
4+
return body()
5+
}
6+
7+
// Check that after removing a copy_block, no retains+releases are inserted for the block.
8+
// CHECK-LABEL: sil {{.*}}@testit :
9+
// CHECK-NOT: retain
10+
// CHECK-NOT: release
11+
// CHECK: } // end sil function 'testit'
12+
@_cdecl("testit")
13+
public func testit(_ block: (_ index: Int) -> Int) -> Bool {
14+
@inline(never)
15+
func c() -> Bool {
16+
return block(0) != 0
17+
}
18+
19+
return callClosure(c)
20+
}

0 commit comments

Comments
 (0)