Skip to content

Commit c4203dd

Browse files
authored
Merge pull request #29887 from slavapestov/conformance-cache-sillyness
Runtime: Less eager instantiation of type metadata in the conformance cache
2 parents 0516c3b + 4e39455 commit c4203dd

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ searchInConformanceCache(const Metadata *type,
481481

482482
namespace {
483483
/// Describes a protocol conformance "candidate" that can be checked
484-
/// against the
484+
/// against a type metadata.
485485
class ConformanceCandidate {
486486
const void *candidate;
487487
bool candidateIsMetadata;
@@ -492,17 +492,17 @@ namespace {
492492
ConformanceCandidate(const ProtocolConformanceDescriptor &conformance)
493493
: ConformanceCandidate()
494494
{
495-
if (auto metadata = conformance.getCanonicalTypeMetadata()) {
496-
candidate = metadata;
497-
candidateIsMetadata = true;
498-
return;
499-
}
500-
501495
if (auto description = conformance.getTypeDescriptor()) {
502496
candidate = description;
503497
candidateIsMetadata = false;
504498
return;
505499
}
500+
501+
if (auto metadata = conformance.getCanonicalTypeMetadata()) {
502+
candidate = metadata;
503+
candidateIsMetadata = true;
504+
return;
505+
}
506506
}
507507

508508
/// Retrieve the conforming type as metadata, or NULL if the candidate's
@@ -513,6 +513,29 @@ namespace {
513513
: nullptr;
514514
}
515515

516+
const ContextDescriptor *
517+
getContextDescriptor(const Metadata *conformingType) const {
518+
const auto *description = conformingType->getTypeContextDescriptor();
519+
if (description)
520+
return description;
521+
522+
// Handle single-protocol existential types for self-conformance.
523+
auto *existentialType = dyn_cast<ExistentialTypeMetadata>(conformingType);
524+
if (existentialType == nullptr ||
525+
existentialType->getProtocols().size() != 1 ||
526+
existentialType->getSuperclassConstraint() != nullptr)
527+
return nullptr;
528+
529+
auto proto = existentialType->getProtocols()[0];
530+
531+
#if SWIFT_OBJC_INTEROP
532+
if (proto.isObjC())
533+
return nullptr;
534+
#endif
535+
536+
return proto.getSwiftProtocol();
537+
}
538+
516539
/// Whether the conforming type exactly matches the conformance candidate.
517540
bool matches(const Metadata *conformingType) const {
518541
// Check whether the types match.
@@ -521,7 +544,7 @@ namespace {
521544

522545
// Check whether the nominal type descriptors match.
523546
if (!candidateIsMetadata) {
524-
const auto *description = conformingType->getTypeContextDescriptor();
547+
const auto *description = getContextDescriptor(conformingType);
525548
auto candidateDescription =
526549
static_cast<const ContextDescriptor *>(candidate);
527550
if (description && equalContexts(description, candidateDescription))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public func getVersion() -> Int {
2+
#if BEFORE
3+
return 0
4+
#else
5+
return 1
6+
#endif
7+
}
8+
9+
#if AFTER
10+
@_weakLinked
11+
public struct NewStruct<T> {
12+
var t: T
13+
14+
public init(_ t: T) {
15+
self.t = t
16+
}
17+
}
18+
#endif
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-resilience-test --backward-deployment
2+
// REQUIRES: executable_test
3+
4+
import StdlibUnittest
5+
import backward_deploy_conformance
6+
7+
8+
var BackwardDeployConformanceTest = TestSuite("BackwardDeployConformance")
9+
10+
public class UsesNewStruct: CustomStringConvertible {
11+
public var field: NewStruct<Bool>? = nil
12+
public let description = "This is my description"
13+
}
14+
15+
public class OtherClass {}
16+
17+
@_optimize(none)
18+
func blackHole<T>(_: T) {}
19+
20+
BackwardDeployConformanceTest.test("ConformanceCache") {
21+
if getVersion() == 1 {
22+
blackHole(UsesNewStruct())
23+
}
24+
25+
blackHole(OtherClass() as? CustomStringConvertible)
26+
}
27+
28+
runAllTests()

0 commit comments

Comments
 (0)