Skip to content

Commit e32174a

Browse files
committed
[Runtime] Don't use the low bit of a WitnessTable pointer in the conformance cache
With relative witness tables, the low bit of a witness table pointer is an indicator that we need to load from the given pointer. We were also using the low bit of the witness table pointer in the conformance cache entry as part of a pointer union. Hilarity ensures [*]. Switch to another low bit by exploding the conformance cache key into separate fields and taking the low bit of one of those pointers that isn't reserved. Fixes the remainder of rdar://149326058, I hope. [*] No, I am not laughing.
1 parent 2de64b6 commit e32174a

File tree

1 file changed

+49
-19
lines changed

1 file changed

+49
-19
lines changed

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -537,47 +537,77 @@ namespace {
537537

538538
struct ConformanceCacheEntry {
539539
private:
540-
ConformanceCacheKey Key;
540+
/// Storage used when we have global actor isolation on the conformance.
541+
struct ExtendedStorage {
542+
/// The protocol to which the type conforms.
543+
const ProtocolDescriptor *Proto;
544+
545+
/// The global actor to which this conformance is isolated, or NULL for
546+
/// a nonisolated conformances.
547+
const Metadata *globalActorIsolationType = nullptr;
548+
549+
/// When the conformance is global-actor-isolated, this is the conformance
550+
/// of globalActorIsolationType to GlobalActor.
551+
const WitnessTable *globalActorIsolationWitnessTable = nullptr;
552+
};
553+
554+
const Metadata *Type;
555+
llvm::PointerUnion<const ProtocolDescriptor *, const ExtendedStorage *>
556+
ProtoOrStorage;
541557

542-
/// The witness table or along with a bit that indicates whether the
543-
/// conformance is isolated to a global actor.
544-
llvm::PointerUnion<const WitnessTable *, const ConformanceLookupResult *>
545-
WitnessTableOrLookupResult;
558+
/// The witness table.
559+
const WitnessTable *Witness;
546560

547561
public:
548562
ConformanceCacheEntry(ConformanceCacheKey key,
549563
ConformanceLookupResult result)
550-
: Key(key) {
564+
: Type(key.Type), Witness(result.witnessTable)
565+
{
551566
if (result.globalActorIsolationType) {
552-
WitnessTableOrLookupResult = new ConformanceLookupResult(result);
567+
ProtoOrStorage = new ExtendedStorage{
568+
key.Proto, result.globalActorIsolationType,
569+
result.globalActorIsolationWitnessTable
570+
};
553571
} else {
554-
WitnessTableOrLookupResult = result.witnessTable;
572+
ProtoOrStorage = key.Proto;
555573
}
556574
}
557575

558576
bool matchesKey(const ConformanceCacheKey &key) const {
559-
return Key.Type == key.Type && Key.Proto == key.Proto;
577+
return Type == key.Type && getProtocol() == key.Proto;
560578
}
561579

562580
friend llvm::hash_code hash_value(const ConformanceCacheEntry &entry) {
563-
return hash_value(entry.Key);
581+
return hash_value(entry.getKey());
582+
}
583+
584+
/// Get the protocol.
585+
const ProtocolDescriptor *getProtocol() const {
586+
if (auto proto = ProtoOrStorage.dyn_cast<const ProtocolDescriptor *>())
587+
return proto;
588+
589+
return ProtoOrStorage.get<const ExtendedStorage *>()->Proto;
590+
}
591+
592+
/// Get the conformance cache key.
593+
ConformanceCacheKey getKey() const {
594+
return ConformanceCacheKey(Type, getProtocol());
564595
}
565596

566597
/// Get the cached witness table, or null if we cached failure.
567598
const WitnessTable *getWitnessTable() const {
568-
if (auto witnessTable = WitnessTableOrLookupResult.dyn_cast<const WitnessTable *>())
569-
return witnessTable;
570-
571-
return WitnessTableOrLookupResult.get<const ConformanceLookupResult *>()
572-
->witnessTable;
599+
return Witness;
573600
}
574601

575602
ConformanceLookupResult getResult() const {
576-
if (auto witnessTable = WitnessTableOrLookupResult.dyn_cast<const WitnessTable *>())
577-
return ConformanceLookupResult { witnessTable, nullptr, nullptr };
603+
if (ProtoOrStorage.is<const ProtocolDescriptor *>())
604+
return ConformanceLookupResult { Witness, nullptr, nullptr };
578605

579-
if (auto lookupResult = WitnessTableOrLookupResult.dyn_cast<const ConformanceLookupResult *>())
580-
return *lookupResult;
606+
if (auto storage = ProtoOrStorage.dyn_cast<const ExtendedStorage *>()) {
607+
return ConformanceLookupResult(
608+
Witness, storage->globalActorIsolationType,
609+
storage->globalActorIsolationWitnessTable);
610+
}
581611

582612
return nullptr;
583613
}

0 commit comments

Comments
 (0)