Skip to content

Commit d5f6d7f

Browse files
authored
Merge pull request #20491 from DougGregor/runtime-conformance-descriptor-cache
[Runtime] Cache protocol conformance descriptors, not witness tables.
2 parents 5a6dfb6 + 3948114 commit d5f6d7f

File tree

8 files changed

+232
-85
lines changed

8 files changed

+232
-85
lines changed

include/swift/Basic/Lazy.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ template <class T> class Lazy {
5858

5959
T &get(void (*initCallback)(void *) = defaultInitCallback);
6060

61+
template<typename Arg1>
62+
T &getWithInit(Arg1 &&arg1);
63+
6164
/// Get the value, assuming it must have already been initialized by this
6265
/// point.
6366
T &unsafeGetAlreadyInitialized() { return *reinterpret_cast<T *>(&Value); }
@@ -80,6 +83,22 @@ template <typename T> inline T &Lazy<T>::get(void (*initCallback)(void*)) {
8083
return unsafeGetAlreadyInitialized();
8184
}
8285

86+
template <typename T>
87+
template <typename Arg1> inline T &Lazy<T>::getWithInit(Arg1 &&arg1) {
88+
struct Data {
89+
void *address;
90+
Arg1 &&arg1;
91+
92+
static void init(void *context) {
93+
Data *data = static_cast<Data *>(context);
94+
::new (data->address) T(static_cast<Arg1&&>(data->arg1));
95+
}
96+
} data{&Value, static_cast<Arg1&&>(arg1)};
97+
98+
SWIFT_ONCE_F(OnceToken, &Data::init, &data);
99+
return unsafeGetAlreadyInitialized();
100+
}
101+
83102
} // end namespace swift
84103

85104
#define SWIFT_LAZY_CONSTANT(INITIAL_VALUE) \

stdlib/public/runtime/Metadata.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,39 @@ namespace {
268268
};
269269
} // end anonymous namespace
270270

271-
using GenericMetadataCache = MetadataCache<GenericCacheEntry, false>;
272-
using LazyGenericMetadataCache = Lazy<GenericMetadataCache>;
271+
namespace {
272+
class GenericMetadataCache : public MetadataCache<GenericCacheEntry, false> {
273+
public:
274+
uint16_t NumKeyParameters;
275+
uint16_t NumWitnessTables;
276+
277+
GenericMetadataCache(const TargetGenericContext<InProcess> &genericContext)
278+
: NumKeyParameters(0), NumWitnessTables(0) {
279+
// Count up the # of key parameters and # of witness tables.
280+
281+
// Find key generic parameters.
282+
for (const auto &gp : genericContext.getGenericParams()) {
283+
if (gp.hasKeyArgument())
284+
++NumKeyParameters;
285+
}
286+
287+
// Find witness tables.
288+
for (const auto &req : genericContext.getGenericRequirements()) {
289+
if (req.Flags.hasKeyArgument() &&
290+
req.getKind() == GenericRequirementKind::Protocol)
291+
++NumWitnessTables;
292+
}
293+
}
294+
};
295+
296+
using LazyGenericMetadataCache = Lazy<GenericMetadataCache>;
297+
}
273298

274299
/// Fetch the metadata cache for a generic metadata structure.
275300
static GenericMetadataCache &getCache(
276-
const TypeGenericContextDescriptorHeader &generics) {
301+
const TypeContextDescriptor &description) {
302+
auto &generics = description.getFullGenericContextHeader();
303+
277304
// Keep this assert even if you change the representation above.
278305
static_assert(sizeof(LazyGenericMetadataCache) <=
279306
sizeof(GenericMetadataInstantiationCache::PrivateData),
@@ -282,7 +309,7 @@ static GenericMetadataCache &getCache(
282309
auto lazyCache =
283310
reinterpret_cast<LazyGenericMetadataCache*>(
284311
generics.getInstantiationCache()->PrivateData);
285-
return lazyCache->get();
312+
return lazyCache->getWithInit(*description.getGenericContext());
286313
}
287314

288315
/// Fetch the metadata cache for a generic metadata structure,
@@ -527,9 +554,11 @@ swift::swift_getGenericMetadata(MetadataRequest request,
527554
auto &generics = description->getFullGenericContextHeader();
528555
size_t numGenericArgs = generics.Base.NumKeyArguments;
529556

530-
auto key = MetadataCacheKey(arguments, numGenericArgs);
531-
auto result =
532-
getCache(generics).getOrInsert(key, request, description, arguments);
557+
auto &cache = getCache(*description);
558+
assert(numGenericArgs == cache.NumKeyParameters + cache.NumWitnessTables);
559+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
560+
arguments);
561+
auto result = cache.getOrInsert(key, request, description, arguments);
533562

534563
return result.second;
535564
}
@@ -4337,11 +4366,15 @@ static Result performOnMetadataCache(const Metadata *metadata,
43374366
auto genericArgs =
43384367
reinterpret_cast<const void * const *>(
43394368
description->getGenericArguments(metadata));
4369+
auto &cache = getCache(*description);
43404370
size_t numGenericArgs = generics.Base.NumKeyArguments;
4341-
auto key = MetadataCacheKey(genericArgs, numGenericArgs);
4371+
assert(numGenericArgs == cache.NumKeyParameters + cache.NumWitnessTables);
4372+
(void)numGenericArgs;
4373+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
4374+
genericArgs);
43424375

43434376
return std::move(callbacks).forGenericMetadata(metadata, description,
4344-
getCache(generics), key);
4377+
cache, key);
43454378
}
43464379

43474380
bool swift::addToMetadataQueue(MetadataCompletionQueueEntry *queueEntry,

stdlib/public/runtime/MetadataCache.h

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -354,25 +354,85 @@ class SimpleLockingCacheEntryBase {
354354
/// A key value as provided to the concurrent map.
355355
class MetadataCacheKey {
356356
const void * const *Data;
357-
uint32_t Length;
357+
uint16_t NumKeyParameters;
358+
uint16_t NumWitnessTables;
358359
uint32_t Hash;
359360

361+
/// Compare two witness tables, which may involving checking the
362+
/// contents of their conformance descriptors.
363+
static int compareWitnessTables(const WitnessTable *awt,
364+
const WitnessTable *bwt) {
365+
if (awt == bwt)
366+
return 0;
367+
368+
auto *aDescription = awt->Description;
369+
auto *bDescription = bwt->Description;
370+
if (aDescription == bDescription)
371+
return 0;
372+
373+
if (!aDescription->isSynthesizedNonUnique() ||
374+
!bDescription->isSynthesizedNonUnique())
375+
return comparePointers(aDescription, bDescription);
376+
377+
auto aType = aDescription->getCanonicalTypeMetadata();
378+
auto bType = bDescription->getCanonicalTypeMetadata();
379+
if (!aType || !bType)
380+
return comparePointers(aDescription, bDescription);
381+
382+
if (int result = comparePointers(aType, bType))
383+
return result;
384+
385+
return comparePointers(aDescription->getProtocol(),
386+
bDescription->getProtocol());
387+
}
388+
389+
/// Compare the content from two keys.
390+
static int compareContent(const void * const *adata,
391+
const void * const *bdata,
392+
unsigned numKeyParameters,
393+
unsigned numWitnessTables) {
394+
// Compare generic arguments for key parameters.
395+
for (unsigned i = 0; i != numKeyParameters; ++i) {
396+
if (auto result = comparePointers(*adata++, *bdata++))
397+
return result;
398+
}
399+
400+
// Compare witness tables.
401+
for (unsigned i = 0; i != numWitnessTables; ++i) {
402+
if (auto result =
403+
compareWitnessTables((const WitnessTable *)*adata++,
404+
(const WitnessTable *)*bdata++))
405+
return result;
406+
}
407+
408+
return 0;
409+
}
410+
360411
public:
361-
MetadataCacheKey(const void * const *data, size_t size)
362-
: Data(data), Length(size), Hash(computeHash()) {}
363-
MetadataCacheKey(const void * const *data, size_t size, uint32_t hash)
364-
: Data(data), Length(size), Hash(hash) {}
412+
MetadataCacheKey(uint16_t numKeyParams,
413+
uint16_t numWitnessTables,
414+
const void * const *data)
415+
: Data(data), NumKeyParameters(numKeyParams),
416+
NumWitnessTables(numWitnessTables), Hash(computeHash()) { }
417+
418+
MetadataCacheKey(uint16_t numKeyParams,
419+
uint16_t numWitnessTables,
420+
const void * const *data,
421+
uint32_t hash)
422+
: Data(data), NumKeyParameters(numKeyParams),
423+
NumWitnessTables(numWitnessTables), Hash(hash) {}
365424

366425
bool operator==(MetadataCacheKey rhs) const {
426+
// Compare the hashes.
427+
if (hash() != rhs.hash()) return false;
428+
367429
// Compare the sizes.
368-
unsigned asize = size(), bsize = rhs.size();
369-
if (asize != bsize) return false;
430+
if (NumKeyParameters != rhs.NumKeyParameters) return false;
431+
if (NumWitnessTables != rhs.NumWitnessTables) return false;
370432

371433
// Compare the content.
372-
auto abegin = begin(), bbegin = rhs.begin();
373-
for (unsigned i = 0; i < asize; ++i)
374-
if (abegin[i] != bbegin[i]) return false;
375-
return true;
434+
return compareContent(begin(), rhs.begin(), NumKeyParameters,
435+
NumWitnessTables) == 0;
376436
}
377437

378438
int compare(const MetadataCacheKey &rhs) const {
@@ -381,38 +441,43 @@ class MetadataCacheKey {
381441
return hashComparison;
382442
}
383443

384-
// Compare the sizes.
385-
if (auto sizeComparison = compareIntegers(size(), rhs.size())) {
386-
return sizeComparison;
444+
// Compare the # of key parameters.
445+
if (auto keyParamsComparison =
446+
compareIntegers(NumKeyParameters, rhs.NumKeyParameters)) {
447+
return keyParamsComparison;
387448
}
388449

389-
// Compare the content.
390-
auto lbegin = begin(), rbegin = rhs.begin();
391-
for (unsigned i = 0, e = size(); i != e; ++i) {
392-
if (auto ptrComparison = comparePointers(lbegin[i], rbegin[i]))
393-
return ptrComparison;
450+
// Compare the # of witness tables.
451+
if (auto witnessTablesComparison =
452+
compareIntegers(NumWitnessTables, rhs.NumWitnessTables)) {
453+
return witnessTablesComparison;
394454
}
395455

396-
// Equal.
397-
return 0;
456+
// Compare the content.
457+
return compareContent(begin(), rhs.begin(), NumKeyParameters,
458+
NumWitnessTables);
398459
}
399460

461+
uint16_t numKeyParameters() const { return NumKeyParameters; }
462+
uint16_t numWitnessTables() const { return NumWitnessTables; }
463+
400464
uint32_t hash() const {
401465
return Hash;
402466
}
403467

404468
const void * const *begin() const { return Data; }
405-
const void * const *end() const { return Data + Length; }
406-
unsigned size() const { return Length; }
469+
const void * const *end() const { return Data + size(); }
470+
unsigned size() const { return NumKeyParameters + NumWitnessTables; }
407471

408472
private:
409473
uint32_t computeHash() const {
410-
size_t H = 0x56ba80d1 * Length;
411-
for (unsigned i = 0; i < Length; i++) {
474+
size_t H = 0x56ba80d1 * NumKeyParameters;
475+
for (unsigned index = 0; index != NumKeyParameters; ++index) {
412476
H = (H >> 10) | (H << ((sizeof(size_t) * 8) - 10));
413-
H ^= (reinterpret_cast<size_t>(Data[i])
414-
^ (reinterpret_cast<size_t>(Data[i]) >> 19));
477+
H ^= (reinterpret_cast<size_t>(Data[index])
478+
^ (reinterpret_cast<size_t>(Data[index]) >> 19));
415479
}
480+
416481
H *= 0x27d4eb2d;
417482

418483
// Rotate right by 10 and then truncate to 32 bits.
@@ -1270,7 +1335,7 @@ class VariadicMetadataCacheEntryBase :
12701335
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
12711336

12721337
size_t numTrailingObjects(OverloadToken<const void *>) const {
1273-
return KeyLength;
1338+
return NumKeyParameters + NumWitnessTables;
12741339
}
12751340

12761341
template <class... Args>
@@ -1284,7 +1349,8 @@ class VariadicMetadataCacheEntryBase :
12841349
// These are arranged to fit into the tail-padding of the superclass.
12851350

12861351
/// These are set during construction and never changed.
1287-
const uint16_t KeyLength;
1352+
const uint16_t NumKeyParameters;
1353+
const uint16_t NumWitnessTables;
12881354
const uint32_t Hash;
12891355

12901356
/// Valid if TrackingInfo.getState() >= PrivateMetadataState::Abstract.
@@ -1300,14 +1366,17 @@ class VariadicMetadataCacheEntryBase :
13001366

13011367
public:
13021368
VariadicMetadataCacheEntryBase(const MetadataCacheKey &key)
1303-
: KeyLength(key.size()), Hash(key.hash()) {
1369+
: NumKeyParameters(key.numKeyParameters()),
1370+
NumWitnessTables(key.numWitnessTables()),
1371+
Hash(key.hash()) {
13041372
memcpy(this->template getTrailingObjects<const void *>(),
13051373
key.begin(), key.size() * sizeof(const void *));
13061374
}
13071375

13081376
MetadataCacheKey getKey() const {
1309-
return MetadataCacheKey(this->template getTrailingObjects<const void*>(),
1310-
KeyLength, Hash);
1377+
return MetadataCacheKey(NumKeyParameters, NumWitnessTables,
1378+
this->template getTrailingObjects<const void*>(),
1379+
Hash);
13111380
}
13121381

13131382
intptr_t getKeyIntValueForDump() const {

stdlib/public/runtime/Private.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,12 @@ class TypeInfo {
507507
const Metadata *type,
508508
const ProtocolConformanceDescriptor *conformance);
509509

510+
/// Determine whether the given type conforms to the given Swift protocol,
511+
/// returning the appropriate protocol conformance descriptor when it does.
512+
const ProtocolConformanceDescriptor *
513+
_conformsToSwiftProtocol(const Metadata * const type,
514+
const ProtocolDescriptor *protocol);
515+
510516
/// Retrieve an associated type witness from the given witness table.
511517
///
512518
/// \param wtable The witness table.

0 commit comments

Comments
 (0)