diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 8be3a9fb70c4a..b72174f0ce638 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -390,7 +390,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, if (Builtin.ID == BuiltinValueKind::InitializeDistributedRemoteActor) { auto actorMetatype = args.claimNext(); - emitDistributedActorInitializeRemote(IGF, actorMetatype, out); + emitDistributedActorInitializeRemote(IGF, resultType, actorMetatype, out); return; } diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 8ee02ca38bb26..ecb7b57bba1c0 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -17,6 +17,7 @@ #include "GenDistributed.h" #include "BitPatternBuilder.h" +#include "ClassTypeInfo.h" #include "ExtraInhabitants.h" #include "GenProto.h" #include "GenType.h" @@ -32,7 +33,12 @@ using namespace swift; using namespace irgen; llvm::Value *irgen::emitDistributedActorInitializeRemote( - IRGenFunction &IGF, llvm::Value *actorMetatype, Explosion &out) { + IRGenFunction &IGF, SILType selfType, llvm::Value *actorMetatype, Explosion &out) { + auto &classTI = IGF.getTypeInfo(selfType).as(); + auto &classLayout = classTI.getClassLayout(IGF.IGM, selfType, + /*forBackwardDeployment=*/false); + llvm::Type *destType = classLayout.getType()->getPointerTo(); + auto fn = IGF.IGM.getDistributedActorInitializeRemoteFn(); actorMetatype = IGF.Builder.CreateBitCast(actorMetatype, IGF.IGM.TypeMetadataPtrTy); @@ -41,9 +47,11 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote( call->setCallingConv(IGF.IGM.SwiftCC); call->setDoesNotThrow(); - out.add(call); + auto result = IGF.Builder.CreateBitCast(call, destType); + + out.add(result); - return call; + return result; } void irgen::emitDistributedActorDestroy(IRGenFunction &IGF, diff --git a/lib/IRGen/GenDistributed.h b/lib/IRGen/GenDistributed.h index df08639a6fa12..97df8f259335e 100644 --- a/lib/IRGen/GenDistributed.h +++ b/lib/IRGen/GenDistributed.h @@ -43,6 +43,7 @@ class IRGenFunction; /// Emit the '_distributedActorRemoteInitialize' call. llvm::Value *emitDistributedActorInitializeRemote( IRGenFunction &IGF, + SILType selfType, llvm::Value *actorMetatype, Explosion &out); diff --git a/lib/SILGen/SILGenDistributed.cpp b/lib/SILGen/SILGenDistributed.cpp index 208e4584f7e7d..3827813cbec32 100644 --- a/lib/SILGen/SILGenDistributed.cpp +++ b/lib/SILGen/SILGenDistributed.cpp @@ -70,6 +70,34 @@ static void emitDistributedIfRemoteBranch(SILGenFunction &SGF, B.createCondBranch(Loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB); } +static AbstractFunctionDecl *lookupActorTransportResolveFunc(ASTContext &C) { + auto transportDecl = C.getActorTransportDecl(); + + for (auto decl : transportDecl->lookupDirect(DeclName(C.Id_resolve))) + if (auto funcDecl = dyn_cast(decl)) + return funcDecl; + + llvm_unreachable("Missing ActorTransport.resolve function"); +} + +static VarDecl *lookupActorTransportProperty(ASTContext &C, ClassDecl *cd, + SILValue selfValue) { + auto transportVarDeclRefs = cd->lookupDirect(C.Id_actorTransport); + assert(transportVarDeclRefs.size() == 1); + return dyn_cast(transportVarDeclRefs.front()); +} + +static EnumElementDecl *lookupEnumCase(ASTContext &C, EnumDecl *target, + Identifier identifier) { + auto elementDecls = target->lookupDirect(DeclName(identifier)); + if (elementDecls.empty()) + return nullptr; + + auto *elementDecl = elementDecls.front(); + + return dyn_cast(elementDecl); +} + /******************************************************************************/ /****************** DISTRIBUTED ACTOR STORAGE INITIALIZATION ******************/ /******************************************************************************/ @@ -120,6 +148,7 @@ static void emitDistributedActorStore_transport( SILValue actorSelf, AbstractFunctionDecl *func, SILArgument *transportArg) { auto &B = SGF.B; + auto &SGM = SGF.SGM; SILGenFunctionBuilder builder(SGM); @@ -135,6 +164,7 @@ static void emitDistributedActorStore_transport( auto *var = dyn_cast(vars.front()); // ---- + auto fieldAddr = B.createRefElementAddr( loc, actorSelf, var, SGF.getLoweredType(var->getInterfaceType())); @@ -166,6 +196,7 @@ emitDistributedActor_init_transportStore( SILValue transportArgValue = getActorTransportArgument(C, F, ctor); // ---- + auto transportFieldAddr = B.createRefElementAddr( loc, borrowedSelfArg.getValue(), var, SGF.getLoweredType(var->getInterfaceType())); @@ -187,6 +218,7 @@ static void emitDistributedActorStore_id( SILValue actorSelf, AbstractFunctionDecl *func, SILArgument *identityArg) { auto &B = SGF.B; + auto &SGM = SGF.SGM; SILGenFunctionBuilder builder(SGM); @@ -237,7 +269,9 @@ static void emitDistributedActorStore_init_assignIdentity( // --- Prepare the arguments SILValue transportArgValue = getActorTransportArgument(C, F, ctor); + ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor); + assert(distributedActorProto); assert(transportProto); @@ -382,6 +416,7 @@ void SILGenFunction::initializeDistributedActorImplicitStorageInit( void SILGenFunction::emitDistributedActorReady( ConstructorDecl *ctor, ManagedValue selfArg) { + auto *dc = ctor->getDeclContext(); auto classDecl = dc->getSelfClassDecl(); auto &C = classDecl->getASTContext(); @@ -462,6 +497,86 @@ void SILGenFunction::emitDistributedActorReady( /******************* DISTRIBUTED ACTOR RESOLVE FUNCTION ***********************/ /******************************************************************************/ +/// Synthesize the distributed actor's identity (`id`) initialization: +/// +/// \verbatim +/// transport.resolve(_, as:) +/// \endverbatim +static void createDistributedActorFactory_resolve( + SILGenFunction &SGF, ASTContext &C, FuncDecl *fd, SILValue identityValue, + SILValue transportValue, Type selfTy, SILValue selfMetatypeValue, + SILType resultTy, SILBasicBlock *normalBB, SILBasicBlock *errorBB) { + auto &B = SGF.B; + auto &SGM = SGF.SGM; + auto &F = SGF.F; + SILGenFunctionBuilder builder(SGM); + + auto loc = SILLocation(fd); + loc.markAutoGenerated(); + + ProtocolDecl *distributedActorProto = + C.getProtocol(KnownProtocolKind::DistributedActor); + ProtocolDecl *transportProto = + C.getProtocol(KnownProtocolKind::ActorTransport); + assert(distributedActorProto); + assert(transportProto); + + // // --- Open the transport existential + OpenedArchetypeType *Opened; + auto transportASTType = transportValue->getType().getASTType(); + auto openedTransportType = + transportASTType->openAnyExistentialType(Opened)->getCanonicalType(); + auto openedTransportSILType = F.getLoweredType(openedTransportType); + auto transportArchetypeValue = + B.createOpenExistentialAddr(loc, transportValue, openedTransportSILType, + OpenedExistentialAccess::Immutable); + + // --- prepare the witness_method + // Note: it does not matter on what module we perform the lookup, + // it is currently ignored. So the Stdlib module is good enough. + auto *module = SGF.getModule().getSwiftModule(); + + // the conformance here is just an abstract thing so we can simplify + auto transportConfRef = ProtocolConformanceRef(transportProto); + assert(!transportConfRef.isInvalid() && + "Missing conformance to `ActorTransport`"); + + auto distributedActorConfRef = + module->lookupConformance(selfTy, distributedActorProto); + assert(!distributedActorConfRef.isInvalid() && + "Missing conformance to `DistributedActor`"); + + auto resolveMethod = + cast(transportProto->getSingleRequirement(C.Id_resolve)); + auto resolveRef = SILDeclRef(resolveMethod, SILDeclRef::Kind::Func); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), resolveRef); + auto resolveSILTy = constantInfo.getSILType(); + + auto resolveWitnessMethod = + B.createWitnessMethod(loc, + /*lookupTy*/ openedTransportType, + /*Conformance*/ transportConfRef, + /*member*/ resolveRef, + /*methodTy*/ resolveSILTy); + + // // --- prepare conformance subs + auto genericSig = resolveMethod->getGenericSignature(); + + SubstitutionMap subs = + SubstitutionMap::get(genericSig, {openedTransportType, selfTy}, + {transportConfRef, distributedActorConfRef}); + + // // ---- actually call transport.resolve(id, as: Self.self) + + SmallVector params; + params.push_back(identityValue); + params.push_back(selfMetatypeValue); + params.push_back(transportArchetypeValue); // self for the call, as last param + + B.createTryApply(loc, resolveWitnessMethod, subs, params, normalBB, errorBB); +} + /// Function body of: /// \verbatim /// DistributedActor.resolve( @@ -487,28 +602,66 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { assert( transportArg->getType().getASTType()->isEqual(C.getActorTransportType())); - // --- Parameter: self + SILValue selfArgValue = F.getSelfArgument(); + ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue); + + // type: SpecificDistributedActor.Type + auto selfArgType = F.mapTypeIntoContext(selfArg.getType().getASTType()); + auto selfMetatype = getLoweredType(selfArgType); + SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype); + + // type: SpecificDistributedActor auto *selfTyDecl = fd->getParent()->getSelfNominalTypeDecl(); assert(selfTyDecl->isDistributedActor()); + auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()); + auto returnTy = getLoweredType(selfTy); - SILValue selfArgValue = F.getSelfArgument(); - ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue); + // ==== Prepare all the basic blocks + auto returnBB = createBasicBlock(); + auto resolvedBB = createBasicBlock(); + auto makeProxyBB = createBasicBlock(); + auto switchBB = createBasicBlock(); + auto errorBB = createBasicBlock(); + + SILFunctionConventions fnConv = F.getConventions(); // TODO: no idea? + + // --- get the uninitialized allocation from the runtime system. + FullExpr scope(Cleanups, CleanupLocation(fd)); + + auto optionalReturnTy = SILType::getOptionalType(returnTy); - // ==== Case 'remote') Create the remote instance + // ==== Call `try transport.resolve(id, as: Self.self)` { - // ==== Create 'remote' distributed actor instance - // --- Prepare param: Self.self - // type: SpecificDistributedActor - auto returnTy = getLoweredType( - F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType())); + createDistributedActorFactory_resolve( + *this, C, fd, identityArg, transportArg, selfTy, selfMetatypeValue, + optionalReturnTy, switchBB, errorBB); + } + + // ==== switch resolved { ... } + { + B.emitBlock(switchBB); + auto resolve = + switchBB->createPhiArgument(optionalReturnTy, OwnershipKind::Owned); + + B.createSwitchEnum( + loc, resolve, nullptr, + {{C.getOptionalSomeDecl(), resolvedBB}, + {std::make_pair(C.getOptionalNoneDecl(), makeProxyBB)}}); + } - // type: SpecificDistributedActor.Type - auto selfMetatype = - getLoweredType(F.mapTypeIntoContext(selfArg.getType().getASTType())); - SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype); + // ==== Case 'some') return the resolved instance + { + B.emitBlock(resolvedBB); + + auto local = resolvedBB->createPhiArgument(returnTy, OwnershipKind::Owned); + + B.createBranch(loc, returnBB, {local}); + } - // --- get the uninitialized allocation from the runtime system. - FullExpr scope(Cleanups, CleanupLocation(fd)); + // ==== Case 'none') Create the remote instance + { + B.emitBlock(makeProxyBB); + // ==== Create 'remote' distributed actor instance // --- Call: _distributedActorRemoteInitialize(Self.self) auto builtinName = C.getIdentifier( @@ -528,8 +681,32 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) { emitDistributedActorStore_transport( C, *this, /*actorSelf*/remote, fd, transportArg); - // ==== Return the fully initialized remote instance - B.createReturn(loc, remote); + // ==== Branch to return the fully initialized remote instance + B.createBranch(loc, returnBB, {remote}); + } + + // --- Emit return logic + // return + { + B.emitBlock(returnBB); + + auto local = returnBB->createPhiArgument(returnTy, OwnershipKind::Owned); + + Cleanups.emitCleanupsForReturn(CleanupLocation(loc), NotForUnwind); + B.createReturn(loc, local); + } + + // --- Emit rethrow logic + // throw error + { + B.emitBlock(errorBB); + + auto error = errorBB->createPhiArgument( + fnConv.getSILErrorType(F.getTypeExpansionContext()), + OwnershipKind::Owned); + + Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind); + B.createThrow(loc, error); } } @@ -563,9 +740,8 @@ void SILGenFunction::emitDistributedActor_resignAddress( getLoweredType(idVarDeclRef->getType())); // ==== locate: self.actorTransport - auto transportVarDeclRefs = cd->lookupDirect(ctx.Id_actorTransport); - assert(transportVarDeclRefs.size() == 1); - auto *transportVarDeclRef = dyn_cast(transportVarDeclRefs.front()); + auto transportVarDeclRef = lookupActorTransportProperty(ctx, cd, selfValue); + auto transportRef = B.createRefElementAddr(Loc, selfValue, transportVarDeclRef, getLoweredType(transportVarDeclRef->getType())); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 0ef4ac034f163..dc70697ac85f3 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -514,17 +514,18 @@ void SILGenFunction::emitFunction(FuncDecl *fd) { emitProfilerIncrement(fd->getTypecheckedBody()); emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd, fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc()); - prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd)); if (fd->isDistributedActorFactory()) { // Synthesize the factory function body emitDistributedActorFactory(fd); } else { + prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd)); + // Emit the actual function body as usual emitStmt(fd->getTypecheckedBody()); - } - emitEpilog(fd); + emitEpilog(fd); + } mergeCleanupBlocks(); } diff --git a/stdlib/public/Distributed/ActorTransport.swift b/stdlib/public/Distributed/ActorTransport.swift index 196f6ee160ec2..66d64d8689b92 100644 --- a/stdlib/public/Distributed/ActorTransport.swift +++ b/stdlib/public/Distributed/ActorTransport.swift @@ -48,7 +48,7 @@ public protocol ActorTransport: Sendable { /// /// Detecting liveness of such remote actors shall be offered / by transport libraries /// by other means, such as "watching an actor for termination" or similar. - func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) throws -> ActorResolved // TODO(distributed): make just optional + func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) throws -> Act? // TODO(distributed): make just optional where Act: DistributedActor // ==== --------------------------------------------------------------------- @@ -73,9 +73,3 @@ public protocol ActorTransport: Sendable { func resignIdentity(_ id: AnyActorIdentity) } - -@available(SwiftStdlib 5.5, *) -public enum ActorResolved { - case resolved(Act) - case makeProxy -} diff --git a/test/Distributed/Runtime/distributed_actor_deinit.swift b/test/Distributed/Runtime/distributed_actor_deinit.swift index f0def5ec69045..07a4830fb50f2 100644 --- a/test/Distributed/Runtime/distributed_actor_deinit.swift +++ b/test/Distributed/Runtime/distributed_actor_deinit.swift @@ -59,10 +59,10 @@ struct FakeTransport: ActorTransport { fatalError("not implemented \(#function)") } - func resolve(_ identity: Act.ID, as actorType: Act.Type) throws -> ActorResolved + func resolve(_ identity: Act.ID, as actorType: Act.Type) throws -> Act? where Act: DistributedActor { print("resolve type:\(actorType), address:\(identity)") - return .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_dynamic_remote_func.swift b/test/Distributed/Runtime/distributed_actor_dynamic_remote_func.swift index 51e8974e5d8b5..4f949bb68f58d 100644 --- a/test/Distributed/Runtime/distributed_actor_dynamic_remote_func.swift +++ b/test/Distributed/Runtime/distributed_actor_dynamic_remote_func.swift @@ -55,9 +55,9 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: Act.ID, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_init_local.swift b/test/Distributed/Runtime/distributed_actor_init_local.swift index a4f5556784c77..1ece89bddbe04 100644 --- a/test/Distributed/Runtime/distributed_actor_init_local.swift +++ b/test/Distributed/Runtime/distributed_actor_init_local.swift @@ -36,7 +36,7 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) - throws -> ActorResolved where Act: DistributedActor { + throws -> Act? where Act: DistributedActor { fatalError("not implemented:\(#function)") } diff --git a/test/Distributed/Runtime/distributed_actor_isRemote.swift b/test/Distributed/Runtime/distributed_actor_isRemote.swift index 2daac2c64e7bb..207663f3c1074 100644 --- a/test/Distributed/Runtime/distributed_actor_isRemote.swift +++ b/test/Distributed/Runtime/distributed_actor_isRemote.swift @@ -55,9 +55,9 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_local.swift b/test/Distributed/Runtime/distributed_actor_local.swift index d9a6907cb93fd..404fec5cc8735 100644 --- a/test/Distributed/Runtime/distributed_actor_local.swift +++ b/test/Distributed/Runtime/distributed_actor_local.swift @@ -49,9 +49,9 @@ struct FakeTransport: ActorTransport { fatalError("not implemented \(#function)") } - func resolve(_ identity: Act.ID, as actorType: Act.Type) throws -> ActorResolved + func resolve(_ identity: Act.ID, as actorType: Act.Type) throws -> Act? where Act: DistributedActor { - return .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_remote_fieldsDontCrashDeinit.swift b/test/Distributed/Runtime/distributed_actor_remote_fieldsDontCrashDeinit.swift index 1e1760e32bcd0..4f78a0e9174c8 100644 --- a/test/Distributed/Runtime/distributed_actor_remote_fieldsDontCrashDeinit.swift +++ b/test/Distributed/Runtime/distributed_actor_remote_fieldsDontCrashDeinit.swift @@ -59,9 +59,9 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_remote_functions.swift b/test/Distributed/Runtime/distributed_actor_remote_functions.swift index e7d9de860c166..a4334a186c6c0 100644 --- a/test/Distributed/Runtime/distributed_actor_remote_functions.swift +++ b/test/Distributed/Runtime/distributed_actor_remote_functions.swift @@ -115,9 +115,9 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: Act.ID, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_actor_remote_retains_transport.swift b/test/Distributed/Runtime/distributed_actor_remote_retains_transport.swift index dd2ce3dff31aa..7432142fc1557 100644 --- a/test/Distributed/Runtime/distributed_actor_remote_retains_transport.swift +++ b/test/Distributed/Runtime/distributed_actor_remote_retains_transport.swift @@ -51,9 +51,9 @@ final class FakeTransport: ActorTransport { } func resolve(_ identity: AnyActorIdentity, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity diff --git a/test/Distributed/Runtime/distributed_no_transport_boom.swift b/test/Distributed/Runtime/distributed_no_transport_boom.swift index b13c720c48dc7..f68263795f025 100644 --- a/test/Distributed/Runtime/distributed_no_transport_boom.swift +++ b/test/Distributed/Runtime/distributed_no_transport_boom.swift @@ -37,9 +37,9 @@ struct FakeTransport: ActorTransport { } func resolve(_ identity: Act.ID, as actorType: Act.Type) - throws -> ActorResolved + throws -> Act? where Act: DistributedActor { - .makeProxy + return nil } func assignIdentity(_ actorType: Act.Type) -> AnyActorIdentity