@@ -31,15 +31,60 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
3131 Loc.markAutoGenerated ();
3232
3333 auto cd = cast<ClassDecl>(dd->getDeclContext ());
34+ auto &C = cd->getASTContext ();
3435 SILValue selfValue = emitSelfDecl (dd->getImplicitSelfDecl ());
3536
3637 // Create a basic block to jump to for the implicit destruction behavior
3738 // of releasing the elements and calling the superclass destructor.
3839 // We won't actually emit the block until we finish with the destructor body.
3940 prepareEpilog (None, false , CleanupLocation (Loc));
4041
42+ auto cleanupLoc = CleanupLocation (Loc);
43+
44+ SILBasicBlock *deinitBodyBB = nullptr ;
45+ SILBasicBlock *finishBB = nullptr ;
46+ if (cd->isDistributedActor ()) {
47+ auto remoteBB = createBasicBlock (" remoteActorDeinitBB" );
48+ finishBB = createBasicBlock (" finishDeinitBB" );
49+ deinitBodyBB = createBasicBlock (" deinitBodyBB" );
50+
51+ // FIXME: what should the type of management be for this?
52+ auto managedSelf = ManagedValue::forBorrowedRValue (selfValue);
53+
54+ auto selfTy = F.mapTypeIntoContext (cd->getDeclaredInterfaceType ());
55+ emitDistributedIfRemoteBranch (
56+ SILLocation (Loc),
57+ managedSelf, selfTy,
58+ /* if remote=*/ remoteBB,
59+ /* if local=*/ deinitBodyBB);
60+
61+ {
62+ B.emitBlock (remoteBB);
63+
64+ // Note that we do NOT execute user-declared the deinit body.
65+ // They would be free to access state which does not exist in a remote DA
66+
67+ // we are a remote instance,
68+ // the only properties we can destroy are the id and system properties.
69+ for (VarDecl *vd : cd->getStoredProperties ()) {
70+ if (getActorIsolation (vd) == ActorIsolation::ActorInstance)
71+ continue ;
72+
73+ // Just to double-check, we only want to destroy `id` and `actorSystem`
74+ if (vd->getBaseIdentifier () == C.Id_id ||
75+ vd->getBaseIdentifier () == C.Id_actorSystem ) {
76+ destroyClassMember (cleanupLoc, managedSelf, vd);
77+ }
78+ }
79+
80+ B.createBranch (SILLocation (Loc), finishBB);
81+ }
82+ }
83+
4184 emitProfilerIncrement (dd->getTypecheckedBody ());
4285 // Emit the destructor body.
86+ if (deinitBodyBB)
87+ B.emitBlock (deinitBodyBB);
4388 emitStmt (dd->getTypecheckedBody ());
4489
4590 Optional<SILValue> maybeReturnValue;
@@ -49,8 +94,6 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
4994 if (!maybeReturnValue)
5095 return ;
5196
52- auto cleanupLoc = CleanupLocation (Loc);
53-
5497 // If we have a superclass, invoke its destructor.
5598 SILValue resultSelfValue;
5699 SILType objectPtrTy = SILType::getNativeObjectType (F.getASTContext ());
@@ -78,22 +121,6 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
78121 resultSelfValue = selfValue;
79122 }
80123
81- // / A distributed actor resigns its identity as it is deallocated.
82- // / This way the transport knows it must not deliver any more messages to it,
83- // / and can remove it from its (weak) lookup tables.
84- if (cd->isDistributedActor ()) {
85- SILBasicBlock *continueBB = createBasicBlock ();
86-
87- RegularLocation loc (dd);
88- if (dd->isImplicit ())
89- loc.markAutoGenerated ();
90-
91- // FIXME: what should the type of management be for this?
92- auto managedSelf = ManagedValue::forBorrowedRValue (selfValue);
93- emitConditionalResignIdentityCall (loc, cd, managedSelf, continueBB);
94- B.emitBlock (continueBB);
95- }
96-
97124 ArgumentScope S (*this , Loc);
98125 ManagedValue borrowedValue =
99126 ManagedValue::forUnmanaged (resultSelfValue).borrow (*this , cleanupLoc);
@@ -103,8 +130,18 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
103130 B.createUncheckedRefCast (cleanupLoc, borrowedValue, classTy);
104131 }
105132
133+ // A distributed actor must invoke `actorSystem.resignID` as it deinits.
134+ if (cd->isDistributedActor ()) {
135+ // This must only be called by a *local* distributed actor (not a remote proxy).
136+ // Since this call is emitted after the user-declared body of the deinit,
137+ // just before returning; this is guaranteed to only be executed in the local
138+ // actor case - because the body is never executed for a remote proxy either.
139+ emitDistributedActorSystemResignIDCall (
140+ cleanupLoc, cd, ManagedValue::forBorrowedRValue (selfValue));
141+ }
142+
106143 // Release our members.
107- emitClassMemberDestruction (borrowedValue, cd, cleanupLoc);
144+ emitClassMemberDestruction (borrowedValue, cd, cleanupLoc, finishBB );
108145
109146 S.pop ();
110147
@@ -199,7 +236,7 @@ void SILGenFunction::emitIVarDestroyer(SILDeclRef ivarDestroyer) {
199236 cleanupLoc, selfValue.forward (*this ), OwnershipKind::Guaranteed);
200237 selfValue = emitManagedBorrowedRValueWithCleanup (guaranteedSelf);
201238 }
202- emitClassMemberDestruction (selfValue, cd, cleanupLoc);
239+ emitClassMemberDestruction (selfValue, cd, cleanupLoc, /* finishBB= */ nullptr );
203240 }
204241
205242 B.createReturn (loc, emitEmptyTuple (loc));
@@ -359,32 +396,10 @@ void SILGenFunction::emitRecursiveChainDestruction(ManagedValue selfValue,
359396
360397void SILGenFunction::emitClassMemberDestruction (ManagedValue selfValue,
361398 ClassDecl *cd,
362- CleanupLocation cleanupLoc) {
399+ CleanupLocation cleanupLoc,
400+ SILBasicBlock *finishBB) {
363401 assert (selfValue.getOwnershipKind () == OwnershipKind::Guaranteed);
364402
365- // / If this ClassDecl is a distributed actor, we must synthesise another code
366- // / path for deallocating a 'remote' actor. In that case, these basic blocks
367- // / are used to return to the "normal" (i.e. 'local' instance) destruction.
368- // /
369- // / For other cases, the basic blocks are not necessary and the destructor
370- // / can just emit all the normal destruction code right into the current block.
371- // If set, used as the basic block for the destroying of all members.
372- SILBasicBlock *normalMemberDestroyBB = nullptr ;
373- // If set, used as the basic block after members have been destroyed,
374- // and we're ready to perform final cleanups before returning.
375- SILBasicBlock *finishBB = nullptr ;
376-
377- // / A distributed actor may be 'remote' in which case there is no need to
378- // / destroy "all" members, because they never had storage to begin with.
379- if (cd->isDistributedActor ()) {
380- finishBB = createBasicBlock ();
381- normalMemberDestroyBB = createBasicBlock ();
382-
383- emitDistributedActorClassMemberDestruction (cleanupLoc, selfValue, cd,
384- normalMemberDestroyBB,
385- finishBB);
386- }
387-
388403 // Before we destroy all fields, we check if any of them are
389404 // recursively the same type as `self`, so we can iteratively
390405 // deinitialize them, to prevent deep recursion and potential
@@ -395,9 +410,6 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
395410
396411 // / Destroy all members.
397412 {
398- if (normalMemberDestroyBB)
399- B.emitBlock (normalMemberDestroyBB);
400-
401413 for (VarDecl *vd : cd->getStoredProperties ()) {
402414 if (recursiveLinks.contains (vd))
403415 continue ;
0 commit comments