@@ -59,10 +59,26 @@ class ExecutorRef {
5959
6060 // We future-proof the ABI here by masking the low bits off the
6161 // implementation pointer before using it as a witness table.
62+ //
63+ // We have 3 bits for future use remaining here.
6264 enum : uintptr_t {
6365 WitnessTableMask = ~uintptr_t (alignof (void *) - 1 )
6466 };
6567
68+ // / The kind is stored in the free bits in the `Implementation` witness table reference.
69+ enum class ExecutorKind : uintptr_t {
70+ // / Ordinary executor.
71+ // /
72+ // / Note that the "Generic" executor is also implicitly "Ordinary".
73+ // / To check if an executor is Generic, explicitly check this by calling `isGeneric`.
74+ Ordinary = 0b00 ,
75+ // / Executor that may need to participate in complex "same context" checks,
76+ // / by invoking `isSameExclusiveExecutionContext` when comparing execution contexts.
77+ ComplexEquality = 0b01 ,
78+ };
79+
80+ static_assert (static_cast <uintptr_t >(ExecutorKind::Ordinary) == 0 );
81+
6682 constexpr ExecutorRef (HeapObject *identity, uintptr_t implementation)
6783 : Identity(identity), Implementation(implementation) {}
6884
@@ -89,7 +105,18 @@ class ExecutorRef {
89105 const SerialExecutorWitnessTable *witnessTable) {
90106 assert (identity);
91107 assert (witnessTable);
92- return ExecutorRef (identity, reinterpret_cast <uintptr_t >(witnessTable));
108+ auto wtable = reinterpret_cast <uintptr_t >(witnessTable) |
109+ static_cast <uintptr_t >(ExecutorKind::Ordinary);
110+ return ExecutorRef (identity, wtable);
111+ }
112+
113+ static ExecutorRef forComplexEquality (HeapObject *identity,
114+ const SerialExecutorWitnessTable *witnessTable) {
115+ assert (identity);
116+ assert (witnessTable);
117+ auto wtable = reinterpret_cast <uintptr_t >(witnessTable) |
118+ static_cast <uintptr_t >(ExecutorKind::ComplexEquality);
119+ return ExecutorRef (identity, wtable);
93120 }
94121
95122 HeapObject *getIdentity () const {
@@ -101,6 +128,23 @@ class ExecutorRef {
101128 return Identity == 0 ;
102129 }
103130
131+ ExecutorKind getExecutorKind () const {
132+ return static_cast <ExecutorKind>(Implementation & ~WitnessTableMask);
133+ }
134+
135+ // / Is this an ordinary executor reference?
136+ // / These executor references are the default kind, and have no special treatment elsewhere in the system.
137+ bool isOrdinary () const {
138+ return getExecutorKind () == ExecutorKind::Ordinary;
139+ }
140+
141+ // / Is this an `complex-equality` executor reference?
142+ // / These executor references should implement `isSameExclusiveExecutionContext` which will be invoked
143+ // / when two executors are compared for being the same exclusive execution context.
144+ bool isComplexEquality () const {
145+ return getExecutorKind () == ExecutorKind::ComplexEquality;
146+ }
147+
104148 // / Is this a default-actor executor reference?
105149 bool isDefaultActor () const {
106150 return !isGeneric () && Implementation == 0 ;
@@ -126,7 +170,9 @@ class ExecutorRef {
126170 bool isMainExecutor () const ;
127171
128172 // / Get the raw value of the Implementation field, for tracing.
129- uintptr_t getRawImplementation () { return Implementation; }
173+ uintptr_t getRawImplementation () const {
174+ return Implementation & WitnessTableMask;
175+ }
130176
131177 bool operator ==(ExecutorRef other) const {
132178 return Identity == other.Identity ;
0 commit comments