Skip to content

Commit f002391

Browse files
committed
[silgen] Teach SILGen how to handle nonisolated(nonsending) thunking for vtables
This ensures that when we generate the vtable thunk for a nonisolated(nonsending) override (or vis-a-versa), we get the ABI correct. I also added tests for all of the relevant cases for vtables that we check for protocols. rdar://151394209 (cherry picked from commit ef23f97)
1 parent 27cf336 commit f002391

File tree

3 files changed

+164
-13
lines changed

3 files changed

+164
-13
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,8 +2624,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
26242624
void collectThunkParams(
26252625
SILLocation loc, SmallVectorImpl<ManagedValue> &params,
26262626
SmallVectorImpl<ManagedValue> *indirectResultParams = nullptr,
2627-
SmallVectorImpl<ManagedValue> *indirectErrorParams = nullptr,
2628-
ThunkGenOptions options = {});
2627+
SmallVectorImpl<ManagedValue> *indirectErrorParams = nullptr);
26292628

26302629
/// Build the type of a function transformation thunk.
26312630
CanSILFunctionType buildThunkType(CanSILFunctionType &sourceType,

lib/SILGen/SILGenPoly.cpp

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple,
986986
void SILGenFunction::collectThunkParams(
987987
SILLocation loc, SmallVectorImpl<ManagedValue> &params,
988988
SmallVectorImpl<ManagedValue> *indirectResults,
989-
SmallVectorImpl<ManagedValue> *indirectErrors, ThunkGenOptions options) {
989+
SmallVectorImpl<ManagedValue> *indirectErrors) {
990990
// Add the indirect results.
991991
for (auto resultTy : F.getConventions().getIndirectSILResultTypes(
992992
getTypeExpansionContext())) {
@@ -5464,7 +5464,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
54645464

54655465
SmallVector<ManagedValue, 8> params;
54665466
SmallVector<ManagedValue, 4> indirectResultParams;
5467-
SGF.collectThunkParams(loc, params, &indirectResultParams, nullptr, options);
5467+
SGF.collectThunkParams(loc, params, &indirectResultParams);
54685468

54695469
// Ignore the self parameter at the SIL level. IRGen will use it to
54705470
// recover type metadata.
@@ -6945,10 +6945,6 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
69456945
cleanupLoc.markAutoGenerated();
69466946
Scope scope(Cleanups, cleanupLoc);
69476947

6948-
SmallVector<ManagedValue, 8> thunkArgs;
6949-
SmallVector<ManagedValue, 8> thunkIndirectResults;
6950-
collectThunkParams(loc, thunkArgs, &thunkIndirectResults);
6951-
69526948
CanSILFunctionType derivedFTy;
69536949
if (baseLessVisibleThanDerived) {
69546950
derivedFTy =
@@ -6973,16 +6969,41 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
69736969
->substGenericArgs(subs)->getCanonicalType());
69746970
}
69756971

6976-
// Emit the indirect return and arguments.
69776972
auto thunkTy = F.getLoweredFunctionType();
69786973

6979-
SmallVector<ManagedValue, 8> substArgs;
6974+
using ThunkGenFlag = SILGenFunction::ThunkGenFlag;
6975+
auto options = SILGenFunction::ThunkGenOptions();
69806976

6977+
{
6978+
auto thunkIsolatedParam = thunkTy->maybeGetIsolatedParameter();
6979+
if (thunkIsolatedParam &&
6980+
thunkIsolatedParam->hasOption(SILParameterInfo::ImplicitLeading))
6981+
options |= ThunkGenFlag::ThunkHasImplicitIsolatedParam;
6982+
auto derivedIsolatedParam = derivedFTy->maybeGetIsolatedParameter();
6983+
if (derivedIsolatedParam &&
6984+
derivedIsolatedParam->hasOption(SILParameterInfo::ImplicitLeading))
6985+
options |= ThunkGenFlag::CalleeHasImplicitIsolatedParam;
6986+
}
6987+
6988+
SmallVector<ManagedValue, 8> thunkArgs;
6989+
SmallVector<ManagedValue, 8> thunkIndirectResults;
6990+
collectThunkParams(loc, thunkArgs, &thunkIndirectResults);
6991+
6992+
// Emit the indirect return and arguments.
6993+
SmallVector<ManagedValue, 8> substArgs;
69816994
AbstractionPattern outputOrigType(outputSubstType);
69826995

6996+
auto derivedFTyParamInfo = derivedFTy->getParameters();
6997+
6998+
// If we are transforming to a callee with an implicit param, drop the
6999+
// implicit param so that we can insert it again later. This ensures
7000+
// TranslateArguments does not need to know about this.
7001+
if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam))
7002+
derivedFTyParamInfo = derivedFTyParamInfo.drop_front();
7003+
69837004
// Reabstract the arguments.
69847005
TranslateArguments(*this, loc, thunkArgs, substArgs,
6985-
derivedFTy, derivedFTy->getParameters())
7006+
derivedFTy, derivedFTyParamInfo)
69867007
.process(outputOrigType,
69877008
outputSubstType.getParams(),
69887009
inputOrigType,
@@ -7012,8 +7033,61 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70127033
}
70137034
}
70147035

7036+
// Now that we have translated arguments and inserted our thunk indirect
7037+
// parameters... before we forward those arguments, insert the implicit
7038+
// leading parameter.
7039+
if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
7040+
auto baseIsolation =
7041+
swift::getActorIsolation(base.getAbstractFunctionDecl());
7042+
switch (baseIsolation) {
7043+
case ActorIsolation::Unspecified:
7044+
case ActorIsolation::Nonisolated:
7045+
case ActorIsolation::NonisolatedUnsafe:
7046+
args.push_back(emitNonIsolatedIsolation(loc).getValue());
7047+
break;
7048+
case ActorIsolation::Erased:
7049+
llvm::report_fatal_error("Found erased actor isolation?!");
7050+
break;
7051+
case ActorIsolation::GlobalActor: {
7052+
auto globalActor = baseIsolation.getGlobalActor()->getCanonicalType();
7053+
args.push_back(emitGlobalActorIsolation(loc, globalActor).getValue());
7054+
break;
7055+
}
7056+
case ActorIsolation::ActorInstance:
7057+
case ActorIsolation::CallerIsolationInheriting: {
7058+
auto derivedIsolation =
7059+
swift::getActorIsolation(derived.getAbstractFunctionDecl());
7060+
switch (derivedIsolation) {
7061+
case ActorIsolation::Unspecified:
7062+
case ActorIsolation::Nonisolated:
7063+
case ActorIsolation::NonisolatedUnsafe:
7064+
args.push_back(emitNonIsolatedIsolation(loc).getValue());
7065+
break;
7066+
case ActorIsolation::Erased:
7067+
llvm::report_fatal_error("Found erased actor isolation?!");
7068+
break;
7069+
case ActorIsolation::GlobalActor: {
7070+
auto globalActor =
7071+
derivedIsolation.getGlobalActor()->getCanonicalType();
7072+
args.push_back(emitGlobalActorIsolation(loc, globalActor).getValue());
7073+
break;
7074+
}
7075+
case ActorIsolation::ActorInstance:
7076+
case ActorIsolation::CallerIsolationInheriting: {
7077+
auto isolatedArg = F.maybeGetIsolatedArgument();
7078+
assert(isolatedArg);
7079+
args.push_back(isolatedArg);
7080+
break;
7081+
}
7082+
}
7083+
break;
7084+
}
7085+
}
7086+
}
7087+
70157088
// Then, the arguments.
7016-
forwardFunctionArguments(*this, loc, derivedFTy, substArgs, args);
7089+
forwardFunctionArguments(*this, loc, derivedFTy, substArgs, args,
7090+
options);
70177091

70187092
// Create the call.
70197093
SILValue derivedRef;
@@ -7316,7 +7390,7 @@ void SILGenFunction::emitProtocolWitness(
73167390

73177391
SmallVector<ManagedValue, 8> origParams;
73187392
SmallVector<ManagedValue, 8> thunkIndirectResults;
7319-
collectThunkParams(loc, origParams, &thunkIndirectResults, nullptr, options);
7393+
collectThunkParams(loc, origParams, &thunkIndirectResults);
73207394

73217395
if (witness.getDecl()->requiresUnavailableDeclABICompatibilityStubs())
73227396
emitApplyOfUnavailableCodeReached();
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -DSWIFT_FIVE | %FileCheck --implicit-check-not=thunk %s
2+
// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple | %FileCheck --implicit-check-not=thunk %s
3+
4+
// REQUIRES: asserts
5+
// REQUIRES: concurrency
6+
7+
// We should only produce thunks when going to/from nonisolated(nonsending)
8+
// since that is the only thing that makes a true ABI change since we have an
9+
// extra parameter. For isolation purposes, we can rely on async functions
10+
// hopping in their prolog and not need a thunk for the purposes of isolation changing.
11+
12+
// NOTE: We use implicit-check-not to make sure we do not create any other
13+
// thunks beyond the ones we pattern match.
14+
15+
class SuperKlass {
16+
nonisolated(nonsending) func callerTest() async {}
17+
@concurrent func concurrentTest() async {}
18+
@MainActor func mainActorTest() async {}
19+
}
20+
21+
class AllDefault : SuperKlass {
22+
// This doesn't need a thunk since we infer it is nonisolated(nonsending).
23+
override func callerTest() async {}
24+
override func concurrentTest() async {}
25+
override func mainActorTest() async {}
26+
}
27+
28+
class AllConcurrent : SuperKlass {
29+
// CHECK-LABEL: vtable thunk for SuperKlass.callerTest() dispatching to AllConcurrent.callerTest()
30+
// CHECK-NEXT: sil private [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentC10callerTestyyYaFAA10SuperKlassCADyyYaFTV : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed AllConcurrent) -> () {
31+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>, [[PARAM:%.*]] : @guaranteed $AllConcurrent):
32+
// CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentC10callerTestyyYaF : $@convention(method) @async (@guaranteed AllConcurrent) -> ()
33+
// CHECK: apply [[FUNC]]([[PARAM]])
34+
// CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentC10callerTestyyYaFAA10SuperKlassCADyyYaFTV'
35+
@concurrent override func callerTest() async {}
36+
@concurrent override func concurrentTest() async {}
37+
@concurrent override func mainActorTest() async {}
38+
}
39+
40+
class AllNonIsolatedUnsafe : SuperKlass {
41+
override nonisolated(nonsending) func callerTest() async {}
42+
43+
// CHECK-LABEL: // vtable thunk for SuperKlass.concurrentTest() dispatching to AllNonIsolatedUnsafe.concurrentTest()
44+
// CHECK-NEXT: sil private [thunk] [ossa] @$s21attr_execution_silgen20AllNonIsolatedUnsafeC14concurrentTestyyYaFAA10SuperKlassCADyyYaFTV : $@convention(method) @async (@guaranteed AllNonIsolatedUnsafe) -> () {
45+
// CHECK: bb0([[ARG:%.*]] : @guaranteed
46+
// CHECK: [[ACTOR:%.*]] = enum $Optional<any Actor>, #Optional.none!enumelt
47+
// CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen20AllNonIsolatedUnsafeC14concurrentTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed AllNonIsolatedUnsafe) -> ()
48+
// CHECK: apply [[FUNC]]([[ACTOR]], [[ARG]])
49+
// CHECK: } // end sil function '$s21attr_execution_silgen20AllNonIsolatedUnsafeC14concurrentTestyyYaFAA10SuperKlassCADyyYaFTV'
50+
override nonisolated(nonsending) func concurrentTest() async {}
51+
52+
// CHECK-LABEL: // vtable thunk for SuperKlass.mainActorTest() dispatching to AllNonIsolatedUnsafe.mainActorTest()
53+
// CHECK-NEXT: sil private [thunk] [ossa] @$s21attr_execution_silgen20AllNonIsolatedUnsafeC13mainActorTestyyYaFAA10SuperKlassCADyyYaFTV : $@convention(method) @async (@guaranteed AllNonIsolatedUnsafe) -> () {
54+
// CHECK: bb0([[ARG:%.*]] : @guaranteed $AllNonIsolatedUnsafe):
55+
// CHECK: [[ACTOR:%.*]] = apply {{%.*}}({{%.*}}) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
56+
// CHECK: [[ACTOR_E:%.*]] = init_existential_ref [[ACTOR]]
57+
// CHECK: [[ACTOR_E_OPT:%.*]] = enum $Optional<any Actor>, #Optional.some!enumelt, [[ACTOR_E]]
58+
// CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen20AllNonIsolatedUnsafeC13mainActorTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed AllNonIsolatedUnsafe) -> ()
59+
// CHECK: apply [[FUNC]]([[ACTOR_E_OPT]], [[ARG]])
60+
// CHECK: } // end sil function '$s21attr_execution_silgen20AllNonIsolatedUnsafeC13mainActorTestyyYaFAA10SuperKlassCADyyYaFTV'
61+
override nonisolated(nonsending) func mainActorTest() async {}
62+
}
63+
64+
// CHECK-LABEL: sil_vtable AllConcurrent {
65+
// CHECK-NEXT: #SuperKlass.callerTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen13AllConcurrentC10callerTestyyYaFAA10SuperKlassCADyyYaFTV [override] // vtable thunk for SuperKlass.callerTest() dispatching to AllConcurrent.callerTest()
66+
// CHECK-NEXT: #SuperKlass.concurrentTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen13AllConcurrentC14concurrentTestyyYaF [override] // AllConcurrent.concurrentTest()
67+
// CHECK-NEXT: #SuperKlass.mainActorTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen13AllConcurrentC13mainActorTestyyYaF [override] // AllConcurrent.mainActorTest()
68+
// CHECK-NEXT: #SuperKlass.init!allocator: (SuperKlass.Type) -> () -> SuperKlass : @$s21attr_execution_silgen13AllConcurrentCACycfC [override] // AllConcurrent.__allocating_init()
69+
// CHECK-NEXT: #AllConcurrent.deinit!deallocator: @$s21attr_execution_silgen13AllConcurrentCfD // AllConcurrent.__deallocating_deinit
70+
// CHECK-NEXT: }
71+
72+
// CHECK-LABEL: sil_vtable AllNonIsolatedUnsafe {
73+
// CHECK-NEXT: #SuperKlass.callerTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen20AllNonIsolatedUnsafeC10callerTestyyYaF [override] // AllNonIsolatedUnsafe.callerTest()
74+
// CHECK-NEXT: #SuperKlass.concurrentTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen20AllNonIsolatedUnsafeC14concurrentTestyyYaFAA10SuperKlassCADyyYaFTV [override] // vtable thunk for SuperKlass.concurrentTest() dispatching to AllNonIsolatedUnsafe.concurrentTest()
75+
// CHECK-NEXT: #SuperKlass.mainActorTest: (SuperKlass) -> () async -> () : @$s21attr_execution_silgen20AllNonIsolatedUnsafeC13mainActorTestyyYaFAA10SuperKlassCADyyYaFTV [override] // vtable thunk for SuperKlass.mainActorTest() dispatching to AllNonIsolatedUnsafe.mainActorTest()
76+
// CHECK-NEXT: #SuperKlass.init!allocator: (SuperKlass.Type) -> () -> SuperKlass : @$s21attr_execution_silgen20AllNonIsolatedUnsafeCACycfC [override] // AllNonIsolatedUnsafe.__allocating_init()
77+
// CHECK-NEXT: #AllNonIsolatedUnsafe.deinit!deallocator: @$s21attr_execution_silgen20AllNonIsolatedUnsafeCfD // AllNonIsolatedUnsafe.__deallocating_deinit
78+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)