Skip to content

Commit 11fbdaa

Browse files
authored
Merge pull request #38129 from ktoso/wip-resignaddress-on-deinit
2 parents 16f45ea + 04a2dd9 commit 11fbdaa

File tree

11 files changed

+380
-14
lines changed

11 files changed

+380
-14
lines changed

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ IDENTIFIER(actorTransport)
255255
IDENTIFIER(actorType)
256256
IDENTIFIER(actorReady)
257257
IDENTIFIER(assignAddress)
258+
IDENTIFIER(resignAddress)
258259
IDENTIFIER(resolve)
259260
IDENTIFIER(address)
260261
IDENTIFIER(actorAddress)

include/swift/AST/KnownProtocols.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, "_" #name)
6060

6161
PROTOCOL(Actor)
62-
PROTOCOL(DistributedActor)
6362
PROTOCOL(Sequence)
6463
PROTOCOL(IteratorProtocol)
6564
PROTOCOL(RawRepresentable)
@@ -95,6 +94,10 @@ PROTOCOL(StringInterpolationProtocol)
9594
PROTOCOL(AdditiveArithmetic)
9695
PROTOCOL(Differentiable)
9796

97+
// Distributed Actors
98+
PROTOCOL(DistributedActor)
99+
PROTOCOL(ActorTransport)
100+
98101
PROTOCOL(AsyncSequence)
99102
PROTOCOL(AsyncIteratorProtocol)
100103

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,7 @@ NominalTypeDecl::lookupDirectRemoteFunc(AbstractFunctionDecl *func) {
14141414
auto remoteFuncId = C.getIdentifier("_remote_" + localFuncName);
14151415

14161416
auto remoteFuncDecls = selfTyDecl->lookupDirect(DeclName(remoteFuncId));
1417+
14171418
if (remoteFuncDecls.empty())
14181419
return nullptr;
14191420

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5165,6 +5165,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
51655165
case KnownProtocolKind::Differentiable:
51665166
case KnownProtocolKind::FloatingPoint:
51675167
case KnownProtocolKind::Actor:
5168+
case KnownProtocolKind::ActorTransport:
51685169
case KnownProtocolKind::DistributedActor:
51695170
case KnownProtocolKind::SerialExecutor:
51705171
case KnownProtocolKind::Sendable:

lib/SILGen/SILGenBridging.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,7 +2045,8 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
20452045
B.createCondBranch(loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
20462046
}
20472047

2048-
// if __isRemoteActor(self) {
2048+
// // if __isRemoteActor(self)
2049+
// {
20492050
// return try await self._remote_X(...)
20502051
// }
20512052
{
@@ -2054,9 +2055,6 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
20542055
auto *selfTyDecl = FunctionDC->getParent()->getSelfNominalTypeDecl();
20552056
assert(selfTyDecl && "distributed function declared outside of actor");
20562057

2057-
// auto selfMetatype = getLoweredType(selfTyDecl->getInterfaceType());
2058-
// SILValue metatypeValue = B.createMetatype(loc, selfMetatype);
2059-
20602058
auto remoteFnDecl = selfTyDecl->lookupDirectRemoteFunc(fd);
20612059
assert(remoteFnDecl && "Could not find _remote_<dist_func_name> function");
20622060
auto remoteFnRef = SILDeclRef(remoteFnDecl);
@@ -2068,13 +2066,12 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
20682066
auto subs = F.getForwardingSubstitutionMap();
20692067

20702068
SmallVector<SILValue, 8> remoteParams(params);
2071-
// remoteParams.emplace_back(metatypeValue);
20722069

2073-
// B.createTryApply(loc, remoteFn, subs, params, remoteReturnBB, remoteErrorBB);
20742070
B.createTryApply(loc, remoteFn, subs, remoteParams, remoteReturnBB, remoteErrorBB);
20752071
}
20762072

2077-
// else {
2073+
// // else
2074+
// {
20782075
// return (try)? (await)? self.X(...)
20792076
// }
20802077
{

lib/SILGen/SILGenDestructor.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SILGenFunction.h"
14+
#include "SILGenFunctionBuilder.h"
1415
#include "RValue.h"
1516
#include "ArgumentScope.h"
1617
#include "swift/AST/GenericSignature.h"
@@ -75,6 +76,13 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
7576
resultSelfValue = selfValue;
7677
}
7778

79+
80+
if (cd->isDistributedActor()) {
81+
SILBasicBlock *continueBB = createBasicBlock();
82+
injectDistributedActorDestructorLifecycleCall(dd, selfValue, continueBB);
83+
B.emitBlock(continueBB);
84+
}
85+
7886
ArgumentScope S(*this, Loc);
7987
ManagedValue borrowedValue =
8088
ManagedValue::forUnmanaged(resultSelfValue).borrow(*this, cleanupLoc);
@@ -101,6 +109,113 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
101109
B.createReturn(returnLoc, resultSelfValue);
102110
}
103111

112+
void SILGenFunction::injectDistributedActorDestructorLifecycleCall(
113+
DestructorDecl *dd, SILValue selfValue, SILBasicBlock *continueBB) {
114+
ASTContext &ctx = getASTContext();
115+
116+
auto cd = cast<ClassDecl>(dd->getDeclContext());
117+
assert(cd->isDistributedActor() &&
118+
"only distributed actors have transport lifecycle hooks in deinit");
119+
120+
RegularLocation Loc(dd);
121+
if (dd->isImplicit())
122+
Loc.markAutoGenerated();
123+
124+
auto selfDecl = dd->getImplicitSelfDecl();
125+
auto selfManagedValue = ManagedValue::forUnmanaged(selfValue);
126+
auto selfType = selfDecl->getType();
127+
128+
// ==== locate: self.actorAddress
129+
auto addressVarDeclRefs = cd->lookupDirect(ctx.Id_actorAddress);
130+
assert(addressVarDeclRefs.size() == 1);
131+
auto *addressVarDeclRef = dyn_cast<VarDecl>(addressVarDeclRefs.front());
132+
assert(addressVarDeclRef);
133+
auto addressRef =
134+
B.createRefElementAddr(Loc, selfValue, addressVarDeclRef,
135+
getLoweredType(addressVarDeclRef->getType()));
136+
137+
// ==== locate: self.actorTransport
138+
auto transportVarDeclRefs = cd->lookupDirect(ctx.Id_actorTransport);
139+
assert(transportVarDeclRefs.size() == 1);
140+
auto *transportVarDeclRef = dyn_cast<VarDecl>(transportVarDeclRefs.front());
141+
auto transportRef =
142+
B.createRefElementAddr(Loc, selfValue, transportVarDeclRef,
143+
getLoweredType(transportVarDeclRef->getType()));
144+
145+
// locate: self.transport.resignAddress(...)
146+
auto *transportDecl = ctx.getActorTransportDecl();
147+
auto resignFnDecls = transportDecl->lookupDirect(ctx.Id_resignAddress);
148+
assert(resignFnDecls.size() == 1);
149+
auto *resignFnDecl = resignFnDecls.front();
150+
auto resignFnRef = SILDeclRef(resignFnDecl);
151+
152+
// we only transport.resignAddress if we are a local actor,
153+
// and thus the address was created by transport.assignAddress.
154+
auto isRemoteBB = createBasicBlock();
155+
auto isLocalBB = createBasicBlock();
156+
157+
// if __isRemoteActor(self) {
158+
// ...
159+
// } else {
160+
// ...
161+
// }
162+
{
163+
FuncDecl *isRemoteFn = ctx.getIsRemoteDistributedActor();
164+
assert(isRemoteFn && "Could not find 'is remote' function, is the "
165+
"'_Distributed' module available?");
166+
167+
ManagedValue selfAnyObject =
168+
B.createInitExistentialRef(Loc, getLoweredType(ctx.getAnyObjectType()),
169+
CanType(selfType), selfManagedValue, {});
170+
auto result = emitApplyOfLibraryIntrinsic(
171+
Loc, isRemoteFn, SubstitutionMap(), {selfAnyObject}, SGFContext());
172+
173+
SILValue isRemoteResult =
174+
std::move(result).forwardAsSingleValue(*this, Loc);
175+
SILValue isRemoteResultUnwrapped =
176+
emitUnwrapIntegerResult(Loc, isRemoteResult);
177+
178+
B.createCondBranch(Loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
179+
}
180+
181+
// if remote
182+
// === <noop>
183+
{
184+
B.emitBlock(isRemoteBB);
185+
// noop, remote actors don't do anything in their deinit
186+
B.createBranch(Loc, continueBB);
187+
}
188+
189+
// if local
190+
// === self.transport.resignAddress(self.address)
191+
{
192+
B.emitBlock(isLocalBB);
193+
194+
auto openedTransport =
195+
OpenedArchetypeType::get(transportVarDeclRef->getType());
196+
auto transportAddr = B.createOpenExistentialAddr(
197+
Loc, /*operand=*/transportRef, getLoweredType(openedTransport),
198+
OpenedExistentialAccess::Immutable);
199+
200+
auto resignFnType = SGM.M.Types.getConstantFunctionType(
201+
TypeExpansionContext::minimal(), resignFnRef);
202+
203+
auto witness = B.createWitnessMethod(
204+
Loc, openedTransport, ProtocolConformanceRef(transportDecl),
205+
resignFnRef, SILType::getPrimitiveObjectType(resignFnType));
206+
207+
auto subs = SubstitutionMap::getProtocolSubstitutions(
208+
transportDecl, openedTransport, ProtocolConformanceRef(transportDecl));
209+
210+
SmallVector<SILValue, 2> params;
211+
params.push_back(addressRef);
212+
params.push_back(transportAddr); // self for the call, as last param
213+
214+
B.createApply(Loc, witness, subs, params);
215+
B.createBranch(Loc, continueBB);
216+
}
217+
}
218+
104219
void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
105220
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));
106221

lib/SILGen/SILGenFunction.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,10 +614,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
614614
/// Emits code for a ClosureExpr.
615615
void emitClosure(AbstractClosureExpr *ce);
616616
/// Generates code for a class destroying destructor. This
617-
/// emits the body code from the DestructorDecl, calls the base class
617+
/// emits the body code from the DestructorDecl, calls the base class
618618
/// destructor, then implicitly releases the elements of the class.
619619
void emitDestroyingDestructor(DestructorDecl *dd);
620620

621+
/// Inject distributed actor and transport interaction code into the destructor.
622+
void injectDistributedActorDestructorLifecycleCall(
623+
DestructorDecl *dd, SILValue selfValue, SILBasicBlock *continueBB);
624+
621625
/// Generates code for an artificial top-level function that starts an
622626
/// application based on a main type and optionally a main type.
623627
void emitArtificialTopLevel(Decl *mainDecl);

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ createDistributedActor_init_local(ClassDecl *classDecl,
251251
/// \param initDecl The function decl whose body to synthesize.
252252
static std::pair<BraceStmt *, bool>
253253
createDistributedActor_init_resolve_body(AbstractFunctionDecl *initDecl, void *) {
254-
255254
auto *funcDC = cast<DeclContext>(initDecl);
256255
auto &C = funcDC->getASTContext();
257256

@@ -285,8 +284,8 @@ createDistributedActor_init_resolve_body(AbstractFunctionDecl *initDecl, void *)
285284
statements.push_back(assignAddressExpr);
286285
// end-of-FIXME: this must be checking with the transport instead
287286

288-
auto *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
289-
/*implicit=*/true);
287+
BraceStmt *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
288+
/*implicit=*/true);
290289

291290
return { body, /*isTypeChecked=*/false };
292291
}
@@ -302,7 +301,6 @@ static ConstructorDecl *
302301
createDistributedActor_init_resolve(ClassDecl *classDecl,
303302
ASTContext &ctx) {
304303
auto &C = ctx;
305-
306304
auto conformanceDC = classDecl;
307305

308306
// Expected type: (Self) -> (ActorAddress, ActorTransport) -> (Self)
@@ -458,6 +456,81 @@ static void addImplicitDistributedActorConstructors(ClassDecl *decl) {
458456
}
459457
}
460458

459+
/******************************************************************************/
460+
/******************************** DEINIT **************************************/
461+
/******************************************************************************/
462+
463+
/// A distributed actor's deinit MUST call `transport.resignAddress` before it
464+
/// is deallocated.
465+
static void addImplicitResignAddress(ClassDecl *decl) {
466+
auto &C = decl->getASTContext();
467+
468+
DestructorDecl *existingDeinit = decl->getDestructor();
469+
assert(existingDeinit);
470+
471+
// DestructorDecl *deinitDecl = existingDeinit != nullptr ? existingDeinit :
472+
// new (C) DestructorDecl(SourceLoc(), decl);
473+
DestructorDecl *deinitDecl = new (C) DestructorDecl(SourceLoc(), decl);
474+
475+
BraceStmt *body = deinitDecl->getBody();
476+
477+
// == Copy all existing statements to the new deinit
478+
SmallVector<ASTNode, 2> statements; // TODO: how to init at body statements count size?
479+
for (auto stmt : body->getElements())
480+
statements.push_back(stmt); // TODO: copy?
481+
482+
// TODO: INJECT THIS AS FIRST THING IN A DEFER {}
483+
484+
// == Inject the lifecycle 'resignAddress' interaction
485+
// ==== self
486+
auto *selfRef = DerivedConformance::createSelfDeclRef(deinitDecl);
487+
488+
// ==== `self.actorTransport`
489+
auto *varTransportExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
490+
C.Id_actorTransport);
491+
492+
// ==== `self.actorAddress`
493+
auto *varAddressExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
494+
C.Id_actorAddress);
495+
// auto addressRef = new (C) DeclRefExpr(varAddressExpr, DeclNameLoc(),
496+
// /*implicit*/ true);
497+
// auto addressRef = new (C) DeclRefExpr(ConcreteDeclRef(varAddressExpr), DeclNameLoc(),
498+
// /*implicit=*/true);
499+
// addressRef->setType(varAddressExpr->getType());
500+
501+
// ==== `self.transport.resignAddress(self.actorAddress)`
502+
auto loc = deinitDecl->getLoc();
503+
// auto resignAddressRef = new (C) DeclRefExpr(varTransportExpr, DeclNameLoc(),
504+
// /*implicit=*/true);
505+
// resignAddressRef->setThrows(false);
506+
auto resignFuncDecls = C.getActorTransportDecl()->lookupDirect(C.Id_resignAddress);
507+
assert(resignFuncDecls.size() == 1);
508+
AbstractFunctionDecl *resignFuncDecl = dyn_cast<AbstractFunctionDecl>(resignFuncDecls.front());
509+
auto resignFuncRef = new (C) DeclRefExpr(resignFuncDecl, DeclNameLoc(), /*implicit=*/true);
510+
511+
auto *addressParam = new (C) ParamDecl(
512+
SourceLoc(), SourceLoc(), Identifier(),
513+
SourceLoc(), C.Id_address, decl);
514+
addressParam->setInterfaceType(C.getActorAddressDecl()->getInterfaceType());
515+
addressParam->setSpecifier(ParamSpecifier::Default);
516+
addressParam->setImplicit();
517+
auto *paramList = ParameterList::createWithoutLoc(addressParam);
518+
519+
auto *resignFuncRefRef = UnresolvedDotExpr::createImplicit(
520+
C, varTransportExpr, C.Id_resignAddress, paramList);
521+
522+
Expr *resignAddressCall = CallExpr::createImplicit(C, resignFuncRefRef,
523+
{ varAddressExpr },
524+
{ Identifier() });
525+
statements.push_back(resignAddressCall);
526+
527+
BraceStmt *newBody = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
528+
/*implicit=*/true);
529+
530+
newBody->dump();
531+
deinitDecl->setBody(newBody, AbstractFunctionDecl::BodyKind::TypeChecked); // FIXME: no idea if Parsed is right, we are NOT type checked I guess?
532+
}
533+
461534
/******************************************************************************/
462535
/******************************** PROPERTIES **********************************/
463536
/******************************************************************************/
@@ -570,7 +643,7 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
570643
auto uintInit = ctx.getIntBuiltinInitDecl(uintDecl);
571644

572645
auto missingTransportDecl = ctx.getMissingDistributedActorTransport();
573-
assert(missingTransportDecl);
646+
assert(missingTransportDecl && "Could not locate '_missingDistributedActorTransport' function");
574647

575648
// Create a call to _Distributed._missingDistributedActorTransport
576649
auto loc = func->getLoc();
@@ -726,4 +799,5 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
726799
addImplicitDistributedActorConstructors(decl);
727800
addImplicitDistributedActorStoredProperties(decl);
728801
addImplicitRemoteActorFunctions(decl);
802+
// addImplicitResignAddress(decl);
729803
}

test.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
struct ADDRESS {}
3+
4+
protocol TRANSPORT_PROTOCOL {
5+
func RESIGN(address: ADDRESS)
6+
}
7+
8+
struct TRANSPORT: TRANSPORT_PROTOCOL {
9+
func RESIGN(address: ADDRESS) {
10+
}
11+
}
12+
13+
class ACTOR {
14+
let address: ADDRESS
15+
let transport: TRANSPORT_PROTOCOL
16+
17+
init() {
18+
self.address = ADDRESS()
19+
self.transport = TRANSPORT()
20+
}
21+
22+
deinit {
23+
if ISREMOTE() {
24+
self.transport.RESIGN(address: self.address);
25+
}
26+
}
27+
}
28+
29+
func ISREMOTE() -> Bool {
30+
false
31+
}

0 commit comments

Comments
 (0)