Skip to content

Commit 8432f94

Browse files
committed
(rdar://87412308) fix missing actor hop for global-actor isolated inits of an actor type.
For global-actor isolated async inits within an actor, we will have separate restrictions on access to self's differently-isolated stored properties to prevent data races. But, we also must be on the global actor while in such initializers. The problem was only that the prologue was missing a hop because of a bad conditional check. Previously the check assumed that actors cannot have global-actor isolated initializers, but they can currently.
1 parent 4f28b87 commit 8432f94

File tree

2 files changed

+83
-7
lines changed

2 files changed

+83
-7
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,34 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
315315
return;
316316
}
317317

318+
/// Returns true if the given async constructor will have its
319+
/// required actor hops injected later by definite initialization.
320+
static bool ctorHopsInjectedByDefiniteInit(ConstructorDecl *ctor,
321+
ActorIsolation const& isolation) {
322+
// must be async, but we can assume that.
323+
assert(ctor->hasAsync());
324+
325+
auto *dc = ctor->getDeclContext();
326+
auto selfClassDecl = dc->getSelfClassDecl();
327+
328+
// must be an actor
329+
if (!selfClassDecl || !selfClassDecl->isAnyActor())
330+
return false;
331+
332+
// must be instance isolated
333+
switch (isolation) {
334+
case ActorIsolation::ActorInstance:
335+
case ActorIsolation::DistributedActorInstance:
336+
return true;
337+
338+
case ActorIsolation::Unspecified:
339+
case ActorIsolation::Independent:
340+
case ActorIsolation::GlobalActor:
341+
case ActorIsolation::GlobalActorUnsafe:
342+
return false;
343+
}
344+
}
345+
318346
void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
319347
MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);
320348

@@ -360,9 +388,13 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
360388

361389
// Make sure we've hopped to the right global actor, if any.
362390
if (ctor->hasAsync()) {
363-
SILLocation prologueLoc(selfDecl);
364-
prologueLoc.markAsPrologue();
365-
emitConstructorPrologActorHop(prologueLoc, getActorIsolation(ctor));
391+
auto isolation = getActorIsolation(ctor);
392+
// if it's not injected by definite init, we do it in the prologue now.
393+
if (!ctorHopsInjectedByDefiniteInit(ctor, isolation)) {
394+
SILLocation prologueLoc(selfDecl);
395+
prologueLoc.markAsPrologue();
396+
emitConstructorPrologActorHop(prologueLoc, isolation);
397+
}
366398
}
367399

368400
// Create a basic block to jump to for the implicit 'self' return.
@@ -754,10 +786,14 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
754786
selfClassDecl->isDistributedActor() && !isDelegating;
755787

756788
// Make sure we've hopped to the right global actor, if any.
757-
if (ctor->hasAsync() && !selfClassDecl->isActor()) {
758-
SILLocation prologueLoc(selfDecl);
759-
prologueLoc.markAsPrologue();
760-
emitConstructorPrologActorHop(prologueLoc, getActorIsolation(ctor));
789+
if (ctor->hasAsync()) {
790+
auto isolation = getActorIsolation(ctor);
791+
// if it's not injected by definite init, we do it in the prologue now.
792+
if (!ctorHopsInjectedByDefiniteInit(ctor, isolation)) {
793+
SILLocation prologueLoc(selfDecl);
794+
prologueLoc.markAsPrologue();
795+
emitConstructorPrologActorHop(prologueLoc, isolation);
796+
}
761797
}
762798

763799
if (!NeedsBoxForSelf) {

test/SILGen/hop_to_executor.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -disable-availability-checking | %FileCheck --enable-var-scope %s --implicit-check-not 'hop_to_executor {{%[0-9]+}}'
22
// REQUIRES: concurrency
33

4+
func unspecifiedAsync() async {}
45

56
actor MyActor {
67

@@ -75,6 +76,45 @@ actor MyActor {
7576
init() {
7677
p = 27
7778
}
79+
80+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC4withACSi_tYacfc : $@convention(method) @async (Int, @owned MyActor) -> @owned MyActor {
81+
// CHECK: bb0({{%[0-9]+}} : $Int, {{%[0-9]+}} : @owned $MyActor):
82+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
83+
// CHECK: builtin "initializeDefaultActor"
84+
// CHECK: [[FUNC:%[0-9]+]] = function_ref @$s4test16unspecifiedAsyncyyYaF : $@convention(thin) @async () -> ()
85+
// CHECK: %24 = apply [[FUNC]]() : $@convention(thin) @async () -> ()
86+
// CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $MainActor
87+
// CHECK: } // end sil function '$s4test7MyActorC4withACSi_tYacfc'
88+
@MainActor
89+
init(with v: Int) async {
90+
p = 1
91+
await unspecifiedAsync()
92+
p = 2
93+
}
94+
95+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC10delegatingACSb_tYacfC : $@convention(method) @async (Bool, @thick MyActor.Type) -> @owned MyActor {
96+
// ** first hop is in the prologue
97+
// CHECK: bb0({{%[0-9]+}} : $Bool, {{%[0-9]+}} : $@thick MyActor.Type):
98+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
99+
// CHECK: struct_extract {{%[0-9]+}} : $Bool, #Bool._value
100+
// CHECK: cond_br
101+
// ** second hop is right after delegating to the async init
102+
// CHECK: = apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(method) @async (Int, @thick MyActor.Type) -> @owned MyActor
103+
// CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $MainActor
104+
// ** third hop is right after calling an arbitrary async function
105+
// CHECK: [[FUNC:%[0-9]+]] = function_ref @$s4test16unspecifiedAsyncyyYaF : $@convention(thin) @async () -> ()
106+
// CHECK: = apply [[FUNC]]() : $@convention(thin) @async () -> ()
107+
// CHECK-NEXT: hop_to_executor %9 : $MainActor
108+
// CHECK: } // end sil function '$s4test7MyActorC10delegatingACSb_tYacfC'
109+
@MainActor
110+
convenience init(delegating c: Bool) async {
111+
if c {
112+
self.init()
113+
} else {
114+
await self.init(with: 0)
115+
}
116+
await unspecifiedAsync()
117+
}
78118
}
79119

80120
@globalActor

0 commit comments

Comments
 (0)