@@ -27,25 +27,42 @@ class AsyncContext;
27
27
class AsyncTask ;
28
28
class DefaultActor ;
29
29
class 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 ;
34
31
35
32
// / An unmanaged reference to an executor.
36
33
// /
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.
45
56
class ExecutorRef {
46
57
HeapObject *Identity; // Not necessarily Swift reference-countable
47
58
uintptr_t Implementation;
48
59
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
+
49
66
constexpr ExecutorRef (HeapObject *identity, uintptr_t implementation)
50
67
: Identity(identity), Implementation(implementation) {}
51
68
@@ -58,23 +75,11 @@ class ExecutorRef {
58
75
return ExecutorRef (nullptr , 0 );
59
76
}
60
77
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
-
73
78
// / Given a pointer to a default actor, return an executor reference
74
79
// / for it.
75
80
static ExecutorRef forDefaultActor (DefaultActor *actor) {
76
81
assert (actor);
77
- return ExecutorRef (actor, unsigned (ExecutorRefFlags::DefaultActor) );
82
+ return ExecutorRef (actor, 0 );
78
83
}
79
84
80
85
HeapObject *getIdentity () const {
@@ -86,37 +91,29 @@ class ExecutorRef {
86
91
return Identity == 0 ;
87
92
}
88
93
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
-
101
94
// / Is this a default-actor executor reference?
102
95
bool isDefaultActor () const {
103
- return Implementation & unsigned (ExecutorRefFlags::DefaultActor) ;
96
+ return ! isGeneric () && Implementation == 0 ;
104
97
}
105
98
DefaultActor *getDefaultActor () const {
106
99
assert (isDefaultActor ());
107
100
return reinterpret_cast <DefaultActor*>(Identity);
108
101
}
109
102
103
+ const SerialExecutorWitnessTable *getSerialExecutorWitnessTable () const {
104
+ assert (!isGeneric () && !isDefaultActor ());
105
+ auto table = Implementation & WitnessTableMask;
106
+ return reinterpret_cast <const SerialExecutorWitnessTable*>(table);
107
+ }
108
+
110
109
// / Do we have to do any work to start running as the requested
111
110
// / executor?
112
111
bool mustSwitchToRun (ExecutorRef newExecutor) const {
113
112
return Identity != newExecutor.Identity ;
114
113
}
115
114
116
115
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 ;
120
117
}
121
118
bool operator !=(ExecutorRef other) const {
122
119
return !(*this == other);
0 commit comments