Skip to content

Commit b1b7818

Browse files
committed
Make the caches be uintptr_t
This simplified a lot of things. (Thanks @mikeash for the suggestion!) Also reorganized the code a bit.
1 parent 4c4975c commit b1b7818

File tree

1 file changed

+81
-67
lines changed

1 file changed

+81
-67
lines changed

stdlib/public/runtime/SwiftValue.mm

Lines changed: 81 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,18 @@ - (id)copyWithZone:(NSZone *)zone;
6767
/// The base type that introduces the `Hashable` or `Equatable` conformance.
6868
/// This member is lazily-initialized.
6969
/// 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;
7174

7275
/// The witness table for `Hashable` conformance.
73-
/// This member is only available for native Swift errors.
7476
/// This member is lazily-initialized.
7577
/// 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;
7782

7883
/// Get the base type that conforms to `Hashable`.
7984
/// Returns NULL if the type does not conform.
@@ -93,101 +98,114 @@ - (id)copyWithZone:(NSZone *)zone;
9398

9499
/// Populate the `cachedConformance` with the Hashable conformance
95100
/// (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;
97106

98107

99108
SwiftValueHeader()
100-
: cachedBaseType(nullptr), cachedConformance((void *)nullptr) {}
109+
: cachedBaseType(0), cachedConformance(0) {}
101110
};
102111

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-
131112
// Set cachedConformance to the Hashable conformance if
132113
// there is one, else the Equatable conformance.
133114
// Also set cachedBaseType to the parent type that
134115
// 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:
137117
// * If the LSbit is not set, it's the Hashable conformance
138118
// * If the value is exactly 1, neither conformance is present
139119
// * 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
142124
SwiftValueHeader::cacheHashableEquatableConformance() const {
143125
// Relevant conformance and baseType
144-
const void * conformance;
145-
const Metadata * baseType;
126+
uintptr_t conformance;
127+
uintptr_t baseType;
146128

147129
// First, see if it's Hashable
148130
const HashableWitnessTable *hashable =
149131
reinterpret_cast<const HashableWitnessTable *>(
150132
swift_conformsToProtocolCommon(type, &HashableProtocolDescriptor));
151133
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));
154136
} else {
155137
// If not Hashable, maybe Equatable?
156138
auto equatable =
157139
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;
159142

160-
// Find equatable base type
143+
if (equatable != nullptr) {
144+
// Find equatable base type
161145
#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();
165149
#else
166-
const auto *conformance = equatable->getDescription();
150+
const auto *description = equatable->getDescription();
167151
#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+
}
171159
}
172160

173161
// Set the conformance/baseType caches atomically
174-
const void * expectedConformance = nullptr;
162+
uintptr_t expectedConformance = 0;
175163
cachedConformance.compare_exchange_strong(
176164
expectedConformance, conformance, std::memory_order_acq_rel);
177-
const Metadata * expectedType = (const Metadata *)nullptr;
165+
uintptr_t expectedType = 0;
178166
cachedBaseType.compare_exchange_strong(
179167
expectedType, baseType, std::memory_order_acq_rel);
180168

181169
return conformance;
182170
}
183171

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+
184202
const hashable_support::HashableWitnessTable *
185203
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) {
188206
wt = cacheHashableEquatableConformance();
189207
}
190-
if ((reinterpret_cast<uintptr_t>(wt) & 1) == 0) {
208+
if ((wt & 1) == 0) {
191209
// Hashable conformance found
192210
return reinterpret_cast<const hashable_support::HashableWitnessTable *>(wt);
193211
} else {
@@ -198,16 +216,16 @@ - (id)copyWithZone:(NSZone *)zone;
198216

199217
const equatable_support::EquatableWitnessTable *
200218
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) {
203221
wt = cacheHashableEquatableConformance();
204222
}
205-
if ((reinterpret_cast<uintptr_t>(wt) & 1) == 0) {
223+
if ((wt & 1) == 0) {
206224
// Hashable conformance found
207225
return nullptr;
208226
} else {
209227
// 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);
211229
}
212230
}
213231

@@ -395,10 +413,8 @@ - (BOOL)isEqual:(id)other {
395413
auto selfHeader = getSwiftValueHeader(self);
396414
auto otherHeader = getSwiftValueHeader(other);
397415

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()) {
402418
auto otherHashableBaseType = otherHeader->getHashableBaseType();
403419
if (selfHashableBaseType == otherHashableBaseType) {
404420
return _swift_stdlib_Hashable_isEqual_indirect(
@@ -411,10 +427,8 @@ - (BOOL)isEqual:(id)other {
411427
}
412428
}
413429

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()) {
418432
auto otherEquatableBaseType = otherHeader->getEquatableBaseType();
419433
if (selfEquatableBaseType == otherEquatableBaseType) {
420434
return _swift_stdlib_Equatable_isEqual_indirect(

0 commit comments

Comments
 (0)