Skip to content

Commit 0fbe171

Browse files
authored
Merge pull request #38767 from DougGregor/foreign-async-hop-back
Emit `hop_to_executor` instructors for foreign `async` calls.
2 parents a7586fb + 865de72 commit 0fbe171

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4459,7 +4459,7 @@ RValue SILGenFunction::emitApply(
44594459
}
44604460

44614461
ExecutorBreadcrumb breadcrumb;
4462-
4462+
44634463
// The presence of `implicitActorHopTarget` indicates that the callee is a
44644464
// synchronous function isolated to an actor other than our own.
44654465
// Such functions require the caller to hop to the callee's executor
@@ -4485,7 +4485,8 @@ RValue SILGenFunction::emitApply(
44854485
}
44864486

44874487
breadcrumb = emitHopToTargetExecutor(loc, executor);
4488-
} else if (ExpectedExecutor && substFnType->isAsync()) {
4488+
} else if (ExpectedExecutor &&
4489+
(substFnType->isAsync() || calleeTypeInfo.foreign.async)) {
44894490
// Otherwise, if we're in an actor method ourselves, and we're calling into
44904491
// any sort of async function, we'll want to make sure to hop back to our
44914492
// own executor afterward, since the callee could have made arbitrary hops
@@ -4502,8 +4503,10 @@ RValue SILGenFunction::emitApply(
45024503
rawDirectResult = rawDirectResults[0];
45034504
}
45044505

4505-
// hop back to the current executor
4506-
breadcrumb.emit(*this, loc);
4506+
if (!calleeTypeInfo.foreign.async) {
4507+
// hop back to the current executor
4508+
breadcrumb.emit(*this, loc);
4509+
}
45074510

45084511
// For objc async calls, lifetime extend the args until the result plan which
45094512
// generates `await_async_continuation`.
@@ -4617,6 +4620,9 @@ RValue SILGenFunction::emitApply(
46174620
B.emitFixLifetime(loc, value);
46184621
B.emitDestroyOperation(loc, value);
46194622
}
4623+
4624+
// hop back to the current executor
4625+
breadcrumb.emit(*this, loc);
46204626
}
46214627

46224628
return result;

test/SILGen/objc_async.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,30 @@ func testGeneric2<T: AnyObject, U>(x: GenericObject<T>, y: U) async throws {
170170
// CHECK: [[RESULT_1_BUF:%.*]] = tuple_element_addr [[RESULT_BUF]] {{.*}}, 1
171171
// CHECK: store %2 to [trivial] [[RESULT_1_BUF]]
172172

173+
// CHECK-LABEL: sil {{.*}}@${{.*}}22testSlowServerFromMain
174+
@MainActor
175+
func testSlowServerFromMain(slowServer: SlowServer) async throws {
176+
// CHECK: hop_to_executor %6 : $MainActor
177+
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int
178+
// CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF :
179+
// CHECK: [[ARG:%.*]] = apply [[STRINGINIT]]
180+
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> ()
181+
// CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]]
182+
// CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation<Int, Never> ([[CONT]] : $Builtin.RawUnsafeContinuation)
183+
// CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage UnsafeContinuation<Int, Never>
184+
// CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]]
185+
// CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT]]
186+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage UnsafeContinuation<Int, Never>, Int) -> ()
187+
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]]
188+
// CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0)
189+
// CHECK: [[COPY:%.*]] = copy_value [[ARG]]
190+
// CHECK: destroy_value [[ARG]]
191+
// CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]]
192+
// CHECK: [[RESUME]]:
193+
// CHECK: [[RESULT:%.*]] = load [trivial] [[RESUME_BUF]]
194+
// CHECK: fix_lifetime [[COPY]]
195+
// CHECK: destroy_value [[COPY]]
196+
// CHECK: hop_to_executor %6 : $MainActor
197+
// CHECK: dealloc_stack [[RESUME_BUF]]
198+
let _: Int = await slowServer.doSomethingSlow("mail")
199+
}

0 commit comments

Comments
 (0)