Skip to content

Commit 3e77eac

Browse files
committed
[Distributed] DA deinit must resign address from the transport
1 parent 3ea3769 commit 3e77eac

File tree

11 files changed

+297
-14
lines changed

11 files changed

+297
-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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,9 +1414,11 @@ 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

1421+
assert(remoteFuncDecls.size() > 1 && "at-most one _remote distributed function expected, found more.");
14201422
if (auto remoteDecl = dyn_cast<AbstractFunctionDecl>(remoteFuncDecls.front())) {
14211423
// TODO: implement more checks here, it has to be the exact right signature.
14221424
return remoteDecl;

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: 80 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,10 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
7576
resultSelfValue = selfValue;
7677
}
7778

79+
if (cd->isDistributedActor()) {
80+
injectDistributedActorDestructorLifecycleCall(dd, selfValue);
81+
}
82+
7883
ArgumentScope S(*this, Loc);
7984
ManagedValue borrowedValue =
8085
ManagedValue::forUnmanaged(resultSelfValue).borrow(*this, cleanupLoc);
@@ -101,6 +106,81 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) {
101106
B.createReturn(returnLoc, resultSelfValue);
102107
}
103108

109+
static AccessorDecl *getActorTransportGetter(ASTContext &ctx,
110+
ProtocolDecl *distributedActorProtocol) {
111+
for (auto member: distributedActorProtocol->getAllMembers()) {
112+
if (auto var = dyn_cast<VarDecl>(member)) {
113+
if (var->getName() == ctx.Id_unownedExecutor)
114+
return var->getAccessor(AccessorKind::Get);
115+
}
116+
}
117+
return nullptr;
118+
}
119+
120+
void SILGenFunction::injectDistributedActorDestructorLifecycleCall(
121+
DestructorDecl *dd, SILValue selfValue) {
122+
ASTContext &ctx = getASTContext();
123+
124+
auto cd = cast<ClassDecl>(dd->getDeclContext());
125+
assert(cd->isDistributedActor() &&
126+
"only distributed actors have transport lifecycle hooks in deinit");
127+
128+
RegularLocation Loc(dd);
129+
if (dd->isImplicit())
130+
Loc.markAutoGenerated();
131+
132+
// ==== locate: self.actorAddress
133+
auto addressVarDeclRefs = cd->lookupDirect(ctx.Id_actorAddress);
134+
assert(addressVarDeclRefs.size() == 1);
135+
auto *addressVarDeclRef = dyn_cast<VarDecl>(addressVarDeclRefs.front());
136+
assert(addressVarDeclRef);
137+
auto addressRef =
138+
B.createRefElementAddr(Loc, selfValue, addressVarDeclRef,
139+
getLoweredType(addressVarDeclRef->getType()));
140+
141+
// ==== locate: self.actorTransport
142+
auto transportVarDeclRefs = cd->lookupDirect(ctx.Id_actorTransport);
143+
assert(transportVarDeclRefs.size() == 1);
144+
auto *transportVarDeclRef = dyn_cast<VarDecl>(transportVarDeclRefs.front());
145+
assert(transportVarDeclRef);
146+
auto transportRef =
147+
B.createRefElementAddr(Loc, selfValue, transportVarDeclRef,
148+
getLoweredType(transportVarDeclRef->getType()));
149+
assert(transportRef);
150+
151+
// locate: self.transport.resignAddress(...)
152+
auto *transportDecl = ctx.getActorTransportDecl();
153+
auto resignFnDecls = transportDecl->lookupDirect(ctx.Id_resignAddress);
154+
assert(resignFnDecls.size() == 1);
155+
ValueDecl *resignFnDecl = resignFnDecls.front();
156+
assert(resignFnDecl && "Unable to find 'resignAddress' on ActorTransport");
157+
auto resignFnRef = SILDeclRef(resignFnDecl);
158+
159+
auto openedTransport =
160+
OpenedArchetypeType::get(transportVarDeclRef->getType());
161+
162+
auto transportAddr = B.createOpenExistentialAddr(
163+
Loc, /*operand=*/transportRef, getLoweredType(openedTransport),
164+
OpenedExistentialAccess::Immutable);
165+
166+
auto resignFnType = SGM.M.Types.getConstantFunctionType(
167+
TypeExpansionContext::minimal(), resignFnRef);
168+
169+
auto witness = B.createWitnessMethod(
170+
Loc, openedTransport, ProtocolConformanceRef(transportDecl), resignFnRef,
171+
SILType::getPrimitiveObjectType(resignFnType));
172+
173+
auto subs = SubstitutionMap::getProtocolSubstitutions(
174+
transportDecl, openedTransport, ProtocolConformanceRef(transportDecl));
175+
176+
SmallVector<SILValue, 2> params;
177+
params.push_back(addressRef);
178+
params.push_back(transportAddr); // self for the call, as last param
179+
180+
// === self.transport.resignAddress(self.address)
181+
B.createApply(Loc, witness, subs, params);
182+
}
183+
104184
void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
105185
MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));
106186

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);
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
@@ -255,7 +255,6 @@ createDistributedActor_init_local(ClassDecl *classDecl,
255255
/// \param initDecl The function decl whose body to synthesize.
256256
static std::pair<BraceStmt *, bool>
257257
createDistributedActor_init_resolve_body(AbstractFunctionDecl *initDecl, void *) {
258-
259258
auto *funcDC = cast<DeclContext>(initDecl);
260259
auto &C = funcDC->getASTContext();
261260

@@ -289,8 +288,8 @@ createDistributedActor_init_resolve_body(AbstractFunctionDecl *initDecl, void *)
289288
statements.push_back(assignAddressExpr);
290289
// end-of-FIXME: this must be checking with the transport instead
291290

292-
auto *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
293-
/*implicit=*/true);
291+
BraceStmt *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
292+
/*implicit=*/true);
294293

295294
return { body, /*isTypeChecked=*/false };
296295
}
@@ -306,7 +305,6 @@ static ConstructorDecl *
306305
createDistributedActor_init_resolve(ClassDecl *classDecl,
307306
ASTContext &ctx) {
308307
auto &C = ctx;
309-
310308
auto conformanceDC = classDecl;
311309

312310
// Expected type: (Self) -> (ActorAddress, ActorTransport) -> (Self)
@@ -465,6 +463,81 @@ static void addImplicitDistributedActorConstructors(ClassDecl *decl) {
465463
}
466464
}
467465

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

579652
auto missingTransportDecl = ctx.getMissingDistributedActorTransport();
580-
assert(missingTransportDecl);
653+
assert(missingTransportDecl && "Could not locate '_missingDistributedActorTransport' function");
581654

582655
// Create a call to _Distributed._missingDistributedActorTransport
583656
auto loc = func->getLoc();
@@ -733,4 +806,5 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
733806
addImplicitDistributedActorConstructors(decl);
734807
addImplicitDistributedActorStoredProperties(decl);
735808
addImplicitRemoteActorFunctions(decl);
809+
// addImplicitResignAddress(decl);
736810
}

test.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
self.transport.RESIGN(address: self.address);
24+
}
25+
}

0 commit comments

Comments
 (0)