@@ -5516,7 +5516,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
55165516 // don't need to do anything. But if the input is synchronous and the
55175517 // executor is asynchronous, we need to treat this like any other call
55185518 // to a synchronous function from an asynchronous context.
5519- bool hopToIsolatedParameter = false ;
5519+ bool hopToIsolatedParameterForSync = false ;
55205520 if (outputSubstType->isAsync () && !inputSubstType->isAsync ()) {
55215521 auto inputIsolation = inputSubstType->getIsolation ();
55225522 switch (inputIsolation.getKind ()) {
@@ -5533,7 +5533,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
55335533 // For a function with parameter isolation, we'll have to dig the
55345534 // argument out after translation but before making the call.
55355535 case FunctionTypeIsolation::Kind::Parameter:
5536- hopToIsolatedParameter = true ;
5536+ hopToIsolatedParameterForSync = true ;
55375537 break ;
55385538
55395539 // For a function with global-actor isolation, hop to the appropriate
@@ -5602,44 +5602,49 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
56025602 argValues.push_back (*innerIndirectErrorAddr);
56035603 }
56045604
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) {
56075608 auto formalIsolatedIndex = getIsolatedParamIndex (inputSubstType);
56085609 auto isolatedIndex = inputOrigType.getLoweredParamIndex (formalIsolatedIndex);
56095610 SGF.B .createHopToExecutor (loc, args[isolatedIndex].getValue (),
56105611 /* mandatory*/ false );
56115612 }
56125613
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.
56155618 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);
56435648 }
56445649
56455650 // Add the rest of the arguments.
@@ -5648,6 +5653,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
56485653 auto fun = fnType->isCalleeGuaranteed () ? fnValue.borrow (SGF, loc).getValue ()
56495654 : fnValue.forward (SGF);
56505655
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+
56515666 SILValue innerResult =
56525667 SGF.emitApplyWithRethrow (loc, fun,
56535668 /* substFnType*/ fnValue.getType (),
@@ -7073,6 +7088,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70737088 if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
70747089 auto baseIsolation =
70757090 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+
70767100 switch (baseIsolation) {
70777101 case ActorIsolation::Unspecified:
70787102 case ActorIsolation::Nonisolated:
@@ -7089,8 +7113,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70897113 }
70907114 case ActorIsolation::ActorInstance:
70917115 case ActorIsolation::CallerIsolationInheriting: {
7092- auto derivedIsolation =
7093- swift::getActorIsolation (derived.getAbstractFunctionDecl ());
7116+ auto derivedIsolation = getDerivedIsolation ();
70947117 switch (derivedIsolation) {
70957118 case ActorIsolation::Unspecified:
70967119 case ActorIsolation::Nonisolated:
@@ -7117,6 +7140,14 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71177140 break ;
71187141 }
71197142 }
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+ }
71207151 }
71217152
71227153 // Then, the arguments.
@@ -7135,6 +7166,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71357166 derivedRef = B.createFunctionRefFor (loc, implFn);
71367167 }
71377168
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+
71387178 SILValue result;
71397179
71407180 switch (coroutineKind) {
@@ -7185,7 +7225,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
71857225 result = B.createTuple (loc, {});
71867226 break ;
71877227 }
7188-
7228+
71897229 scope.pop ();
71907230 B.createReturn (loc, result);
71917231
@@ -7553,6 +7593,14 @@ void SILGenFunction::emitProtocolWitness(
75537593 if (options.contains (ThunkGenFlag::CalleeHasImplicitIsolatedParam)) {
75547594 auto reqtIsolation =
75557595 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+ };
75567604 switch (reqtIsolation) {
75577605 case ActorIsolation::Unspecified:
75587606 case ActorIsolation::Nonisolated:
@@ -7569,8 +7617,7 @@ void SILGenFunction::emitProtocolWitness(
75697617 }
75707618 case ActorIsolation::ActorInstance:
75717619 case ActorIsolation::CallerIsolationInheriting: {
7572- auto witnessIsolation =
7573- swift::getActorIsolation (witness.getAbstractFunctionDecl ());
7620+ auto witnessIsolation = getWitnessIsolation ();
75747621 switch (witnessIsolation) {
75757622 case ActorIsolation::Unspecified:
75767623 case ActorIsolation::Nonisolated:
@@ -7597,6 +7644,25 @@ void SILGenFunction::emitProtocolWitness(
75977644 break ;
75987645 }
75997646 }
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));
76007666 }
76017667
76027668 // - the rest of the arguments
0 commit comments