Skip to content

Commit 80b5ab8

Browse files
committed
Reference runtime-only ObjC classes with bare strings.
As part of this, rename TypeMetadataRecordKind to TypeReferenceKind and consistently give it three bits of storage. The better modelling of these type references appears to have been sufficient to make dynamic conformance checks succeed, which is good but unexpected.
1 parent c26012d commit 80b5ab8

File tree

12 files changed

+277
-158
lines changed

12 files changed

+277
-158
lines changed

include/swift/ABI/Metadata.h

Lines changed: 86 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,32 +2062,37 @@ struct TargetTypeMetadataRecord {
20622062
union {
20632063
/// A direct reference to a nominal type descriptor.
20642064
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime>,
2065-
TypeMetadataRecordKind>
2065+
TypeReferenceKind>
20662066
DirectNominalTypeDescriptor;
20672067

20682068
/// An indirect reference to a nominal type descriptor.
20692069
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime> * const,
2070-
TypeMetadataRecordKind>
2070+
TypeReferenceKind>
20712071
IndirectNominalTypeDescriptor;
2072+
2073+
// We only allow a subset of the TypeReferenceKinds here.
2074+
// Should we just acknowledge that this is a different enum?
20722075
};
20732076

20742077
public:
2075-
TypeMetadataRecordKind getTypeKind() const {
2078+
TypeReferenceKind getTypeKind() const {
20762079
return DirectNominalTypeDescriptor.getInt();
20772080
}
20782081

20792082
const TargetTypeContextDescriptor<Runtime> *
20802083
getTypeContextDescriptor() const {
20812084
switch (getTypeKind()) {
2082-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2085+
case TypeReferenceKind::DirectNominalTypeDescriptor:
20832086
return DirectNominalTypeDescriptor.getPointer();
20842087

2085-
case TypeMetadataRecordKind::Reserved:
2086-
case TypeMetadataRecordKind::IndirectObjCClass:
2087-
return nullptr;
2088-
2089-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2088+
case TypeReferenceKind::IndirectNominalTypeDescriptor:
20902089
return *IndirectNominalTypeDescriptor.getPointer();
2090+
2091+
// These types (and any others we might add to TypeReferenceKind
2092+
// in the future) are just never used in these lists.
2093+
case TypeReferenceKind::DirectObjCClassName:
2094+
case TypeReferenceKind::IndirectObjCClass:
2095+
return nullptr;
20912096
}
20922097

20932098
return nullptr;
@@ -2117,6 +2122,67 @@ using ProtocolRecord = TargetProtocolRecord<InProcess>;
21172122

21182123
template<typename Runtime> class TargetGenericRequirementDescriptor;
21192124

2125+
2126+
/// A referenc to a type.
2127+
template <typename Runtime>
2128+
struct TargetTypeReference {
2129+
union {
2130+
/// A direct reference to a nominal type descriptor.
2131+
RelativeDirectPointer<TargetTypeContextDescriptor<Runtime>>
2132+
DirectNominalTypeDescriptor;
2133+
2134+
/// An indirect reference to a nominal type descriptor.
2135+
RelativeDirectPointer<
2136+
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>>
2137+
IndirectNominalTypeDescriptor;
2138+
2139+
/// An indirect reference to an Objective-C class.
2140+
RelativeDirectPointer<
2141+
ConstTargetMetadataPointer<Runtime, TargetClassMetadata>>
2142+
IndirectObjCClass;
2143+
2144+
/// A direct reference to an Objective-C class name.
2145+
RelativeDirectPointer<const char>
2146+
DirectObjCClassName;
2147+
};
2148+
2149+
const TargetTypeContextDescriptor<Runtime> *
2150+
getTypeContextDescriptor(TypeReferenceKind kind) const {
2151+
switch (kind) {
2152+
case TypeReferenceKind::DirectNominalTypeDescriptor:
2153+
return DirectNominalTypeDescriptor;
2154+
2155+
case TypeReferenceKind::IndirectNominalTypeDescriptor:
2156+
return *IndirectNominalTypeDescriptor;
2157+
2158+
case TypeReferenceKind::DirectObjCClassName:
2159+
case TypeReferenceKind::IndirectObjCClass:
2160+
return nullptr;
2161+
}
2162+
2163+
return nullptr;
2164+
}
2165+
2166+
#if SWIFT_OBJC_INTEROP
2167+
/// If this type reference is one of the kinds that supports ObjC
2168+
/// references,
2169+
const TargetClassMetadata<Runtime> *
2170+
getObjCClass(TypeReferenceKind kind) const;
2171+
#endif
2172+
2173+
const TargetClassMetadata<Runtime> * const *
2174+
getIndirectObjCClass(TypeReferenceKind kind) const {
2175+
assert(kind == TypeReferenceKind::IndirectObjCClass);
2176+
return IndirectObjCClass.get();
2177+
}
2178+
2179+
const char *getDirectObjCClassName(TypeReferenceKind kind) const {
2180+
assert(kind == TypeReferenceKind::DirectObjCClassName);
2181+
return DirectObjCClassName.get();
2182+
}
2183+
};
2184+
using TypeReference = TargetTypeReference<InProcess>;
2185+
21202186
/// The structure of a protocol conformance.
21212187
///
21222188
/// This contains enough static information to recover the witness table for a
@@ -2153,21 +2219,7 @@ struct TargetProtocolConformanceDescriptor final
21532219
RelativeIndirectablePointer<ProtocolDescriptor> Protocol;
21542220

21552221
// Some description of the type that conforms to the protocol.
2156-
union {
2157-
/// A direct reference to a nominal type descriptor.
2158-
RelativeDirectPointer<TargetTypeContextDescriptor<Runtime>>
2159-
DirectNominalTypeDescriptor;
2160-
2161-
/// An indirect reference to a nominal type descriptor.
2162-
RelativeDirectPointer<
2163-
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>>
2164-
IndirectNominalTypeDescriptor;
2165-
2166-
/// An indirect reference to the metadata.
2167-
RelativeDirectPointer<
2168-
ConstTargetMetadataPointer<Runtime, TargetClassMetadata>>
2169-
IndirectObjCClass;
2170-
};
2222+
TargetTypeReference<Runtime> TypeRef;
21712223

21722224
// The conformance, or a generator function for the conformance.
21732225
union {
@@ -2187,45 +2239,24 @@ struct TargetProtocolConformanceDescriptor final
21872239
return Protocol;
21882240
}
21892241

2190-
TypeMetadataRecordKind getTypeKind() const {
2242+
TypeReferenceKind getTypeKind() const {
21912243
return Flags.getTypeReferenceKind();
21922244
}
21932245

21942246
typename ConformanceFlags::ConformanceKind getConformanceKind() const {
21952247
return Flags.getConformanceKind();
21962248
}
2197-
2198-
const TargetClassMetadata<Runtime> * const *getIndirectObjCClass() const {
2199-
switch (getTypeKind()) {
2200-
case TypeMetadataRecordKind::IndirectObjCClass:
2201-
break;
22022249

2203-
case TypeMetadataRecordKind::Reserved:
2204-
return nullptr;
2250+
const char *getDirectObjCClassName() const {
2251+
return TypeRef.getDirectObjCClassName(getTypeKind());
2252+
}
22052253

2206-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2207-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2208-
assert(false && "not indirect class object");
2209-
}
2210-
2211-
return IndirectObjCClass.get();
2254+
const TargetClassMetadata<Runtime> * const *getIndirectObjCClass() const {
2255+
return TypeRef.getIndirectObjCClass(getTypeKind());
22122256
}
22132257

2214-
const TargetTypeContextDescriptor<Runtime> *
2215-
getTypeContextDescriptor() const {
2216-
switch (getTypeKind()) {
2217-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2218-
return DirectNominalTypeDescriptor;
2219-
2220-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2221-
return *IndirectNominalTypeDescriptor;
2222-
2223-
case TypeMetadataRecordKind::Reserved:
2224-
case TypeMetadataRecordKind::IndirectObjCClass:
2225-
return nullptr;
2226-
}
2227-
2228-
return nullptr;
2258+
const TargetTypeContextDescriptor<Runtime> *getTypeContextDescriptor() const {
2259+
return TypeRef.getTypeContextDescriptor(getTypeKind());
22292260
}
22302261

22312262
/// Retrieve the context of a retroactive conformance.
@@ -2287,7 +2318,7 @@ struct TargetProtocolConformanceDescriptor final
22872318
///
22882319
/// We currently check that the descriptor:
22892320
///
2290-
/// 1. Has a valid TypeMetadataRecordKind.
2321+
/// 1. Has a valid TypeReferenceKind.
22912322
/// 2. Has a valid conformance kind.
22922323
void verify() const LLVM_ATTRIBUTE_USED;
22932324
#endif
@@ -3344,7 +3375,7 @@ class TargetClassDescriptor final
33443375
return !Superclass.isNull();
33453376
}
33463377

3347-
TypeMetadataRecordKind getSuperclassReferenceKind() const {
3378+
TypeReferenceKind getSuperclassReferenceKind() const {
33483379
return getTypeContextDescriptorFlags().class_getSuperclassReferenceKind();
33493380
}
33503381

include/swift/ABI/MetadataValues.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ enum : unsigned {
350350
};
351351

352352
/// Kinds of type metadata/protocol conformance records.
353-
enum class TypeMetadataRecordKind : unsigned {
353+
enum class TypeReferenceKind : unsigned {
354354
/// The conformance is for a nominal type referenced directly;
355355
/// getNominalTypeDescriptor() points to the nominal type descriptor.
356356
DirectNominalTypeDescriptor = 0x00,
@@ -359,9 +359,10 @@ enum class TypeMetadataRecordKind : unsigned {
359359
/// getNominalTypeDescriptor() points to the nominal type descriptor.
360360
IndirectNominalTypeDescriptor = 0x01,
361361

362-
/// Reserved for future use.
363-
Reserved = 0x02,
364-
362+
/// The conformance is for an Objective-C class that should be looked up
363+
/// by class name.
364+
DirectObjCClassName = 0x02,
365+
365366
/// The conformance is for an Objective-C class that has no nominal type
366367
/// descriptor.
367368
/// getIndirectObjCClass() points to a variable that contains the pointer to
@@ -371,6 +372,8 @@ enum class TypeMetadataRecordKind : unsigned {
371372
/// unused.
372373
IndirectObjCClass = 0x03,
373374

375+
// We only reserve three bits for this in the various places we store it.
376+
374377
First_Kind = DirectNominalTypeDescriptor,
375378
Last_Kind = IndirectObjCClass,
376379
};
@@ -593,7 +596,7 @@ class ConformanceFlags {
593596
return ConformanceFlags((Value & ~ConformanceKindMask) | int_type(kind));
594597
}
595598

596-
ConformanceFlags withTypeReferenceKind(TypeMetadataRecordKind kind) const {
599+
ConformanceFlags withTypeReferenceKind(TypeReferenceKind kind) const {
597600
return ConformanceFlags((Value & ~TypeMetadataKindMask)
598601
| (int_type(kind) << TypeMetadataKindShift));
599602
}
@@ -621,8 +624,8 @@ class ConformanceFlags {
621624
}
622625

623626
/// Retrieve the type reference kind kind.
624-
TypeMetadataRecordKind getTypeReferenceKind() const {
625-
return TypeMetadataRecordKind(
627+
TypeReferenceKind getTypeReferenceKind() const {
628+
return TypeReferenceKind(
626629
(Value & TypeMetadataKindMask) >> TypeMetadataKindShift);
627630
}
628631

@@ -1231,16 +1234,16 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12311234
/// Only meaningful for class descriptors.
12321235
Class_HasResilientSuperclass = 14,
12331236

1237+
/// Whether the immediate class members in this metadata are allocated
1238+
/// at negative offsets. For now, we don't use this.
1239+
Class_AreImmediateMembersNegative = 13,
1240+
12341241
/// The kind of reference that this class makes to its superclass
1235-
/// descriptor. A TypeMetadataRecordKind.
1242+
/// descriptor. A TypeReferenceKind.
12361243
///
12371244
/// Only meaningful for class descriptors.
1238-
Class_SuperclassReferenceKind = 12,
1239-
Class_SuperclassReferenceKind_width = 2,
1240-
1241-
/// Whether the immediate class members in this metadata are allocated
1242-
/// at negative offsets. For now, we don't use this.
1243-
Class_AreImmediateMembersNegative = 11,
1245+
Class_SuperclassReferenceKind = 10,
1246+
Class_SuperclassReferenceKind_width = 3,
12441247
};
12451248

12461249
public:
@@ -1327,7 +1330,7 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
13271330

13281331
FLAGSET_DEFINE_FIELD_ACCESSORS(Class_SuperclassReferenceKind,
13291332
Class_SuperclassReferenceKind_width,
1330-
TypeMetadataRecordKind,
1333+
TypeReferenceKind,
13311334
class_getSuperclassReferenceKind,
13321335
class_setSuperclassReferenceKind)
13331336
};

include/swift/Remote/MetadataReader.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -603,16 +603,23 @@ class MetadataReader {
603603
return llvm::None;
604604

605605
return cls->getClassBoundsAsSwiftSuperclass();
606+
},
607+
[](StoredPointer objcClassName) -> llvm::Optional<ClassMetadataBounds> {
608+
// We have no ability to look up an ObjC class by name.
609+
// FIXME: add a query for this; clients may have a way to do it.
610+
return llvm::None;
606611
});
607612
}
608613

609-
template <class Result, class DescriptorFn, class MetadataFn>
614+
template <class Result, class DescriptorFn, class MetadataFn,
615+
class ClassNameFn>
610616
llvm::Optional<Result>
611-
forTypeReference(TypeMetadataRecordKind refKind, StoredPointer ref,
617+
forTypeReference(TypeReferenceKind refKind, StoredPointer ref,
612618
const DescriptorFn &descriptorFn,
613-
const MetadataFn &metadataFn) {
619+
const MetadataFn &metadataFn,
620+
const ClassNameFn &classNameFn) {
614621
switch (refKind) {
615-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor: {
622+
case TypeReferenceKind::IndirectNominalTypeDescriptor: {
616623
StoredPointer descriptorAddress = 0;
617624
if (!Reader->readInteger(RemoteAddress(ref), &descriptorAddress))
618625
return llvm::None;
@@ -621,15 +628,18 @@ class MetadataReader {
621628
LLVM_FALLTHROUGH;
622629
}
623630

624-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor: {
631+
case TypeReferenceKind::DirectNominalTypeDescriptor: {
625632
auto descriptor = readContextDescriptor(ref);
626633
if (!descriptor)
627634
return llvm::None;
628635

629636
return descriptorFn(descriptor);
630637
}
631638

632-
case TypeMetadataRecordKind::IndirectObjCClass: {
639+
case TypeReferenceKind::DirectObjCClassName:
640+
return classNameFn(ref);
641+
642+
case TypeReferenceKind::IndirectObjCClass: {
633643
StoredPointer classRef = 0;
634644
if (!Reader->readInteger(RemoteAddress(ref), &classRef))
635645
return llvm::None;
@@ -640,10 +650,9 @@ class MetadataReader {
640650

641651
return metadataFn(metadata);
642652
}
643-
644-
default:
645-
return llvm::None;
646653
}
654+
655+
return llvm::None;
647656
}
648657

649658
/// Read a single generic type argument from a bound generic type

0 commit comments

Comments
 (0)