Skip to content

Commit 537be30

Browse files
authored
Merge pull request #79785 from DougGregor/isolated-conformances-metadata-runtime
2 parents 911fbb6 + d9ed5d9 commit 537be30

File tree

23 files changed

+705
-80
lines changed

23 files changed

+705
-80
lines changed

include/swift/ABI/Metadata.h

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,21 @@ struct TargetResilientWitnessesHeader {
27342734
};
27352735
using ResilientWitnessesHeader = TargetResilientWitnessesHeader<InProcess>;
27362736

2737+
/// Describes a reference to a global actor type and its conformance to the
2738+
/// global actor protocol.
2739+
template<typename Runtime>
2740+
struct TargetGlobalActorReference {
2741+
/// The type of the global actor.
2742+
RelativeDirectPointer<const char, /*nullable*/ false> type;
2743+
2744+
/// The conformance of the global actor to the GlobalActor protocol.
2745+
TargetRelativeProtocolConformanceDescriptorPointer<Runtime> conformance;
2746+
};
2747+
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+
27372752
/// The structure of a protocol conformance.
27382753
///
27392754
/// This contains enough static information to recover the witness table for a
@@ -2747,7 +2762,8 @@ struct TargetProtocolConformanceDescriptor final
27472762
GenericPackShapeDescriptor,
27482763
TargetResilientWitnessesHeader<Runtime>,
27492764
TargetResilientWitness<Runtime>,
2750-
TargetGenericWitnessTable<Runtime>> {
2765+
TargetGenericWitnessTable<Runtime>,
2766+
TargetGlobalActorReference<Runtime>> {
27512767

27522768
using TrailingObjects = swift::ABI::TrailingObjects<
27532769
TargetProtocolConformanceDescriptor<Runtime>,
@@ -2756,7 +2772,8 @@ struct TargetProtocolConformanceDescriptor final
27562772
GenericPackShapeDescriptor,
27572773
TargetResilientWitnessesHeader<Runtime>,
27582774
TargetResilientWitness<Runtime>,
2759-
TargetGenericWitnessTable<Runtime>>;
2775+
TargetGenericWitnessTable<Runtime>,
2776+
TargetGlobalActorReference<Runtime>>;
27602777
friend TrailingObjects;
27612778

27622779
template<typename T>
@@ -2871,8 +2888,13 @@ struct TargetProtocolConformanceDescriptor final
28712888
/// Get the witness table for the specified type, realizing it if
28722889
/// necessary, or return null if the conformance does not apply to the
28732890
/// type.
2891+
///
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.
28742895
const swift::TargetWitnessTable<Runtime> *
2875-
getWitnessTable(const TargetMetadata<Runtime> *type) const;
2896+
getWitnessTable(const TargetMetadata<Runtime> *type,
2897+
ConformanceExecutionContext &context) const;
28762898

28772899
/// Retrieve the resilient witnesses.
28782900
llvm::ArrayRef<ResilientWitness> getResilientWitnesses() const {
@@ -2892,6 +2914,32 @@ struct TargetProtocolConformanceDescriptor final
28922914
return this->template getTrailingObjects<GenericWitnessTable>();
28932915
}
28942916

2917+
/// Whether this conformance has any conditional requirements that need to
2918+
/// be evaluated.
2919+
bool hasGlobalActorIsolation() const {
2920+
return Flags.hasGlobalActorIsolation();
2921+
}
2922+
2923+
/// Retrieve the global actor type to which this conformance is isolated, if
2924+
/// any.
2925+
llvm::StringRef
2926+
getGlobalActorType() const {
2927+
if (!Flags.hasGlobalActorIsolation())
2928+
return llvm::StringRef();
2929+
2930+
return Demangle::makeSymbolicMangledNameStringRef(this->template getTrailingObjects<TargetGlobalActorReference<Runtime>>()->type);
2931+
}
2932+
2933+
/// Retrieve the protocol conformance of the global actor type to the
2934+
/// GlobalActor protocol.
2935+
const TargetProtocolConformanceDescriptor<Runtime> *
2936+
getGlobalActorConformance() const {
2937+
if (!Flags.hasGlobalActorIsolation())
2938+
return nullptr;
2939+
2940+
return this->template getTrailingObjects<TargetGlobalActorReference<Runtime>>()->conformance;
2941+
}
2942+
28952943
#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP
28962944
void dump() const;
28972945
#endif
@@ -2934,6 +2982,10 @@ struct TargetProtocolConformanceDescriptor final
29342982
size_t numTrailingObjects(OverloadToken<GenericWitnessTable>) const {
29352983
return Flags.hasGenericWitnessTable() ? 1 : 0;
29362984
}
2985+
2986+
size_t numTrailingObjects(OverloadToken<RelativeDirectPointer<const char, /*nullable*/ true>>) const {
2987+
return Flags.hasGlobalActorIsolation() ? 1 : 0;
2988+
}
29372989
};
29382990
using ProtocolConformanceDescriptor
29392991
= TargetProtocolConformanceDescriptor<InProcess>;

include/swift/ABI/MetadataValues.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ class ConformanceFlags {
746746
HasResilientWitnessesMask = 0x01u << 16,
747747
HasGenericWitnessTableMask = 0x01u << 17,
748748
IsConformanceOfProtocolMask = 0x01u << 18,
749+
HasGlobalActorIsolation = 0x01u << 19,
749750

750751
NumConditionalPackDescriptorsMask = 0xFFu << 24,
751752
NumConditionalPackDescriptorsShift = 24
@@ -805,6 +806,14 @@ class ConformanceFlags {
805806
: 0));
806807
}
807808

809+
ConformanceFlags withHasGlobalActorIsolation(
810+
bool hasGlobalActorIsolation) const {
811+
return ConformanceFlags((Value & ~HasGlobalActorIsolation)
812+
| (hasGlobalActorIsolation
813+
? HasGlobalActorIsolation
814+
: 0));
815+
}
816+
808817
/// Retrieve the type reference kind kind.
809818
TypeReferenceKind getTypeReferenceKind() const {
810819
return TypeReferenceKind(
@@ -843,7 +852,12 @@ class ConformanceFlags {
843852
bool isConformanceOfProtocol() const {
844853
return Value & IsConformanceOfProtocolMask;
845854
}
846-
855+
856+
/// Does this conformance have a global actor to which it is isolated?
857+
bool hasGlobalActorIsolation() const {
858+
return Value & HasGlobalActorIsolation;
859+
}
860+
847861
/// Retrieve the # of conditional requirements.
848862
unsigned getNumConditionalRequirements() const {
849863
return (Value & NumConditionalRequirementsMask)
@@ -1755,6 +1769,10 @@ namespace SpecialPointerAuthDiscriminators {
17551769

17561770
/// Isolated deinit body function pointer
17571771
const uint16_t DeinitWorkFunction = 0x8438; // = 33848
1772+
1773+
/// IsCurrentGlobalActor function used between the Swift runtime and
1774+
/// concurrency runtime.
1775+
const uint16_t IsCurrentGlobalActorFunction = 0xd1b8; // = 53688
17581776
}
17591777

17601778
/// The number of arguments that will be passed directly to a generic

include/swift/Runtime/Casting.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,32 @@ 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+
267+
/// Check whether a type conforms to a given native Swift protocol. This
268+
/// is similar to swift_conformsToProtocolCommon, but allows the caller to
269+
/// either capture the execution context (in *context).
270+
SWIFT_RUNTIME_EXPORT
271+
const WitnessTable *
272+
swift_conformsToProtocolWithExecutionContext(
273+
const Metadata *type,
274+
const ProtocolDescriptor *protocol,
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);
288+
263289
} // end namespace swift
264290

265291
#endif // SWIFT_RUNTIME_CASTING_H

include/swift/Runtime/Config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ extern uintptr_t __COMPATIBILITY_LIBRARIES_CANNOT_CHECK_THE_IS_SWIFT_BIT_DIRECTL
327327
#define __ptrauth_swift_deinit_work_function \
328328
__ptrauth(ptrauth_key_function_pointer, 1, \
329329
SpecialPointerAuthDiscriminators::DeinitWorkFunction)
330+
#define __ptrauth_swift_is_global_actor_function \
331+
__ptrauth(ptrauth_key_function_pointer, 1, \
332+
SpecialPointerAuthDiscriminators::IsCurrentGlobalActorFunction)
330333

331334
#if __has_attribute(ptrauth_struct)
332335
#define swift_ptrauth_struct(key, discriminator) \
@@ -368,6 +371,7 @@ extern uintptr_t __COMPATIBILITY_LIBRARIES_CANNOT_CHECK_THE_IS_SWIFT_BIT_DIRECTL
368371
#define swift_ptrauth_sign_opaque_modify_resume_function(__fn, __buffer) (__fn)
369372
#define __ptrauth_swift_type_layout_string
370373
#define __ptrauth_swift_deinit_work_function
374+
#define __ptrauth_swift_is_global_actor_function
371375
#define swift_ptrauth_struct(key, discriminator)
372376
#define swift_ptrauth_struct_derived(from)
373377
#endif

include/swift/Runtime/Metadata.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,11 +1057,20 @@ struct ConcurrencyStandardTypeDescriptors {
10571057
#include "swift/Demangling/StandardTypesMangling.def"
10581058
};
10591059

1060-
/// Register the type descriptors with standard manglings from the Concurrency
1061-
/// runtime. The passed-in struct must be immortal.
1060+
/// Function that determines whether we are executing on the given global
1061+
/// actor. The metadata is for the global actor type, and the witness table
1062+
/// is the conformance of that type to the GlobalActor protocol.
1063+
typedef bool (* SWIFT_CC(swift) IsCurrentGlobalActor)(const Metadata *, const WitnessTable *);
1064+
1065+
/// Register various concurrency-related data and hooks needed in the Swift
1066+
/// standard library / runtime. This includes type descriptors with standard
1067+
/// manglings from the Concurrency runtime as well as a hook to check whether
1068+
/// we are running on a specific global actor. Any pointers passed in here must
1069+
/// be immortal.
10621070
SWIFT_RUNTIME_STDLIB_SPI
1063-
void _swift_registerConcurrencyStandardTypeDescriptors(
1064-
const ConcurrencyStandardTypeDescriptors *descriptors);
1071+
void _swift_registerConcurrencyRuntime(
1072+
const ConcurrencyStandardTypeDescriptors *descriptors,
1073+
IsCurrentGlobalActor isCurrentGlobalActor);
10651074

10661075
/// Initialize the value witness table for a struct using the provided like type
10671076
/// as the basis for the layout.

lib/IRGen/GenProto.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/ASTContext.h"
3131
#include "swift/AST/CanTypeVisitor.h"
3232
#include "swift/AST/Types.h"
33+
#include "swift/AST/ConformanceLookup.h"
3334
#include "swift/AST/Decl.h"
3435
#include "swift/AST/DiagnosticsIRGen.h"
3536
#include "swift/AST/GenericEnvironment.h"
@@ -93,6 +94,11 @@
9394
using namespace swift;
9495
using namespace irgen;
9596

97+
namespace swift {
98+
// FIXME: Move this on to ProtocolConformance?
99+
ActorIsolation getConformanceIsolation(ProtocolConformance *conformance);
100+
}
101+
96102
namespace {
97103

98104
/// A class for computing how to pass arguments to a polymorphic
@@ -2180,6 +2186,7 @@ namespace {
21802186
addConditionalRequirements();
21812187
addResilientWitnesses();
21822188
addGenericWitnessTable();
2189+
addGlobalActorIsolation();
21832190

21842191
// We fill the flags last, since we continue filling them in
21852192
// after the call to addFlags() deposits the placeholder.
@@ -2216,6 +2223,7 @@ namespace {
22162223
Flags = Flags.withIsRetroactive(conf->isRetroactive());
22172224
Flags = Flags.withIsSynthesizedNonUnique(conf->isSynthesizedNonUnique());
22182225
Flags = Flags.withIsConformanceOfProtocol(conf->isConformanceOfProtocol());
2226+
Flags = Flags.withHasGlobalActorIsolation(conf->isIsolated());
22192227
} else {
22202228
Flags = Flags.withIsRetroactive(false)
22212229
.withIsSynthesizedNonUnique(false);
@@ -2403,6 +2411,42 @@ namespace {
24032411
B.addRelativeAddress(privateData);
24042412
}
24052413
}
2414+
2415+
void addGlobalActorIsolation() {
2416+
if (!Flags.hasGlobalActorIsolation())
2417+
return;
2418+
2419+
auto normal = cast<NormalProtocolConformance>(Conformance);
2420+
assert(normal->isIsolated());
2421+
auto nominal = normal->getDeclContext()->getSelfNominalTypeDecl();
2422+
2423+
// Add global actor type.
2424+
auto sig = nominal->getGenericSignatureOfContext();
2425+
auto isolation = getConformanceIsolation(
2426+
const_cast<RootProtocolConformance *>(Conformance));
2427+
assert(isolation.isGlobalActor());
2428+
Type globalActorType = isolation.getGlobalActor();
2429+
auto globalActorTypeName = IGM.getTypeRef(
2430+
globalActorType, sig, MangledTypeRefRole::Metadata).first;
2431+
B.addRelativeAddress(globalActorTypeName);
2432+
2433+
// Add conformance of the global actor type to the GlobalActor protocol.
2434+
SmallVector<ProtocolConformance *, 1> globalActorConformances;
2435+
auto globalActorProtocol =
2436+
IGM.Context.getProtocol(KnownProtocolKind::GlobalActor);
2437+
auto globalActorConformance = lookupConformance(
2438+
globalActorType, globalActorProtocol);
2439+
2440+
auto rootGlobalActorConformance = globalActorConformance.getConcrete()
2441+
->getRootConformance();
2442+
IGM.IRGen.addLazyWitnessTable(rootGlobalActorConformance);
2443+
2444+
auto globalActorConformanceDescriptor =
2445+
IGM.getAddrOfLLVMVariableOrGOTEquivalent(
2446+
LinkEntity::forProtocolConformanceDescriptor(
2447+
rootGlobalActorConformance));
2448+
B.addRelativeAddress(globalActorConformanceDescriptor);
2449+
}
24062450
};
24072451
}
24082452

stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def

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

196+
OVERRIDE_PROTOCOLCONFORMANCE(conformsToProtocolWithExecutionContext,
197+
const WitnessTable *, , , swift::,
198+
(const Metadata * const type,
199+
const ProtocolDescriptor *protocol,
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))
208+
196209
OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::,
197210
(const void *pattern, const void *arguments),
198211
(pattern, arguments))

stdlib/public/Concurrency/Setup.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND));
3434
#include "swift/Demangling/StandardTypesMangling.def"
3535

36+
// Defined in Swift, redeclared here so we can register it with the runtime.
37+
extern "C" SWIFT_CC(swift)
38+
bool _swift_task_isCurrentGlobalActor(
39+
const swift::Metadata *, const swift::WitnessTable *);
40+
3641
// Register our type descriptors with standard manglings when the concurrency
3742
// runtime is loaded. This allows the runtime to quickly resolve those standard
3843
// manglings.
@@ -43,5 +48,7 @@ __attribute__((constructor)) static void setupStandardConcurrencyDescriptors() {
4348
&DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)),
4449
#include "swift/Demangling/StandardTypesMangling.def"
4550
};
46-
_swift_registerConcurrencyStandardTypeDescriptors(&descriptors);
51+
_swift_registerConcurrencyRuntime(
52+
&descriptors,
53+
&_swift_task_isCurrentGlobalActor);
4754
}

stdlib/public/Concurrency/Task.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,14 @@ func _taskIsCurrentExecutor(_ executor: Builtin.Executor) -> Bool
15471547
internal func _taskIsCurrentExecutor(
15481548
executor: Builtin.Executor, flags: UInt64) -> Bool
15491549

1550+
extension GlobalActor {
1551+
@available(SwiftStdlib 6.2, *)
1552+
@_silgen_name("_swift_task_isCurrentGlobalActor")
1553+
internal static func _taskIsCurrentGlobalActor() -> Bool {
1554+
let executor = unsafe sharedUnownedExecutor
1555+
return unsafe _taskIsCurrentExecutor(executor: executor.executor, flags: 0)
1556+
}
1557+
}
15501558
#endif
15511559

15521560
@available(SwiftStdlib 5.1, *)

0 commit comments

Comments
 (0)