@@ -5517,7 +5517,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
55175517 // don't need to do anything. But if the input is synchronous and the
55185518 // executor is asynchronous, we need to treat this like any other call
55195519 // to a synchronous function from an asynchronous context.
5520- bool hopToIsolatedParameter = false ;
5520+ bool hopToIsolatedParameterForSync = false ;
55215521 if (outputSubstType->isAsync () && !inputSubstType->isAsync ()) {
55225522 auto inputIsolation = inputSubstType->getIsolation ();
55235523 switch (inputIsolation.getKind ()) {
@@ -5534,7 +5534,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
55345534 // For a function with parameter isolation, we'll have to dig the
55355535 // argument out after translation but before making the call.
55365536 case FunctionTypeIsolation::Kind::Parameter:
5537- hopToIsolatedParameter = true ;
5537+ hopToIsolatedParameterForSync = true ;
55385538 break ;
55395539
55405540 // For a function with global-actor isolation, hop to the appropriate
@@ -5603,44 +5603,49 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
56035603 argValues.push_back (*innerIndirectErrorAddr);
56045604 }
56055605
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) {
56085609 auto formalIsolatedIndex = getIsolatedParamIndex (inputSubstType);
56095610 auto isolatedIndex = inputOrigType.getLoweredParamIndex (formalIsolatedIndex);
56105611 SGF.B .createHopToExecutor (loc, args[isolatedIndex].getValue (),
56115612 /* mandatory*/ false );
56125613 }
56135614
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.
56165619 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);
56445649 }
56455650
56465651 // Add the rest of the arguments.
@@ -5649,6 +5654,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
56495654 auto fun = fnType->isCalleeGuaranteed () ? fnValue.borrow (SGF, loc).getValue ()
56505655 : fnValue.forward (SGF);
56515656
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+
56525667 SILValue innerResult =
56535668 SGF.emitApplyWithRethrow (loc, fun,
56545669 /* substFnType*/ fnValue.getType (),
@@ -7080,6 +7095,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70807095 if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
70817096 auto baseIsolation =
70827097 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+
70837107 switch (baseIsolation) {
70847108 case ActorIsolation::Unspecified:
70857109 case ActorIsolation::Nonisolated:
@@ -7096,8 +7120,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70967120 }
70977121 case ActorIsolation::ActorInstance:
70987122 case ActorIsolation::CallerIsolationInheriting: {
7099- auto derivedIsolation =
7100- swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7123+ auto derivedIsolation = getDerivedIsolation ();
71017124 switch (derivedIsolation) {
71027125 case ActorIsolation::Unspecified:
71037126 case ActorIsolation::Nonisolated:
@@ -7124,6 +7147,14 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71247147 break ;
71257148 }
71267149 }
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+ }
71277158 }
71287159
71297160 // Then, the arguments.
@@ -7142,6 +7173,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71427173 derivedRef = B.createFunctionRefFor (loc, implFn);
71437174 }
71447175
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+
71457185 SILValue result;
71467186
71477187 switch (coroutineKind) {
@@ -7192,7 +7232,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71927232 result = B.createTuple (loc, {});
71937233 break ;
71947234 }
7195-
7235+
71967236 scope.pop ();
71977237 B.createReturn (loc, result);
71987238
@@ -7560,6 +7600,14 @@ void SILGenFunction::emitProtocolWitness(
75607600 if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
75617601 auto reqtIsolation =
75627602 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+ };
75637611 switch (reqtIsolation) {
75647612 case ActorIsolation::Unspecified:
75657613 case ActorIsolation::Nonisolated:
@@ -7576,8 +7624,7 @@ void SILGenFunction::emitProtocolWitness(
75767624 }
75777625 case ActorIsolation::ActorInstance:
75787626 case ActorIsolation::CallerIsolationInheriting: {
7579- auto witnessIsolation =
7580- swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7627+ auto witnessIsolation = getWitnessIsolation ();
75817628 switch (witnessIsolation) {
75827629 case ActorIsolation::Unspecified:
75837630 case ActorIsolation::Nonisolated:
@@ -7604,6 +7651,25 @@ void SILGenFunction::emitProtocolWitness(
76047651 break ;
76057652 }
76067653 }
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));
76077673 }
76087674
76097675 // - the rest of the arguments
0 commit comments