Skip to content

Commit b6b99f6

Browse files
authored
Merge pull request #34824 from eeckstein/hop_to_executor_in_closures
[concurrency] SILGen: emit hop_to_executor instructions in actor-isolated closures.
2 parents 6722d71 + a3026a3 commit b6b99f6

File tree

3 files changed

+74
-22
lines changed

3 files changed

+74
-22
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
843843
Type resultType, DeclContext *DC,
844844
bool throws, SourceLoc throwsLoc);
845845

846+
/// Initializes 'actor' with the loaded shared instance of the \p globalActor
847+
/// type.
848+
void loadGlobalActor(Type globalActor);
849+
846850
/// Create SILArguments in the entry block that bind a single value
847851
/// of the given parameter suitably for being forwarded.
848852
void bindParameterForForwarding(ParamDecl *param,

lib/SILGen/SILGenProlog.cpp

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,9 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
454454
if (!F.isAsync())
455455
return;
456456

457+
// Initialize 'actor' if the function is an actor-isolated function or
458+
// closure.
459+
457460
if (auto *funcDecl =
458461
dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) {
459462
auto actorIsolation = getActorIsolation(funcDecl);
@@ -465,38 +468,58 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
465468
case ActorIsolation::ActorInstance: {
466469
assert(selfParam && "no self parameter for ActorInstance isolation");
467470
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
468-
ManagedValue borrowedSelf = selfArg.borrow(*this, F.getLocation());
469-
actor = borrowedSelf.getValue();
471+
actor = selfArg.borrow(*this, F.getLocation()).getValue();
470472
break;
471473
}
472-
case ActorIsolation::GlobalActor: {
473-
CanType actorType = CanType(actorIsolation.getGlobalActor());
474-
NominalTypeDecl *nominal = actorType->getNominalOrBoundGenericNominal();
475-
VarDecl *sharedInstanceDecl = nominal->getGlobalActorInstance();
476-
assert(sharedInstanceDecl && "no shared actor field in global actor");
477-
SubstitutionMap subs =
478-
actorType->getContextSubstitutionMap(SGM.SwiftModule, nominal);
479-
SILLocation loc = F.getLocation();
480-
Type instanceType =
481-
actorType->getTypeOfMember(SGM.SwiftModule, sharedInstanceDecl);
482-
483-
ManagedValue actorMetaType =
484-
ManagedValue::forUnmanaged(B.createMetatype(loc,
485-
SILType::getPrimitiveObjectType(
486-
CanMetatypeType::get(actorType, MetatypeRepresentation::Thin))));
487-
488-
RValue actorInstanceRV = emitRValueForStorageLoad(loc, actorMetaType,
489-
actorType, /*isSuper*/ false, sharedInstanceDecl, PreparedArguments(),
490-
subs, AccessSemantics::Ordinary, instanceType, SGFContext());
474+
case ActorIsolation::GlobalActor:
475+
loadGlobalActor(actorIsolation.getGlobalActor());
476+
break;
477+
}
478+
} else if (auto *closureExpr = dyn_cast<AbstractClosureExpr>(FunctionDC)) {
479+
auto actorIsolation = closureExpr->getActorIsolation();
480+
switch (actorIsolation.getKind()) {
481+
case ClosureActorIsolation::Independent:
482+
break;
483+
case ClosureActorIsolation::ActorInstance: {
484+
VarDecl *actorDecl = actorIsolation.getActorInstance();
485+
RValue actorInstanceRV = emitRValueForDecl(F.getLocation(),
486+
actorDecl, actorDecl->getType(), AccessSemantics::Ordinary);
491487
ManagedValue actorInstance = std::move(actorInstanceRV).getScalarValue();
492-
actor = actorInstance.borrow(*this, loc).getValue();
488+
actor = actorInstance.borrow(*this, F.getLocation()).getValue();
493489
break;
494490
}
491+
case ClosureActorIsolation::GlobalActor:
492+
loadGlobalActor(actorIsolation.getGlobalActor());
493+
break;
495494
}
496495
}
497496
emitHopToCurrentExecutor(F.getLocation());
498497
}
499498

499+
void SILGenFunction::loadGlobalActor(Type globalActor) {
500+
assert(F.isAsync());
501+
CanType actorType = CanType(globalActor);
502+
NominalTypeDecl *nominal = actorType->getNominalOrBoundGenericNominal();
503+
VarDecl *sharedInstanceDecl = nominal->getGlobalActorInstance();
504+
assert(sharedInstanceDecl && "no shared actor field in global actor");
505+
SubstitutionMap subs =
506+
actorType->getContextSubstitutionMap(SGM.SwiftModule, nominal);
507+
SILLocation loc = F.getLocation();
508+
Type instanceType =
509+
actorType->getTypeOfMember(SGM.SwiftModule, sharedInstanceDecl);
510+
511+
ManagedValue actorMetaType =
512+
ManagedValue::forUnmanaged(B.createMetatype(loc,
513+
SILType::getPrimitiveObjectType(
514+
CanMetatypeType::get(actorType, MetatypeRepresentation::Thin))));
515+
516+
RValue actorInstanceRV = emitRValueForStorageLoad(loc, actorMetaType,
517+
actorType, /*isSuper*/ false, sharedInstanceDecl, PreparedArguments(),
518+
subs, AccessSemantics::Ordinary, instanceType, SGFContext());
519+
ManagedValue actorInstance = std::move(actorInstanceRV).getScalarValue();
520+
actor = actorInstance.borrow(*this, loc).getValue();
521+
}
522+
500523
static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType,
501524
DeclContext *DC) {
502525
// Expand tuples.

test/SILGen/hop_to_executor.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ actor class MyActor {
4747
await callee(p)
4848
}
4949

50+
51+
// CHECK-LABEL: sil private [ossa] @$s4test7MyActorC0A7ClosureSiyYFSiyYXEfU_ : $@convention(thin) @async (@guaranteed MyActor) -> Int {
52+
// CHECK: [[COPIED_SELF:%[0-9]+]] = copy_value %0 : $MyActor
53+
// CHECK: [[BORROWED_SELF:%[0-9]+]] = begin_borrow [[COPIED_SELF]] : $MyActor
54+
// CHECK: hop_to_executor [[BORROWED_SELF]] : $MyActor
55+
// CHECK: = apply
56+
// CHECK: } // end sil function '$s4test7MyActorC0A7ClosureSiyYFSiyYXEfU_'
57+
func testClosure() async -> Int {
58+
return await { () async in p }()
59+
}
60+
5061
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC13dontInsertHTESiyF : $@convention(method) (@guaranteed MyActor) -> Int {
5162
// CHECK-NOT: hop_to_executor
5263
// CHECK: } // end sil function '$s4test7MyActorC13dontInsertHTESiyF'
@@ -77,6 +88,20 @@ struct GlobalActor {
7788
func testGlobalActor() async {
7889
}
7990

91+
// CHECK-LABEL: sil private [ossa] @$s4test0A22GlobalActorWithClosureyyYFyyYXEfU_ : $@convention(thin) @async () -> () {
92+
// CHECK: [[F:%[0-9]+]] = function_ref @$s4test11GlobalActorV6sharedAA02MyC0Cvau : $@convention(thin) () -> Builtin.RawPointer
93+
// CHECK: [[P:%[0-9]+]] = apply [[F]]() : $@convention(thin) () -> Builtin.RawPointer
94+
// CHECK: [[A:%[0-9]+]] = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*MyActor
95+
// CHECK: [[ACC:%[0-9]+]] = begin_access [read] [dynamic] [[A]] : $*MyActor
96+
// CHECK: [[L:%[0-9]+]] = load [copy] [[ACC]] : $*MyActor
97+
// CHECK: [[B:%[0-9]+]] = begin_borrow [[L]] : $MyActor
98+
// CHECK: hop_to_executor [[B]] : $MyActor
99+
// CHECK: } // end sil function '$s4test0A22GlobalActorWithClosureyyYFyyYXEfU_'
100+
@GlobalActor
101+
func testGlobalActorWithClosure() async {
102+
await { () async in }()
103+
}
104+
80105
@globalActor
81106
struct GenericGlobalActorWithGetter<T> {
82107
static var shared: MyActor { return MyActor() }

0 commit comments

Comments
 (0)