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:
Kavon Farvardin
2022-03-15 18:20:00 -07:00
parent 13cbe0dd15
commit af683dc271
25 changed files with 290 additions and 117 deletions

View File

@@ -788,48 +788,14 @@ void LifetimeChecker::diagnoseBadExplicitStore(SILInstruction *Inst) {
/// Determines whether the given function is a constructor that belogs to a
/// distributed actor declaration.
static bool isDistributedActorCtor(SILFunction &F) {
/// \returns nullptr if false, and the class decl for the actor otherwise.
static ClassDecl* getDistributedActorOfCtor(SILFunction &F) {
auto *context = F.getDeclContext();
if (auto *ctor = dyn_cast_or_null<ConstructorDecl>(context->getAsDecl()))
if (auto *cls = dyn_cast<ClassDecl>(ctor->getDeclContext()->getAsDecl()))
return cls->isDistributedActor();
return false;
}
//static SILValue emitActorPropertyReference(
// SILGenFunction &SGF, SILLocation loc, SILValue actorSelf,
// VarDecl *property) {
// Type formalType = SGF.F.mapTypeIntoContext(property->getInterfaceType());
// SILType loweredType = SGF.getLoweredType(formalType).getAddressType();
// return SGF.B.createRefElementAddr(loc, actorSelf, property, loweredType);
//}
/// Creates a reference to the distributed actor's \p actorSystem
/// stored property.
static SILValue refDistributedActorSystem(SILLocation loc,
SILBuilder &b,
SILValue actorInstance,
SILFunction &F) {
ClassDecl *clsDecl = F.getDeclContext()->getSelfClassDecl();
assert(clsDecl->isDistributedActor());
// get the VarDecl corresponding to the actorSystem.
auto refs = clsDecl->lookupDirect(clsDecl->getASTContext().Id_actorSystem);
assert(refs.size() == 1);
VarDecl *actorSystemVar = dyn_cast<VarDecl>(refs.front());
return b.createRefElementAddr(loc, actorInstance, actorSystemVar);
}
static void loadCopyWithCleanups(SILLocation loc, SILBuilder& b, SILValue ref,
llvm::function_ref<void(SILValue)> scope) {
auto copy = b.createLoad(loc, ref, LoadOwnershipQualifier::Copy);
auto borrow = b.createBeginBorrow(loc, copy);
scope(borrow);
b.createEndBorrow(loc, borrow);
b.createDestroyValue(loc, copy);
if (cls->isDistributedActor())
return cls;
return nullptr;
}
/// Injects a hop_to_executor instruction after the specified insertion point.
@@ -854,6 +820,7 @@ static void injectHopToExecutorAfter(SILLocation loc,
SILLocation genLoc = loc.asAutoGenerated();
const bool delegating = !TheMemory.isNonDelegatingInit();
SILValue val = TheMemory.getUninitializedValue();
auto &F = b.getFunction();
// delegating inits always have an alloc we need to load it from.
if (delegating)
@@ -861,16 +828,16 @@ static void injectHopToExecutorAfter(SILLocation loc,
SILValue actor = b.createBeginBorrow(genLoc, val);
b.createHopToExecutor(loc.asAutoGenerated(), actor, /*mandatory=*/false);
b.createHopToExecutor(genLoc, actor, /*mandatory=*/false);
// Distributed actors also need to notify their transport immediately
// after performing the hop.
if (!delegating && isDistributedActorCtor(b.getFunction())) {
SILValue systemRef = refDistributedActorSystem(loc.asAutoGenerated(),
b, actor, b.getFunction());
loadCopyWithCleanups(genLoc, b, systemRef, [&](SILValue systemVal) {
emitActorReadyCall(b, genLoc, actor, systemVal);
});
if (!delegating) {
if (auto *actorDecl = getDistributedActorOfCtor(F)) {
SILValue systemRef = refDistributedActorSystem(b, genLoc,
actorDecl, actor);
emitActorReadyCall(b, genLoc, actor, systemRef);
}
}
b.createEndBorrow(genLoc, actor);