@@ -5517,7 +5517,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5517
5517
// don't need to do anything. But if the input is synchronous and the
5518
5518
// executor is asynchronous, we need to treat this like any other call
5519
5519
// to a synchronous function from an asynchronous context.
5520
- bool hopToIsolatedParameter = false ;
5520
+ bool hopToIsolatedParameterForSync = false ;
5521
5521
if (outputSubstType->isAsync () && !inputSubstType->isAsync ()) {
5522
5522
auto inputIsolation = inputSubstType->getIsolation ();
5523
5523
switch (inputIsolation.getKind ()) {
@@ -5534,7 +5534,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5534
5534
// For a function with parameter isolation, we'll have to dig the
5535
5535
// argument out after translation but before making the call.
5536
5536
case FunctionTypeIsolation::Kind::Parameter:
5537
- hopToIsolatedParameter = true ;
5537
+ hopToIsolatedParameterForSync = true ;
5538
5538
break ;
5539
5539
5540
5540
// For a function with global-actor isolation, hop to the appropriate
@@ -5603,44 +5603,49 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5603
5603
argValues.push_back (*innerIndirectErrorAddr);
5604
5604
}
5605
5605
5606
- // If we need to jump to an isolated parameter, do so before the call.
5607
- if (hopToIsolatedParameter) {
5606
+ // If we need to jump to an isolated parameter for a synchronous function, do
5607
+ // so before the call.
5608
+ if (hopToIsolatedParameterForSync) {
5608
5609
auto formalIsolatedIndex = getIsolatedParamIndex (inputSubstType);
5609
5610
auto isolatedIndex = inputOrigType.getLoweredParamIndex (formalIsolatedIndex);
5610
5611
SGF.B .createHopToExecutor (loc, args[isolatedIndex].getValue (),
5611
5612
/* mandatory*/ false );
5612
5613
}
5613
5614
5614
- // If the input function has caller isolation, we need to fill in that
5615
- // argument with the formal isolation of the output function.
5615
+ // If the input function has caller isolation (and thus is async), we need to
5616
+ // fill in that argument with the formal isolation of the output function and
5617
+ // hop to it so that it is able to assume that it does not need to hop in its
5618
+ // prologue.
5616
5619
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
5617
- auto outputIsolation = outputSubstType->getIsolation ();
5618
- switch (outputIsolation.getKind ()) {
5619
- case FunctionTypeIsolation::Kind::NonIsolated:
5620
- case FunctionTypeIsolation::Kind::Erased:
5621
- // Converting a caller-isolated function to @isolated(any) makes
5622
- // it @concurrent. In either case, emit a nil actor reference.
5623
- argValues.push_back (SGF.emitNonIsolatedIsolation (loc).getValue ());
5624
- break ;
5625
- case FunctionTypeIsolation::Kind::GlobalActor: {
5626
- auto globalActor =
5627
- outputIsolation.getGlobalActorType ()->getCanonicalType ();
5628
- argValues.push_back (
5629
- SGF.emitGlobalActorIsolation (loc, globalActor).getValue ());
5630
- break ;
5631
- }
5632
- case FunctionTypeIsolation::Kind::NonIsolatedCaller: {
5633
- argValues.push_back (implicitIsolationParam.getValue ());
5634
- break ;
5635
- }
5636
- case FunctionTypeIsolation::Kind::Parameter:
5637
- // This would require a conversion from a type with caller
5638
- // isolation to a type with parameter isolation, which is not
5639
- // currently allowed and probably won't ever be. Anyway, to
5640
- // implement it, we'd need to borrow the isolated parameter
5641
- // and wrap it up as an `Optional<any Actor>`.
5642
- llvm_unreachable (" Should never see this" );
5643
- }
5620
+ auto forwardedIsolationValue = [&]() -> SILValue {
5621
+ auto outputIsolation = outputSubstType->getIsolation ();
5622
+ switch (outputIsolation.getKind ()) {
5623
+ case FunctionTypeIsolation::Kind::NonIsolated:
5624
+ case FunctionTypeIsolation::Kind::Erased:
5625
+ // Converting a caller-isolated function to @isolated(any) makes
5626
+ // it @concurrent. In either case, emit a nil actor reference.
5627
+ return SGF.emitNonIsolatedIsolation (loc).getValue ();
5628
+ case FunctionTypeIsolation::Kind::GlobalActor: {
5629
+ auto globalActor =
5630
+ outputIsolation.getGlobalActorType ()->getCanonicalType ();
5631
+ return SGF.emitGlobalActorIsolation (loc, globalActor).getValue ();
5632
+ }
5633
+ case FunctionTypeIsolation::Kind::NonIsolatedCaller: {
5634
+ return implicitIsolationParam.getValue ();
5635
+ }
5636
+ case FunctionTypeIsolation::Kind::Parameter:
5637
+ // This would require a conversion from a type with caller
5638
+ // isolation to a type with parameter isolation, which is not
5639
+ // currently allowed and probably won't ever be. Anyway, to
5640
+ // implement it, we'd need to borrow the isolated parameter
5641
+ // and wrap it up as an `Optional<any Actor>`.
5642
+ llvm::report_fatal_error (" Should never see this?!" );
5643
+ }
5644
+ }();
5645
+
5646
+ assert (forwardedIsolationValue);
5647
+ SGF.B .createHopToExecutor (loc, forwardedIsolationValue, false );
5648
+ argValues.push_back (forwardedIsolationValue);
5644
5649
}
5645
5650
5646
5651
// Add the rest of the arguments.
@@ -5649,6 +5654,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
5649
5654
auto fun = fnType->isCalleeGuaranteed () ? fnValue.borrow (SGF, loc).getValue ()
5650
5655
: fnValue.forward (SGF);
5651
5656
5657
+ // If our thunk is a caller isolated function, we need to insert a hop to
5658
+ // return to our isolation so that our caller can assume that we preserve
5659
+ // isolation.
5660
+ if (auto isolatedArg = llvm::cast_or_null<SILFunctionArgument>(
5661
+ SGF.F .maybeGetIsolatedArgument ());
5662
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
5663
+ SILParameterInfo::ImplicitLeading)) {
5664
+ SGF.emitScopedHopToTargetActor (loc, isolatedArg);
5665
+ }
5666
+
5652
5667
SILValue innerResult =
5653
5668
SGF.emitApplyWithRethrow (loc, fun,
5654
5669
/* substFnType*/ fnValue.getType (),
@@ -7080,6 +7095,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7080
7095
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
7081
7096
auto baseIsolation =
7082
7097
swift::getActorIsolation (base.getAbstractFunctionDecl ());
7098
+ std::optional<ActorIsolation> derivedIsolationCache;
7099
+ auto getDerivedIsolation = [&]() -> ActorIsolation {
7100
+ if (!derivedIsolationCache) {
7101
+ derivedIsolationCache =
7102
+ swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7103
+ }
7104
+ return *derivedIsolationCache;
7105
+ };
7106
+
7083
7107
switch (baseIsolation) {
7084
7108
case ActorIsolation::Unspecified:
7085
7109
case ActorIsolation::Nonisolated:
@@ -7096,8 +7120,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7096
7120
}
7097
7121
case ActorIsolation::ActorInstance:
7098
7122
case ActorIsolation::CallerIsolationInheriting: {
7099
- auto derivedIsolation =
7100
- swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7123
+ auto derivedIsolation = getDerivedIsolation ();
7101
7124
switch (derivedIsolation) {
7102
7125
case ActorIsolation::Unspecified:
7103
7126
case ActorIsolation::Nonisolated:
@@ -7124,6 +7147,14 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7124
7147
break ;
7125
7148
}
7126
7149
}
7150
+
7151
+ // If our derived isolation is caller isolation inheriting and our base
7152
+ // isn't, we need to insert a hop so that derived can assume that it does
7153
+ // not have to hop in its prologue.
7154
+ if (!baseIsolation.isCallerIsolationInheriting () &&
7155
+ getDerivedIsolation ().isCallerIsolationInheriting ()) {
7156
+ B.createHopToExecutor (loc, args.back (), false /* mandatory*/ );
7157
+ }
7127
7158
}
7128
7159
7129
7160
// Then, the arguments.
@@ -7142,6 +7173,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7142
7173
derivedRef = B.createFunctionRefFor (loc, implFn);
7143
7174
}
7144
7175
7176
+ // Check if our base was caller isolation inheriting. In such a case, we need
7177
+ // to insert a hop back to our original actor.
7178
+ if (auto isolatedArg = llvm::dyn_cast_or_null<SILFunctionArgument>(
7179
+ F.maybeGetIsolatedArgument ());
7180
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
7181
+ SILParameterInfo::ImplicitLeading)) {
7182
+ emitScopedHopToTargetActor (loc, {isolatedArg});
7183
+ }
7184
+
7145
7185
SILValue result;
7146
7186
7147
7187
switch (coroutineKind) {
@@ -7192,7 +7232,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
7192
7232
result = B.createTuple (loc, {});
7193
7233
break ;
7194
7234
}
7195
-
7235
+
7196
7236
scope.pop ();
7197
7237
B.createReturn (loc, result);
7198
7238
@@ -7560,6 +7600,14 @@ void SILGenFunction::emitProtocolWitness(
7560
7600
if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
7561
7601
auto reqtIsolation =
7562
7602
swift::getActorIsolation (requirement.getAbstractFunctionDecl ());
7603
+ std::optional<ActorIsolation> witnessIsolationCache;
7604
+ auto getWitnessIsolation = [&]() -> ActorIsolation {
7605
+ if (!witnessIsolationCache) {
7606
+ witnessIsolationCache =
7607
+ swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7608
+ }
7609
+ return *witnessIsolationCache;
7610
+ };
7563
7611
switch (reqtIsolation) {
7564
7612
case ActorIsolation::Unspecified:
7565
7613
case ActorIsolation::Nonisolated:
@@ -7576,8 +7624,7 @@ void SILGenFunction::emitProtocolWitness(
7576
7624
}
7577
7625
case ActorIsolation::ActorInstance:
7578
7626
case ActorIsolation::CallerIsolationInheriting: {
7579
- auto witnessIsolation =
7580
- swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7627
+ auto witnessIsolation = getWitnessIsolation ();
7581
7628
switch (witnessIsolation) {
7582
7629
case ActorIsolation::Unspecified:
7583
7630
case ActorIsolation::Nonisolated:
@@ -7604,6 +7651,25 @@ void SILGenFunction::emitProtocolWitness(
7604
7651
break ;
7605
7652
}
7606
7653
}
7654
+
7655
+ // If our reqtIsolation was not caller isolation inheriting, but our witness
7656
+ // isolation is caller isolation inheriting, hop onto the reqtIsolation so
7657
+ // that it is safe for our witness to assume that it is already on its
7658
+ // actor.
7659
+ if (!reqtIsolation.isCallerIsolationInheriting () &&
7660
+ getWitnessIsolation ().isCallerIsolationInheriting ()) {
7661
+ B.createHopToExecutor (loc, args.back (), false /* mandatory*/ );
7662
+ }
7663
+ }
7664
+
7665
+ // Check if our caller has an implicit isolated param. If so, we need to
7666
+ // insert a hop at the end of the function to ensure that our caller can
7667
+ // assume that we are going to be on its isolation.
7668
+ if (auto isolatedArg =
7669
+ cast_or_null<SILFunctionArgument>(F.maybeGetIsolatedArgument ());
7670
+ isolatedArg && isolatedArg->getKnownParameterInfo ().hasOption (
7671
+ SILParameterInfo::ImplicitLeading)) {
7672
+ emitScopedHopToTargetActor (loc, SILValue (isolatedArg));
7607
7673
}
7608
7674
7609
7675
// - the rest of the arguments
0 commit comments