Skip to content

Commit 5ea3bb2

Browse files
authored
Merge pull request #34769 from mikeash/concurrentmap-misc-to-concurrentreadablehashmap
[Runtime] Change ProtocolCache, NominalCache, and HashableConformances to ConcurrentReadableHashMap.
2 parents 632c9ff + c8f1a53 commit 5ea3bb2

File tree

2 files changed

+81
-32
lines changed

2 files changed

+81
-32
lines changed

stdlib/public/runtime/AnyHashableSupport.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ struct HashableConformanceKey {
2929
/// The lookup key, the metadata of a type that is possibly derived
3030
/// from a type that conforms to `Hashable`.
3131
const Metadata *derivedType;
32+
33+
friend llvm::hash_code hash_value(const HashableConformanceKey &key) {
34+
return llvm::hash_value(key.derivedType);
35+
}
3236
};
3337

3438
struct HashableConformanceEntry {
@@ -48,12 +52,12 @@ struct HashableConformanceEntry {
4852
: derivedType(key.derivedType),
4953
baseTypeThatConformsToHashable(baseTypeThatConformsToHashable) {}
5054

51-
int compareWithKey(const HashableConformanceKey &key) const {
52-
if (key.derivedType != derivedType) {
53-
return (uintptr_t(key.derivedType) < uintptr_t(derivedType) ? -1 : 1);
54-
} else {
55-
return 0;
56-
}
55+
bool matchesKey(const HashableConformanceKey &key) {
56+
return derivedType == key.derivedType;
57+
}
58+
59+
friend llvm::hash_code hash_value(const HashableConformanceEntry &value) {
60+
return hash_value(HashableConformanceKey{value.derivedType});
5761
}
5862

5963
static size_t
@@ -70,16 +74,18 @@ struct HashableConformanceEntry {
7074

7175
// FIXME(performance): consider merging this cache into the regular
7276
// protocol conformance cache.
73-
static ConcurrentMap<HashableConformanceEntry, /*Destructor*/ false>
74-
HashableConformances;
77+
static ConcurrentReadableHashMap<HashableConformanceEntry> HashableConformances;
7578

7679
template <bool KnownToConformToHashable>
7780
SWIFT_ALWAYS_INLINE static const Metadata *
7881
findHashableBaseTypeImpl(const Metadata *type) {
7982
// Check the cache first.
80-
if (HashableConformanceEntry *entry =
81-
HashableConformances.find(HashableConformanceKey{type})) {
82-
return entry->baseTypeThatConformsToHashable;
83+
{
84+
auto snapshot = HashableConformances.snapshot();
85+
if (const HashableConformanceEntry *entry =
86+
snapshot.find(HashableConformanceKey{type})) {
87+
return entry->baseTypeThatConformsToHashable;
88+
}
8389
}
8490

8591
auto witnessTable =
@@ -93,8 +99,13 @@ findHashableBaseTypeImpl(const Metadata *type) {
9399
const auto *conformance = witnessTable->getDescription();
94100
const Metadata *baseTypeThatConformsToHashable =
95101
findConformingSuperclass(type, conformance);
96-
HashableConformances.getOrInsert(HashableConformanceKey{type},
97-
baseTypeThatConformsToHashable);
102+
HashableConformanceKey key{type};
103+
HashableConformances.getOrInsert(key, [&](HashableConformanceEntry *entry,
104+
bool created) {
105+
if (created)
106+
new (entry) HashableConformanceEntry(key, baseTypeThatConformsToHashable);
107+
return true; // Keep the new entry.
108+
});
98109
return baseTypeThatConformsToHashable;
99110
}
100111

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -211,20 +211,29 @@ namespace {
211211

212212
struct NominalTypeDescriptorCacheEntry {
213213
private:
214-
std::string Name;
214+
const char *Name;
215+
size_t NameLength;
215216
const ContextDescriptor *Description;
216217

217218
public:
218219
NominalTypeDescriptorCacheEntry(const llvm::StringRef name,
219220
const ContextDescriptor *description)
220-
: Name(name.str()), Description(description) {}
221+
: Description(description) {
222+
char *nameCopy = reinterpret_cast<char *>(malloc(name.size()));
223+
memcpy(nameCopy, name.data(), name.size());
224+
Name = nameCopy;
225+
NameLength = name.size();
226+
}
227+
228+
const ContextDescriptor *getDescription() const { return Description; }
221229

222-
const ContextDescriptor *getDescription() {
223-
return Description;
230+
bool matchesKey(llvm::StringRef aName) {
231+
return aName == llvm::StringRef{Name, NameLength};
224232
}
225233

226-
int compareWithKey(llvm::StringRef aName) const {
227-
return aName.compare(Name);
234+
friend llvm::hash_code
235+
hash_value(const NominalTypeDescriptorCacheEntry &value) {
236+
return hash_value(llvm::StringRef{value.Name, value.NameLength});
228237
}
229238

230239
template <class... T>
@@ -235,7 +244,7 @@ namespace {
235244
} // end anonymous namespace
236245

237246
struct TypeMetadataPrivateState {
238-
ConcurrentMap<NominalTypeDescriptorCacheEntry> NominalCache;
247+
ConcurrentReadableHashMap<NominalTypeDescriptorCacheEntry> NominalCache;
239248
ConcurrentReadableArray<TypeMetadataSection> SectionsToScan;
240249

241250
TypeMetadataPrivateState() {
@@ -713,8 +722,11 @@ _findContextDescriptor(Demangle::NodePointer node,
713722

714723
// Look for an existing entry.
715724
// Find the bucket for the metadata entry.
716-
if (auto Value = T.NominalCache.find(mangledName))
717-
return Value->getDescription();
725+
{
726+
auto snapshot = T.NominalCache.snapshot();
727+
if (auto Value = snapshot.find(mangledName))
728+
return Value->getDescription();
729+
}
718730

719731
// Check type metadata records
720732
// Scan any newly loaded images for context descriptors, then try the context
@@ -726,7 +738,13 @@ _findContextDescriptor(Demangle::NodePointer node,
726738
foundContext = _searchConformancesByMangledTypeName(node);
727739

728740
if (foundContext)
729-
T.NominalCache.getOrInsert(mangledName, foundContext);
741+
T.NominalCache.getOrInsert(mangledName, [&](NominalTypeDescriptorCacheEntry
742+
*entry,
743+
bool created) {
744+
if (created)
745+
new (entry) NominalTypeDescriptorCacheEntry{mangledName, foundContext};
746+
return true;
747+
});
730748

731749
return foundContext;
732750
}
@@ -746,18 +764,29 @@ namespace {
746764

747765
struct ProtocolDescriptorCacheEntry {
748766
private:
749-
std::string Name;
767+
const char *Name;
768+
size_t NameLength;
750769
const ProtocolDescriptor *Description;
751770

752771
public:
753772
ProtocolDescriptorCacheEntry(const llvm::StringRef name,
754773
const ProtocolDescriptor *description)
755-
: Name(name.str()), Description(description) {}
774+
: Description(description) {
775+
char *nameCopy = reinterpret_cast<char *>(malloc(name.size()));
776+
memcpy(nameCopy, name.data(), name.size());
777+
Name = nameCopy;
778+
NameLength = name.size();
779+
}
756780

757-
const ProtocolDescriptor *getDescription() { return Description; }
781+
const ProtocolDescriptor *getDescription() const { return Description; }
758782

759-
int compareWithKey(llvm::StringRef aName) const {
760-
return aName.compare(Name);
783+
bool matchesKey(llvm::StringRef aName) {
784+
return aName == llvm::StringRef{Name, NameLength};
785+
}
786+
787+
friend llvm::hash_code
788+
hash_value(const ProtocolDescriptorCacheEntry &value) {
789+
return hash_value(llvm::StringRef{value.Name, value.NameLength});
761790
}
762791

763792
template <class... T>
@@ -767,7 +796,7 @@ namespace {
767796
};
768797

769798
struct ProtocolMetadataPrivateState {
770-
ConcurrentMap<ProtocolDescriptorCacheEntry> ProtocolCache;
799+
ConcurrentReadableHashMap<ProtocolDescriptorCacheEntry> ProtocolCache;
771800
ConcurrentReadableArray<ProtocolSection> SectionsToScan;
772801

773802
ProtocolMetadataPrivateState() {
@@ -849,14 +878,23 @@ _findProtocolDescriptor(NodePointer node,
849878

850879
// Look for an existing entry.
851880
// Find the bucket for the metadata entry.
852-
if (auto Value = T.ProtocolCache.find(mangledName))
853-
return Value->getDescription();
881+
{
882+
auto snapshot = T.ProtocolCache.snapshot();
883+
if (auto Value = snapshot.find(mangledName))
884+
return Value->getDescription();
885+
}
854886

855887
// Check type metadata records
856888
foundProtocol = _searchProtocolRecords(T, node);
857889

858890
if (foundProtocol) {
859-
T.ProtocolCache.getOrInsert(mangledName, foundProtocol);
891+
T.ProtocolCache.getOrInsert(mangledName, [&](ProtocolDescriptorCacheEntry
892+
*entry,
893+
bool created) {
894+
if (created)
895+
new (entry) ProtocolDescriptorCacheEntry{mangledName, foundProtocol};
896+
return true;
897+
});
860898
}
861899

862900
return foundProtocol;

0 commit comments

Comments
 (0)