Skip to content

Commit 296e146

Browse files
committed
Rework runtime entrypoints for isolated conformance checking
Replace the pair of global actor type/conformance we are passing around with a general "conformance execution context" that could grow new functionality over time. Add three external symbols to the runtime: * swift_conformsToProtocolWithExecutionContext: a conforms-to-protocol check that also captures the execution context that should be checked before using the conformance for anything. The only execution context right now is for an isolated conformance. * swift_isInConformanceExecutionContext: checks whether the function is being executed in the given execution context, i.e., running on the executor for the given global actor. * swift_ConformanceExecutionContextSize: the size of the conformance execution context. Client code outside of the Swift runtime can allocate a pointer-aligned region of memory of this size to use with the runtime functions above.
1 parent 48aa75d commit 296e146

File tree

9 files changed

+167
-118
lines changed

9 files changed

+167
-118
lines changed

include/swift/ABI/Metadata.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2745,6 +2745,10 @@ struct TargetGlobalActorReference {
27452745
TargetRelativeProtocolConformanceDescriptorPointer<Runtime> conformance;
27462746
};
27472747

2748+
/// Describes the context of a protocol conformance that is relevant when
2749+
/// the conformance is used, such as global actor isolation.
2750+
struct ConformanceExecutionContext;
2751+
27482752
/// The structure of a protocol conformance.
27492753
///
27502754
/// This contains enough static information to recover the witness table for a
@@ -2885,15 +2889,12 @@ struct TargetProtocolConformanceDescriptor final
28852889
/// necessary, or return null if the conformance does not apply to the
28862890
/// type.
28872891
///
2888-
/// The globalActorIsolationType will be populated with the type of the global
2889-
/// actor to which this conformance is isolated, or NULL if this is a
2890-
/// nonisolated conformances. When it is isolated,
2891-
/// globalActorIsolationConformance is the conformance of
2892-
/// globalActorIsolationType to the GlobalActor protocol.
2892+
/// The context will be populated with any information that needs to be
2893+
/// checked before this witness table can be used within a given execution
2894+
/// context.
28932895
const swift::TargetWitnessTable<Runtime> *
28942896
getWitnessTable(const TargetMetadata<Runtime> *type,
2895-
const Metadata *&globalActorIsolationType,
2896-
const WitnessTable *&globalActorIsolationConformance) const;
2897+
ConformanceExecutionContext &context) const;
28972898

28982899
/// Retrieve the resilient witnesses.
28992900
llvm::ArrayRef<ResilientWitness> getResilientWitnesses() const {

include/swift/Runtime/Casting.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,17 +260,31 @@ const WitnessTable *
260260
swift_conformsToProtocolCommon(const Metadata *type,
261261
const ProtocolDescriptor *protocol);
262262

263+
/// The size of the ConformanceExecutionContext structure.
264+
SWIFT_RUNTIME_EXPORT
265+
size_t swift_ConformanceExecutionContextSize;
266+
263267
/// Check whether a type conforms to a given native Swift protocol. This
264268
/// is similar to swift_conformsToProtocolCommon, but allows the caller to
265-
/// capture the global actor isolation of the conformance rather than
266-
/// checking that the code is currently executing on that global actor.
269+
/// either capture the execution context (in *context).
267270
SWIFT_RUNTIME_EXPORT
268271
const WitnessTable *
269-
swift_conformsToProtocolCommonIsolated(
272+
swift_conformsToProtocolWithExecutionContext(
270273
const Metadata *type,
271274
const ProtocolDescriptor *protocol,
272-
const Metadata **globalActorIsolationType,
273-
const WitnessTable **globalActorIsolationWitnessTable);
275+
ConformanceExecutionContext *context);
276+
277+
/// Determine whether this function is being executed within the execution
278+
/// context for a conformance. For example, if the conformance is
279+
/// isolated to a given global actor, checks whether this code is running on
280+
/// that global actor's executor.
281+
///
282+
/// The context should have been filled in by
283+
/// swift_conformsToProtocolWithExecutionContext.
284+
SWIFT_RUNTIME_EXPORT
285+
bool swift_isInConformanceExecutionContext(
286+
const Metadata *type,
287+
const ConformanceExecutionContext *context);
274288

275289
} // end namespace swift
276290

stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,18 @@ OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocolCommon, const WitnessTable *, , ,
193193
const ProtocolDescriptor *protocol),
194194
(type, protocol))
195195

196-
OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocolCommonIsolated,
196+
OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocolWithExecutionContext,
197197
const WitnessTable *, , , swift::,
198198
(const Metadata * const type,
199199
const ProtocolDescriptor *protocol,
200-
const Metadata **globalActorIsolationType,
201-
const WitnessTable **
202-
globalActorIsolationWitnessTable),
203-
(type, protocol, globalActorIsolationType,
204-
globalActorIsolationWitnessTable))
200+
ConformanceExecutionContext *context),
201+
(type, protocol, context))
202+
203+
OVERRIDE_PROTOCOLCONFORMANCE(isInConformanceExecutionContext,
204+
bool, , , swift::,
205+
(const Metadata * const type,
206+
const ConformanceExecutionContext *context),
207+
(type, context))
205208

206209
OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::,
207210
(const void *pattern, const void *arguments),

stdlib/public/runtime/Casting.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -534,13 +534,11 @@ bool swift::_conformsToProtocol(
534534
const Metadata *type,
535535
ProtocolDescriptorRef protocol,
536536
const WitnessTable **conformance,
537-
const Metadata **globalActorIsolationType,
538-
const WitnessTable **globalActorIsolationWitnessTable) {
537+
ConformanceExecutionContext *context) {
539538
// Look up the witness table for protocols that need them.
540539
if (protocol.needsWitnessTable()) {
541-
auto witness = swift_conformsToProtocolCommonIsolated(
542-
type, protocol.getSwiftProtocol(), globalActorIsolationType,
543-
globalActorIsolationWitnessTable);
540+
auto witness = swift_conformsToProtocolWithExecutionContext(
541+
type, protocol.getSwiftProtocol(), context);
544542
if (!witness)
545543
return false;
546544
if (conformance)
@@ -612,6 +610,22 @@ bool swift::_conformsToProtocol(
612610
return false;
613611
}
614612

613+
bool swift::_conformsToProtocolInContext(
614+
const OpaqueValue *value,
615+
const Metadata *type,
616+
ProtocolDescriptorRef protocol,
617+
const WitnessTable **conformance) {
618+
619+
ConformanceExecutionContext context;
620+
if (!_conformsToProtocol(value, type, protocol, conformance, &context))
621+
return false;
622+
623+
if (!swift_isInConformanceExecutionContext(type, &context))
624+
return false;
625+
626+
return true;
627+
}
628+
615629
/// Check whether a type conforms to the given protocols, filling in a
616630
/// list of conformances.
617631
static bool _conformsToProtocols(const OpaqueValue *value,
@@ -629,8 +643,8 @@ static bool _conformsToProtocols(const OpaqueValue *value,
629643
}
630644

631645
for (auto protocol : existentialType->getProtocols()) {
632-
if (!_conformsToProtocol(
633-
value, type, protocol, conformances, nullptr, nullptr))
646+
if (!_conformsToProtocolInContext(
647+
value, type, protocol, conformances))
634648
return false;
635649
if (conformances != nullptr && protocol.needsWitnessTable()) {
636650
assert(*conformances != nullptr);

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,8 +1384,8 @@ static bool _conformsToProtocols(const OpaqueValue *value,
13841384
}
13851385

13861386
for (auto protocol : existentialType->getProtocols()) {
1387-
if (!swift::_conformsToProtocol(value, type, protocol, conformances,
1388-
nullptr, nullptr))
1387+
if (!swift::_conformsToProtocolInContext(
1388+
value, type, protocol, conformances))
13891389
return false;
13901390
if (conformances != nullptr && protocol.needsWitnessTable()) {
13911391
assert(*conformances != nullptr);
@@ -1867,6 +1867,7 @@ static DynamicCastResult tryCastToExtendedExistential(
18671867
allGenericArgsVec.data());
18681868
// Verify the requirements in the requirement signature against the
18691869
// arguments from the source value.
1870+
ConformanceExecutionContext context;
18701871
auto requirementSig = destExistentialShape->getRequirementSignature();
18711872
auto error = swift::_checkGenericRequirements(
18721873
requirementSig.getParams(),
@@ -1881,9 +1882,12 @@ static DynamicCastResult tryCastToExtendedExistential(
18811882
[](const Metadata *type, unsigned index) -> const WitnessTable * {
18821883
swift_unreachable("Resolution of witness tables is not supported");
18831884
},
1884-
nullptr, nullptr);
1885+
&context);
18851886
if (error)
18861887
return DynamicCastResult::Failure;
1888+
1889+
if (!swift_isInConformanceExecutionContext(selfType, &context))
1890+
return DynamicCastResult::Failure;
18871891
}
18881892

18891893
OpaqueValue *destBox = nullptr;

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@ _gatherGenericParameters(const ContextDescriptor *context,
16031603
[&substitutions](const Metadata *type, unsigned index) {
16041604
return substitutions.getWitnessTable(type, index);
16051605
},
1606-
nullptr, nullptr);
1606+
nullptr);
16071607
if (error)
16081608
return *error;
16091609

@@ -2045,7 +2045,7 @@ class DecodedMetadataBuilder {
20452045
[](const Metadata *type, unsigned index) -> const WitnessTable * {
20462046
swift_unreachable("never called");
20472047
},
2048-
nullptr, nullptr);
2048+
nullptr);
20492049
if (error)
20502050
return *error;
20512051

@@ -3059,7 +3059,7 @@ swift_distributed_getWitnessTables(GenericEnvironmentDescriptor *genericEnv,
30593059
[&substFn](const Metadata *type, unsigned index) {
30603060
return substFn.getWitnessTable(type, index);
30613061
},
3062-
nullptr, nullptr);
3062+
nullptr);
30633063

30643064
if (error) {
30653065
return {/*ptr=*/nullptr, -1};

stdlib/public/runtime/Private.h

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,9 @@ class TypeInfo {
567567
/// generic requirements (e.g., those that need to be
568568
/// passed to an instantiation function) will be added to this vector.
569569
///
570-
/// \param globalActorIsolationType When non-NULL, the global actor isolation
571-
/// of these requirements will be reported through this OUT parameter.
572-
/// When NULL, any global actor isolation will be checked dynamically.
573-
///
570+
/// \param context When non-NULL, receives any information about the
571+
/// execution context that is required to use this conformance.
572+
///
574573
/// \returns the error if an error occurred, None otherwise.
575574
std::optional<TypeLookupError> _checkGenericRequirements(
576575
llvm::ArrayRef<GenericParamDescriptor> genericParams,
@@ -579,8 +578,7 @@ class TypeInfo {
579578
SubstGenericParameterFn substGenericParam,
580579
SubstGenericParameterOrdinalFn substGenericParamOrdinal,
581580
SubstDependentWitnessTableFn substWitnessTable,
582-
const Metadata **globalActorIsolationType,
583-
const WitnessTable **globalActorIsolationWitnessTable);
581+
ConformanceExecutionContext *context);
584582

585583
/// A helper function which avoids performing a store if the destination
586584
/// address already contains the source value. This is useful when
@@ -685,26 +683,45 @@ class TypeInfo {
685683
bool _isCImportedTagType(const TypeContextDescriptor *type,
686684
const ParsedTypeIdentity &identity);
687685

686+
/// The execution context for a conformance, containing any additional
687+
/// checking that has to be done in context to determine whether a given
688+
/// conformance is available.
689+
struct ConformanceExecutionContext {
690+
/// The global actor to which this conformance is isolated, or NULL for
691+
/// a nonisolated conformances.
692+
const Metadata *globalActorIsolationType = nullptr;
693+
694+
/// When the conformance is global-actor-isolated, this is the conformance
695+
/// of globalActorIsolationType to GlobalActor.
696+
const WitnessTable *globalActorIsolationWitnessTable = nullptr;
697+
};
698+
688699
/// Check whether a type conforms to a protocol.
689700
///
690701
/// \param value - can be null, in which case the question should
691702
/// be answered abstractly if possible
692703
/// \param conformance - if non-null, and the protocol requires a
693704
/// witness table, and the type implements the protocol, the witness
694705
/// table will be placed here
695-
/// \param globalActorIsolationType - when non-NULL and the conformance is
696-
/// global-actor-isolated, capture the global actor isolation type in this
697-
/// out variable rather than checking when we are executing on that global
698-
/// actor.
699-
/// \param globalActorIsolationWitnessTable - receives the witness table for
700-
/// *globalActorIsolationType's conformance to GlobalActor.
706+
/// \param context - when non-NULL, receives any information about the
707+
/// required execution context for this conformance.
701708
bool _conformsToProtocol(
702709
const OpaqueValue *value,
703710
const Metadata *type,
704711
ProtocolDescriptorRef protocol,
705712
const WitnessTable **conformance,
706-
const Metadata **globalActorIsolationType,
707-
const WitnessTable **globalActorIsolationWitnessTable);
713+
ConformanceExecutionContext *context);
714+
715+
/// Check whether a type conforms to a value within the currently-executing
716+
/// context.
717+
///
718+
/// This is equivalent to a _conformsToProtocol check followed by runtime
719+
/// checking for global actor isolation, if needed.
720+
bool _conformsToProtocolInContext(
721+
const OpaqueValue *value,
722+
const Metadata *type,
723+
ProtocolDescriptorRef protocol,
724+
const WitnessTable **conformance);
708725

709726
/// Construct type metadata for the given protocol.
710727
const Metadata *

0 commit comments

Comments
 (0)