@@ -28,8 +28,9 @@ class AsyncTask;
28
28
class DefaultActor ;
29
29
class Job ;
30
30
class SerialExecutorWitnessTable ;
31
+ class TaskExecutorWitnessTable ;
31
32
32
- // / An unmanaged reference to an executor.
33
+ // / An unmanaged reference to a serial executor.
33
34
// /
34
35
// / This type corresponds to the type Optional<Builtin.Executor> in
35
36
// / Swift. The representation of nil in Optional<Builtin.Executor>
@@ -53,7 +54,7 @@ class SerialExecutorWitnessTable;
53
54
// / bits off before accessing the witness table, so setting them
54
55
// / in the future should back-deploy as long as the witness table
55
56
// / reference is still present.
56
- class ExecutorRef {
57
+ class SerialExecutorRef {
57
58
HeapObject *Identity; // Not necessarily Swift reference-countable
58
59
uintptr_t Implementation;
59
60
@@ -79,7 +80,7 @@ class ExecutorRef {
79
80
80
81
static_assert (static_cast <uintptr_t >(ExecutorKind::Ordinary) == 0 );
81
82
82
- constexpr ExecutorRef (HeapObject *identity, uintptr_t implementation)
83
+ constexpr SerialExecutorRef (HeapObject *identity, uintptr_t implementation)
83
84
: Identity(identity), Implementation(implementation) {}
84
85
85
86
public:
@@ -88,35 +89,35 @@ class ExecutorRef {
88
89
// / environment, it's presumed to be okay to switch synchronously
89
90
// / to an actor. As an executor request, this represents a request
90
91
// / to drop whatever the current actor is.
91
- constexpr static ExecutorRef generic () {
92
- return ExecutorRef (nullptr , 0 );
92
+ constexpr static SerialExecutorRef generic () {
93
+ return SerialExecutorRef (nullptr , 0 );
93
94
}
94
95
95
96
// / Given a pointer to a default actor, return an executor reference
96
97
// / for it.
97
- static ExecutorRef forDefaultActor (DefaultActor *actor) {
98
+ static SerialExecutorRef forDefaultActor (DefaultActor *actor) {
98
99
assert (actor);
99
- return ExecutorRef (actor, 0 );
100
+ return SerialExecutorRef (actor, 0 );
100
101
}
101
102
102
103
// / Given a pointer to a serial executor and its SerialExecutor
103
104
// / conformance, return an executor reference for it.
104
- static ExecutorRef forOrdinary (HeapObject *identity,
105
+ static SerialExecutorRef forOrdinary (HeapObject *identity,
105
106
const SerialExecutorWitnessTable *witnessTable) {
106
107
assert (identity);
107
108
assert (witnessTable);
108
109
auto wtable = reinterpret_cast <uintptr_t >(witnessTable) |
109
110
static_cast <uintptr_t >(ExecutorKind::Ordinary);
110
- return ExecutorRef (identity, wtable);
111
+ return SerialExecutorRef (identity, wtable);
111
112
}
112
113
113
- static ExecutorRef forComplexEquality (HeapObject *identity,
114
+ static SerialExecutorRef forComplexEquality (HeapObject *identity,
114
115
const SerialExecutorWitnessTable *witnessTable) {
115
116
assert (identity);
116
117
assert (witnessTable);
117
118
auto wtable = reinterpret_cast <uintptr_t >(witnessTable) |
118
119
static_cast <uintptr_t >(ExecutorKind::ComplexEquality);
119
- return ExecutorRef (identity, wtable);
120
+ return SerialExecutorRef (identity, wtable);
120
121
}
121
122
122
123
HeapObject *getIdentity () const {
@@ -162,7 +163,7 @@ class ExecutorRef {
162
163
163
164
// / Do we have to do any work to start running as the requested
164
165
// / executor?
165
- bool mustSwitchToRun (ExecutorRef newExecutor) const {
166
+ bool mustSwitchToRun (SerialExecutorRef newExecutor) const {
166
167
return Identity != newExecutor.Identity ;
167
168
}
168
169
@@ -174,10 +175,94 @@ class ExecutorRef {
174
175
return Implementation & WitnessTableMask;
175
176
}
176
177
177
- bool operator ==(ExecutorRef other) const {
178
+ bool operator ==(SerialExecutorRef other) const {
178
179
return Identity == other.Identity ;
179
180
}
180
- bool operator !=(ExecutorRef other) const {
181
+ bool operator !=(SerialExecutorRef other) const {
182
+ return !(*this == other);
183
+ }
184
+ };
185
+
186
+ class TaskExecutorRef {
187
+ HeapObject *Identity; // Not necessarily Swift reference-countable
188
+ uintptr_t Implementation;
189
+
190
+ // We future-proof the ABI here by masking the low bits off the
191
+ // implementation pointer before using it as a witness table.
192
+ //
193
+ // We have 3 bits for future use remaining here.
194
+ enum : uintptr_t {
195
+ WitnessTableMask = ~uintptr_t (alignof (void *) - 1 )
196
+ };
197
+
198
+ // / The kind is stored in the free bits in the `Implementation` witness table reference.
199
+ enum class TaskExecutorKind : uintptr_t {
200
+ // / Ordinary executor.
201
+ Ordinary = 0b00 ,
202
+ };
203
+
204
+ static_assert (static_cast <uintptr_t >(TaskExecutorKind::Ordinary) == 0 );
205
+
206
+ constexpr TaskExecutorRef (HeapObject *identity, uintptr_t implementation)
207
+ : Identity(identity), Implementation(implementation) {}
208
+
209
+ public:
210
+
211
+ constexpr static TaskExecutorRef undefined () {
212
+ return TaskExecutorRef (nullptr , 0 );
213
+ }
214
+
215
+ // / Given a pointer to a serial executor and its TaskExecutor
216
+ // / conformance, return an executor reference for it.
217
+ static TaskExecutorRef forOrdinary (HeapObject *identity,
218
+ const SerialExecutorWitnessTable *witnessTable) {
219
+ assert (identity);
220
+ assert (witnessTable);
221
+ auto wtable = reinterpret_cast <uintptr_t >(witnessTable) |
222
+ static_cast <uintptr_t >(TaskExecutorKind::Ordinary);
223
+ return TaskExecutorRef (identity, wtable);
224
+ }
225
+
226
+ HeapObject *getIdentity () const {
227
+ return Identity;
228
+ }
229
+
230
+ // / Is this the generic executor reference?
231
+ bool isUndefined () const {
232
+ return Identity == 0 ;
233
+ }
234
+
235
+ TaskExecutorKind getExecutorKind () const {
236
+ return static_cast <TaskExecutorKind>(Implementation & ~WitnessTableMask);
237
+ }
238
+
239
+ // / Is this an ordinary executor reference?
240
+ // / These executor references are the default kind, and have no special treatment elsewhere in the system.
241
+ bool isOrdinary () const {
242
+ return getExecutorKind () == TaskExecutorKind::Ordinary;
243
+ }
244
+
245
+ const TaskExecutorWitnessTable *getTaskExecutorWitnessTable () const {
246
+ assert (!isUndefined ());
247
+ auto table = Implementation & WitnessTableMask;
248
+ return reinterpret_cast <const TaskExecutorWitnessTable*>(table);
249
+ }
250
+
251
+ // /// Do we have to do any work to start running as the requested
252
+ // /// executor?
253
+ // bool mustSwitchToRun(TaskExecutorRef newExecutor) const {
254
+ // return Identity != newExecutor.Identity;
255
+ // }
256
+
257
+ // / Get the raw value of the Implementation field, for tracing.
258
+ uintptr_t getRawImplementation () const {
259
+ return Implementation & WitnessTableMask;
260
+ }
261
+
262
+ bool operator ==(TaskExecutorRef other) const {
263
+ return Identity == other.Identity ;
264
+ }
265
+ bool operator !=(TaskExecutorRef other) const {
181
266
return !(*this == other);
182
267
}
183
268
};
0 commit comments