@@ -67,13 +67,18 @@ - (id)copyWithZone:(NSZone *)zone;
67
67
// / The base type that introduces the `Hashable` or `Equatable` conformance.
68
68
// / This member is lazily-initialized.
69
69
// / Instead of using it directly, call `getHashableBaseType()` or `getEquatableBaseType()`
70
- mutable std::atomic<const Metadata *> cachedBaseType;
70
+ // / Value here is encoded:
71
+ // / * Least-significant bit set: This is an Equatable base type
72
+ // / * Least-significant bit not set: This is a Hashable base type
73
+ mutable std::atomic<uintptr_t > cachedBaseType;
71
74
72
75
// / The witness table for `Hashable` conformance.
73
- // / This member is only available for native Swift errors.
74
76
// / This member is lazily-initialized.
75
77
// / Instead of using it directly, call `getHashableConformance()`.
76
- mutable std::atomic<const void *> cachedConformance;
78
+ // / Value here is encoded:
79
+ // / * Least-significant bit set: This is an Equatable conformance
80
+ // / * Least-significant bit not set: This is a Hashable conformance
81
+ mutable std::atomic<uintptr_t > cachedConformance;
77
82
78
83
// / Get the base type that conforms to `Hashable`.
79
84
// / Returns NULL if the type does not conform.
@@ -93,101 +98,114 @@ - (id)copyWithZone:(NSZone *)zone;
93
98
94
99
// / Populate the `cachedConformance` with the Hashable conformance
95
100
// / (if there is one), else the Equatable conformance.
96
- const void * cacheHashableEquatableConformance () const ;
101
+ // / Returns the encoded conformance: least-significant
102
+ // / bit is set if this is an Equatable conformance,
103
+ // / else it is a Hashable conformance. 0 (or 1) indicates
104
+ // / neither was found.
105
+ uintptr_t cacheHashableEquatableConformance () const ;
97
106
98
107
99
108
SwiftValueHeader ()
100
- : cachedBaseType(nullptr ), cachedConformance(( void *) nullptr ) {}
109
+ : cachedBaseType(0 ), cachedConformance(0 ) {}
101
110
};
102
111
103
- const Metadata *SwiftValueHeader::getHashableBaseType () const {
104
- auto type = cachedBaseType.load (std::memory_order_acquire);
105
- if (type == nullptr ) {
106
- cacheHashableEquatableConformance ();
107
- type = cachedBaseType.load (std::memory_order_acquire);
108
- }
109
- if ((reinterpret_cast <uintptr_t >(type) & 1 ) == 0 ) {
110
- return type;
111
- } else {
112
- return nullptr ;
113
- }
114
- }
115
-
116
- const Metadata *SwiftValueHeader::getEquatableBaseType () const {
117
- auto type = cachedBaseType.load (std::memory_order_acquire);
118
- if (type == nullptr ) {
119
- cacheHashableEquatableConformance ();
120
- type = cachedBaseType.load (std::memory_order_acquire);
121
- }
122
- if ((reinterpret_cast <uintptr_t >(type) & 1 ) == 0 ) {
123
- // A Hashable conformance was found
124
- return nullptr ;
125
- } else {
126
- // An Equatable conformance (or neither) was found
127
- return reinterpret_cast <const Metadata *>(reinterpret_cast <uintptr_t >(type) & ~1ULL );
128
- }
129
- }
130
-
131
112
// Set cachedConformance to the Hashable conformance if
132
113
// there is one, else the Equatable conformance.
133
114
// Also set cachedBaseType to the parent type that
134
115
// introduced the Hashable/Equatable conformance.
135
- // The cached conformance and type set the LSbit to indicate
136
- // which conformance is present:
116
+ // The cached conformance and type are encoded:
137
117
// * If the LSbit is not set, it's the Hashable conformance
138
118
// * If the value is exactly 1, neither conformance is present
139
119
// * If the LSbit is 1, strip it and you'll have the Equatable conformance
140
- // (Null indicates the cache has not been initialized yet)
141
- const void *
120
+ // (Null indicates the cache has not been initialized yet;
121
+ // that will never be true on exit of this function.)
122
+ // Return: encoded cachedConformance value
123
+ uintptr_t
142
124
SwiftValueHeader::cacheHashableEquatableConformance () const {
143
125
// Relevant conformance and baseType
144
- const void * conformance;
145
- const Metadata * baseType;
126
+ uintptr_t conformance;
127
+ uintptr_t baseType;
146
128
147
129
// First, see if it's Hashable
148
130
const HashableWitnessTable *hashable =
149
131
reinterpret_cast <const HashableWitnessTable *>(
150
132
swift_conformsToProtocolCommon (type, &HashableProtocolDescriptor));
151
133
if (hashable != nullptr ) {
152
- conformance = hashable;
153
- baseType = findHashableBaseType (type);
134
+ conformance = reinterpret_cast < uintptr_t >( hashable) ;
135
+ baseType = reinterpret_cast < uintptr_t >( findHashableBaseType (type) );
154
136
} else {
155
137
// If not Hashable, maybe Equatable?
156
138
auto equatable =
157
139
swift_conformsToProtocolCommon (type, &equatable_support::EquatableProtocolDescriptor);
158
- conformance = reinterpret_cast <const void *>(reinterpret_cast <uintptr_t >(equatable) | 1 );
140
+ // Encode the equatable conformance
141
+ conformance = reinterpret_cast <uintptr_t >(equatable) | 1 ;
159
142
160
- // Find equatable base type
143
+ if (equatable != nullptr ) {
144
+ // Find equatable base type
161
145
#if SWIFT_STDLIB_USE_RELATIVE_PROTOCOL_WITNESS_TABLES
162
- const auto *conformance = lookThroughOptionalConditionalWitnessTable (
163
- reinterpret_cast <const RelativeWitnessTable*>(equatable))
164
- ->getDescription ();
146
+ const auto *description = lookThroughOptionalConditionalWitnessTable (
147
+ reinterpret_cast <const RelativeWitnessTable*>(equatable))
148
+ ->getDescription ();
165
149
#else
166
- const auto *conformance = equatable->getDescription ();
150
+ const auto *description = equatable->getDescription ();
167
151
#endif
168
- const Metadata *baseTypeThatConformsToEquatable =
169
- findConformingSuperclass (type, conformance);
170
- baseType = reinterpret_cast <const Metadata *>(reinterpret_cast <uintptr_t >(baseTypeThatConformsToEquatable) | 1 );
152
+ const Metadata *baseTypeThatConformsToEquatable =
153
+ findConformingSuperclass (type, description);
154
+ // Encode the equatable base type
155
+ baseType = reinterpret_cast <uintptr_t >(baseTypeThatConformsToEquatable) | 1 ;
156
+ } else {
157
+ baseType = 1 ; // Neither equatable nor hashable
158
+ }
171
159
}
172
160
173
161
// Set the conformance/baseType caches atomically
174
- const void * expectedConformance = nullptr ;
162
+ uintptr_t expectedConformance = 0 ;
175
163
cachedConformance.compare_exchange_strong (
176
164
expectedConformance, conformance, std::memory_order_acq_rel);
177
- const Metadata * expectedType = ( const Metadata *) nullptr ;
165
+ uintptr_t expectedType = 0 ;
178
166
cachedBaseType.compare_exchange_strong (
179
167
expectedType, baseType, std::memory_order_acq_rel);
180
168
181
169
return conformance;
182
170
}
183
171
172
+ const Metadata *SwiftValueHeader::getHashableBaseType () const {
173
+ auto type = cachedBaseType.load (std::memory_order_acquire);
174
+ if (type == 0 ) {
175
+ cacheHashableEquatableConformance ();
176
+ type = cachedBaseType.load (std::memory_order_acquire);
177
+ }
178
+ if ((type & 1 ) == 0 ) {
179
+ // A Hashable conformance was found
180
+ return reinterpret_cast <const Metadata *>(type);
181
+ } else {
182
+ // Equatable conformance (or no conformance) found
183
+ return nullptr ;
184
+ }
185
+ }
186
+
187
+ const Metadata *SwiftValueHeader::getEquatableBaseType () const {
188
+ auto type = cachedBaseType.load (std::memory_order_acquire);
189
+ if (type == 0 ) {
190
+ cacheHashableEquatableConformance ();
191
+ type = cachedBaseType.load (std::memory_order_acquire);
192
+ }
193
+ if ((type & 1 ) == 0 ) {
194
+ // A Hashable conformance was found
195
+ return nullptr ;
196
+ } else {
197
+ // An Equatable conformance (or neither) was found
198
+ return reinterpret_cast <const Metadata *>(type & ~1ULL );
199
+ }
200
+ }
201
+
184
202
const hashable_support::HashableWitnessTable *
185
203
SwiftValueHeader::getHashableConformance () const {
186
- const void * wt = cachedConformance.load (std::memory_order_acquire);
187
- if (wt == nullptr ) {
204
+ uintptr_t wt = cachedConformance.load (std::memory_order_acquire);
205
+ if (wt == 0 ) {
188
206
wt = cacheHashableEquatableConformance ();
189
207
}
190
- if ((reinterpret_cast < uintptr_t >(wt) & 1 ) == 0 ) {
208
+ if ((wt & 1 ) == 0 ) {
191
209
// Hashable conformance found
192
210
return reinterpret_cast <const hashable_support::HashableWitnessTable *>(wt);
193
211
} else {
@@ -198,16 +216,16 @@ - (id)copyWithZone:(NSZone *)zone;
198
216
199
217
const equatable_support::EquatableWitnessTable *
200
218
SwiftValueHeader::getEquatableConformance () const {
201
- const void * wt = cachedConformance.load (std::memory_order_acquire);
202
- if (wt == nullptr ) {
219
+ uintptr_t wt = cachedConformance.load (std::memory_order_acquire);
220
+ if (wt == 0 ) {
203
221
wt = cacheHashableEquatableConformance ();
204
222
}
205
- if ((reinterpret_cast < uintptr_t >(wt) & 1 ) == 0 ) {
223
+ if ((wt & 1 ) == 0 ) {
206
224
// Hashable conformance found
207
225
return nullptr ;
208
226
} else {
209
227
// Equatable conformance (or no conformance) found
210
- return reinterpret_cast <const equatable_support::EquatableWitnessTable *>(reinterpret_cast < uintptr_t >(wt) & ~1ULL );
228
+ return reinterpret_cast <const equatable_support::EquatableWitnessTable *>(wt & ~1ULL );
211
229
}
212
230
}
213
231
@@ -395,10 +413,8 @@ - (BOOL)isEqual:(id)other {
395
413
auto selfHeader = getSwiftValueHeader (self);
396
414
auto otherHeader = getSwiftValueHeader (other);
397
415
398
- auto hashableConformance = selfHeader->getHashableConformance ();
399
- if (hashableConformance) {
400
- auto selfHashableBaseType = selfHeader->getHashableBaseType ();
401
- if (selfHashableBaseType) {
416
+ if (auto hashableConformance = selfHeader->getHashableConformance ()) {
417
+ if (auto selfHashableBaseType = selfHeader->getHashableBaseType ()) {
402
418
auto otherHashableBaseType = otherHeader->getHashableBaseType ();
403
419
if (selfHashableBaseType == otherHashableBaseType) {
404
420
return _swift_stdlib_Hashable_isEqual_indirect (
@@ -411,10 +427,8 @@ - (BOOL)isEqual:(id)other {
411
427
}
412
428
}
413
429
414
- auto equatableConformance = selfHeader->getEquatableConformance ();
415
- if (equatableConformance) {
416
- auto selfEquatableBaseType = selfHeader->getEquatableBaseType ();
417
- if (selfEquatableBaseType) {
430
+ if (auto equatableConformance = selfHeader->getEquatableConformance ()) {
431
+ if (auto selfEquatableBaseType = selfHeader->getEquatableBaseType ()) {
418
432
auto otherEquatableBaseType = otherHeader->getEquatableBaseType ();
419
433
if (selfEquatableBaseType == otherEquatableBaseType) {
420
434
return _swift_stdlib_Equatable_isEqual_indirect (
0 commit comments