Files
swift-mirror/lib/SILGen/SILGenDistributed.cpp
Konrad `ktoso` Malawski d414a26ef1 [Distributed] cleanup some warnings in SILGenDistributed (#38901)
* [Distributed] cleanup some warnings in SILGenDistributed

* [Distributed] cleanup SILGenDestructor, move dist logic to
SILGenDistributed

* [Distributed] de-duplicate SIL gen for if remote/local branch
2021-08-17 13:36:05 +09:00

865 lines
30 KiB
C++

//===--- SILGenDistributed.cpp - SILGen for distributed -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "ArgumentSource.h"
#include "Conversion.h"
#include "ExecutorBreadcrumb.h"
#include "Initialization.h"
#include "LValue.h"
#include "RValue.h"
#include "SILGenFunction.h"
#include "SILGenFunctionBuilder.h"
#include "Scope.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/Basic/Defer.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
using namespace swift;
using namespace Lowering;
/******************************************************************************/
/******************* COMMON (DISTRIBUTED) SIL PATTERNS ************************/
/******************************************************************************/
/// Emit the following branch SIL instruction:
/// \verbatim
/// if __isRemoteActor(self) {
/// <isRemoteBB>
/// } else {
/// <isLocalBB>
/// }
/// \endverbatim
static void emitDistributedIfRemoteBranch(SILGenFunction &SGF,
SILLocation Loc,
ManagedValue selfValue, Type selfTy,
SILBasicBlock *isRemoteBB,
SILBasicBlock *isLocalBB) {
ASTContext &ctx = SGF.getASTContext();
auto &B = SGF.B;
FuncDecl *isRemoteFn = ctx.getIsRemoteDistributedActor();
assert(isRemoteFn && "Could not find 'is remote' function, is the "
"'_Distributed' module available?");
ManagedValue selfAnyObject =
B.createInitExistentialRef(Loc, SGF.getLoweredType(ctx.getAnyObjectType()),
CanType(selfTy), selfValue, {});
auto result = SGF.emitApplyOfLibraryIntrinsic(
Loc, isRemoteFn, SubstitutionMap(), {selfAnyObject}, SGFContext());
SILValue isRemoteResult =
std::move(result).forwardAsSingleValue(SGF, Loc);
SILValue isRemoteResultUnwrapped =
SGF.emitUnwrapIntegerResult(Loc, isRemoteResult);
B.createCondBranch(Loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
}
/******************************************************************************/
/****************** DISTRIBUTED ACTOR STORAGE INITIALIZATION ******************/
/******************************************************************************/
/// Get the `ActorTransport` parameter of the constructor.
/// Sema should have guaranteed that there is exactly one of them for any
/// designated initializer of a distributed actor.
static SILArgument*
getActorTransportArgument(ASTContext& C, SILFunction& F, ConstructorDecl *ctor) {
auto *DC = cast<DeclContext>(ctor);
auto module = DC->getParentModule();
auto *transportProto =
C.getProtocol(KnownProtocolKind::ActorTransport);
Type transportTy = transportProto->getDeclaredInterfaceType();
for (auto arg : F.getArguments()) {
// TODO(distributed): also be able to locate a generic transport
Type argTy = arg->getType().getASTType();
auto argDecl = arg->getDecl();
auto conformsToTransport = module->lookupConformance(
argDecl->getInterfaceType(), transportProto);
// Is it a protocol that conforms to ActorTransport?
if (argTy->isEqual(transportTy) || conformsToTransport) {
return arg;
}
// Is it some specific ActorTransport?
auto result = module->lookupConformance(argTy, transportProto);
if (!result.isInvalid()) {
return arg;
}
}
// did not find argument of ActorTransport type!
llvm_unreachable("Missing required ActorTransport argument!");
}
/// Synthesize the actorTransport initialization:
///
/// \verbatim
/// self.actorTransport = <<constructor parameter:ActorTransport>>
/// \endverbatim
static void emitDistributedActorStore_transport(
ASTContext& C, SILGenFunction &SGF,
SILValue actorSelf, AbstractFunctionDecl *func,
SILArgument *transportArg) {
auto &B = SGF.B;
auto &SGM = SGF.SGM;
SILGenFunctionBuilder builder(SGM);
auto *dc = func->getDeclContext();
auto classDecl = dc->getSelfClassDecl();
auto loc = SILLocation(func);
loc.markAutoGenerated();
// ==== Prepare the property reference: self.id
auto vars = classDecl->lookupDirect(C.Id_actorTransport);
assert(vars.size() == 1);
auto *var = dyn_cast<VarDecl>(vars.front());
// ----
auto fieldAddr = B.createRefElementAddr(
loc, actorSelf, var,
SGF.getLoweredType(var->getInterfaceType()));
// ==== Store the transport
B.createCopyAddr(loc,
/*src*/transportArg,
/*dest*/fieldAddr,
IsNotTake, IsInitialization);
}
// TODO(distributed): remove this store impl and reuse Store_transport
static void
emitDistributedActor_init_transportStore(
SILGenFunction &SGF,
ManagedValue borrowedSelfArg, VarDecl *selfDecl,
ConstructorDecl *ctor,
Pattern *pattern, VarDecl *var) {
auto &C = selfDecl->getASTContext();
auto &B = SGF.B;
auto &F = SGF.F;
auto &SGM = SGF.SGM;
SILGenFunctionBuilder builder(SGM);
auto loc = SILLocation(ctor);
loc.markAutoGenerated();
// ==== Prepare assignment: get the self.transport address
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
// ----
auto transportFieldAddr = B.createRefElementAddr(
loc, borrowedSelfArg.getValue(), var,
SGF.getLoweredType(var->getInterfaceType()));
// ==== Store the transport
B.createCopyAddr(loc,
/*src*/transportArgValue,
/*dest*/transportFieldAddr,
IsNotTake, IsInitialization);
}
/// Synthesize storing the passed in managed identity to the `id` property:
///
/// \verbatim
/// self.id = <<parameter:identity>>
/// \endverbatim
static void emitDistributedActorStore_id(
ASTContext& C, SILGenFunction &SGF,
SILValue actorSelf, AbstractFunctionDecl *func,
SILArgument *identityArg) {
auto &B = SGF.B;
auto &SGM = SGF.SGM;
SILGenFunctionBuilder builder(SGM);
auto *dc = func->getDeclContext();
auto classDecl = dc->getSelfClassDecl();
auto loc = SILLocation(func);
loc.markAutoGenerated();
// ==== Prepare the property reference: self.id
auto vars = classDecl->lookupDirect(C.Id_id);
assert(vars.size() == 1);
auto *var = dyn_cast<VarDecl>(vars.front());
// ==== Prepare assignment
auto fieldAddr = B.createRefElementAddr(
loc, actorSelf, var,
SGF.getLoweredType(var->getInterfaceType()));
// ==== Store the transport
B.createCopyAddr(loc,
/*src*/identityArg,
/*dest*/fieldAddr,
IsNotTake, IsInitialization);
}
/// Synthesize the distributed actor's identity (`id`) initialization:
///
/// \verbatim
/// self.id = transport.assignIdentity(Self.self)
/// \endverbatim
static void emitDistributedActorStore_init_assignIdentity(
SILGenFunction &SGF,
ManagedValue borrowedSelfArg, VarDecl *selfVarDecl,
ConstructorDecl *ctor,
Pattern *pattern, VarDecl *var) {
auto &C = selfVarDecl->getASTContext();
auto &B = SGF.B;
auto &F = SGF.F;
auto &SGM = SGF.SGM;
SILGenFunctionBuilder builder(SGM);
auto loc = SILLocation(ctor);
loc.markAutoGenerated();
// ==== prepare the transport.assignIdentity(_:) function
ProtocolDecl *transportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
// --- Prepare the arguments
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
assert(distributedActorProto);
assert(transportProto);
// --- Open the transport existential
OpenedArchetypeType *Opened;
auto transportASTType = transportArgValue->getType().getASTType();
auto openedTransportType =
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
auto openedTransportSILType = F.getLoweredType(openedTransportType);
auto transportArchetypeValue = B.createOpenExistentialAddr(
loc, transportArgValue, openedTransportSILType, OpenedExistentialAccess::Immutable);
// --- prepare `Self.self` metatype
auto *selfTyDecl = ctor->getParent()->getSelfNominalTypeDecl();
// This would be bad: since not ok for generic
// auto selfMetatype = SGF.getLoweredType(selfTyDecl->getInterfaceType());
auto selfMetatype =
SGF.getLoweredType(F.mapTypeIntoContext(selfTyDecl->getInterfaceType()));
// selfVarDecl.getType() // TODO: do this; then dont need the self type decl
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
// === Make the transport.assignIdentity call
// --- 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 selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()); // TODO: thats just self var devl getType
auto distributedActorConfRef = module->lookupConformance(
selfTy,
distributedActorProto);
assert(!distributedActorConfRef.isInvalid() && "Missing conformance to `DistributedActor`");
auto assignIdentityMethod =
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_assignIdentity));
auto assignIdentityRef = SILDeclRef(assignIdentityMethod, SILDeclRef::Kind::Func);
auto assignIdentitySILTy =
SGF.getConstantInfo(SGF.getTypeExpansionContext(), assignIdentityRef)
.getSILType();
auto assignWitnessMethod = B.createWitnessMethod(
loc,
/*lookupTy*/openedTransportType,
/*Conformance*/transportConfRef,
/*member*/assignIdentityRef,
/*methodTy*/assignIdentitySILTy);
// --- prepare conformance subs
auto genericSig = assignIdentityMethod->getGenericSignature();
SubstitutionMap subs =
SubstitutionMap::get(genericSig,
{openedTransportType, selfTy},
{transportConfRef, distributedActorConfRef});
// --- create a temporary storage for the result of the call
// it will be deallocated automatically as we exit this scope
auto resultTy = SGF.getLoweredType(var->getInterfaceType());
auto temp = SGF.emitTemporaryAllocation(loc, resultTy);
// ---- actually call transport.assignIdentity(Self.self)
B.createApply(
loc, assignWitnessMethod, subs,
{ temp, selfMetatypeValue, transportArchetypeValue});
// ==== Assign the identity to stored property
// TODO(distributed): reuse emitDistributedActorStore_id here, pass the SILValue
// --- Prepare address of self.id
auto idFieldAddr = B.createRefElementAddr(
loc, borrowedSelfArg.getValue(), var,
SGF.getLoweredType(var->getInterfaceType()));
// --- assign to the property
B.createCopyAddr(loc, /*src*/temp, /*dest*/idFieldAddr,
IsTake, IsInitialization);
}
/******************************************************************************/
/******************* DISTRIBUTED ACTOR LOCAL INIT *****************************/
/******************************************************************************/
void SILGenFunction::initializeDistributedActorImplicitStorageInit(
ConstructorDecl *ctor, ManagedValue selfArg) {
VarDecl *selfVarDecl = ctor->getImplicitSelfDecl();
auto *dc = ctor->getDeclContext();
auto classDecl = dc->getSelfClassDecl();
auto &C = classDecl->getASTContext();
// Only designated initializers get the lifecycle handling injected
if (!ctor->isDesignatedInit())
return;
SILLocation prologueLoc = RegularLocation(ctor);
prologueLoc.markAsPrologue(); // TODO: no idea if this is necessary or makes sense
auto transportTy = C.getActorTransportType();
auto identityProtoTy = C.getActorIdentityType();
auto anyIdentityTy = C.getAnyActorIdentityType();
// ==== Find the stored properties we will initialize
VarDecl *transportMember = nullptr;
VarDecl *idMember = nullptr;
auto borrowedSelfArg = selfArg.borrow(*this, prologueLoc);
// TODO(distributed): getStoredProperties might be better here, avoid the `break;`
for (auto member : classDecl->getMembers()) {
PatternBindingDecl *pbd = dyn_cast<PatternBindingDecl>(member);
if (!pbd) continue;
if (pbd->isStatic()) continue;
Pattern *pattern = pbd->getPattern(0);
VarDecl *var = pbd->getSingleVar();
if (!var) continue;
if (var->getName() == C.Id_actorTransport &&
var->getInterfaceType()->isEqual(transportTy)) {
transportMember = var;
// TODO(distributed): reuse emitDistributedActorStore_transport
emitDistributedActor_init_transportStore(
*this, borrowedSelfArg, selfVarDecl, ctor, pattern, var);
} else if (var->getName() == C.Id_id &&
(var->getInterfaceType()->isEqual(identityProtoTy) ||
var->getInterfaceType()->isEqual(anyIdentityTy))) { // TODO(distributed): stick one way to store, but today we can't yet store the existential
idMember = var;
emitDistributedActorStore_init_assignIdentity(
*this, borrowedSelfArg, selfVarDecl, ctor, pattern, var);
}
if (transportMember && idMember) {
break; // we found all properties we care about, break out of the loop early
}
}
assert(transportMember && "Missing DistributedActor.actorTransport member");
assert(idMember && "Missing DistributedActor.id member");
}
void SILGenFunction::emitDistributedActorReady(
ConstructorDecl *ctor, ManagedValue selfArg) {
auto *dc = ctor->getDeclContext();
auto classDecl = dc->getSelfClassDecl();
auto &C = classDecl->getASTContext();
// Only designated initializers get the lifecycle handling injected
if (!ctor->isDesignatedInit())
return;
SILLocation loc = RegularLocation(ctor);
loc.markAutoGenerated();
// === Prepare the arguments
SILValue transportArgValue = getActorTransportArgument(C, F, ctor);
SILValue selfArgValue = F.getSelfArgument();
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
ProtocolDecl *transportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
assert(distributedActorProto);
assert(transportProto);
// --- Open the transport existential
OpenedArchetypeType *Opened;
auto transportASTType = transportArgValue->getType().getASTType();
auto openedTransportType =
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
auto openedTransportSILType = F.getLoweredType(openedTransportType);
auto transportArchetypeValue = B.createOpenExistentialAddr(
loc, transportArgValue, openedTransportSILType, OpenedExistentialAccess::Immutable);
// === Make the transport.actorReady call
// --- 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 = 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 *selfTyDecl = ctor->getParent()->getSelfNominalTypeDecl();
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()); // TODO: thats just self var devl getType
auto distributedActorConfRef = module->lookupConformance(
selfTy,
distributedActorProto);
assert(!distributedActorConfRef.isInvalid() && "Missing conformance to `DistributedActor`");
// === Prepare the actorReady function
auto actorReadyMethod =
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_actorReady));
auto actorReadyRef = SILDeclRef(actorReadyMethod, SILDeclRef::Kind::Func);
auto actorReadySILTy =
getConstantInfo(getTypeExpansionContext(), actorReadyRef)
.getSILType();
auto readyWitnessMethod = B.createWitnessMethod(
loc,
/*lookupTy*/openedTransportType,
/*Conformance*/transportConfRef,
/*member*/actorReadyRef,
/*methodTy*/actorReadySILTy);
// --- prepare conformance subs
auto genericSig = actorReadyMethod->getGenericSignature();
SubstitutionMap subs =
SubstitutionMap::get(genericSig,
{openedTransportType, selfTy},
{transportConfRef, distributedActorConfRef});
// ---- actually call transport.actorReady(self)
B.createApply(
loc, readyWitnessMethod, subs,
{ selfArgValue, transportArchetypeValue});
}
/******************************************************************************/
/******************* DISTRIBUTED ACTOR RESOLVE FUNCTION ***********************/
/******************************************************************************/
/// Function body of:
/// \verbatim
/// DistributedActor.resolve(
/// _ identity: Identity,
/// using transport: ActorTransport
/// ) throws -> Self where Identity: ActorIdentity
/// \endverbatim
void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
/// NOTE: this will only be reached if the resolve function is actually
/// demanded. For example, by declaring the actor as `public` or
/// having at least one call to the resolve function.
auto &C = getASTContext();
SILLocation loc = fd;
// ==== Prepare argument references
// --- Parameter: identity
SILArgument *identityArg = F.getArgument(0);
assert(identityArg->getType().getASTType()->isEqual(C.getAnyActorIdentityType()));
// --- Parameter: transport
SILArgument *transportArg = F.getArgument(1);
assert(
transportArg->getType().getASTType()->isEqual(C.getActorTransportType()));
// --- Parameter: self
auto *selfTyDecl = fd->getParent()->getSelfNominalTypeDecl();
assert(selfTyDecl->isDistributedActor());
SILValue selfArgValue = F.getSelfArgument();
ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue);
// ==== Case 'remote') Create the remote instance
{
// ==== Create 'remote' distributed actor instance
// --- Prepare param: Self.self
// type: SpecificDistributedActor
auto returnTy = getLoweredType(
F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()));
// type: SpecificDistributedActor.Type
auto selfMetatype =
getLoweredType(F.mapTypeIntoContext(selfArg.getType().getASTType()));
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
// --- get the uninitialized allocation from the runtime system.
FullExpr scope(Cleanups, CleanupLocation(fd));
// --- Call: _distributedActorRemoteInitialize(Self.self)
auto builtinName = C.getIdentifier(
getBuiltinName(BuiltinValueKind::InitializeDistributedRemoteActor));
auto *remote = B.createBuiltin(
loc, builtinName,
/*returnTy*/returnTy,
/*subs*/ {},
{selfMetatypeValue});
// ==== Initialize distributed actor properties
// --- Store the identity: self.id = identity
emitDistributedActorStore_id(
C, *this, /*actorSelf*/remote, fd, identityArg);
// --- Store the transport: self.actorTransport = transport
emitDistributedActorStore_transport(
C, *this, /*actorSelf*/remote, fd, transportArg);
// ==== Return the fully initialized remote instance
B.createReturn(loc, remote);
}
}
/******************************************************************************/
/******************* DISTRIBUTED DEINIT: resignAddress ************************/
/******************************************************************************/
void SILGenFunction::emitDistributedActor_resignAddress(
DestructorDecl *dd, SILValue selfValue, SILBasicBlock *continueBB) {
ASTContext &ctx = getASTContext();
auto cd = cast<ClassDecl>(dd->getDeclContext());
assert(cd->isDistributedActor() &&
"only distributed actors have transport lifecycle hooks in deinit");
RegularLocation Loc(dd);
if (dd->isImplicit())
Loc.markAutoGenerated();
auto selfDecl = dd->getImplicitSelfDecl();
auto selfManagedValue = ManagedValue::forUnmanaged(selfValue);
auto selfTy = selfDecl->getType();
// ==== locate: self.id
auto idVarDeclRefs = cd->lookupDirect(ctx.Id_id);
assert(idVarDeclRefs.size() == 1);
auto *idVarDeclRef = dyn_cast<VarDecl>(idVarDeclRefs.front());
assert(idVarDeclRef);
auto idRef =
B.createRefElementAddr(Loc, selfValue, idVarDeclRef,
getLoweredType(idVarDeclRef->getType()));
// ==== locate: self.actorTransport
auto transportVarDeclRefs = cd->lookupDirect(ctx.Id_actorTransport);
assert(transportVarDeclRefs.size() == 1);
auto *transportVarDeclRef = dyn_cast<VarDecl>(transportVarDeclRefs.front());
auto transportRef =
B.createRefElementAddr(Loc, selfValue, transportVarDeclRef,
getLoweredType(transportVarDeclRef->getType()));
// locate: self.transport.resignIdentity(...)
auto *transportDecl = ctx.getActorTransportDecl();
auto resignFnDecls = transportDecl->lookupDirect(ctx.Id_resignIdentity);
assert(resignFnDecls.size() == 1);
auto *resignFnDecl = resignFnDecls.front();
auto resignFnRef = SILDeclRef(resignFnDecl);
// we only transport.resignIdentity if we are a local actor,
// and thus the address was created by transport.assignIdentity.
auto isRemoteBB = createBasicBlock();
auto isLocalBB = createBasicBlock();
// if __isRemoteActor(self) {
// ...
// } else {
// ...
// }
emitDistributedIfRemoteBranch(*this, Loc,
selfManagedValue, selfTy,
/*if remote*/isRemoteBB,
/*if local*/isLocalBB);
// if remote
// === <noop>
{
B.emitBlock(isRemoteBB);
// noop, remote actors don't do anything in their deinit
B.createBranch(Loc, continueBB);
}
// if local
// === self.transport.resignIdentity(self.address)
{
B.emitBlock(isLocalBB);
auto openedTransport =
OpenedArchetypeType::get(transportVarDeclRef->getType());
auto transportAddr = B.createOpenExistentialAddr(
Loc, /*operand=*/transportRef, getLoweredType(openedTransport),
OpenedExistentialAccess::Immutable);
auto resignFnType = SGM.M.Types.getConstantFunctionType(
TypeExpansionContext::minimal(), resignFnRef);
auto witness = B.createWitnessMethod(
Loc, openedTransport, ProtocolConformanceRef(transportDecl),
resignFnRef, SILType::getPrimitiveObjectType(resignFnType));
auto subs = SubstitutionMap::getProtocolSubstitutions(
transportDecl, openedTransport, ProtocolConformanceRef(transportDecl));
SmallVector<SILValue, 2> params;
params.push_back(idRef);
params.push_back(transportAddr); // self for the call, as last param
B.createApply(Loc, witness, subs, params);
B.createBranch(Loc, continueBB);
}
}
/******************************************************************************/
/******************* DISTRIBUTED DEINIT: class memberwise destruction *********/
/******************************************************************************/
void SILGenFunction::emitDistributedActorClassMemberDestruction(
SILLocation cleanupLoc, ManagedValue selfValue, ClassDecl *cd,
SILBasicBlock *normalMemberDestroyBB, SILBasicBlock *finishBB) {
ASTContext &ctx = getASTContext();
auto selfTy = cd->getDeclaredInterfaceType();
Scope scope(Cleanups, CleanupLocation(cleanupLoc));
auto isLocalBB = createBasicBlock();
auto remoteMemberDestroyBB = createBasicBlock();
// if __isRemoteActor(self) {
// ...
// } else {
// ...
// }
emitDistributedIfRemoteBranch(*this, cleanupLoc,
selfValue, selfTy,
/*if remote*/remoteMemberDestroyBB,
/*if local*/isLocalBB);
// // if __isRemoteActor(self)
// {
// // destroy only self.id and self.actorTransport
// }
{
B.emitBlock(remoteMemberDestroyBB);
for (VarDecl *vd : cd->getStoredProperties()) {
if (!vd->getAttrs().hasAttribute<DistributedActorIndependentAttr>())
continue;
destroyClassMember(cleanupLoc, selfValue, vd);
}
B.createBranch(cleanupLoc, finishBB);
}
// // else (local distributed actor)
// {
// <continue normal deinit>
// }
{
B.emitBlock(isLocalBB);
B.createBranch(cleanupLoc, normalMemberDestroyBB);
}
}
/******************************************************************************/
/***************************** DISTRIBUTED THUNKS *****************************/
/******************************************************************************/
void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
// Check if actor is local or remote and call respective function
//
// func X_distributedThunk(...) async throws -> T {
// if __isRemoteActor(self) {
// return try await self._remote_X(...)
// } else {
// return try await self.X(...)
// }
// }
//
assert(thunk.isDistributed);
SILDeclRef native = thunk.asDistributed(false);
auto fd = cast<AbstractFunctionDecl>(thunk.getDecl());
ASTContext &ctx = getASTContext();
// Use the same generic environment as the native entry point.
F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native));
auto loc = thunk.getAsRegularLocation();
loc.markAutoGenerated();
Scope scope(Cleanups, CleanupLocation(loc));
auto isRemoteBB = createBasicBlock();
auto isLocalBB = createBasicBlock();
auto localErrorBB = createBasicBlock();
auto remoteErrorBB = createBasicBlock();
auto localReturnBB = createBasicBlock();
auto remoteReturnBB = createBasicBlock();
auto errorBB = createBasicBlock();
auto returnBB = createBasicBlock();
auto methodTy = SGM.Types.getConstantOverrideType(getTypeExpansionContext(),
thunk);
auto derivativeFnSILTy = SILType::getPrimitiveObjectType(methodTy);
auto silFnType = derivativeFnSILTy.castTo<SILFunctionType>();
SILFunctionConventions fnConv(silFnType, SGM.M);
auto resultType = fnConv.getSILResultType(getTypeExpansionContext());
auto *selfVarDecl = fd->getImplicitSelfDecl();
SmallVector<SILValue, 8> params;
bindParametersForForwarding(fd->getParameters(), params);
bindParameterForForwarding(selfVarDecl, params);
auto selfValue = ManagedValue::forUnmanaged(params[params.size() - 1]); // TODO(distributed): getSelfArgument instead
auto selfTy = selfVarDecl->getType();
// if __isRemoteActor(self) {
// ...
// } else {
// ...
// }
{
FuncDecl* isRemoteFn = ctx.getIsRemoteDistributedActor();
assert(isRemoteFn &&
"Could not find 'is remote' function, is the '_Distributed' module available?");
ManagedValue selfAnyObject = B.createInitExistentialRef(
loc, getLoweredType(ctx.getAnyObjectType()),
CanType(selfTy), selfValue, {});
auto result = emitApplyOfLibraryIntrinsic(
loc, isRemoteFn, SubstitutionMap(),
{selfAnyObject}, SGFContext());
SILValue isRemoteResult = std::move(result).forwardAsSingleValue(*this, loc);
SILValue isRemoteResultUnwrapped = emitUnwrapIntegerResult(loc, isRemoteResult);
B.createCondBranch(loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
}
// // if __isRemoteActor(self)
// {
// return try await self._remote_X(...)
// }
{
B.emitBlock(isRemoteBB);
auto *selfTyDecl = FunctionDC->getParent()->getSelfNominalTypeDecl();
assert(selfTyDecl && "distributed function declared outside of actor");
auto remoteFnDecl = selfTyDecl->lookupDirectRemoteFunc(fd);
assert(remoteFnDecl && "Could not find _remote_<dist_func_name> function");
auto remoteFnRef = SILDeclRef(remoteFnDecl);
SILGenFunctionBuilder builder(SGM);
auto remoteFnSIL = builder.getOrCreateFunction(loc, remoteFnRef, ForDefinition);
SILValue remoteFn = B.createFunctionRefFor(loc, remoteFnSIL);
auto subs = F.getForwardingSubstitutionMap();
SmallVector<SILValue, 8> remoteParams(params);
B.createTryApply(loc, remoteFn, subs, remoteParams, remoteReturnBB, remoteErrorBB);
}
// // else
// {
// return (try)? (await)? self.X(...)
// }
{
B.emitBlock(isLocalBB);
auto nativeMethodTy = SGM.Types.getConstantOverrideType(getTypeExpansionContext(),
native);
auto nativeFnSILTy = SILType::getPrimitiveObjectType(nativeMethodTy);
auto nativeSilFnType = nativeFnSILTy.castTo<SILFunctionType>();
SILValue nativeFn = emitClassMethodRef(
loc, params[params.size() - 1], native, nativeMethodTy);
auto subs = F.getForwardingSubstitutionMap();
if (nativeSilFnType->hasErrorResult()) {
B.createTryApply(loc, nativeFn, subs, params, localReturnBB, localErrorBB);
} else {
auto result = B.createApply(loc, nativeFn, subs, params);
B.createBranch(loc, returnBB, {result});
}
}
// TODO(distributed): to use a emitAndBranch local function, since these four blocks are so similar
{
B.emitBlock(remoteErrorBB);
SILValue error = remoteErrorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);
B.createBranch(loc, errorBB, {error});
}
{
B.emitBlock(localErrorBB);
SILValue error = localErrorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);
B.createBranch(loc, errorBB, {error});
}
{
B.emitBlock(remoteReturnBB);
SILValue result = remoteReturnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createBranch(loc, returnBB, {result});
}
{
B.emitBlock(localReturnBB);
SILValue result = localReturnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createBranch(loc, returnBB, {result});
}
// Emit return logic
{
B.emitBlock(returnBB);
SILValue resArg = returnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createReturn(loc, resArg);
}
// Emit the rethrow logic.
{
B.emitBlock(errorBB);
SILValue error = errorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);
Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind);
B.createThrow(loc, error);
}
}