Skip to content

Commit 97f8ef6

Browse files
authored
Merge pull request #41055 from rjmccall/hop-to-generic-executor-5.6
[5.6] Hop to the generic executor in non-actor-isolated async functions
2 parents 8ab196b + 0106bde commit 97f8ef6

17 files changed

+256
-140
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
15881588
// A hop is only needed in the thunk if it is global-actor isolated.
15891589
// Native, instance-isolated async methods will hop in the prologue.
15901590
if (isolation && isolation->isGlobalActor()) {
1591-
emitHopToTargetActor(loc, *isolation, None);
1591+
emitPrologGlobalActorHop(loc, isolation->getGlobalActor());
15921592
}
15931593
}
15941594

lib/SILGen/SILGenConstructor.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -672,13 +672,17 @@ static void emitDefaultActorInitialization(
672672
void SILGenFunction::emitConstructorPrologActorHop(
673673
SILLocation loc,
674674
Optional<ActorIsolation> maybeIso) {
675-
if (!maybeIso)
676-
return;
677-
678-
if (auto executor = emitExecutor(loc, *maybeIso, None)) {
679-
ExpectedExecutor = *executor;
680-
B.createHopToExecutor(loc.asAutoGenerated(), *executor, /*mandatory*/ false);
675+
loc = loc.asAutoGenerated();
676+
if (maybeIso) {
677+
if (auto executor = emitExecutor(loc, *maybeIso, None)) {
678+
ExpectedExecutor = *executor;
679+
}
681680
}
681+
682+
if (!ExpectedExecutor)
683+
ExpectedExecutor = emitGenericExecutor(loc);
684+
685+
B.createHopToExecutor(loc, ExpectedExecutor, /*mandatory*/ false);
682686
}
683687

684688
// MARK: class constructor

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -922,36 +922,7 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
922922
JobType, {}, {task});
923923
jobResult = wrapCallArgs(jobResult, swiftJobRunFuncDecl, 0);
924924

925-
// Get main executor
926-
FuncDecl *getMainExecutorFuncDecl = SGM.getGetMainExecutor();
927-
if (!getMainExecutorFuncDecl) {
928-
// If it doesn't exist due to an SDK-compiler mismatch, we can conjure one
929-
// up instead of crashing:
930-
// @available(SwiftStdlib 5.1, *)
931-
// @_silgen_name("swift_task_getMainExecutor")
932-
// internal func _getMainExecutor() -> Builtin.Executor
933-
934-
ParameterList *emptyParams = ParameterList::createEmpty(getASTContext());
935-
getMainExecutorFuncDecl = FuncDecl::createImplicit(
936-
getASTContext(), StaticSpellingKind::None,
937-
DeclName(
938-
getASTContext(),
939-
DeclBaseName(getASTContext().getIdentifier("_getMainExecutor")),
940-
/*Arguments*/ emptyParams),
941-
{}, /*async*/ false, /*throws*/ false, {}, emptyParams,
942-
getASTContext().TheExecutorType,
943-
entryPoint.getDecl()->getModuleContext());
944-
getMainExecutorFuncDecl->getAttrs().add(
945-
new (getASTContext())
946-
SILGenNameAttr("swift_task_getMainExecutor", /*implicit*/ true));
947-
}
948-
949-
SILFunction *getMainExeutorSILFunc = SGM.getFunction(
950-
SILDeclRef(getMainExecutorFuncDecl, SILDeclRef::Kind::Func),
951-
NotForDefinition);
952-
SILValue getMainExeutorFunc =
953-
B.createFunctionRefFor(moduleLoc, getMainExeutorSILFunc);
954-
SILValue mainExecutor = B.createApply(moduleLoc, getMainExeutorFunc, {}, {});
925+
SILValue mainExecutor = emitMainExecutor(moduleLoc);
955926
mainExecutor = wrapCallArgs(mainExecutor, swiftJobRunFuncDecl, 1);
956927

957928
// Run first part synchronously

lib/SILGen/SILGenFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,11 +874,22 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
874874
void emitConstructorPrologActorHop(SILLocation loc,
875875
Optional<ActorIsolation> actorIso);
876876

877+
/// Set the given global actor as the isolation for this function
878+
/// (generally a thunk) and hop to it.
879+
void emitPrologGlobalActorHop(SILLocation loc, Type globalActor);
880+
877881
/// Emit the executor for the given actor isolation.
878882
Optional<SILValue> emitExecutor(SILLocation loc,
879883
ActorIsolation isolation,
880884
Optional<ManagedValue> maybeSelf);
881885

886+
/// Emit the executor value that corresponds to the generic (concurrent)
887+
/// executor.
888+
SILValue emitGenericExecutor(SILLocation loc);
889+
890+
/// Emit the executor value that corresponds to the main actor.
891+
SILValue emitMainExecutor(SILLocation loc);
892+
882893
/// Emit a precondition check to ensure that the function is executing in
883894
/// the expected isolation context.
884895
void emitPreconditionCheckExpectedExecutor(

lib/SILGen/SILGenPoly.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,11 +2944,10 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
29442944

29452945
// If the input is synchronous and global-actor-qualified, and the
29462946
// output is asynchronous, hop to the executor expected by the input.
2947-
ExecutorBreadcrumb prevExecutor;
2947+
// Treat this thunk as if it were isolated to that global actor.
29482948
if (outputSubstType->isAsync() && !inputSubstType->isAsync()) {
29492949
if (Type globalActor = inputSubstType->getGlobalActor()) {
2950-
prevExecutor = SGF.emitHopToTargetActor(
2951-
loc, ActorIsolation::forGlobalActor(globalActor, false), None);
2950+
SGF.emitPrologGlobalActorHop(loc, globalActor);
29522951
}
29532952
}
29542953

@@ -2995,9 +2994,6 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
29952994
// Reabstract the result.
29962995
SILValue outerResult = resultPlanner.execute(innerResult);
29972996

2998-
// If we hopped to the target's executor, then we need to hop back.
2999-
prevExecutor.emit(SGF, loc);
3000-
30012997
scope.pop();
30022998
SGF.B.createReturn(loc, outerResult);
30032999
}

lib/SILGen/SILGenProlog.cpp

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
552552
return false;
553553
};
554554

555-
// Initialize ExpectedExecutor if the function is an actor-isolated
555+
// Initialize ExpectedExecutor if the function is an async
556556
// function or closure.
557557
bool wantDataRaceChecks = getOptions().EnableActorDataRaceChecks &&
558558
!F.isAsync() &&
@@ -642,6 +642,13 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
642642
}
643643
}
644644
}
645+
646+
// In async functions, the generic executor is our expected executor
647+
// if we don't have any sort of isolation.
648+
if (!ExpectedExecutor && F.isAsync()) {
649+
ExpectedExecutor = emitGenericExecutor(
650+
RegularLocation::getAutoGeneratedLocation(F.getLocation()));
651+
}
645652

646653
// Jump to the expected executor.
647654
if (ExpectedExecutor) {
@@ -661,6 +668,54 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
661668
}
662669
}
663670

671+
SILValue SILGenFunction::emitMainExecutor(SILLocation loc) {
672+
// Get main executor
673+
FuncDecl *getMainExecutorFuncDecl = SGM.getGetMainExecutor();
674+
if (!getMainExecutorFuncDecl) {
675+
// If it doesn't exist due to an SDK-compiler mismatch, we can conjure one
676+
// up instead of crashing:
677+
// @available(SwiftStdlib 5.1, *)
678+
// @_silgen_name("swift_task_getMainExecutor")
679+
// internal func _getMainExecutor() -> Builtin.Executor
680+
auto &ctx = getASTContext();
681+
682+
ParameterList *emptyParams = ParameterList::createEmpty(ctx);
683+
getMainExecutorFuncDecl = FuncDecl::createImplicit(
684+
ctx, StaticSpellingKind::None,
685+
DeclName(
686+
ctx,
687+
DeclBaseName(ctx.getIdentifier("_getMainExecutor")),
688+
/*Arguments*/ emptyParams),
689+
{}, /*async*/ false, /*throws*/ false, {}, emptyParams,
690+
ctx.TheExecutorType,
691+
getModule().getSwiftModule());
692+
getMainExecutorFuncDecl->getAttrs().add(
693+
new (ctx)
694+
SILGenNameAttr("swift_task_getMainExecutor", /*implicit*/ true));
695+
}
696+
697+
auto fn = SGM.getFunction(
698+
SILDeclRef(getMainExecutorFuncDecl, SILDeclRef::Kind::Func),
699+
NotForDefinition);
700+
SILValue fnRef = B.createFunctionRefFor(loc, fn);
701+
return B.createApply(loc, fnRef, {}, {});
702+
}
703+
704+
SILValue SILGenFunction::emitGenericExecutor(SILLocation loc) {
705+
// The generic executor is encoded as the nil value of
706+
// Optional<Builtin.SerialExecutor>.
707+
auto ty = SILType::getOptionalType(
708+
SILType::getPrimitiveObjectType(
709+
getASTContext().TheExecutorType));
710+
return B.createOptionalNone(loc, ty);
711+
}
712+
713+
void SILGenFunction::emitPrologGlobalActorHop(SILLocation loc,
714+
Type globalActor) {
715+
ExpectedExecutor = emitLoadGlobalActorExecutor(globalActor);
716+
B.createHopToExecutor(loc, ExpectedExecutor, /*mandatory*/ false);
717+
}
718+
664719
SILValue SILGenFunction::emitLoadGlobalActorExecutor(Type globalActor) {
665720
CanType actorType = CanType(globalActor);
666721
NominalTypeDecl *nominal = actorType->getNominalOrBoundGenericNominal();
@@ -800,19 +855,8 @@ void ExecutorBreadcrumb::emit(SILGenFunction &SGF, SILLocation loc) {
800855
}
801856

802857
SILValue SILGenFunction::emitGetCurrentExecutor(SILLocation loc) {
803-
// If this is an actor method, then the actor is the only executor we should
804-
// be running on (if we aren't setting up for a cross-actor call).
805-
if (ExpectedExecutor)
806-
return ExpectedExecutor;
807-
808-
// Otherwise, we'll have to ask the current task what executor it's running
809-
// on.
810-
auto &ctx = getASTContext();
811-
return B.createBuiltin(
812-
loc,
813-
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::GetCurrentExecutor)),
814-
getLoweredType(OptionalType::get(ctx.TheExecutorType)),
815-
SubstitutionMap(), { });
858+
assert(ExpectedExecutor && "prolog failed to set up expected executor?");
859+
return ExpectedExecutor;
816860
}
817861

818862
static void emitIndirectResultParameters(SILGenFunction &SGF,

test/Concurrency/Runtime/class_resilience.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
// REQUIRES: concurrency_runtime
1616
// UNSUPPORTED: back_deployment_runtime
1717

18-
// XFAIL: windows
19-
// XFAIL: openbsd
20-
2118
import StdlibUnittest
2219
import resilient_class
2320

test/Concurrency/Runtime/protocol_resilience.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
// REQUIRES: concurrency_runtime
1616
// UNSUPPORTED: back_deployment_runtime
1717

18-
// XFAIL: windows
19-
// UNSUPPORTED: linux
20-
// UNSUPPORTED: openbsd
21-
2218
import StdlibUnittest
2319
import resilient_protocol
2420

test/Concurrency/cross_module_let_sil.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import OtherActors
77

88
// CHECK-LABEL: sil hidden [ossa] @$s4test6check1ySi11OtherActors0C11ModuleActorCYaF : $@convention(thin) @async (@guaranteed OtherModuleActor) -> Int {
99
// CHECK: bb0([[SELF:%[0-9]+]] : @guaranteed $OtherModuleActor):
10+
// CHECK: [[GENERIC_EXEC:%.*]] = enum $Optional<Builtin.Executor>, #Optional.none
11+
// CHECK-NEXT: hop_to_executor [[GENERIC_EXEC]] : $Optional<Builtin.Executor>
1012
// CHECK: [[REF:%[0-9]+]] = ref_element_addr [[SELF]] : $OtherModuleActor, #OtherModuleActor.a
11-
// CHECK: [[OLD:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
1213
// CHECK: hop_to_executor [[SELF]] : $OtherModuleActor
1314
// CHECK-NEXT: load [trivial] [[REF]]
14-
// CHECK-NEXT: hop_to_executor [[OLD]] : $Optional<Builtin.Executor>
15+
// CHECK-NEXT: hop_to_executor [[GENERIC_EXEC]] : $Optional<Builtin.Executor>
1516
// CHECK: } // end sil function '$s4test6check1ySi11OtherActors0C11ModuleActorCYaF'
1617
func check1(_ actor: OtherModuleActor) async -> Int {
1718
return await actor.a
@@ -21,20 +22,25 @@ func check2(_ actor: isolated OtherModuleActor) -> Int {
2122
return actor.a
2223
}
2324

25+
// CHECK-LABEL: sil hidden [ossa] @$s4test6check3ySi11OtherActors0C11ModuleActorCYaF : $@convention(thin) @async (@guaranteed OtherModuleActor) -> Int {
26+
// CHECK: bb0([[SELF:%[0-9]+]] : @guaranteed $OtherModuleActor):
27+
// CHECK: [[GENERIC_EXEC:%.*]] = enum $Optional<Builtin.Executor>, #Optional.none
28+
// CHECK-NEXT: hop_to_executor [[GENERIC_EXEC]] : $Optional<Builtin.Executor>
2429
func check3(_ actor: OtherModuleActor) async -> Int {
2530
return actor.b
2631
}
2732

2833
// CHECK-LABEL: sil hidden [ossa] @$s4test6check4y11OtherActors17SomeSendableClassCSgAC0C11ModuleActorCSgYaF : $@convention(thin) @async (@guaranteed Optional<OtherModuleActor>) -> @owned Optional<SomeSendableClass> {
2934
// CHECK: bb0({{%[0-9]+}} : @guaranteed $Optional<OtherModuleActor>):
35+
// CHECK: [[GENERIC_EXEC:%.*]] = enum $Optional<Builtin.Executor>, #Optional.none
36+
// CHECK-NEXT: hop_to_executor [[GENERIC_EXEC]] : $Optional<Builtin.Executor>
3037
// CHECK: switch_enum {{%[0-9]+}} : $Optional<OtherModuleActor>, case #Optional.some!enumelt: [[SOME:bb[0-9]+]], case #Optional.none!enumelt: {{bb[0-9]+}}
3138

3239
// CHECK: [[SOME]]({{%[0-9]+}} : @owned $OtherModuleActor):
3340
// CHECK: [[REF:%[0-9]+]] = ref_element_addr {{%[0-9]+}} : $OtherModuleActor, #OtherModuleActor.d
34-
// CHECK: [[OLD:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
3541
// CHECK: hop_to_executor {{%[0-9]+}} : $OtherModuleActor
3642
// CHECK-NEXT: load [copy] [[REF]]
37-
// CHECK: hop_to_executor [[OLD]] : $Optional<Builtin.Executor>
43+
// CHECK: hop_to_executor [[GENERIC_EXEC]] : $Optional<Builtin.Executor>
3844
// CHECK: } // end sil function '$s4test6check4y11OtherActors17SomeSendableClassCSgAC0C11ModuleActorCSgYaF'
3945
func check4(_ actor: OtherModuleActor?) async -> SomeSendableClass? {
4046
return await actor?.d

test/Concurrency/throwing.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
// REQUIRES: concurrency_runtime
77
// UNSUPPORTED: back_deployment_runtime
88

9-
// SR-15252
10-
// XFAIL: OS=windows-msvc
11-
129
import _Concurrency
1310
import StdlibUnittest
1411

0 commit comments

Comments
 (0)