Skip to content

Runtime: Less eager instantiation of type metadata in the conformance cache #29887

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ searchInConformanceCache(const Metadata *type,

namespace {
/// Describes a protocol conformance "candidate" that can be checked
/// against the
/// against a type metadata.
class ConformanceCandidate {
const void *candidate;
bool candidateIsMetadata;
Expand All @@ -492,17 +492,17 @@ namespace {
ConformanceCandidate(const ProtocolConformanceDescriptor &conformance)
: ConformanceCandidate()
{
if (auto metadata = conformance.getCanonicalTypeMetadata()) {
candidate = metadata;
candidateIsMetadata = true;
return;
}

if (auto description = conformance.getTypeDescriptor()) {
candidate = description;
candidateIsMetadata = false;
return;
}

if (auto metadata = conformance.getCanonicalTypeMetadata()) {
candidate = metadata;
candidateIsMetadata = true;
return;
}
}

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

const ContextDescriptor *
getContextDescriptor(const Metadata *conformingType) const {
const auto *description = conformingType->getTypeContextDescriptor();
if (description)
return description;

// Handle single-protocol existential types for self-conformance.
auto *existentialType = dyn_cast<ExistentialTypeMetadata>(conformingType);
if (existentialType == nullptr ||
existentialType->getProtocols().size() != 1 ||
existentialType->getSuperclassConstraint() != nullptr)
return nullptr;

auto proto = existentialType->getProtocols()[0];

#if SWIFT_OBJC_INTEROP
if (proto.isObjC())
return nullptr;
#endif

return proto.getSwiftProtocol();
}

/// Whether the conforming type exactly matches the conformance candidate.
bool matches(const Metadata *conformingType) const {
// Check whether the types match.
Expand All @@ -521,7 +544,7 @@ namespace {

// Check whether the nominal type descriptors match.
if (!candidateIsMetadata) {
const auto *description = conformingType->getTypeContextDescriptor();
const auto *description = getContextDescriptor(conformingType);
auto candidateDescription =
static_cast<const ContextDescriptor *>(candidate);
if (description && equalContexts(description, candidateDescription))
Expand Down
18 changes: 18 additions & 0 deletions validation-test/Evolution/Inputs/backward_deploy_conformance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
public func getVersion() -> Int {
#if BEFORE
return 0
#else
return 1
#endif
}

#if AFTER
@_weakLinked
public struct NewStruct<T> {
var t: T

public init(_ t: T) {
self.t = t
}
}
#endif
28 changes: 28 additions & 0 deletions validation-test/Evolution/test_backward_deploy_conformance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %target-resilience-test --backward-deployment
// REQUIRES: executable_test

import StdlibUnittest
import backward_deploy_conformance


var BackwardDeployConformanceTest = TestSuite("BackwardDeployConformance")

public class UsesNewStruct: CustomStringConvertible {
public var field: NewStruct<Bool>? = nil
public let description = "This is my description"
}

public class OtherClass {}

@_optimize(none)
func blackHole<T>(_: T) {}

BackwardDeployConformanceTest.test("ConformanceCache") {
if getVersion() == 1 {
blackHole(UsesNewStruct())
}

blackHole(OtherClass() as? CustomStringConvertible)
}

runAllTests()