Skip to content

Commit d102393

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 14f7799 commit d102393

File tree

12 files changed

+276
-158
lines changed

12 files changed

+276
-158
lines changed

include/swift/ABI/Metadata.h

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,32 +2150,37 @@ struct TargetTypeMetadataRecord {
21502150
union {
21512151
/// A direct reference to a nominal type descriptor.
21522152
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime>,
2153-
TypeMetadataRecordKind>
2153+
TypeReferenceKind>
21542154
DirectNominalTypeDescriptor;
21552155

21562156
/// An indirect reference to a nominal type descriptor.
21572157
RelativeDirectPointerIntPair<TargetTypeContextDescriptor<Runtime> * const,
2158-
TypeMetadataRecordKind>
2158+
TypeReferenceKind>
21592159
IndirectNominalTypeDescriptor;
2160+
2161+
// We only allow a subset of the TypeReferenceKinds here.
2162+
// Should we just acknowledge that this is a different enum?
21602163
};
21612164

21622165
public:
2163-
TypeMetadataRecordKind getTypeKind() const {
2166+
TypeReferenceKind getTypeKind() const {
21642167
return DirectNominalTypeDescriptor.getInt();
21652168
}
21662169

21672170
const TargetTypeContextDescriptor<Runtime> *
21682171
getTypeContextDescriptor() const {
21692172
switch (getTypeKind()) {
2170-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2173+
case TypeReferenceKind::DirectNominalTypeDescriptor:
21712174
return DirectNominalTypeDescriptor.getPointer();
21722175

2173-
case TypeMetadataRecordKind::Reserved:
2174-
case TypeMetadataRecordKind::IndirectObjCClass:
2175-
return nullptr;
2176-
2177-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2176+
case TypeReferenceKind::IndirectNominalTypeDescriptor:
21782177
return *IndirectNominalTypeDescriptor.getPointer();
2178+
2179+
// These types (and any others we might add to TypeReferenceKind
2180+
// in the future) are just never used in these lists.
2181+
case TypeReferenceKind::DirectObjCClassName:
2182+
case TypeReferenceKind::IndirectObjCClass:
2183+
return nullptr;
21792184
}
21802185

21812186
return nullptr;
@@ -2250,6 +2255,66 @@ class RelativeTargetProtocolDescriptorPointer {
22502255
}
22512256
};
22522257

2258+
/// A referenc to a type.
2259+
template <typename Runtime>
2260+
struct TargetTypeReference {
2261+
union {
2262+
/// A direct reference to a nominal type descriptor.
2263+
RelativeDirectPointer<TargetTypeContextDescriptor<Runtime>>
2264+
DirectNominalTypeDescriptor;
2265+
2266+
/// An indirect reference to a nominal type descriptor.
2267+
RelativeDirectPointer<
2268+
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>>
2269+
IndirectNominalTypeDescriptor;
2270+
2271+
/// An indirect reference to an Objective-C class.
2272+
RelativeDirectPointer<
2273+
ConstTargetMetadataPointer<Runtime, TargetClassMetadata>>
2274+
IndirectObjCClass;
2275+
2276+
/// A direct reference to an Objective-C class name.
2277+
RelativeDirectPointer<const char>
2278+
DirectObjCClassName;
2279+
};
2280+
2281+
const TargetTypeContextDescriptor<Runtime> *
2282+
getTypeContextDescriptor(TypeReferenceKind kind) const {
2283+
switch (kind) {
2284+
case TypeReferenceKind::DirectNominalTypeDescriptor:
2285+
return DirectNominalTypeDescriptor;
2286+
2287+
case TypeReferenceKind::IndirectNominalTypeDescriptor:
2288+
return *IndirectNominalTypeDescriptor;
2289+
2290+
case TypeReferenceKind::DirectObjCClassName:
2291+
case TypeReferenceKind::IndirectObjCClass:
2292+
return nullptr;
2293+
}
2294+
2295+
return nullptr;
2296+
}
2297+
2298+
#if SWIFT_OBJC_INTEROP
2299+
/// If this type reference is one of the kinds that supports ObjC
2300+
/// references,
2301+
const TargetClassMetadata<Runtime> *
2302+
getObjCClass(TypeReferenceKind kind) const;
2303+
#endif
2304+
2305+
const TargetClassMetadata<Runtime> * const *
2306+
getIndirectObjCClass(TypeReferenceKind kind) const {
2307+
assert(kind == TypeReferenceKind::IndirectObjCClass);
2308+
return IndirectObjCClass.get();
2309+
}
2310+
2311+
const char *getDirectObjCClassName(TypeReferenceKind kind) const {
2312+
assert(kind == TypeReferenceKind::DirectObjCClassName);
2313+
return DirectObjCClassName.get();
2314+
}
2315+
};
2316+
using TypeReference = TargetTypeReference<InProcess>;
2317+
22532318
/// The structure of a protocol conformance.
22542319
///
22552320
/// This contains enough static information to recover the witness table for a
@@ -2284,21 +2349,7 @@ struct TargetProtocolConformanceDescriptor final
22842349
RelativeIndirectablePointer<ProtocolDescriptor> Protocol;
22852350

22862351
// Some description of the type that conforms to the protocol.
2287-
union {
2288-
/// A direct reference to a nominal type descriptor.
2289-
RelativeDirectPointer<TargetTypeContextDescriptor<Runtime>>
2290-
DirectNominalTypeDescriptor;
2291-
2292-
/// An indirect reference to a nominal type descriptor.
2293-
RelativeDirectPointer<
2294-
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>>
2295-
IndirectNominalTypeDescriptor;
2296-
2297-
/// An indirect reference to the metadata.
2298-
RelativeDirectPointer<
2299-
ConstTargetMetadataPointer<Runtime, TargetClassMetadata>>
2300-
IndirectObjCClass;
2301-
};
2352+
TargetTypeReference<Runtime> TypeRef;
23022353

23032354
// The conformance, or a generator function for the conformance.
23042355
union {
@@ -2318,45 +2369,24 @@ struct TargetProtocolConformanceDescriptor final
23182369
return Protocol;
23192370
}
23202371

2321-
TypeMetadataRecordKind getTypeKind() const {
2372+
TypeReferenceKind getTypeKind() const {
23222373
return Flags.getTypeReferenceKind();
23232374
}
23242375

23252376
typename ConformanceFlags::ConformanceKind getConformanceKind() const {
23262377
return Flags.getConformanceKind();
23272378
}
2328-
2329-
const TargetClassMetadata<Runtime> * const *getIndirectObjCClass() const {
2330-
switch (getTypeKind()) {
2331-
case TypeMetadataRecordKind::IndirectObjCClass:
2332-
break;
23332379

2334-
case TypeMetadataRecordKind::Reserved:
2335-
return nullptr;
2380+
const char *getDirectObjCClassName() const {
2381+
return TypeRef.getDirectObjCClassName(getTypeKind());
2382+
}
23362383

2337-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2338-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2339-
assert(false && "not indirect class object");
2340-
}
2341-
2342-
return IndirectObjCClass.get();
2384+
const TargetClassMetadata<Runtime> * const *getIndirectObjCClass() const {
2385+
return TypeRef.getIndirectObjCClass(getTypeKind());
23432386
}
23442387

2345-
const TargetTypeContextDescriptor<Runtime> *
2346-
getTypeContextDescriptor() const {
2347-
switch (getTypeKind()) {
2348-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor:
2349-
return DirectNominalTypeDescriptor;
2350-
2351-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor:
2352-
return *IndirectNominalTypeDescriptor;
2353-
2354-
case TypeMetadataRecordKind::Reserved:
2355-
case TypeMetadataRecordKind::IndirectObjCClass:
2356-
return nullptr;
2357-
}
2358-
2359-
return nullptr;
2388+
const TargetTypeContextDescriptor<Runtime> *getTypeContextDescriptor() const {
2389+
return TypeRef.getTypeContextDescriptor(getTypeKind());
23602390
}
23612391

23622392
/// Retrieve the context of a retroactive conformance.
@@ -2418,7 +2448,7 @@ struct TargetProtocolConformanceDescriptor final
24182448
///
24192449
/// We currently check that the descriptor:
24202450
///
2421-
/// 1. Has a valid TypeMetadataRecordKind.
2451+
/// 1. Has a valid TypeReferenceKind.
24222452
/// 2. Has a valid conformance kind.
24232453
void verify() const LLVM_ATTRIBUTE_USED;
24242454
#endif
@@ -3563,7 +3593,7 @@ class TargetClassDescriptor final
35633593
return !Superclass.isNull();
35643594
}
35653595

3566-
TypeMetadataRecordKind getSuperclassReferenceKind() const {
3596+
TypeReferenceKind getSuperclassReferenceKind() const {
35673597
return getTypeContextDescriptorFlags().class_getSuperclassReferenceKind();
35683598
}
35693599

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

@@ -1237,16 +1240,16 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12371240
/// Only meaningful for class descriptors.
12381241
Class_HasResilientSuperclass = 14,
12391242

1243+
/// Whether the immediate class members in this metadata are allocated
1244+
/// at negative offsets. For now, we don't use this.
1245+
Class_AreImmediateMembersNegative = 13,
1246+
12401247
/// The kind of reference that this class makes to its superclass
1241-
/// descriptor. A TypeMetadataRecordKind.
1248+
/// descriptor. A TypeReferenceKind.
12421249
///
12431250
/// Only meaningful for class descriptors.
1244-
Class_SuperclassReferenceKind = 12,
1245-
Class_SuperclassReferenceKind_width = 2,
1246-
1247-
/// Whether the immediate class members in this metadata are allocated
1248-
/// at negative offsets. For now, we don't use this.
1249-
Class_AreImmediateMembersNegative = 11,
1251+
Class_SuperclassReferenceKind = 10,
1252+
Class_SuperclassReferenceKind_width = 3,
12501253
};
12511254

12521255
public:
@@ -1333,7 +1336,7 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
13331336

13341337
FLAGSET_DEFINE_FIELD_ACCESSORS(Class_SuperclassReferenceKind,
13351338
Class_SuperclassReferenceKind_width,
1336-
TypeMetadataRecordKind,
1339+
TypeReferenceKind,
13371340
class_getSuperclassReferenceKind,
13381341
class_setSuperclassReferenceKind)
13391342
};

include/swift/Remote/MetadataReader.h

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

742742
return cls->getClassBoundsAsSwiftSuperclass();
743+
},
744+
[](StoredPointer objcClassName) -> llvm::Optional<ClassMetadataBounds> {
745+
// We have no ability to look up an ObjC class by name.
746+
// FIXME: add a query for this; clients may have a way to do it.
747+
return llvm::None;
743748
});
744749
}
745750

746-
template <class Result, class DescriptorFn, class MetadataFn>
751+
template <class Result, class DescriptorFn, class MetadataFn,
752+
class ClassNameFn>
747753
llvm::Optional<Result>
748-
forTypeReference(TypeMetadataRecordKind refKind, StoredPointer ref,
754+
forTypeReference(TypeReferenceKind refKind, StoredPointer ref,
749755
const DescriptorFn &descriptorFn,
750-
const MetadataFn &metadataFn) {
756+
const MetadataFn &metadataFn,
757+
const ClassNameFn &classNameFn) {
751758
switch (refKind) {
752-
case TypeMetadataRecordKind::IndirectNominalTypeDescriptor: {
759+
case TypeReferenceKind::IndirectNominalTypeDescriptor: {
753760
StoredPointer descriptorAddress = 0;
754761
if (!Reader->readInteger(RemoteAddress(ref), &descriptorAddress))
755762
return llvm::None;
@@ -758,15 +765,18 @@ class MetadataReader {
758765
LLVM_FALLTHROUGH;
759766
}
760767

761-
case TypeMetadataRecordKind::DirectNominalTypeDescriptor: {
768+
case TypeReferenceKind::DirectNominalTypeDescriptor: {
762769
auto descriptor = readContextDescriptor(ref);
763770
if (!descriptor)
764771
return llvm::None;
765772

766773
return descriptorFn(descriptor);
767774
}
768775

769-
case TypeMetadataRecordKind::IndirectObjCClass: {
776+
case TypeReferenceKind::DirectObjCClassName:
777+
return classNameFn(ref);
778+
779+
case TypeReferenceKind::IndirectObjCClass: {
770780
StoredPointer classRef = 0;
771781
if (!Reader->readInteger(RemoteAddress(ref), &classRef))
772782
return llvm::None;
@@ -777,10 +787,9 @@ class MetadataReader {
777787

778788
return metadataFn(metadata);
779789
}
780-
781-
default:
782-
return llvm::None;
783790
}
791+
792+
return llvm::None;
784793
}
785794

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

0 commit comments

Comments
 (0)