mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Runtime] Introduce equality operation for nominal type descriptors.
Nominal type descriptors are not always unique, so testing them via pointer equality is not correct. Introduce an "isEqual()" operation for nominal type descriptors that performs the appropriate equality check, using pointer equality when possible, and falling back to string comparisons of the mangled type name when it is not possible. Introduce a "nonunique" flag into nominal type descriptors to describe when they are, in fact, not unique. The only nonunique nominal type descriptors currently come from Clang-imported types; all Swift-defined types have unique nominal type descriptors. Use this flag to make the aforementioned operation efficient in the "unique" case. Use the new isEqual() operation for protocol conformance lookup, and make sure we're caching results based on the known-canonical nominal type descriptor.
This commit is contained in:
@@ -288,6 +288,7 @@ enum class ProtocolDispatchStrategy: uint8_t {
|
||||
class GenericParameterDescriptorFlags {
|
||||
typedef uint16_t int_type;
|
||||
enum : int_type {
|
||||
IsNonUnique = 0x0002,
|
||||
HasVTable = 0x0004,
|
||||
HasResilientSuperclass = 0x0008,
|
||||
};
|
||||
@@ -302,6 +303,17 @@ public:
|
||||
: (Data & ~HasVTable));
|
||||
}
|
||||
|
||||
constexpr GenericParameterDescriptorFlags withIsUnique(bool b) const {
|
||||
return GenericParameterDescriptorFlags(!b ? (Data | IsNonUnique)
|
||||
: (Data & ~IsNonUnique));
|
||||
}
|
||||
|
||||
/// Whether this nominal type descriptor is known to be nonunique, requiring
|
||||
/// comparison operations to check string equality of the mangled name.
|
||||
bool isUnique() const {
|
||||
return !(Data & IsNonUnique);
|
||||
}
|
||||
|
||||
/// If this type is a class, does it have a vtable? If so, the number
|
||||
/// of vtable entries immediately follows the generic requirement
|
||||
/// descriptor.
|
||||
|
||||
@@ -1333,6 +1333,10 @@ public:
|
||||
return getGenericContexts()[i];
|
||||
}
|
||||
|
||||
bool isUnique() const {
|
||||
return GenericParams.Flags.isUnique();
|
||||
}
|
||||
|
||||
bool hasVTable() const {
|
||||
return getKind() == NominalTypeKind::Class
|
||||
&& GenericParams.Flags.hasVTable();
|
||||
@@ -1356,6 +1360,9 @@ public:
|
||||
return getMethodDescriptors()[i].Impl.get();
|
||||
}
|
||||
|
||||
/// Determine whether two nominal type descriptors are equivalent.
|
||||
bool isEqual(const TargetNominalTypeDescriptor *other) const;
|
||||
|
||||
private:
|
||||
size_t numTrailingObjects(OverloadToken<GenericContextDescriptor>) const {
|
||||
return GenericParams.NestingDepth;
|
||||
|
||||
@@ -2205,6 +2205,9 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the nominal type descriptor is known to be unique.
|
||||
flags = flags.withIsUnique(asImpl().isUniqueDescriptor());
|
||||
|
||||
// Calculate the number of generic parameters at each nesting depth.
|
||||
unsigned totalGenericParams = 0;
|
||||
SmallVector<unsigned, 2> numPrimaryParams;
|
||||
@@ -2264,11 +2267,20 @@ namespace {
|
||||
return var;
|
||||
}
|
||||
|
||||
// Imported declarations have nonunique nominal type descriptors.
|
||||
bool isUniqueDescriptor() {
|
||||
return !isa<ClangModuleUnit>(
|
||||
asImpl().getTarget()->getModuleScopeContext());
|
||||
}
|
||||
|
||||
// Derived class must provide:
|
||||
// NominalTypeDecl *getTarget();
|
||||
// unsigned getKind();
|
||||
// unsigned getGenericParamsOffset();
|
||||
// void addKindDependentFields();
|
||||
//
|
||||
// Derived class can override:
|
||||
// bool isUniqueDescriptor();
|
||||
};
|
||||
|
||||
/// Build a doubly-null-terminated list of field names.
|
||||
|
||||
@@ -1051,6 +1051,21 @@ swift::swift_getTupleTypeMetadata3(const Metadata *elt0, const Metadata *elt1,
|
||||
return swift_getTupleTypeMetadata(3, elts, labels, proposedWitnesses);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/*** Nominal type descriptors **********************************************/
|
||||
/***************************************************************************/
|
||||
template<>
|
||||
bool NominalTypeDescriptor::isEqual(const NominalTypeDescriptor *other) const {
|
||||
// Fast path: pointer equality.
|
||||
if (this == other) return true;
|
||||
|
||||
// If both nominal type descriptors are known to be unique, we're done.
|
||||
if (this->isUnique() && other->isUnique()) return false;
|
||||
|
||||
// Compare the mangled names.
|
||||
return strcmp(this->Name.get(), other->Name.get()) == 0;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/*** Common value witnesses ************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
@@ -435,14 +435,18 @@ bool isRelatedType(const Metadata *type, const void *candidate,
|
||||
bool candidateIsMetadata) {
|
||||
|
||||
while (true) {
|
||||
if (type == candidate && candidateIsMetadata)
|
||||
// Check whether the types match.
|
||||
if (candidateIsMetadata && type == candidate)
|
||||
return true;
|
||||
|
||||
// If the type is resilient or generic, see if there's a witness table
|
||||
// keyed off the nominal type descriptor.
|
||||
// Check whether the nominal type descriptors match.
|
||||
if (!candidateIsMetadata) {
|
||||
const auto *description = type->getNominalTypeDescriptor();
|
||||
if (description == candidate && !candidateIsMetadata)
|
||||
auto candidateDescription =
|
||||
static_cast<const NominalTypeDescriptor *>(candidate);
|
||||
if (description && description->isEqual(candidateDescription))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the type is a class, try its superclass.
|
||||
if (const ClassMetadata *classType = type->getClassObject()) {
|
||||
@@ -568,7 +572,8 @@ swift::swift_conformsToProtocol(const Metadata * const type,
|
||||
case ProtocolConformanceReferenceKind::WitnessTable:
|
||||
// If the record provides a nondependent witness table for all
|
||||
// instances of a generic type, cache it for the generic pattern.
|
||||
C.cacheSuccess(R, P, record.getStaticWitnessTable());
|
||||
C.cacheSuccess(type->getNominalTypeDescriptor(), P,
|
||||
record.getStaticWitnessTable());
|
||||
break;
|
||||
|
||||
case ProtocolConformanceReferenceKind::WitnessTableAccessor:
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
|
||||
// CHECK: [[MUTABLE_REFRIGERATOR_NAME:@.*]] = private constant [27 x i8] c"So21CCMutableRefrigeratorC\00"
|
||||
|
||||
// CHECK-64: @_T0So21CCMutableRefrigeratorCMn = linkonce_odr hidden constant
|
||||
// CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]
|
||||
// CHECK-64-SAME: @get_field_types_CCMutableRefrigerator
|
||||
// CHECK-64-SAME: i16 1, i16 2, i32 0 }>
|
||||
|
||||
// CHECK-64: @_T0So21CCMutableRefrigeratorCN = linkonce_odr hidden global <{ {{.*}} }> <{
|
||||
// CHECK-64-SAME: @initialize_metadata_CCMutableRefrigerator
|
||||
// CHECK-64-SAME: i32 trunc {{.*}} [[MUTABLE_REFRIGERATOR_NAME]] to i64
|
||||
|
||||
Reference in New Issue
Block a user