Skip to content

Commit 2323904

Browse files
authored
Merge pull request #20774 from DougGregor/runtime-conformance-descriptor-cache-5.0
[5.0] [Runtime] Cache and unique based on protocol conformance descriptors, not witness tables
2 parents 9f7531d + 163dc92 commit 2323904

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
@@ -310,12 +310,39 @@ namespace {
310310
};
311311
} // end anonymous namespace
312312

313-
using GenericMetadataCache = MetadataCache<GenericCacheEntry, false>;
314-
using LazyGenericMetadataCache = Lazy<GenericMetadataCache>;
313+
namespace {
314+
class GenericMetadataCache : public MetadataCache<GenericCacheEntry, false> {
315+
public:
316+
uint16_t NumKeyParameters;
317+
uint16_t NumWitnessTables;
318+
319+
GenericMetadataCache(const TargetGenericContext<InProcess> &genericContext)
320+
: NumKeyParameters(0), NumWitnessTables(0) {
321+
// Count up the # of key parameters and # of witness tables.
322+
323+
// Find key generic parameters.
324+
for (const auto &gp : genericContext.getGenericParams()) {
325+
if (gp.hasKeyArgument())
326+
++NumKeyParameters;
327+
}
328+
329+
// Find witness tables.
330+
for (const auto &req : genericContext.getGenericRequirements()) {
331+
if (req.Flags.hasKeyArgument() &&
332+
req.getKind() == GenericRequirementKind::Protocol)
333+
++NumWitnessTables;
334+
}
335+
}
336+
};
337+
338+
using LazyGenericMetadataCache = Lazy<GenericMetadataCache>;
339+
}
315340

316341
/// Fetch the metadata cache for a generic metadata structure.
317342
static GenericMetadataCache &getCache(
318-
const TypeGenericContextDescriptorHeader &generics) {
343+
const TypeContextDescriptor &description) {
344+
auto &generics = description.getFullGenericContextHeader();
345+
319346
// Keep this assert even if you change the representation above.
320347
static_assert(sizeof(LazyGenericMetadataCache) <=
321348
sizeof(GenericMetadataInstantiationCache::PrivateData),
@@ -324,7 +351,7 @@ static GenericMetadataCache &getCache(
324351
auto lazyCache =
325352
reinterpret_cast<LazyGenericMetadataCache*>(
326353
generics.getInstantiationCache()->PrivateData);
327-
return lazyCache->get();
354+
return lazyCache->getWithInit(*description.getGenericContext());
328355
}
329356

330357
/// Fetch the metadata cache for a generic metadata structure,
@@ -569,9 +596,11 @@ swift::swift_getGenericMetadata(MetadataRequest request,
569596
auto &generics = description->getFullGenericContextHeader();
570597
size_t numGenericArgs = generics.Base.NumKeyArguments;
571598

572-
auto key = MetadataCacheKey(arguments, numGenericArgs);
573-
auto result =
574-
getCache(generics).getOrInsert(key, request, description, arguments);
599+
auto &cache = getCache(*description);
600+
assert(numGenericArgs == cache.NumKeyParameters + cache.NumWitnessTables);
601+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
602+
arguments);
603+
auto result = cache.getOrInsert(key, request, description, arguments);
575604

576605
return result.second;
577606
}
@@ -4379,11 +4408,15 @@ static Result performOnMetadataCache(const Metadata *metadata,
43794408
auto genericArgs =
43804409
reinterpret_cast<const void * const *>(
43814410
description->getGenericArguments(metadata));
4411+
auto &cache = getCache(*description);
43824412
size_t numGenericArgs = generics.Base.NumKeyArguments;
4383-
auto key = MetadataCacheKey(genericArgs, numGenericArgs);
4413+
assert(numGenericArgs == cache.NumKeyParameters + cache.NumWitnessTables);
4414+
(void)numGenericArgs;
4415+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
4416+
genericArgs);
43844417

43854418
return std::move(callbacks).forGenericMetadata(metadata, description,
4386-
getCache(generics), key);
4419+
cache, key);
43874420
}
43884421

43894422
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)