@@ -5516,7 +5516,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5516
5516
// don't need to do anything. But if the input is synchronous and the
5517
5517
// executor is asynchronous, we need to treat this like any other call
5518
5518
// to a synchronous function from an asynchronous context.
5519
- bool hopToIsolatedParameter = false ;
5519
+ bool hopToIsolatedParameterForSync = false ;
5520
5520
if (outputSubstType->isAsync () && !inputSubstType->isAsync ()) {
5521
5521
auto inputIsolation = inputSubstType->getIsolation ();
5522
5522
switch (inputIsolation.getKind ()) {
@@ -5533,7 +5533,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5533
5533
// For a function with parameter isolation, we'll have to dig the
5534
5534
// argument out after translation but before making the call.
5535
5535
case FunctionTypeIsolation::Kind::Parameter:
5536
- hopToIsolatedParameter = true ;
5536
+ hopToIsolatedParameterForSync = true ;
5537
5537
break ;
5538
5538
5539
5539
// For a function with global-actor isolation, hop to the appropriate
@@ -5602,44 +5602,49 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5602
5602
argValues.push_back (*innerIndirectErrorAddr);
5603
5603
}
5604
5604
5605
- // If we need to jump to an isolated parameter, do so before the call.
5606
- if (hopToIsolatedParameter) {
5605
+ // If we need to jump to an isolated parameter for a synchronous function, do
5606
+ // so before the call.
5607
+ if (hopToIsolatedParameterForSync) {
5607
5608
auto formalIsolatedIndex = getIsolatedParamIndex (inputSubstType);
5608
5609
auto isolatedIndex = inputOrigType.getLoweredParamIndex (formalIsolatedIndex);
5609
5610
SGF.B .createHopToExecutor (loc, args[isolatedIndex].getValue (),
5610
5611
/* mandatory*/ false );
5611
5612
}
5612
5613
5613
- // If the input function has caller isolation, we need to fill in that
5614
- // argument with the formal isolation of the output function.
5614
+ // If the input function has caller isolation (and thus is async), we need to
5615
+ // fill in that argument with the formal isolation of the output function and
5616
+ // hop to it so that it is able to assume that it does not need to hop in its
5617
+ // prologue.
5615
5618
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
5616
- auto outputIsolation = outputSubstType->getIsolation ();
5617
- switch (outputIsolation.getKind ()) {
5618
- case FunctionTypeIsolation::Kind::NonIsolated:
5619
- case FunctionTypeIsolation::Kind::Erased:
5620
- // Converting a caller-isolated function to @isolated(any) makes
5621
- // it @concurrent. In either case, emit a nil actor reference.
5622
- argValues.push_back (SGF.emitNonIsolatedIsolation (loc).getValue ());
5623
- break ;
5624
- case FunctionTypeIsolation::Kind::GlobalActor: {
5625
- auto globalActor =
5626
- outputIsolation.getGlobalActorType ()->getCanonicalType ();
5627
- argValues.push_back (
5628
- SGF.emitGlobalActorIsolation (loc, globalActor).getValue ());
5629
- break ;
5630
- }
5631
- case FunctionTypeIsolation::Kind::NonIsolatedCaller: {
5632
- argValues.push_back (implicitIsolationParam.getValue ());
5633
- break ;
5634
- }
5635
- case FunctionTypeIsolation::Kind::Parameter:
5636
- // This would require a conversion from a type with caller
5637
- // isolation to a type with parameter isolation, which is not
5638
- // currently allowed and probably won't ever be. Anyway, to
5639
- // implement it, we'd need to borrow the isolated parameter
5640
- // and wrap it up as an `Optional<any Actor>`.
5641
- llvm_unreachable (" Should never see this" );
5642
- }
5619
+ auto forwardedIsolationValue = [&]() -> SILValue {
5620
+ auto outputIsolation = outputSubstType->getIsolation ();
5621
+ switch (outputIsolation.getKind ()) {
5622
+ case FunctionTypeIsolation::Kind::NonIsolated:
5623
+ case FunctionTypeIsolation::Kind::Erased:
5624
+ // Converting a caller-isolated function to @isolated(any) makes
5625
+ // it @concurrent. In either case, emit a nil actor reference.
5626
+ return SGF.emitNonIsolatedIsolation (loc).getValue ();
5627
+ case FunctionTypeIsolation::Kind::GlobalActor: {
5628
+ auto globalActor =
5629
+ outputIsolation.getGlobalActorType ()->getCanonicalType ();
5630
+ return SGF.emitGlobalActorIsolation (loc, globalActor).getValue ();
5631
+ }
5632
+ case FunctionTypeIsolation::Kind::NonIsolatedCaller: {
5633
+ return implicitIsolationParam.getValue ();
5634
+ }
5635
+ case FunctionTypeIsolation::Kind::Parameter:
5636
+ // This would require a conversion from a type with caller
5637
+ // isolation to a type with parameter isolation, which is not
5638
+ // currently allowed and probably won't ever be. Anyway, to
5639
+ // implement it, we'd need to borrow the isolated parameter
5640
+ // and wrap it up as an `Optional<any Actor>`.
5641
+ llvm::report_fatal_error (" Should never see this?!" );
5642
+ }
5643
+ }();
5644
+
5645
+ assert (forwardedIsolationValue);
5646
+ SGF.B .createHopToExecutor (loc, forwardedIsolationValue, false );
5647
+ argValues.push_back (forwardedIsolationValue);
5643
5648
}
5644
5649
5645
5650
// Add the rest of the arguments.
@@ -5648,6 +5653,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5648
5653
auto fun = fnType->isCalleeGuaranteed () ? fnValue.borrow (SGF, loc).getValue ()
5649
5654
: fnValue.forward (SGF);
5650
5655
5656
+ // If our thunk is a caller isolated function, we need to insert a hop to
5657
+ // return to our isolation so that our caller can assume that we preserve
5658
+ // isolation.
5659
+ if (auto isolatedArg = llvm::cast_or_null<SILFunctionArgument>(
5660
+ SGF.F .maybeGetIsolatedArgument ());
5661
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
5662
+ SILParameterInfo::ImplicitLeading)) {
5663
+ SGF.emitScopedHopToTargetActor (loc, isolatedArg);
5664
+ }
5665
+
5651
5666
SILValue innerResult =
5652
5667
SGF.emitApplyWithRethrow (loc, fun,
5653
5668
/* substFnType*/ fnValue.getType (),
@@ -7073,6 +7088,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7073
7088
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
7074
7089
auto baseIsolation =
7075
7090
swift::getActorIsolation (base.getAbstractFunctionDecl ());
7091
+ std::optional<ActorIsolation> derivedIsolationCache;
7092
+ auto getDerivedIsolation = [&]() -> ActorIsolation {
7093
+ if (!derivedIsolationCache) {
7094
+ derivedIsolationCache =
7095
+ swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7096
+ }
7097
+ return *derivedIsolationCache;
7098
+ };
7099
+
7076
7100
switch (baseIsolation) {
7077
7101
case ActorIsolation::Unspecified:
7078
7102
case ActorIsolation::Nonisolated:
@@ -7089,8 +7113,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7089
7113
}
7090
7114
case ActorIsolation::ActorInstance:
7091
7115
case ActorIsolation::CallerIsolationInheriting: {
7092
- auto derivedIsolation =
7093
- swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7116
+ auto derivedIsolation = getDerivedIsolation ();
7094
7117
switch (derivedIsolation) {
7095
7118
case ActorIsolation::Unspecified:
7096
7119
case ActorIsolation::Nonisolated:
@@ -7117,6 +7140,14 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7117
7140
break ;
7118
7141
}
7119
7142
}
7143
+
7144
+ // If our derived isolation is caller isolation inheriting and our base
7145
+ // isn't, we need to insert a hop so that derived can assume that it does
7146
+ // not have to hop in its prologue.
7147
+ if (!baseIsolation.isCallerIsolationInheriting () &&
7148
+ getDerivedIsolation ().isCallerIsolationInheriting ()) {
7149
+ B.createHopToExecutor (loc, args.back (), false /* mandatory*/ );
7150
+ }
7120
7151
}
7121
7152
7122
7153
// Then, the arguments.
@@ -7135,6 +7166,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7135
7166
derivedRef = B.createFunctionRefFor (loc, implFn);
7136
7167
}
7137
7168
7169
+ // Check if our base was caller isolation inheriting. In such a case, we need
7170
+ // to insert a hop back to our original actor.
7171
+ if (auto isolatedArg = llvm::dyn_cast_or_null<SILFunctionArgument>(
7172
+ F.maybeGetIsolatedArgument ());
7173
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
7174
+ SILParameterInfo::ImplicitLeading)) {
7175
+ emitScopedHopToTargetActor (loc, {isolatedArg});
7176
+ }
7177
+
7138
7178
SILValue result;
7139
7179
7140
7180
switch (coroutineKind) {
@@ -7185,7 +7225,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7185
7225
result = B.createTuple (loc, {});
7186
7226
break ;
7187
7227
}
7188
-
7228
+
7189
7229
scope.pop ();
7190
7230
B.createReturn (loc, result);
7191
7231
@@ -7553,6 +7593,14 @@ void SILGenFunction::emitProtocolWitness(
7553
7593
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
7554
7594
auto reqtIsolation =
7555
7595
swift::getActorIsolation (requirement.getAbstractFunctionDecl ());
7596
+ std::optional<ActorIsolation> witnessIsolationCache;
7597
+ auto getWitnessIsolation = [&]() -> ActorIsolation {
7598
+ if (!witnessIsolationCache) {
7599
+ witnessIsolationCache =
7600
+ swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7601
+ }
7602
+ return *witnessIsolationCache;
7603
+ };
7556
7604
switch (reqtIsolation) {
7557
7605
case ActorIsolation::Unspecified:
7558
7606
case ActorIsolation::Nonisolated:
@@ -7569,8 +7617,7 @@ void SILGenFunction::emitProtocolWitness(
7569
7617
}
7570
7618
case ActorIsolation::ActorInstance:
7571
7619
case ActorIsolation::CallerIsolationInheriting: {
7572
- auto witnessIsolation =
7573
- swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7620
+ auto witnessIsolation = getWitnessIsolation ();
7574
7621
switch (witnessIsolation) {
7575
7622
case ActorIsolation::Unspecified:
7576
7623
case ActorIsolation::Nonisolated:
@@ -7597,6 +7644,25 @@ void SILGenFunction::emitProtocolWitness(
7597
7644
break ;
7598
7645
}
7599
7646
}
7647
+
7648
+ // If our reqtIsolation was not caller isolation inheriting, but our witness
7649
+ // isolation is caller isolation inheriting, hop onto the reqtIsolation so
7650
+ // that it is safe for our witness to assume that it is already on its
7651
+ // actor.
7652
+ if (!reqtIsolation.isCallerIsolationInheriting () &&
7653
+ getWitnessIsolation ().isCallerIsolationInheriting ()) {
7654
+ B.createHopToExecutor (loc, args.back (), false /* mandatory*/ );
7655
+ }
7656
+ }
7657
+
7658
+ // Check if our caller has an implicit isolated param. If so, we need to
7659
+ // insert a hop at the end of the function to ensure that our caller can
7660
+ // assume that we are going to be on its isolation.
7661
+ if (auto isolatedArg =
7662
+ cast_or_null<SILFunctionArgument>(F.maybeGetIsolatedArgument ());
7663
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
7664
+ SILParameterInfo::ImplicitLeading)) {
7665
+ emitScopedHopToTargetActor (loc, SILValue (isolatedArg));
7600
7666
}
7601
7667
7602
7668
// - the rest of the arguments
0 commit comments