Skip to content

Commit e5d54e3

Browse files
committed
[SILGen] Emit expected executor preconditions to synchronous isolated @objc thunks
When `PreconcurrencyConformances` feature is enabled, emit a precondition into every synchronous isolated @objc thunk to make sure that it's always called on the right executor.
1 parent d4f64b9 commit e5d54e3

File tree

2 files changed

+97
-14
lines changed

2 files changed

+97
-14
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,22 +1592,29 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
15921592
auto loc = thunk.getAsRegularLocation();
15931593
loc.markAutoGenerated();
15941594
Scope scope(Cleanups, CleanupLocation(loc));
1595-
1596-
// Hop to the actor for the method's actor constraint, if any.
1597-
// Note that, since an async native-to-foreign thunk only ever runs in a
1598-
// task purpose-built for running the Swift async code triggering the
1599-
// completion handler, there is no need for us to hop back to the existing
1600-
// executor, since the task will end after we invoke the completion handler.
1601-
if (F.isAsync()) {
1602-
llvm::Optional<ActorIsolation> isolation;
1603-
if (thunk.hasDecl()) {
1604-
isolation = getActorIsolation(thunk.getDecl());
1605-
}
16061595

1607-
// A hop is only needed in the thunk if it is global-actor isolated.
1608-
// Native, instance-isolated async methods will hop in the prologue.
1609-
if (isolation && isolation->isGlobalActor()) {
1596+
bool emitExecutorPrecondition =
1597+
getASTContext().LangOpts.hasFeature(Feature::PreconcurrencyConformances);
1598+
1599+
llvm::Optional<ActorIsolation> isolation;
1600+
if ((F.isAsync() || emitExecutorPrecondition) && thunk.hasDecl()) {
1601+
isolation = getActorIsolation(thunk.getDecl());
1602+
}
1603+
1604+
// A hop/check is only needed in the thunk if it is global-actor isolated.
1605+
// Native, instance-isolated async methods will hop in the prologue.
1606+
if (isolation && isolation->isGlobalActor()) {
1607+
if (F.isAsync()) {
1608+
// Hop to the actor for the method's actor constraint.
1609+
// Note that, since an async native-to-foreign thunk only ever runs in a
1610+
// task purpose-built for running the Swift async code triggering the
1611+
// completion handler, there is no need for us to hop back to the existing
1612+
// executor, since the task will end after we invoke the completion handler.
16101613
emitPrologGlobalActorHop(loc, isolation->getGlobalActor());
1614+
} else {
1615+
auto executor =
1616+
emitLoadGlobalActorExecutor(isolation->getGlobalActor());
1617+
emitPreconditionCheckExpectedExecutor(loc, executor);
16111618
}
16121619
}
16131620

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-feature PreconcurrencyConformances -emit-silgen %s | %FileCheck %s
2+
3+
// REQUIRES: asserts
4+
// REQUIRES: concurrency
5+
// REQUIRES: objc_interop
6+
7+
import Foundation
8+
9+
actor MyActor {
10+
}
11+
12+
@globalActor
13+
struct GlobalActor {
14+
static var shared: MyActor = MyActor()
15+
}
16+
17+
@objc protocol P {
18+
var data: String? { get set }
19+
20+
init()
21+
func test() -> Any?
22+
}
23+
24+
@MainActor
25+
final class K : @preconcurrency P {
26+
var data: String? {
27+
get { nil }
28+
set {}
29+
}
30+
31+
init() {}
32+
@GlobalActor func test() -> Any? { nil }
33+
}
34+
35+
// @objc K.data.getter
36+
// CHECK-LABEL: sil private [thunk] [ossa] @$s27preconcurrency_conformances1KC4dataSSSgvgTo : $@convention(objc_method) (K) -> @autoreleased Optional<NSString>
37+
// CHECK: [[MAIN_ACTOR_METATYPE:%.*]] = metatype $@thick MainActor.Type
38+
// CHECK: [[SHARED_FIELD:%.*]] = function_ref @$sScM6sharedScMvgZ : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
39+
// CHECK-NEXT: [[SHARED_ACTOR:%.*]] = apply [[SHARED_FIELD]]([[MAIN_ACTOR_METATYPE]]) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
40+
// CHECK-NEXT: [[MAIN_ACTOR:%.*]] = begin_borrow [[SHARED_ACTOR]] : $MainActor
41+
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
42+
// CHECK: [[PRECONDITION:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
43+
// CHECK-NEXT: {{.*}} = apply [[PRECONDITION]]({{.*}}, [[EXEC]]) : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
44+
45+
// @objc K.data.setter
46+
// CHECK-LABEL: sil private [thunk] [ossa] @$s27preconcurrency_conformances1KC4dataSSSgvsTo : $@convention(objc_method) (Optional<NSString>, K) -> ()
47+
// CHECK: [[MAIN_ACTOR_METATYPE:%.*]] = metatype $@thick MainActor.Type
48+
// CHECK: [[SHARED_FIELD:%.*]] = function_ref @$sScM6sharedScMvgZ : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
49+
// CHECK-NEXT: [[SHARED_ACTOR:%.*]] = apply [[SHARED_FIELD]]([[MAIN_ACTOR_METATYPE]]) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
50+
// CHECK-NEXT: [[MAIN_ACTOR:%.*]] = begin_borrow [[SHARED_ACTOR]] : $MainActor
51+
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
52+
// CHECK: [[PRECONDITION:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
53+
// CHECK-NEXT: {{.*}} = apply [[PRECONDITION]]({{.*}}, [[EXEC]]) : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
54+
55+
// @objc K.init()
56+
// CHECK-LABEL: sil private [thunk] [ossa] @$s27preconcurrency_conformances1KCACycfcTo : $@convention(objc_method) (@owned K) -> @owned K
57+
// CHECK: [[MAIN_ACTOR_METATYPE:%.*]] = metatype $@thick MainActor.Type
58+
// CHECK: [[SHARED_FIELD:%.*]] = function_ref @$sScM6sharedScMvgZ : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
59+
// CHECK-NEXT: [[SHARED_ACTOR:%.*]] = apply [[SHARED_FIELD]]([[MAIN_ACTOR_METATYPE]]) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
60+
// CHECK-NEXT: [[MAIN_ACTOR:%.*]] = begin_borrow [[SHARED_ACTOR]] : $MainActor
61+
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor
62+
// CHECK: [[PRECONDITION:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
63+
// CHECK-NEXT: {{.*}} = apply [[PRECONDITION]]({{.*}}, [[EXEC]]) : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
64+
65+
// @objc K.test()
66+
// CHECK-LABEL: sil private [thunk] [ossa] @$s27preconcurrency_conformances1KC4testypSgyFTo : $@convention(objc_method) (K) -> @autoreleased Optional<AnyObject>
67+
// CHECK: [[GLOBAL_ACTOR_METATYPE:%.*]] = metatype $@thin GlobalActor.Type
68+
// CHECK: [[SHARED_ACTOR_GETTER:%.*]] = function_ref @$s27preconcurrency_conformances11GlobalActorV6sharedAA02MyD0Cvau : $@convention(thin) () -> Builtin.RawPointer
69+
// CHECK-NEXT: [[ACTOR_PTR:%.*]] = apply [[SHARED_ACTOR_GETTER]]() : $@convention(thin) () -> Builtin.RawPointer
70+
// CHECK-NEXT: [[MY_ACTOR_ADDR:%.*]] = pointer_to_address [[ACTOR_PTR]] : $Builtin.RawPointer to [strict] $*MyActor
71+
// CHECK-NEXT: [[MY_ACTOR_ACCESS:%.*]] = begin_access [read] [dynamic] [[MY_ACTOR_ADDR]] : $*MyActor
72+
// CHECK-NEXT: [[MY_ACTOR:%.*]] = load [copy] [[MY_ACTOR_ACCESS]] : $*MyActor
73+
// CHECK: [[MY_ACTOR_REF:%.*]] = begin_borrow [[MY_ACTOR]] : $MyActor
74+
// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MY_ACTOR_REF]] : $MyActor
75+
// CHECK: [[PRECONDITION:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()
76+
// CHECK-NEXT: {{.*}} = apply [[PRECONDITION]]({{.*}}, [[EXEC]]) : $@convention(thin) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word, Builtin.Executor) -> ()

0 commit comments

Comments
 (0)