Skip to content

Commit c7a02a2

Browse files
committed
[ABI] Distinguish Swift/ObjC protocols in TargetGenericRequirement.
In a generic requirement, distinguish between Swift and Objective-C protocols using a spare bit within the relative (indirectable) reference to the protocol.
1 parent 03c3baa commit c7a02a2

File tree

6 files changed

+85
-24
lines changed

6 files changed

+85
-24
lines changed

include/swift/ABI/Metadata.h

+48-6
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,51 @@ using ProtocolRecord = TargetProtocolRecord<InProcess>;
23032303

23042304
template<typename Runtime> class TargetGenericRequirementDescriptor;
23052305

2306+
/// A relative pointer to a protocol descriptor, which provides the relative-
2307+
/// pointer equivalent to \c TargetProtocolDescriptorRef.
2308+
template <typename Runtime>
2309+
class RelativeTargetProtocolDescriptorPointer {
2310+
union AnyProtocol {
2311+
TargetProtocolDescriptor<Runtime> descriptor;
2312+
};
2313+
2314+
/// The relative pointer itself.
2315+
///
2316+
/// The \c AnyProtocol value type ensures that we can reference any
2317+
/// protocol descriptor; it will be reinterpret_cast to the appropriate
2318+
/// protocol descriptor type.
2319+
///
2320+
/// The \c bool integer value will be false to indicate that the protocol
2321+
/// is a Swift protocol, or true to indicate that this references
2322+
/// an Objective-C protocol.
2323+
RelativeIndirectablePointerIntPair<AnyProtocol, bool> pointer;
2324+
2325+
#if SWIFT_OBJC_INTEROP
2326+
bool isObjC() const {
2327+
return pointer.getInt();
2328+
}
2329+
#endif
2330+
2331+
public:
2332+
/// Retrieve a reference to the protocol.
2333+
TargetProtocolDescriptorRef<Runtime> getProtocol() const {
2334+
#if SWIFT_OBJC_INTEROP
2335+
if (isObjC()) {
2336+
return TargetProtocolDescriptorRef<Runtime>::forObjC(
2337+
protocol_const_cast(pointer.getPointer()));
2338+
}
2339+
#endif
2340+
2341+
return TargetProtocolDescriptorRef<Runtime>::forSwift(
2342+
reinterpret_cast<ConstTargetMetadataPointer<
2343+
Runtime, TargetProtocolDescriptor>>(pointer.getPointer()));
2344+
}
2345+
2346+
operator TargetProtocolDescriptorRef<Runtime>() const {
2347+
return getProtocol();
2348+
}
2349+
};
2350+
23062351
/// The structure of a protocol conformance.
23072352
///
23082353
/// This contains enough static information to recover the witness table for a
@@ -2334,8 +2379,6 @@ struct TargetProtocolConformanceDescriptor final
23342379

23352380
private:
23362381
/// The protocol being conformed to.
2337-
///
2338-
/// The remaining low bit is reserved for future use.
23392382
RelativeIndirectablePointer<ProtocolDescriptor> Protocol;
23402383

23412384
// Some description of the type that conforms to the protocol.
@@ -2704,8 +2747,7 @@ class TargetGenericRequirementDescriptor {
27042747
/// The protocol the param is constrained to.
27052748
///
27062749
/// Only valid if the requirement has Protocol kind.
2707-
RelativeIndirectablePointer<TargetProtocolDescriptor<Runtime>,
2708-
/*nullable*/ false> Protocol;
2750+
RelativeTargetProtocolDescriptorPointer<Runtime> Protocol;
27092751

27102752
/// The conformance the param is constrained to use.
27112753
///
@@ -2733,8 +2775,8 @@ class TargetGenericRequirementDescriptor {
27332775
return Param;
27342776
}
27352777

2736-
/// Retrieve the protocol descriptor for a Protocol requirement.
2737-
const TargetProtocolDescriptor<Runtime> *getProtocol() const {
2778+
/// Retrieve the protocol for a Protocol requirement.
2779+
TargetProtocolDescriptorRef<Runtime> getProtocol() const {
27382780
assert(getKind() == GenericRequirementKind::Protocol);
27392781
return Protocol;
27402782
}

lib/IRGen/GenMeta.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -3853,7 +3853,15 @@ GenericRequirementsMetadata irgen::addGenericRequirements(
38533853
IGM.getConstantReferenceForProtocolDescriptor(protocol);
38543854
addGenericRequirement(IGM, B, metadata, sig, flags,
38553855
requirement.getFirstType(),
3856-
[&]{ B.addRelativeAddress(descriptorRef); });
3856+
[&]{
3857+
unsigned tag = unsigned(descriptorRef.isIndirect());
3858+
if (protocol->isObjC())
3859+
tag |= 0x02;
3860+
3861+
B.addTaggedRelativeOffset(IGM.RelativeAddressTy,
3862+
descriptorRef.getValue(),
3863+
tag);
3864+
});
38573865
break;
38583866
}
38593867

stdlib/public/runtime/Casting.cpp

+14-15
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static const char *class_getName(const ClassMetadata* type) {
6969
extern "C" const void *swift_dynamicCastObjCProtocolConditional(
7070
const void *object,
7171
size_t numProtocols,
72-
const ProtocolDescriptor * const *protocols);
72+
Protocol * const *protocols);
7373
#endif
7474

7575
// Build a user-comprehensible name for a type.
@@ -303,7 +303,7 @@ swift_dynamicCastClassUnconditionalImpl(const void *object,
303303

304304
#if SWIFT_OBJC_INTEROP
305305
static bool _unknownClassConformsToObjCProtocol(const OpaqueValue *value,
306-
const ProtocolDescriptor *protocol) {
306+
Protocol *protocol) {
307307
const void *object
308308
= *reinterpret_cast<const void * const *>(value);
309309
return swift_dynamicCastObjCProtocolConditional(object, 1, &protocol);
@@ -312,11 +312,11 @@ static bool _unknownClassConformsToObjCProtocol(const OpaqueValue *value,
312312

313313
bool swift::_conformsToProtocol(const OpaqueValue *value,
314314
const Metadata *type,
315-
const ProtocolDescriptor *protocol,
315+
ProtocolDescriptorRef protocol,
316316
const WitnessTable **conformance) {
317317
// Look up the witness table for protocols that need them.
318-
if (protocol->Flags.needsWitnessTable()) {
319-
auto witness = swift_conformsToProtocol(type, protocol);
318+
if (protocol.needsWitnessTable()) {
319+
auto witness = swift_conformsToProtocol(type, protocol.getSwiftProtocol());
320320
if (!witness)
321321
return false;
322322
if (conformance)
@@ -330,22 +330,22 @@ bool swift::_conformsToProtocol(const OpaqueValue *value,
330330
case MetadataKind::Class:
331331
#if SWIFT_OBJC_INTEROP
332332
if (value) {
333-
return _unknownClassConformsToObjCProtocol(value, protocol);
333+
return _unknownClassConformsToObjCProtocol(value,
334+
protocol.getObjCProtocol());
334335
} else {
335-
return classConformsToObjCProtocol(type,
336-
ProtocolDescriptorRef(protocol, ProtocolDispatchStrategy::ObjC));
336+
return classConformsToObjCProtocol(type, protocol);
337337
}
338338
#endif
339339
return false;
340340

341341
case MetadataKind::ObjCClassWrapper: {
342342
#if SWIFT_OBJC_INTEROP
343343
if (value) {
344-
return _unknownClassConformsToObjCProtocol(value, protocol);
344+
return _unknownClassConformsToObjCProtocol(value,
345+
protocol.getObjCProtocol());
345346
} else {
346347
auto wrapper = cast<ObjCClassWrapperMetadata>(type);
347-
return classConformsToObjCProtocol(wrapper->Class,
348-
ProtocolDescriptorRef(protocol, ProtocolDispatchStrategy::ObjC));
348+
return classConformsToObjCProtocol(wrapper->Class, protocol);
349349
}
350350
#endif
351351
return false;
@@ -354,7 +354,8 @@ bool swift::_conformsToProtocol(const OpaqueValue *value,
354354
case MetadataKind::ForeignClass:
355355
#if SWIFT_OBJC_INTEROP
356356
if (value)
357-
return _unknownClassConformsToObjCProtocol(value, protocol);
357+
return _unknownClassConformsToObjCProtocol(value,
358+
protocol.getObjCProtocol());
358359
return false;
359360
#else
360361
return false;
@@ -387,9 +388,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
387388
}
388389

389390
for (auto protocol : existentialType->getProtocols()) {
390-
if (!_conformsToProtocol(value, type,
391-
protocol.getProtocolDescriptorUnchecked(),
392-
conformances))
391+
if (!_conformsToProtocol(value, type, protocol, conformances))
393392
return false;
394393
if (protocol.needsWitnessTable()) {
395394
assert(*conformances != nullptr);

stdlib/public/runtime/Private.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ class TypeInfo {
323323
/// table will be placed here
324324
bool _conformsToProtocol(const OpaqueValue *value,
325325
const Metadata *type,
326-
const ProtocolDescriptor *protocol,
326+
ProtocolDescriptorRef protocol,
327327
const WitnessTable **conformance);
328328

329329
void _swift_getFieldAt(

stdlib/public/runtime/ProtocolConformance.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ bool swift::_checkGenericRequirements(
711711
return true;
712712

713713
// If we need a witness table, add it.
714-
if (req.getProtocol()->Flags.needsWitnessTable()) {
714+
if (req.getProtocol().needsWitnessTable()) {
715715
assert(witnessTable);
716716
extraArguments.push_back(witnessTable);
717717
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
import Builtin
6+
7+
@objc protocol ObjCProto { }
8+
9+
// CHECK: @"$S24generic_requirement_objc13GenericStructVMn" =
10+
// CHECK-SAME: i32 add {{.*}} ptrtoint (i8** @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP24generic_requirement_objc9ObjCProto_" {{.*}} @"$S24generic_requirement_objc13GenericStructVMn", {{.*}} i32 3)
11+
12+
struct GenericStruct<T: ObjCProto> { }

0 commit comments

Comments
 (0)