Skip to content

Commit aaf8137

Browse files
committed
[Distributed] work in progress SIL actorReady call
1 parent 0c3720b commit aaf8137

File tree

6 files changed

+174
-62
lines changed

6 files changed

+174
-62
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -850,11 +850,6 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
850850
// Emit the constructor body.
851851
emitStmt(ctor->getTypecheckedBody());
852852

853-
// For distributed actors, emit "actor ready" since we successfully initialized
854-
if (selfClassDecl->isDistributedActor() && !isDelegating) {
855-
emitDistributedActorReady(ctor, selfArg);
856-
}
857-
858853
// Emit the call to super.init() right before exiting from the initializer.
859854
if (NeedsBoxForSelf) {
860855
if (auto *SI = ctor->getSuperInitCall()) {
@@ -929,13 +924,19 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
929924
// problem.
930925
ReturnDest = std::move(ReturnDest).translate(getTopCleanup());
931926
}
932-
927+
933928
// Emit the epilog and post-matter.
934929
auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true);
935930

936931
// Unpop our selfArg cleanup, so we can forward.
937932
std::move(SelfCleanupSave).pop();
938933

934+
// TODO(distributed): rdar://81783599 if this is a distributed actor, jump to the distributedReady block?
935+
// // For distributed actors, emit "actor ready" since we successfully initialized
936+
// if (selfClassDecl->isDistributedActor() && !isDelegating) {
937+
// emitDistributedActorReady(ctor, selfArg);
938+
// }
939+
939940
// Finish off the epilog by returning. If this is a failable ctor, then we
940941
// actually jump to the failure epilog to keep the invariant that there is
941942
// only one SIL return instruction per SIL function.

lib/SILGen/SILGenDistributed.cpp

Lines changed: 112 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@
3232
using namespace swift;
3333
using namespace Lowering;
3434

35+
static AbstractFunctionDecl *lookupAssignIdentityFunc(ASTContext &C) {
36+
auto transportDecl = C.getActorTransportDecl();
37+
38+
for (auto decl : transportDecl->lookupDirect(DeclName(C.Id_assignIdentity)))
39+
if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(decl))
40+
return funcDecl;
41+
42+
llvm_unreachable("Missing ActorTransport.assignIdentity function");
43+
}
44+
45+
static AbstractFunctionDecl *lookupActorReadyFunc(ASTContext &C) {
46+
auto transportDecl = C.getActorTransportDecl();
47+
48+
for (auto decl : transportDecl->lookupDirect(DeclName(C.Id_actorReady)))
49+
if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(decl))
50+
return funcDecl;
51+
52+
llvm_unreachable("Missing ActorTransport.actorReady function");
53+
}
54+
3555
/******************************************************************************/
3656
/****************** DISTRIBUTED ACTOR STORAGE INITIALIZATION ******************/
3757
/******************************************************************************/
@@ -72,18 +92,6 @@ getActorTransportArgument(ASTContext& C, SILFunction& F, ConstructorDecl *ctor)
7292
llvm_unreachable("Missing required ActorTransport argument!");
7393
}
7494

75-
76-
static AbstractFunctionDecl*
77-
lookupAssignIdentityFunc(ASTContext& C) {
78-
auto transportDecl = C.getActorTransportDecl();
79-
80-
for (auto decl : transportDecl->lookupDirect(DeclName(C.Id_assignIdentity)))
81-
if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(decl))
82-
return funcDecl;
83-
84-
return nullptr;
85-
}
86-
8795
/// Synthesize the actorTransport initialization:
8896
///
8997
/// \verbatim
@@ -183,22 +191,19 @@ static void emitDistributedActorIdentity_init_assignIdentity(
183191
auto loc = SILLocation(ctor);
184192
loc.markAutoGenerated();
185193

186-
// === prepare the transport.assignIdentity(_:) function
187-
194+
// ==== prepare the transport.assignIdentity(_:) function
188195
AbstractFunctionDecl *assignIdentityFuncDecl = lookupAssignIdentityFunc(C);
189-
190-
assert(assignIdentityFuncDecl && "Cannot find ActorTransport.assignIdentity!");
191196
auto assignIdentityFnRef = SILDeclRef(assignIdentityFuncDecl);
192197

193-
// === Open the transport existential before call
198+
// --- Prepare the arguments
194199
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
195200
SILValue selfArgValue = F.getSelfArgument();
196201
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
197202
ProtocolDecl *transportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
198203
assert(distributedActorProto);
199204
assert(transportProto);
200205

201-
// --- open the transport existential
206+
// --- Open the transport existential
202207
OpenedArchetypeType *Opened;
203208
auto transportASTType = transportArgValue->getType().getASTType();
204209
auto openedTransportType =
@@ -279,6 +284,10 @@ static void emitDistributedActorIdentity_init_assignIdentity(
279284
IsTake, IsInitialization);
280285
}
281286

287+
/******************************************************************************/
288+
/******************* DISTRIBUTED ACTOR LOCAL INIT *****************************/
289+
/******************************************************************************/
290+
282291
void SILGenFunction::initializeDistributedActorImplicitStorageInit(
283292
ConstructorDecl *ctor, ManagedValue selfArg) {
284293
VarDecl *selfVarDecl = ctor->getImplicitSelfDecl();
@@ -336,7 +345,89 @@ void SILGenFunction::initializeDistributedActorImplicitStorageInit(
336345

337346
void SILGenFunction::emitDistributedActorReady(
338347
ConstructorDecl *ctor, ManagedValue selfArg) {
339-
// TODO(distributed): implement actorReady call
348+
VarDecl *selfVarDecl = ctor->getImplicitSelfDecl();
349+
auto *dc = ctor->getDeclContext();
350+
auto classDecl = dc->getSelfClassDecl();
351+
auto &C = classDecl->getASTContext();
352+
353+
// Only designated initializers get the lifecycle handling injected
354+
if (!ctor->isDesignatedInit())
355+
return;
356+
357+
SILLocation loc = RegularLocation(ctor);
358+
loc.markAutoGenerated();
359+
360+
// // ==== Prepare basic blocks
361+
// auto actorReadyBB = createBasicBlock();
362+
// B.setInsertionPoint(actorReadyBB);
363+
364+
// === Prepare the arguments
365+
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
366+
SILValue selfArgValue = F.getSelfArgument();
367+
368+
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
369+
ProtocolDecl *transportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
370+
assert(distributedActorProto);
371+
assert(transportProto);
372+
373+
// --- Open the transport existential
374+
OpenedArchetypeType *Opened;
375+
auto transportASTType = transportArgValue->getType().getASTType();
376+
auto openedTransportType =
377+
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
378+
auto openedTransportSILType = F.getLoweredType(openedTransportType);
379+
auto transportArchetypeValue = B.createOpenExistentialAddr(
380+
loc, transportArgValue, openedTransportSILType, OpenedExistentialAccess::Immutable);
381+
382+
// === Make the transport.actorReady call
383+
// --- prepare the witness_method
384+
// Note: it does not matter on what module we perform the lookup,
385+
// it is currently ignored. So the Stdlib module is good enough.
386+
auto *module = getModule().getSwiftModule();
387+
388+
// the conformance here is just an abstract thing so we can simplify
389+
// auto transportConfRef = module->lookupConformance(
390+
// openedTransportType, transportProto);
391+
auto transportConfRef = ProtocolConformanceRef(transportProto);
392+
assert(!transportConfRef.isInvalid() && "Missing conformance to `ActorTransport`");
393+
394+
auto *selfTyDecl = ctor->getParent()->getSelfNominalTypeDecl();
395+
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()); // TODO: thats just self var devl getType
396+
397+
auto distributedActorConfRef = module->lookupConformance(
398+
selfTy,
399+
distributedActorProto);
400+
assert(!distributedActorConfRef.isInvalid() && "Missing conformance to `DistributedActor`");
401+
402+
// === Prepare the actorReady function
403+
auto actorReadyMethod =
404+
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_actorReady));
405+
auto actorReadyRef = SILDeclRef(actorReadyMethod, SILDeclRef::Kind::Func);
406+
auto actorReadySILTy =
407+
getConstantInfo(getTypeExpansionContext(), actorReadyRef)
408+
.getSILType();
409+
410+
auto readyWitnessMethod = B.createWitnessMethod(
411+
loc,
412+
/*lookupTy*/openedTransportType,
413+
/*Conformance*/transportConfRef,
414+
/*member*/actorReadyRef,
415+
/*methodTy*/actorReadySILTy);
416+
417+
// --- prepare conformance subs
418+
auto genericSig = actorReadyMethod->getGenericSignature();
419+
fprintf(stderr, "[%s:%d] (%s) GENERIC SIG\n", __FILE__, __LINE__, __FUNCTION__);
420+
genericSig->dump();
421+
422+
SubstitutionMap subs =
423+
SubstitutionMap::get(genericSig,
424+
{openedTransportType, selfTy},
425+
{transportConfRef, distributedActorConfRef});
426+
427+
// ---- actually call transport.actorReady(self)
428+
B.createApply(
429+
loc, readyWitnessMethod, subs,
430+
{ selfArgValue, transportArchetypeValue});
340431
}
341432

342433
/******************************************************************************/
@@ -437,13 +528,10 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
437528
/*subs*/ {},
438529
{selfMetatypeValue});
439530

440-
// ManagedValue remoteCast =
441-
// B.createUncheckedBitCast(loc, ManagedValue::forUnmanaged(remote), returnTy);
442-
443531
// ==== Initialize distributed actor properties
444532
// --- Store the identity: self.id = identity
445-
// emitDistributedActorIdentityStore(
446-
// C, *this, /*actorSelf*/remote, fd, identityArg);
533+
emitDistributedActorIdentityStore(
534+
C, *this, /*actorSelf*/remote, fd, identityArg);
447535

448536
// --- Store the transport: self.transport = transport
449537
// FIXME(distributed): IMPLEMENT:
@@ -452,7 +540,6 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
452540

453541
// ==== Return the fully initialized remote instance
454542
B.createReturn(loc, remote);
455-
// B.createReturn(loc, remoteCast);
456543

457544
// // ==== Branch to return the fully initialized remote instance
458545
// B.createBranch(loc, returnBB, {remote});
@@ -492,7 +579,6 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
492579
// TODO: implement calling resignAddress via a defer in deinit
493580

494581

495-
496582
/******************************************************************************/
497583
/***************************** DISTRIBUTED THUNKS *****************************/
498584
/******************************************************************************/

stdlib/public/Concurrency/Actor.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ class DefaultActorImpl : public HeapObject {
618618
Status_width = 3,
619619

620620
HasActiveInlineJob = 3,
621+
621622
IsDistributedRemote = 4,
622623

623624
MaxPriority = 8,
@@ -683,11 +684,7 @@ class DefaultActorImpl : public HeapObject {
683684

684685
public:
685686
/// Properly construct an actor, except for the heap header.
686-
/// \param isDistributedRemote When true sets the IsDistributedRemote flag
687-
void initialize(bool isDistributedRemote = false) {
688-
// TODO: this is just a simple implementation, rather we would want to allocate a proxy
689-
auto flags = Flags();
690-
flags.setIsDistributedRemote(isDistributedRemote);
687+
void initialize(Flags flags = Flags()) {
691688
new (&CurrentState) std::atomic<State>(State{JobRef(), flags});
692689
}
693690

@@ -1754,15 +1751,35 @@ void swift::swift_defaultActor_deallocateResilient(HeapObject *actor) {
17541751

17551752
OpaqueValue*
17561753
swift::swift_distributedActor_remote_initialize(const Metadata *actorType) {
1754+
fprintf(stderr, "[%s:%d] (%s) ================================================================\n", __FILE__, __LINE__, __FUNCTION__);
1755+
fprintf(stderr, "[%s:%d] (%s) ================================================================\n", __FILE__, __LINE__, __FUNCTION__);
1756+
fprintf(stderr, "[%s:%d] (%s) swift_distributedActor_remote_initialize =======================\n", __FILE__, __LINE__, __FUNCTION__);
17571757
auto *classMetadata = actorType->getClassObject();
17581758

17591759
// TODO(distributed): make this allocation smaller
1760+
// ==== Allocate the memory for the remote instance
17601761
HeapObject *alloc = swift_allocObject(classMetadata,
17611762
classMetadata->getInstanceSize(),
17621763
classMetadata->getInstanceAlignMask());
17631764

1764-
// TODO(distributed): if we are going to keep the remote flag in the header,
1765-
// allocate that header and mark / register this as being remote instance.
1765+
// --- Currently we ride on the DefaultActorImpl to reuse the memory layout
1766+
// of the flags etc. So initialize the default actor into the allocation.
1767+
new (alloc) DefaultActorImpl();
1768+
1769+
1770+
// TODO(distributed): a remote one does not have to have the "real"
1771+
// default actor body, e.g. we don't need an executor at all; so
1772+
// we can allocate more efficiently and only share the flags/status field
1773+
// between the both memory representations
1774+
auto _actor = reinterpret_cast<DefaultActor>(alloc);
1775+
auto flags = DefaultActorImpl.Flags();
1776+
flags.setIsDistributedRemote(true);
1777+
flags.setIsDistributed(true);
1778+
auto defaultActor = asImpl(_actor);
1779+
defaultActor->initialize(flags);
1780+
1781+
assert(defaultActor->isDistributedRemote());
1782+
assert(defaultActor->isDistributed());
17661783

17671784
return reinterpret_cast<OpaqueValue*>(alloc);
17681785
}
@@ -1987,5 +2004,5 @@ static void swift_task_enqueueImpl(Job *job, ExecutorRef executor) {
19872004

19882005
bool DefaultActorImpl::isDistributedRemote() {
19892006
auto state = CurrentState.load(std::memory_order_relaxed);
1990-
return state.Flags.isDistributedRemote() == 1;
2007+
return state.Flags.isDistributedRemote();
19912008
}

stdlib/public/Distributed/ActorTransport.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public protocol ActorTransport: Sendable {
6464
/// E.g. if an actor is created under address `addr1` then immediately invoking
6565
/// `transport.resolve(address: addr1, as: Greeter.self)` MUST return a reference
6666
/// to the same actor.
67-
// FIXME: make it Act.ID needs changes in AST gen
6867
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity
6968
where Act: DistributedActor
7069

test/Distributed/Runtime/distributed_actor_init_local.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ import _Distributed
1414

1515
@available(SwiftStdlib 5.5, *)
1616
distributed actor LocalWorker {
17+
init(transport: ActorTransport) {
18+
defer { transport.actorReady(self) } // FIXME(distributed): rdar://81783599 this should be injected automatically
19+
}
1720
}
1821

1922
// ==== Fake Transport ---------------------------------------------------------
2023

2124
@available(SwiftStdlib 5.5, *)
2225
struct ActorAddress: ActorIdentity {
2326
let address: String
24-
init(parse address : String) {
27+
init(parse address: String) {
2528
self.address = address
2629
}
2730
}
@@ -32,9 +35,8 @@ struct FakeTransport: ActorTransport {
3235
fatalError("not implemented:\(#function)")
3336
}
3437

35-
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type)
36-
throws -> ActorResolved<Act>
37-
where Act: DistributedActor {
38+
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
39+
throws -> ActorResolved<Act> where Act: DistributedActor {
3840
fatalError("not implemented:\(#function)")
3941
}
4042

@@ -50,7 +52,7 @@ struct FakeTransport: ActorTransport {
5052
}
5153

5254
func resignIdentity(_ id: AnyActorIdentity) {
53-
print("ready id:\(id)")
55+
print("resign id:\(id)")
5456
}
5557
}
5658

@@ -61,8 +63,9 @@ func test() {
6163
let transport = FakeTransport()
6264

6365
_ = LocalWorker(transport: transport)
64-
// CHECK: assign type:LocalWorker, id:[[ID:.*]]
65-
// CHECK: ready actor:main.LocalWorker, id:AnyActorIdentity([[ID]])
66+
// CHECK: assign type:LocalWorker, id:ActorAddress(address: "[[ID:.*]]")
67+
// CHECK: ready actor:main.LocalWorker, id:AnyActorIdentity(ActorAddress(address: "[[ID]]"))
68+
// CHECK: resign id:AnyActorIdentity(ActorAddress(address: "[[ID]]"))
6669
}
6770

6871
@available(SwiftStdlib 5.5, *)

0 commit comments

Comments
 (0)