15
15
#include " swift/Runtime/Concurrent.h"
16
16
#include " swift/Runtime/Debug.h"
17
17
#include " swift/Runtime/Metadata.h"
18
- #include " ../runtime/Private.h"
18
+ #include " Private.h"
19
+ #include " SwiftValue.h"
20
+ #include " SwiftHashableSupport.h"
19
21
20
22
using namespace swift ;
21
-
22
- // / The name demangles to "protocol descriptor for Swift.Hashable".
23
- extern " C" const ProtocolDescriptor _TMps8Hashable;
23
+ using namespace swift ::hashable_support;
24
24
25
25
namespace {
26
26
struct HashableConformanceKey {
@@ -36,6 +36,9 @@ struct HashableConformanceEntry {
36
36
37
37
// / The highest (closest to the root) type in the superclass chain
38
38
// / that conforms to `Hashable`.
39
+ // /
40
+ // / Always non-NULL. We don't cache negative responses so that we
41
+ // / don't have to deal with cache invalidation.
39
42
const Metadata *baseTypeThatConformsToHashable;
40
43
41
44
HashableConformanceEntry (HashableConformanceKey key,
@@ -59,16 +62,26 @@ struct HashableConformanceEntry {
59
62
};
60
63
} // end unnamed namesapce
61
64
65
+ // FIXME(performance): consider merging this cache into the regular
66
+ // protocol conformance cache.
62
67
static Lazy<ConcurrentMap<HashableConformanceEntry>> HashableConformances;
63
68
64
- // / Find the base type that introduces the `Hashable` conformance.
65
- // /
66
- // / - Precondition: `type` conforms to `Hashable` (not checked).
67
- static const Metadata * findHashableBaseType ( const Metadata *type) {
69
+ template < bool KnownToConformToHashable>
70
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
71
+ static const Metadata * findHashableBaseTypeImpl ( const Metadata *type) {
72
+ // Check the cache first.
68
73
if (HashableConformanceEntry *entry =
69
74
HashableConformances->find (HashableConformanceKey{type})) {
70
75
return entry->baseTypeThatConformsToHashable ;
71
76
}
77
+ if (!KnownToConformToHashable &&
78
+ !swift_conformsToProtocol (type, &_TMps8Hashable)) {
79
+ // Don't cache the negative response because we don't invalidate
80
+ // this cache when a new conformance is loaded dynamically.
81
+ return nullptr ;
82
+ }
83
+ // By this point, `type` is known to conform to `Hashable`.
84
+
72
85
const Metadata *baseTypeThatConformsToHashable = type;
73
86
while (true ) {
74
87
const Metadata *superclass =
@@ -84,6 +97,26 @@ static const Metadata *findHashableBaseType(const Metadata *type) {
84
97
return baseTypeThatConformsToHashable;
85
98
}
86
99
100
+ // / Find the base type that introduces the `Hashable` conformance.
101
+ // / Because the provided type is known to conform to `Hashable`, this
102
+ // / function always returns non-null.
103
+ // /
104
+ // / - Precondition: `type` conforms to `Hashable` (not checked).
105
+ const Metadata *swift::hashable_support::findHashableBaseTypeOfHashableType (
106
+ const Metadata *type) {
107
+ auto result =
108
+ findHashableBaseTypeImpl</* KnownToConformToHashable=*/ true >(type);
109
+ assert (result && " Known-hashable types should have a `Hashable` conformance." );
110
+ return result;
111
+ }
112
+
113
+ // / Find the base type that introduces the `Hashable` conformance.
114
+ // / If `type` does not conform to `Hashable`, `nullptr` is returned.
115
+ const Metadata *swift::hashable_support::findHashableBaseType (
116
+ const Metadata *type) {
117
+ return findHashableBaseTypeImpl</* KnownToConformToHashable=*/ false >(type);
118
+ }
119
+
87
120
SWIFT_CC (swift) SWIFT_RUNTIME_STDLIB_INTERFACE
88
121
extern "C" void _swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
89
122
const OpaqueValue *value,
@@ -94,7 +127,7 @@ extern "C" void _swift_stdlib_makeAnyHashableUsingDefaultRepresentation(
94
127
95
128
SWIFT_CC (swift) SWIFT_RUNTIME_STDLIB_INTERFACE
96
129
extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
97
- const OpaqueValue *value,
130
+ OpaqueValue *value,
98
131
const void *anyHashableResultPointer,
99
132
const Metadata *type,
100
133
const WitnessTable *hashableWT
@@ -103,8 +136,35 @@ extern "C" void _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType(
103
136
case MetadataKind::Class:
104
137
case MetadataKind::ObjCClassWrapper:
105
138
case MetadataKind::ForeignClass: {
139
+ #if SWIFT_OBJC_INTEROP
140
+ id srcObject;
141
+ memcpy (&srcObject, value, sizeof (id));
142
+ // Do we have a SwiftValue?
143
+ if (SwiftValue *srcSwiftValue = getAsSwiftValue (srcObject)) {
144
+ // If so, extract the boxed value and try to cast it.
145
+ const Metadata *unboxedType;
146
+ const OpaqueValue *unboxedValue;
147
+ std::tie (unboxedType, unboxedValue) =
148
+ getValueFromSwiftValue (srcSwiftValue);
149
+
150
+ if (auto unboxedHashableWT =
151
+ swift_conformsToProtocol (type, &_TMps8Hashable)) {
152
+ ValueBuffer unboxedCopyBuf;
153
+ auto unboxedValueCopy = unboxedType->vw_initializeBufferWithCopy (
154
+ &unboxedCopyBuf, const_cast <OpaqueValue *>(unboxedValue));
155
+ _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType (
156
+ unboxedValueCopy, anyHashableResultPointer, unboxedType,
157
+ unboxedHashableWT);
158
+ unboxedType->vw_deallocateBuffer (&unboxedCopyBuf);
159
+ type->vw_destroy (value);
160
+ return ;
161
+ }
162
+ }
163
+ #endif
164
+
106
165
_swift_stdlib_makeAnyHashableUsingDefaultRepresentation (
107
- value, anyHashableResultPointer, findHashableBaseType (type),
166
+ value, anyHashableResultPointer,
167
+ findHashableBaseTypeOfHashableType (type),
108
168
hashableWT);
109
169
return ;
110
170
}
0 commit comments