mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
basic implementation of performing an init of the id after an assign of the actorSystem.
The resignID call within the initializer moved into DI, because an assignment to the actorSystem, and thus initialization of the id, is no longer guaranteed to happen. Thus, while we previously could model the resignation as a clean-up emitted on all unwind paths in an initializer, now it's conditional, based on whether the id was initialized. This is exactly what DI is designed to do, so we inject the resignation call just before we call the identity's deinit.
This commit is contained in:
@@ -137,24 +137,24 @@ static SILArgument *findFirstDistributedActorSystemArg(SILFunction &F) {
|
||||
auto *module = F.getModule().getSwiftModule();
|
||||
auto &C = F.getASTContext();
|
||||
|
||||
auto *transportProto = C.getProtocol(KnownProtocolKind::DistributedActorSystem);
|
||||
Type transportTy = transportProto->getDeclaredInterfaceType();
|
||||
auto *DAS = C.getDistributedActorSystemDecl();
|
||||
Type systemTy = DAS->getDeclaredInterfaceType();
|
||||
|
||||
for (auto arg : F.getArguments()) {
|
||||
// TODO(distributed): also be able to locate a generic transport
|
||||
// TODO(distributed): also be able to locate a generic system
|
||||
Type argTy = arg->getType().getASTType();
|
||||
auto argDecl = arg->getDecl();
|
||||
|
||||
auto conformsToTransport =
|
||||
module->lookupConformance(argDecl->getInterfaceType(), transportProto);
|
||||
auto conformsToSystem =
|
||||
module->lookupConformance(argDecl->getInterfaceType(), DAS);
|
||||
|
||||
// Is it a protocol that conforms to DistributedActorSystem?
|
||||
if (argTy->isEqual(transportTy) || conformsToTransport) {
|
||||
if (argTy->isEqual(systemTy) || conformsToSystem) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
// Is it some specific DistributedActorSystem?
|
||||
auto result = module->lookupConformance(argTy, transportProto);
|
||||
auto result = module->lookupConformance(argTy, DAS);
|
||||
if (!result.isInvalid()) {
|
||||
return arg;
|
||||
}
|
||||
@@ -172,7 +172,8 @@ static SILArgument *findFirstDistributedActorSystemArg(SILFunction &F) {
|
||||
static void emitActorSystemInit(SILGenFunction &SGF,
|
||||
ConstructorDecl *ctor,
|
||||
SILLocation loc,
|
||||
ManagedValue actorSelf) {
|
||||
ManagedValue actorSelf,
|
||||
SILValue systemValue) {
|
||||
assert(ctor->isImplicit() && "unexpected explicit dist actor init");
|
||||
assert(ctor->isDesignatedInit());
|
||||
|
||||
@@ -183,11 +184,10 @@ static void emitActorSystemInit(SILGenFunction &SGF,
|
||||
// By construction, automatically generated distributed actor ctors have
|
||||
// exactly one ActorSystem-conforming argument to the constructor,
|
||||
// so we grab the first one from the params.
|
||||
SILValue systemArg = findFirstDistributedActorSystemArg(SGF.F);
|
||||
VarDecl *var = lookupProperty(classDecl, C.Id_actorSystem);
|
||||
assert(var);
|
||||
|
||||
initializeProperty(SGF, loc, actorSelf.getValue(), var, systemArg);
|
||||
initializeProperty(SGF, loc, actorSelf.getValue(), var, systemValue);
|
||||
}
|
||||
|
||||
/// Emits the distributed actor's identity (`id`) initialization.
|
||||
@@ -196,72 +196,98 @@ static void emitActorSystemInit(SILGenFunction &SGF,
|
||||
/// \verbatim
|
||||
/// self.id = system.assignID(Self.self)
|
||||
/// \endverbatim
|
||||
static void emitIDInit(SILGenFunction &SGF, ConstructorDecl *ctor,
|
||||
SILLocation loc, ManagedValue borrowedSelfArg) {
|
||||
assert(ctor->isImplicit() && "unexpected explicit dist actor init");
|
||||
void SILGenFunction::emitDistActorIdentityInit(ConstructorDecl *ctor,
|
||||
SILLocation loc,
|
||||
SILValue borrowedSelfArg,
|
||||
SILValue actorSystem) {
|
||||
assert(ctor->isDesignatedInit());
|
||||
|
||||
auto &C = ctor->getASTContext();
|
||||
auto &B = SGF.B;
|
||||
auto &F = SGF.F;
|
||||
|
||||
auto *dc = ctor->getDeclContext();
|
||||
auto classDecl = dc->getSelfClassDecl();
|
||||
|
||||
assert(classDecl->isDistributedActor());
|
||||
|
||||
// --- prepare `Self.self` metatype
|
||||
auto *selfTyDecl = ctor->getParent()->getSelfNominalTypeDecl();
|
||||
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType());
|
||||
auto selfMetatype = SGF.getLoweredType(MetatypeType::get(selfTy));
|
||||
auto selfMetatype = getLoweredType(MetatypeType::get(selfTy));
|
||||
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
|
||||
|
||||
// since we're doing this only for the implicitly defined ctors, grab from arg
|
||||
SILValue actorSystem = findFirstDistributedActorSystemArg(SGF.F);
|
||||
|
||||
// --- create a temporary storage for the result of the call
|
||||
// it will be deallocated automatically as we exit this scope
|
||||
VarDecl *var = lookupProperty(classDecl, C.Id_id);
|
||||
auto resultTy = SGF.getLoweredType(
|
||||
F.mapTypeIntoContext(var->getInterfaceType()));
|
||||
auto temp = SGF.emitTemporaryAllocation(loc, resultTy);
|
||||
auto resultTy = getLoweredType(F.mapTypeIntoContext(var->getInterfaceType()));
|
||||
auto temp = emitTemporaryAllocation(loc, resultTy);
|
||||
|
||||
// --- emit the call itself.
|
||||
emitDistributedActorSystemWitnessCall(
|
||||
B, loc, C.Id_assignID,
|
||||
actorSystem, SGF.getLoweredType(selfTy),
|
||||
actorSystem, getLoweredType(selfTy),
|
||||
{ temp, selfMetatypeValue });
|
||||
|
||||
// --- initialize the property.
|
||||
initializeProperty(SGF, loc, borrowedSelfArg.getValue(), var, temp);
|
||||
initializeProperty(*this, loc, borrowedSelfArg, var, temp);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Cleanup to resign the identity of a distributed actor if an abnormal exit happens.
|
||||
class ResignIdentity : public Cleanup {
|
||||
ClassDecl *actorDecl;
|
||||
SILValue self;
|
||||
public:
|
||||
ResignIdentity(ClassDecl *actorDecl, SILValue self)
|
||||
: actorDecl(actorDecl), self(self) {
|
||||
assert(actorDecl->isDistributedActor());
|
||||
}
|
||||
InitializeDistActorIdentity::InitializeDistActorIdentity(ConstructorDecl *ctor,
|
||||
ManagedValue actorSelf)
|
||||
: ctor(ctor),
|
||||
actorSelf(actorSelf) {
|
||||
systemVar = ctor->getDeclContext()
|
||||
->getSelfClassDecl()
|
||||
->getDistributedActorSystemProperty();
|
||||
assert(systemVar);
|
||||
}
|
||||
|
||||
void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override {
|
||||
if (forUnwind == IsForUnwind) {
|
||||
l.markAutoGenerated();
|
||||
SGF.emitDistributedActorSystemResignIDCall(l, actorDecl,
|
||||
ManagedValue::forUnmanaged(self));
|
||||
}
|
||||
void InitializeDistActorIdentity::emit(SILGenFunction &SGF, CleanupLocation loc,
|
||||
ForUnwind_t forUnwind) {
|
||||
|
||||
// If we're unwinding, that must mean we're in the case where the
|
||||
// evaluating the expression being assigned to the actorSystem has
|
||||
// thrown an error. In that case, we cannot initialize the identity,
|
||||
// since there is no actorSystem.
|
||||
if (forUnwind == IsForUnwind)
|
||||
return;
|
||||
|
||||
|
||||
// Save the current clean-up depth
|
||||
auto baseDepth = SGF.getCleanupsDepth();
|
||||
{
|
||||
loc.markAutoGenerated();
|
||||
auto borrowedSelf = actorSelf.borrow(SGF, loc);
|
||||
|
||||
// load the actorSystem value
|
||||
Type formalType = SGF.F.mapTypeIntoContext(systemVar->getInterfaceType());
|
||||
SILType loweredType = SGF.getLoweredType(formalType).getAddressType();
|
||||
auto ref =
|
||||
SGF.B.createRefElementAddr(loc, borrowedSelf, systemVar, loweredType);
|
||||
|
||||
SGFContext ctx;
|
||||
auto systemVal =
|
||||
SGF.emitLoad(loc, ref.getValue(),
|
||||
SGF.getTypeLowering(loweredType), ctx, IsNotTake);
|
||||
|
||||
// Important that we mark the location as auto-generated, since the id
|
||||
// is a @_compilerInitialized field.
|
||||
SGF.emitDistActorIdentityInit(ctor, loc,
|
||||
borrowedSelf.getValue(), systemVal.getValue());
|
||||
}
|
||||
|
||||
void dump(SILGenFunction &SGF) const override {
|
||||
// Emit any active clean-ups we just pushed.
|
||||
while (SGF.getTopCleanup() != baseDepth)
|
||||
SGF.Cleanups.popAndEmitCleanup(SGF.getTopCleanup(), loc, forUnwind);
|
||||
|
||||
}
|
||||
|
||||
void InitializeDistActorIdentity::dump(SILGenFunction &) const {
|
||||
#ifndef NDEBUG
|
||||
llvm::errs() << "ResignIdentity "
|
||||
<< "State:" << getState() << " "
|
||||
<< "Self: " << self << "\n";
|
||||
llvm::errs() << "InitializeDistActorIdentity\n"
|
||||
<< "State: " << getState()
|
||||
<< "\n";
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
}
|
||||
|
||||
void SILGenFunction::emitDistributedActorImplicitPropertyInits(
|
||||
ConstructorDecl *ctor, ManagedValue selfArg) {
|
||||
@@ -273,18 +299,18 @@ void SILGenFunction::emitDistributedActorImplicitPropertyInits(
|
||||
|
||||
selfArg = selfArg.borrow(*this, loc);
|
||||
|
||||
// register a clean-up to resign the identity upon abnormal exit
|
||||
// we do this regardless of initializer kind, since it's easy to do in SILGen.
|
||||
auto *actorDecl = cast<ClassDecl>(ctor->getParent()->getAsDecl());
|
||||
Cleanups.pushCleanup<ResignIdentity>(actorDecl, selfArg.getValue());
|
||||
|
||||
// Users must initialize the actorSystem property explicitly in their ctors
|
||||
if (!ctor->isImplicit())
|
||||
// implicit ctors initialize the system and identity from
|
||||
// its ActorSystem parameter.
|
||||
if (ctor->isImplicit()) {
|
||||
SILValue actorSystem = findFirstDistributedActorSystemArg(F);
|
||||
emitActorSystemInit(*this, ctor, loc, selfArg, actorSystem);
|
||||
emitDistActorIdentityInit(ctor, loc, selfArg.getValue(), actorSystem);
|
||||
return;
|
||||
}
|
||||
|
||||
// implicit ctors initialize these from the ActorSystem parameter.
|
||||
emitActorSystemInit(*this, ctor, loc, selfArg);
|
||||
emitIDInit(*this, ctor, loc, selfArg);
|
||||
// for explicit ctors, store (but do not push) a clean-up that will
|
||||
// initialize the identity in whichever scope it's pushed to.
|
||||
DistActorCtorContext = InitializeDistActorIdentity(ctor, selfArg);
|
||||
}
|
||||
|
||||
void SILGenFunction::emitDistributedActorReady(
|
||||
@@ -505,7 +531,7 @@ SILGenFunction::emitConditionalResignIdentityCall(SILLocation loc,
|
||||
ManagedValue actorSelf,
|
||||
SILBasicBlock *continueBB) {
|
||||
assert(actorDecl->isDistributedActor() &&
|
||||
"only distributed actors have transport lifecycle hooks in deinit");
|
||||
"only distributed actors have actorSystem lifecycle hooks in deinit");
|
||||
|
||||
auto selfTy = actorDecl->getDeclaredInterfaceType();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user