@@ -27,25 +27,42 @@ class AsyncContext;
2727class AsyncTask ;
2828class DefaultActor ;
2929class Job ;
30-
31- // / FIXME: only exists for the quick-and-dirty MainActor implementation.
32- SWIFT_EXPORT_FROM (swift_Concurrency)
33- Metadata* MainActorMetadata;
30+ class SerialExecutorWitnessTable ;
3431
3532// / An unmanaged reference to an executor.
3633// /
37- // / The representation is two words: identity and implementation.
38- // / The identity word is a reference to the executor object; for
39- // / default actors, this is the actor object. The implementation
40- // / word describes how the executor works; it carries a witness table
41- // / as well as a small number of bits indicating various special
42- // / implementation properties. As an exception to both of these
43- // / rules, a null identity represents a generic executor and
44- // / implies a null implementation word.
34+ // / This type corresponds to the type Optional<Builtin.Executor> in
35+ // / Swift. The representation of nil in Optional<Builtin.Executor>
36+ // / aligns with what this type calls the generic executor, so the
37+ // / notional subtype of this type which is never generic corresponds
38+ // / to the type Builtin.Executor.
39+ // /
40+ // / An executor reference is divided into two pieces:
41+ // /
42+ // / - The identity, which is just a (potentially ObjC) object
43+ // / reference; when this is null, the reference is generic.
44+ // / Equality of executor references is based solely on equality
45+ // / of identity.
46+ // /
47+ // / - The implementation, which is an optional reference to a
48+ // / witness table for the SerialExecutor protocol. When this
49+ // / is null, but the identity is non-null, the reference is to
50+ // / a default actor. The low bits of the implementation pointer
51+ // / are reserved for the use of marking interesting properties
52+ // / about the executor's implementation. The runtime masks these
53+ // / bits off before accessing the witness table, so setting them
54+ // / in the future should back-deploy as long as the witness table
55+ // / reference is still present.
4556class ExecutorRef {
4657 HeapObject *Identity; // Not necessarily Swift reference-countable
4758 uintptr_t Implementation;
4859
60+ // We future-proof the ABI here by masking the low bits off the
61+ // implementation pointer before using it as a witness table.
62+ enum : uintptr_t {
63+ WitnessTableMask = ~uintptr_t (alignof (void *) - 1 )
64+ };
65+
4966 constexpr ExecutorRef (HeapObject *identity, uintptr_t implementation)
5067 : Identity(identity), Implementation(implementation) {}
5168
@@ -58,23 +75,11 @@ class ExecutorRef {
5875 return ExecutorRef (nullptr , 0 );
5976 }
6077
61- // / FIXME: only exists for the quick-and-dirty MainActor implementation.
62- // / NOTE: I didn't go with Executor::forMainActor(DefaultActor*) because
63- // / __swift_run_job_main_executor can't take more than one argument.
64- static ExecutorRef mainExecutor () {
65- auto identity = getMainActorIdentity ();
66- return ExecutorRef (identity, 0 );
67- }
68- static HeapObject *getMainActorIdentity () {
69- return reinterpret_cast <HeapObject*>(
70- ExecutorRefFlags::MainActorIdentity);
71- }
72-
7378 // / Given a pointer to a default actor, return an executor reference
7479 // / for it.
7580 static ExecutorRef forDefaultActor (DefaultActor *actor) {
7681 assert (actor);
77- return ExecutorRef (actor, unsigned (ExecutorRefFlags::DefaultActor) );
82+ return ExecutorRef (actor, 0 );
7883 }
7984
8085 HeapObject *getIdentity () const {
@@ -86,37 +91,29 @@ class ExecutorRef {
8691 return Identity == 0 ;
8792 }
8893
89- // / FIXME: only exists for the quick-and-dirty MainActor implementation.
90- bool isMainExecutor () const {
91- if (Identity == getMainActorIdentity ())
92- return true ;
93-
94- if (Identity == nullptr || MainActorMetadata == nullptr )
95- return false ;
96-
97- Metadata const * metadata = swift_getObjectType (Identity);
98- return metadata == MainActorMetadata;
99- }
100-
10194 // / Is this a default-actor executor reference?
10295 bool isDefaultActor () const {
103- return Implementation & unsigned (ExecutorRefFlags::DefaultActor) ;
96+ return ! isGeneric () && Implementation == 0 ;
10497 }
10598 DefaultActor *getDefaultActor () const {
10699 assert (isDefaultActor ());
107100 return reinterpret_cast <DefaultActor*>(Identity);
108101 }
109102
103+ const SerialExecutorWitnessTable *getSerialExecutorWitnessTable () const {
104+ assert (!isGeneric () && !isDefaultActor ());
105+ auto table = Implementation & WitnessTableMask;
106+ return reinterpret_cast <const SerialExecutorWitnessTable*>(table);
107+ }
108+
110109 // / Do we have to do any work to start running as the requested
111110 // / executor?
112111 bool mustSwitchToRun (ExecutorRef newExecutor) const {
113112 return Identity != newExecutor.Identity ;
114113 }
115114
116115 bool operator ==(ExecutorRef other) const {
117- return Identity == other.Identity
118- // / FIXME: only exists for the quick-and-dirty MainActor implementation.
119- || (isMainExecutor () && other.isMainExecutor ());
116+ return Identity == other.Identity ;
120117 }
121118 bool operator !=(ExecutorRef other) const {
122119 return !(*this == other);
0 commit comments