Skip to content

Commit b7d5e0a

Browse files
committed
invoke resignIdentity in an async failable initializer
For distributed actors, their async initializers will call actorReady prior to the end of the initializer. If that happens, we need to resign the identity if we end up in the failure path of the init.
1 parent 8d3c9b0 commit b7d5e0a

File tree

4 files changed

+99
-65
lines changed

4 files changed

+99
-65
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -822,8 +822,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
822822
// For an async distributed actor init, we must `resignIdentity` before
823823
// the clean-ups are triggered in this failure block.
824824
if (isDesignatedDistActorInit && ctor->hasAsync()) {
825-
// TODO: refactor emitDistributedActor_resignAddress so we can call it
826-
// within this initializer.
825+
emitResignIdentityCall(loc, selfClassDecl, selfArg);
827826
}
828827

829828
Cleanups.emitCleanupsForReturn(ctor, IsForUnwind);
@@ -880,7 +879,8 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
880879
// For distributed actors, their synchronous initializers invoke "actor ready"
881880
// at the very end, just before returning on a successful initialization.
882881
// There is no need for injecting `resignIdentity` calls in such inits,
883-
// because we can never call `actorReady` prematurely.
882+
// even if they are failable or throwing, because we will never call
883+
// `actorReady` at a point before the init can exit abnormally.
884884
if (isDesignatedDistActorInit && !ctor->hasAsync()) {
885885
RegularLocation loc(ctor);
886886
loc.markAutoGenerated();

lib/SILGen/SILGenDestructor.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,14 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
8181
/// and can remove it from its (weak) lookup tables.
8282
if (cd->isDistributedActor()) {
8383
SILBasicBlock *continueBB = createBasicBlock();
84-
emitDistributedActor_resignIdentity(dd, selfValue, continueBB);
84+
85+
RegularLocation loc(dd);
86+
if (dd->isImplicit())
87+
loc.markAutoGenerated();
88+
89+
// FIXME: what should the type of management be for this?
90+
auto managedSelf = ManagedValue::forBorrowedRValue(selfValue);
91+
emitConditionalResignIdentityCall(loc, cd, managedSelf, continueBB);
8592
B.emitBlock(continueBB);
8693
}
8794

lib/SILGen/SILGenDistributed.cpp

Lines changed: 63 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -636,45 +636,73 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
636636
}
637637
}
638638

639-
/******************************************************************************/
640-
/******************* DISTRIBUTED DEINIT: resignIdentity ***********************/
641-
/******************************************************************************/
639+
// MARK: transport.resignIdentity()
642640

643-
void SILGenFunction::emitDistributedActor_resignIdentity(
644-
DestructorDecl *dd, SILValue selfValue, SILBasicBlock *continueBB) {
641+
void SILGenFunction::emitResignIdentityCall(SILLocation loc,
642+
ClassDecl *actorDecl,
643+
ManagedValue actorSelf) {
645644
ASTContext &ctx = getASTContext();
646-
647-
auto cd = cast<ClassDecl>(dd->getDeclContext());
648-
assert(cd->isDistributedActor() &&
649-
"only distributed actors have transport lifecycle hooks in deinit");
650-
651-
RegularLocation Loc(dd);
652-
if (dd->isImplicit())
653-
Loc.markAutoGenerated();
654-
655-
auto selfDecl = dd->getImplicitSelfDecl();
656-
auto selfManagedValue = ManagedValue::forUnmanaged(selfValue);
657-
auto selfTy = selfDecl->getType();
658-
645+
646+
FormalEvaluationScope scope(*this);
647+
659648
// ==== locate: self.id
660-
auto *idVarDeclRef = lookupProperty(cd, ctx.Id_id);
649+
auto *idVarDeclRef = lookupProperty(actorDecl, ctx.Id_id);
661650
auto idRef =
662-
B.createRefElementAddr(Loc, selfValue, idVarDeclRef,
663-
getLoweredType(idVarDeclRef->getType()));
664-
651+
B.createRefElementAddr(loc, actorSelf, idVarDeclRef,
652+
getLoweredType(idVarDeclRef->getType()));
653+
665654
// ==== locate: self.actorTransport
666-
auto transportVarDeclRef = lookupProperty(cd, ctx.Id_actorTransport);
655+
auto transportVarDeclRef = lookupProperty(actorDecl, ctx.Id_actorTransport);
667656
auto transportRef =
668-
B.createRefElementAddr(Loc, selfValue, transportVarDeclRef,
669-
getLoweredType(transportVarDeclRef->getType()));
670-
671-
// locate: self.transport.resignIdentity(...)
657+
B.createRefElementAddr(loc, actorSelf, transportVarDeclRef,
658+
getLoweredType(transportVarDeclRef->getType()));
659+
660+
// ==== locate: self.transport.resignIdentity(...)
672661
auto *transportDecl = ctx.getActorTransportDecl();
673662
auto resignFnDecls = transportDecl->lookupDirect(ctx.Id_resignIdentity);
674663
assert(resignFnDecls.size() == 1);
675664
auto *resignFnDecl = resignFnDecls.front();
676665
auto resignFnRef = SILDeclRef(resignFnDecl);
666+
667+
// ==== perform the call
668+
auto openedTransport =
669+
OpenedArchetypeType::get(transportVarDeclRef->getType());
670+
auto transportAddr =
671+
B.createOpenExistentialAddr(loc, /*operand=*/transportRef.getValue(),
672+
getLoweredType(openedTransport),
673+
OpenedExistentialAccess::Immutable);
674+
675+
auto resignFnType =
676+
SGM.M.Types.getConstantFunctionType(TypeExpansionContext::minimal(),
677+
resignFnRef);
678+
679+
auto conformance = ProtocolConformanceRef(transportDecl);
680+
auto witness =
681+
B.createWitnessMethod(loc, openedTransport,
682+
conformance, resignFnRef,
683+
SILType::getPrimitiveObjectType(resignFnType));
684+
685+
auto subs = SubstitutionMap::getProtocolSubstitutions(transportDecl,
686+
openedTransport,
687+
conformance);
688+
689+
SmallVector<SILValue, 2> params;
690+
params.push_back(idRef.getValue());
691+
params.push_back(transportAddr); // self for the call, as last param
692+
693+
B.createApply(loc, witness, subs, params);
694+
}
695+
696+
void
697+
SILGenFunction::emitConditionalResignIdentityCall(SILLocation loc,
698+
ClassDecl *actorDecl,
699+
ManagedValue actorSelf,
700+
SILBasicBlock *continueBB) {
701+
assert(actorDecl->isDistributedActor() &&
702+
"only distributed actors have transport lifecycle hooks in deinit");
677703

704+
auto selfTy = actorDecl->getDeclaredInterfaceType();
705+
678706
// we only transport.resignIdentity if we are a local actor,
679707
// and thus the address was created by transport.assignIdentity.
680708
auto isRemoteBB = createBasicBlock();
@@ -685,46 +713,24 @@ void SILGenFunction::emitDistributedActor_resignIdentity(
685713
// } else {
686714
// ...
687715
// }
688-
emitDistributedIfRemoteBranch(*this, Loc,
689-
selfManagedValue, selfTy,
716+
emitDistributedIfRemoteBranch(*this, loc,
717+
actorSelf, selfTy,
690718
/*if remote*/isRemoteBB,
691719
/*if local*/isLocalBB);
692720

693-
// if remote
694-
// === <noop>
721+
// if remote, do nothing.
695722
{
696723
B.emitBlock(isRemoteBB);
697-
// noop, remote actors don't do anything in their deinit
698-
B.createBranch(Loc, continueBB);
724+
B.createBranch(loc, continueBB);
699725
}
700726

701-
// if local
702-
// === self.transport.resignIdentity(self.address)
727+
// if local, resign identity.
703728
{
704729
B.emitBlock(isLocalBB);
705730

706-
auto openedTransport =
707-
OpenedArchetypeType::get(transportVarDeclRef->getType());
708-
auto transportAddr = B.createOpenExistentialAddr(
709-
Loc, /*operand=*/transportRef, getLoweredType(openedTransport),
710-
OpenedExistentialAccess::Immutable);
711-
712-
auto resignFnType = SGM.M.Types.getConstantFunctionType(
713-
TypeExpansionContext::minimal(), resignFnRef);
714-
715-
auto witness = B.createWitnessMethod(
716-
Loc, openedTransport, ProtocolConformanceRef(transportDecl),
717-
resignFnRef, SILType::getPrimitiveObjectType(resignFnType));
718-
719-
auto subs = SubstitutionMap::getProtocolSubstitutions(
720-
transportDecl, openedTransport, ProtocolConformanceRef(transportDecl));
721-
722-
SmallVector<SILValue, 2> params;
723-
params.push_back(idRef);
724-
params.push_back(transportAddr); // self for the call, as last param
725-
726-
B.createApply(Loc, witness, subs, params);
727-
B.createBranch(Loc, continueBB);
731+
emitResignIdentityCall(loc, actorDecl, actorSelf);
732+
733+
B.createBranch(loc, continueBB);
728734
}
729735
}
730736

lib/SILGen/SILGenFunction.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,10 +2021,31 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
20212021
/// and is ready to receive messages.
20222022
void emitDistributedActorReady(
20232023
SILLocation loc, ConstructorDecl *ctor, ManagedValue actorSelf);
2024-
2025-
/// Inject distributed actor and transport interaction code into the destructor.
2026-
void emitDistributedActor_resignIdentity(
2027-
DestructorDecl *dd, SILValue selfValue, SILBasicBlock *continueBB);
2024+
2025+
/// For a distributed actor, emits code to invoke the transport's
2026+
/// resignIdentity function.
2027+
///
2028+
/// Specifically, this code emits SIL that performs the call
2029+
///
2030+
/// \verbatim
2031+
/// self.transport.resignIdentity(self.id)
2032+
/// \endverbatim
2033+
///
2034+
/// using the current builder's state as the injection point.
2035+
///
2036+
/// \param actorDecl the declaration corresponding to the actor
2037+
/// \param actorSelf the SIL value representing the distributed actor instance
2038+
void emitResignIdentityCall(SILLocation loc,
2039+
ClassDecl *actorDecl, ManagedValue actorSelf);
2040+
2041+
/// Emit code that tests whether the distributed actor is local, and if so,
2042+
/// resigns the distributed actor's identity.
2043+
/// \param continueBB the target block where execution will continue after
2044+
/// the conditional call, whether actor is local or remote.
2045+
void emitConditionalResignIdentityCall(SILLocation loc,
2046+
ClassDecl *actorDecl,
2047+
ManagedValue actorSelf,
2048+
SILBasicBlock *continueBB);
20282049

20292050
void emitDistributedActorClassMemberDestruction(
20302051
SILLocation cleanupLoc, ManagedValue selfValue, ClassDecl *cd,

0 commit comments

Comments
 (0)