Skip to content

Commit 3363a54

Browse files
committed
[5.4] IRGen: We can only reuse methods for partial apply thunks if their abi uses swiftself for self
Explanation: A mismatch between the ABI of methods and the partial apply thunk they are used for in an optimization -- the swiftself argument of the closure context is is not reflected in the method's abi -- causes crashes. Only certain methods use the swiftself register for the self parameter. The code determining reuse of the method for the partial apply thunk did not correctly compute the match. Origination: This was introduced by an optimization in a commit in May. Risk: Low. The fix uses the function that method signature lowering use to determine whether swiftself is used in the method signature. Testing: A regression test was added. rdar://73777202
1 parent eb5989d commit 3363a54

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,12 @@ static bool isSimplePartialApply(IRGenFunction &IGF, PartialApplyInst *i) {
29562956
// handled by a simplification pass in SIL.)
29572957
if (i->getNumArguments() != 1)
29582958
return false;
2959-
2959+
// The closure application is going to expect to pass the context in swiftself
2960+
// only methods where the call to `hasSelfContextParameter` returns true will
2961+
// use swiftself for the self parameter.
2962+
if (!hasSelfContextParameter(calleeTy))
2963+
return false;
2964+
29602965
auto appliedParam = calleeTy->getParameters().back();
29612966
if (resultTy->isNoEscape()) {
29622967
// A trivial closure accepts an unowned or guaranteed argument, possibly

test/IRGen/simple_partial_apply.sil

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ entry(%body : $@convention(method) (Int, @guaranteed C) -> Int, %context : $C):
2323
return %closure : $@callee_guaranteed (Int) -> Int
2424
}
2525

26+
// Can't reuse the method because it does not have swiftself.
27+
2628
// CHECK-LABEL: define {{.*}} @escape_partial_apply_swift_single_refcount_struct
27-
// CHECK-arm64e: call i64 @llvm.ptrauth.resign.i64
28-
// CHECK: [[FPTR:%.*]] = insertvalue { i8*, %swift.refcounted* } undef, i8* {{.*}}, 0
29-
// CHECK-NEXT: [[FCTX:%.*]] = insertvalue { i8*, %swift.refcounted* } [[FPTR]], %swift.refcounted* {{.*}}, 1
29+
// CHECK: [[CTXT:%.*]] = call {{.*}} @swift_allocObject
30+
// CHECK: [[FCTX:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (i{{(64|32)}} (i{{(64|32)}}, %swift.refcounted*)* @"$sTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* [[CTXT]], 1
3031
// CHECK-NEXT: ret { i8*, %swift.refcounted* } [[FCTX]]
3132
sil @escape_partial_apply_swift_single_refcount_struct : $@convention(thin) (@convention(method) (Int, @guaranteed SingleRefcounted) -> Int, @guaranteed SingleRefcounted) -> @callee_guaranteed (Int) -> Int {
3233
entry(%body : $@convention(method) (Int, @guaranteed SingleRefcounted) -> Int, %context : $SingleRefcounted):
@@ -47,11 +48,9 @@ entry(%body : $@convention(method) (Int, @in_guaranteed C) -> Int, %context : $*
4748
return undef : $()
4849
}
4950

51+
// Can't reuse the method because it does not have swiftself.
5052
// CHECK-LABEL: define {{.*}} @noescape_partial_apply_swift_direct_word
51-
// CHECK-arm64e: call i64 @llvm.ptrauth.resign.i64
52-
// CHECK: [[CTX:%.*]] = inttoptr i{{.*}} %1 to %swift.opaque*
53-
// CHECK-NEXT: [[CONT:%.*]] = bitcast i8* %2
54-
// CHECK-NEXT: call {{.*}}void [[CONT]](i8* {{.*}}, %swift.opaque* [[CTX]], %swift.refcounted* {{.*}}%3)
53+
// CHECK: call swiftcc void %11(i8* bitcast (i{{(64|32)}} (i{{(64|32)}}, %swift.refcounted*)* @"$sTA.1" to i8*), %swift.opaque* {{.*}}, %swift.refcounted* swiftself {{.*}})
5554
sil @noescape_partial_apply_swift_direct_word : $@convention(thin) (@convention(method) (Int, Int) -> Int, Int, @guaranteed @callee_guaranteed (@noescape @callee_guaranteed (Int) -> Int) -> ()) -> () {
5655
entry(%body : $@convention(method) (Int, Int) -> Int, %context : $Int, %cont : $@callee_guaranteed (@noescape @callee_guaranteed (Int) -> Int) -> ()):
5756
%closure = partial_apply [callee_guaranteed] [on_stack] %body(%context) : $@convention(method) (Int, Int) -> Int
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %target-swift-emit-ir -module-name test %s | %FileCheck %s
2+
// RUN: %target-run-simple-swift %s | %FileCheck %s --check-prefix=CHECK-EXEC
3+
4+
@propertyWrapper
5+
struct State<T> {
6+
private class Reference {
7+
var value: T
8+
init(value: T) { self.value = value }
9+
}
10+
11+
private let ref: Reference
12+
13+
init(wrappedValue: T) {
14+
ref = Reference(value: wrappedValue)
15+
}
16+
17+
var wrappedValue: T {
18+
get { ref.value }
19+
nonmutating set { ref.value = newValue }
20+
}
21+
}
22+
23+
struct S {
24+
@State var value: Int = 1
25+
26+
init() {
27+
value = 10 // CRASH
28+
}
29+
}
30+
31+
print("Hello!")
32+
let s = S()
33+
print(s)
34+
35+
// CHECK: define {{.*}}swiftcc %T4test5StateV9Reference33_C903A018FCE7355FD30EF8324850EB90LLCySi_G* @"$s4test1SVACycfC"()
36+
// CHECK: call swiftcc void @"$s4test1SV5valueSivsTA"(i{{(32|64)}} 10, %swift.refcounted* swiftself {{.*}})
37+
// CHECK: ret %T4test5StateV9Reference33_C903A018FCE7355FD30EF8324850EB90LLCySi_G
38+
39+
// This used to crash.
40+
41+
// CHECK-EXEC: Hello!
42+
// CHECK-EXEC: S(_value: main.State<Swift.Int>(ref: main.State<Swift.Int>.(unknown context at {{.*}}).Reference))

0 commit comments

Comments
 (0)