Skip to content

Commit 97ab864

Browse files
authored
Merge pull request #37931 from jckarter/actor-hop-objc-async
SILGen: Hop to the executor for actor-constrained methods in their @objc async thunks.
2 parents 256a9c5 + e39dca4 commit 97ab864

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "ArgumentScope.h"
1414
#include "Callee.h"
15+
#include "ExecutorBreadcrumb.h"
1516
#include "RValue.h"
1617
#include "ResultPlan.h"
1718
#include "SILGenFunction.h"
@@ -1479,10 +1480,11 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) {
14791480
}
14801481

14811482
// Create the closure implementation function. It has the same signature,
1482-
// but is just swiftcc and async.
1483+
// but is swiftcc and async.
14831484
auto closureExtInfo = objcFnTy->getExtInfo().intoBuilder()
14841485
.withRepresentation(SILFunctionTypeRepresentation::Thin)
14851486
.withAsync()
1487+
.withConcurrent()
14861488
.build();
14871489
auto closureTy = objcFnTy->getWithExtInfo(closureExtInfo);
14881490

@@ -1556,6 +1558,22 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
15561558
auto loc = thunk.getAsRegularLocation();
15571559
loc.markAutoGenerated();
15581560
Scope scope(Cleanups, CleanupLocation(loc));
1561+
1562+
// Hop to the actor for the method's actor constraint, if any.
1563+
// Note that, since an async native-to-foreign thunk only ever runs in a
1564+
// task purpose-built for running the Swift async code triggering the
1565+
// completion handler, there is no need for us to hop back to the existing
1566+
// executor, since the task will end after we invoke the completion handler.
1567+
if (F.isAsync()) {
1568+
Optional<ActorIsolation> isolation;
1569+
if (thunk.hasDecl()) {
1570+
isolation = getActorIsolation(thunk.getDecl());
1571+
}
1572+
1573+
if (isolation) {
1574+
emitHopToTargetActor(loc, *isolation, None);
1575+
}
1576+
}
15591577

15601578
// If we are bridging a Swift method with an Any return value, create a
15611579
// stack allocation to hold the result, since Any is address-only.

stdlib/public/Concurrency/Task.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -801,12 +801,8 @@ func _getCurrentThreadPriority() -> Int
801801
@available(SwiftStdlib 5.5, *)
802802
@_alwaysEmitIntoClient
803803
@usableFromInline
804-
internal func _runTaskForBridgedAsyncMethod(_ body: @escaping () async -> Void) {
805-
#if compiler(>=5.5) && $Sendable && $InheritActorContext && $ImplicitSelfCapture
806-
Task { await body() }
807-
#else
808-
Task.runDetached { await body() }
809-
#endif
804+
internal func _runTaskForBridgedAsyncMethod(@_inheritActorContext _ body: __owned @Sendable @escaping () async -> Void) {
805+
Task(operation: body)
810806
}
811807

812808
#endif

test/SILGen/objc_async_from_swift.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,15 @@ class SlowServerlet: SlowServer {
108108
}
109109
}
110110

111+
@globalActor actor FooActor {
112+
static var shared = FooActor()
113+
}
114+
115+
@FooActor
116+
class ActorConstrained: NSObject {
117+
// CHECK-LABEL: sil shared [thunk] [ossa] @$s{{.*}}16ActorConstrainedC3foo{{.*}}U_To
118+
// CHECK: hop_to_executor {{%.*}} : $FooActor
119+
@objc func foo() async -> Bool {
120+
return true
121+
}
122+
}

0 commit comments

Comments
 (0)