Skip to content

Commit 3161d8f

Browse files
committed
[Distributed] Generate SIL for DistributedActor.resolve
rdar://78484431
1 parent 810e2cf commit 3161d8f

12 files changed

+218
-47
lines changed

lib/SILGen/SILGenDistributed.cpp

Lines changed: 196 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,34 @@ static void emitDistributedIfRemoteBranch(SILGenFunction &SGF,
7070
B.createCondBranch(Loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
7171
}
7272

73+
static AbstractFunctionDecl *lookupActorTransportResolveFunc(ASTContext &C) {
74+
auto transportDecl = C.getActorTransportDecl();
75+
76+
for (auto decl : transportDecl->lookupDirect(DeclName(C.Id_resolve)))
77+
if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(decl))
78+
return funcDecl;
79+
80+
llvm_unreachable("Missing ActorTransport.resolve function");
81+
}
82+
83+
static VarDecl *lookupActorTransportProperty(ASTContext &C, ClassDecl *cd,
84+
SILValue selfValue) {
85+
auto transportVarDeclRefs = cd->lookupDirect(C.Id_actorTransport);
86+
assert(transportVarDeclRefs.size() == 1);
87+
return dyn_cast<VarDecl>(transportVarDeclRefs.front());
88+
}
89+
90+
static EnumElementDecl *lookupEnumCase(ASTContext &C, EnumDecl *target,
91+
Identifier identifier) {
92+
auto elementDecls = target->lookupDirect(DeclName(identifier));
93+
if (elementDecls.empty())
94+
return nullptr;
95+
96+
auto *elementDecl = elementDecls.front();
97+
98+
return dyn_cast<EnumElementDecl>(elementDecl);
99+
}
100+
73101
/******************************************************************************/
74102
/****************** DISTRIBUTED ACTOR STORAGE INITIALIZATION ******************/
75103
/******************************************************************************/
@@ -120,6 +148,7 @@ static void emitDistributedActorStore_transport(
120148
SILValue actorSelf, AbstractFunctionDecl *func,
121149
SILArgument *transportArg) {
122150
auto &B = SGF.B;
151+
123152
auto &SGM = SGF.SGM;
124153
SILGenFunctionBuilder builder(SGM);
125154

@@ -135,6 +164,7 @@ static void emitDistributedActorStore_transport(
135164
auto *var = dyn_cast<VarDecl>(vars.front());
136165

137166
// ----
167+
138168
auto fieldAddr = B.createRefElementAddr(
139169
loc, actorSelf, var,
140170
SGF.getLoweredType(var->getInterfaceType()));
@@ -166,6 +196,7 @@ emitDistributedActor_init_transportStore(
166196
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
167197

168198
// ----
199+
169200
auto transportFieldAddr = B.createRefElementAddr(
170201
loc, borrowedSelfArg.getValue(), var,
171202
SGF.getLoweredType(var->getInterfaceType()));
@@ -187,6 +218,7 @@ static void emitDistributedActorStore_id(
187218
SILValue actorSelf, AbstractFunctionDecl *func,
188219
SILArgument *identityArg) {
189220
auto &B = SGF.B;
221+
190222
auto &SGM = SGF.SGM;
191223
SILGenFunctionBuilder builder(SGM);
192224

@@ -237,7 +269,9 @@ static void emitDistributedActorStore_init_assignIdentity(
237269

238270
// --- Prepare the arguments
239271
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
272+
240273
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
274+
241275
assert(distributedActorProto);
242276
assert(transportProto);
243277

@@ -382,6 +416,7 @@ void SILGenFunction::initializeDistributedActorImplicitStorageInit(
382416

383417
void SILGenFunction::emitDistributedActorReady(
384418
ConstructorDecl *ctor, ManagedValue selfArg) {
419+
385420
auto *dc = ctor->getDeclContext();
386421
auto classDecl = dc->getSelfClassDecl();
387422
auto &C = classDecl->getASTContext();
@@ -462,6 +497,86 @@ void SILGenFunction::emitDistributedActorReady(
462497
/******************* DISTRIBUTED ACTOR RESOLVE FUNCTION ***********************/
463498
/******************************************************************************/
464499

500+
/// Synthesize the distributed actor's identity (`id`) initialization:
501+
///
502+
/// \verbatim
503+
/// transport.resolve(_, as:)
504+
/// \endverbatim
505+
static void createDistributedActorFactory_resolve(
506+
SILGenFunction &SGF, ASTContext &C, FuncDecl *fd, SILValue identityValue,
507+
SILValue transportValue, Type selfTy, SILValue selfMetatypeValue,
508+
SILType resultTy, SILBasicBlock *normalBB, SILBasicBlock *errorBB) {
509+
auto &B = SGF.B;
510+
auto &SGM = SGF.SGM;
511+
auto &F = SGF.F;
512+
SILGenFunctionBuilder builder(SGM);
513+
514+
auto loc = SILLocation(fd);
515+
loc.markAutoGenerated();
516+
517+
ProtocolDecl *distributedActorProto =
518+
C.getProtocol(KnownProtocolKind::DistributedActor);
519+
ProtocolDecl *transportProto =
520+
C.getProtocol(KnownProtocolKind::ActorTransport);
521+
assert(distributedActorProto);
522+
assert(transportProto);
523+
524+
// // --- Open the transport existential
525+
OpenedArchetypeType *Opened;
526+
auto transportASTType = transportValue->getType().getASTType();
527+
auto openedTransportType =
528+
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
529+
auto openedTransportSILType = F.getLoweredType(openedTransportType);
530+
auto transportArchetypeValue =
531+
B.createOpenExistentialAddr(loc, transportValue, openedTransportSILType,
532+
OpenedExistentialAccess::Immutable);
533+
534+
// --- prepare the witness_method
535+
// Note: it does not matter on what module we perform the lookup,
536+
// it is currently ignored. So the Stdlib module is good enough.
537+
auto *module = SGF.getModule().getSwiftModule();
538+
539+
// the conformance here is just an abstract thing so we can simplify
540+
auto transportConfRef = ProtocolConformanceRef(transportProto);
541+
assert(!transportConfRef.isInvalid() &&
542+
"Missing conformance to `ActorTransport`");
543+
544+
auto distributedActorConfRef =
545+
module->lookupConformance(selfTy, distributedActorProto);
546+
assert(!distributedActorConfRef.isInvalid() &&
547+
"Missing conformance to `DistributedActor`");
548+
549+
auto resolveMethod =
550+
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_resolve));
551+
auto resolveRef = SILDeclRef(resolveMethod, SILDeclRef::Kind::Func);
552+
auto constantInfo =
553+
SGF.getConstantInfo(SGF.getTypeExpansionContext(), resolveRef);
554+
auto resolveSILTy = constantInfo.getSILType();
555+
556+
auto resolveWitnessMethod =
557+
B.createWitnessMethod(loc,
558+
/*lookupTy*/ openedTransportType,
559+
/*Conformance*/ transportConfRef,
560+
/*member*/ resolveRef,
561+
/*methodTy*/ resolveSILTy);
562+
563+
// // --- prepare conformance subs
564+
auto genericSig = resolveMethod->getGenericSignature();
565+
566+
SubstitutionMap subs =
567+
SubstitutionMap::get(genericSig, {openedTransportType, selfTy},
568+
{transportConfRef, distributedActorConfRef});
569+
570+
// // ---- actually call transport.resolve(id, as: Self.self)
571+
572+
SmallVector<SILValue, 3> params;
573+
params.push_back(identityValue);
574+
params.push_back(selfMetatypeValue);
575+
params.push_back(transportArchetypeValue); // self for the call, as last param
576+
577+
B.createTryApply(loc, resolveWitnessMethod, subs, params, normalBB, errorBB);
578+
}
579+
465580
/// Function body of:
466581
/// \verbatim
467582
/// DistributedActor.resolve(
@@ -487,28 +602,66 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
487602
assert(
488603
transportArg->getType().getASTType()->isEqual(C.getActorTransportType()));
489604

490-
// --- Parameter: self
605+
SILValue selfArgValue = F.getSelfArgument();
606+
ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue);
607+
608+
// type: SpecificDistributedActor.Type
609+
auto selfArgType = F.mapTypeIntoContext(selfArg.getType().getASTType());
610+
auto selfMetatype = getLoweredType(selfArgType);
611+
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
612+
613+
// type: SpecificDistributedActor
491614
auto *selfTyDecl = fd->getParent()->getSelfNominalTypeDecl();
492615
assert(selfTyDecl->isDistributedActor());
616+
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType());
617+
auto returnTy = getLoweredType(selfTy);
493618

494-
SILValue selfArgValue = F.getSelfArgument();
495-
ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue);
619+
// ==== Prepare all the basic blocks
620+
auto returnBB = createBasicBlock();
621+
auto resolvedBB = createBasicBlock();
622+
auto makeProxyBB = createBasicBlock();
623+
auto switchBB = createBasicBlock();
624+
auto errorBB = createBasicBlock();
625+
626+
SILFunctionConventions fnConv = F.getConventions(); // TODO: no idea?
627+
628+
// --- get the uninitialized allocation from the runtime system.
629+
FullExpr scope(Cleanups, CleanupLocation(fd));
630+
631+
auto optionalReturnTy = SILType::getOptionalType(returnTy);
496632

497-
// ==== Case 'remote') Create the remote instance
633+
// ==== Call `try transport.resolve(id, as: Self.self)`
498634
{
499-
// ==== Create 'remote' distributed actor instance
500-
// --- Prepare param: Self.self
501-
// type: SpecificDistributedActor
502-
auto returnTy = getLoweredType(
503-
F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()));
635+
createDistributedActorFactory_resolve(
636+
*this, C, fd, identityArg, transportArg, selfTy, selfMetatypeValue,
637+
optionalReturnTy, switchBB, errorBB);
638+
}
639+
640+
// ==== switch resolved { ... }
641+
{
642+
B.emitBlock(switchBB);
643+
auto resolve =
644+
switchBB->createPhiArgument(optionalReturnTy, OwnershipKind::Owned);
645+
646+
B.createSwitchEnum(
647+
loc, resolve, nullptr,
648+
{{C.getOptionalSomeDecl(), resolvedBB},
649+
{std::make_pair(C.getOptionalNoneDecl(), makeProxyBB)}});
650+
}
504651

505-
// type: SpecificDistributedActor.Type
506-
auto selfMetatype =
507-
getLoweredType(F.mapTypeIntoContext(selfArg.getType().getASTType()));
508-
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
652+
// ==== Case 'some') return the resolved instance
653+
{
654+
B.emitBlock(resolvedBB);
655+
656+
auto local = resolvedBB->createPhiArgument(returnTy, OwnershipKind::Owned);
657+
658+
B.createBranch(loc, returnBB, {local});
659+
}
509660

510-
// --- get the uninitialized allocation from the runtime system.
511-
FullExpr scope(Cleanups, CleanupLocation(fd));
661+
// ==== Case 'none') Create the remote instance
662+
{
663+
B.emitBlock(makeProxyBB);
664+
// ==== Create 'remote' distributed actor instance
512665

513666
// --- Call: _distributedActorRemoteInitialize(Self.self)
514667
auto builtinName = C.getIdentifier(
@@ -528,8 +681,32 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
528681
emitDistributedActorStore_transport(
529682
C, *this, /*actorSelf*/remote, fd, transportArg);
530683

531-
// ==== Return the fully initialized remote instance
532-
B.createReturn(loc, remote);
684+
// ==== Branch to return the fully initialized remote instance
685+
B.createBranch(loc, returnBB, {remote});
686+
}
687+
688+
// --- Emit return logic
689+
// return <remote>
690+
{
691+
B.emitBlock(returnBB);
692+
693+
auto local = returnBB->createPhiArgument(returnTy, OwnershipKind::Owned);
694+
695+
Cleanups.emitCleanupsForReturn(CleanupLocation(loc), NotForUnwind);
696+
B.createReturn(loc, local);
697+
}
698+
699+
// --- Emit rethrow logic
700+
// throw error
701+
{
702+
B.emitBlock(errorBB);
703+
704+
auto error = errorBB->createPhiArgument(
705+
fnConv.getSILErrorType(F.getTypeExpansionContext()),
706+
OwnershipKind::Owned);
707+
708+
Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind);
709+
B.createThrow(loc, error);
533710
}
534711
}
535712

@@ -563,9 +740,8 @@ void SILGenFunction::emitDistributedActor_resignAddress(
563740
getLoweredType(idVarDeclRef->getType()));
564741

565742
// ==== locate: self.actorTransport
566-
auto transportVarDeclRefs = cd->lookupDirect(ctx.Id_actorTransport);
567-
assert(transportVarDeclRefs.size() == 1);
568-
auto *transportVarDeclRef = dyn_cast<VarDecl>(transportVarDeclRefs.front());
743+
auto transportVarDeclRef = lookupActorTransportProperty(ctx, cd, selfValue);
744+
569745
auto transportRef =
570746
B.createRefElementAddr(Loc, selfValue, transportVarDeclRef,
571747
getLoweredType(transportVarDeclRef->getType()));

lib/SILGen/SILGenFunction.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,17 +514,18 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
514514
emitProfilerIncrement(fd->getTypecheckedBody());
515515
emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd,
516516
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
517-
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));
518517

519518
if (fd->isDistributedActorFactory()) {
520519
// Synthesize the factory function body
521520
emitDistributedActorFactory(fd);
522521
} else {
522+
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));
523+
523524
// Emit the actual function body as usual
524525
emitStmt(fd->getTypecheckedBody());
525-
}
526526

527-
emitEpilog(fd);
527+
emitEpilog(fd);
528+
}
528529

529530
mergeCleanupBlocks();
530531
}

stdlib/public/Distributed/ActorTransport.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public protocol ActorTransport: Sendable {
4848
///
4949
/// Detecting liveness of such remote actors shall be offered / by transport libraries
5050
/// by other means, such as "watching an actor for termination" or similar.
51-
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type) throws -> ActorResolved<Act> // TODO(distributed): make just optional
51+
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type) throws -> Act? // TODO(distributed): make just optional
5252
where Act: DistributedActor
5353

5454
// ==== ---------------------------------------------------------------------
@@ -73,9 +73,3 @@ public protocol ActorTransport: Sendable {
7373
func resignIdentity(_ id: AnyActorIdentity)
7474

7575
}
76-
77-
@available(SwiftStdlib 5.5, *)
78-
public enum ActorResolved<Act: DistributedActor> {
79-
case resolved(Act)
80-
case makeProxy
81-
}

test/Distributed/Runtime/distributed_actor_deinit.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ struct FakeTransport: ActorTransport {
5959
fatalError("not implemented \(#function)")
6060
}
6161

62-
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type) throws -> ActorResolved<Act>
62+
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type) throws -> Act?
6363
where Act: DistributedActor {
6464
print("resolve type:\(actorType), address:\(identity)")
65-
return .makeProxy
65+
return nil
6666
}
6767

6868
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity

test/Distributed/Runtime/distributed_actor_dynamic_remote_func.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ struct FakeTransport: ActorTransport {
5555
}
5656

5757
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type)
58-
throws -> ActorResolved<Act>
58+
throws -> Act?
5959
where Act: DistributedActor {
60-
.makeProxy
60+
return nil
6161
}
6262

6363
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity

test/Distributed/Runtime/distributed_actor_init_local.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct FakeTransport: ActorTransport {
3636
}
3737

3838
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
39-
throws -> ActorResolved<Act> where Act: DistributedActor {
39+
throws -> Act? where Act: DistributedActor {
4040
fatalError("not implemented:\(#function)")
4141
}
4242

test/Distributed/Runtime/distributed_actor_isRemote.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ struct FakeTransport: ActorTransport {
5555
}
5656

5757
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
58-
throws -> ActorResolved<Act>
58+
throws -> Act?
5959
where Act: DistributedActor {
60-
.makeProxy
60+
return nil
6161
}
6262

6363
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity

test/Distributed/Runtime/distributed_actor_local.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ struct FakeTransport: ActorTransport {
4949
fatalError("not implemented \(#function)")
5050
}
5151

52-
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type) throws -> ActorResolved<Act>
52+
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type) throws -> Act?
5353
where Act: DistributedActor {
54-
return .makeProxy
54+
return nil
5555
}
5656

5757
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity

0 commit comments

Comments
 (0)