Make Objective-C interoperability configurable in the runtime

In order to be able to debug, for example, a Linux process from a macOS host, we
need to be able to initialize a ReflectionContext without Objective-C
interoperability. This patch turns ObjCInterOp into another template trait, so
it's possible to instantiate a non-ObjC MetadataReader on a system built with
ObjC-interop (but not vice versa).

This patch changes the class hierarchy to

                          TargetMetadata<Runtime>
                                    |
                          TargetHeapMetadata<Runtime>
                                    |
                          TargetAnyClassMetadata<Runtime>
                                   /                \
                                  /               TargetAnyClassMetadataObjCInterop<Runtime>
                                 /                              \
TargetClassMetadata<Runtime, TargetAnyClassMetadata<Runtime>>    \
                                                                  \
                    TargetClassMetadata<Runtime, TargetAnyClassMetadataObjCInterop<Runtime>>

TargetAnyClassMetadataObjCInterop inherits from TargetAnyClassMetadata because
most of the implementation is the same. This choice makes TargetClassMetadata a
bit tricky. In this patch I went with templating the parent class.

rdar://87179578
This commit is contained in:
Adrian Prantl
2022-01-13 14:49:48 -08:00
parent 477b4d68fa
commit fede775269
7 changed files with 332 additions and 188 deletions

View File

@@ -48,6 +48,24 @@
#include "llvm/Support/Casting.h"
namespace swift {
template <typename Runtime> struct TargetGenericMetadataInstantiationCache;
template <typename Runtime> struct TargetAnyClassMetadata;
template <typename Runtime> struct TargetAnyClassMetadataObjCInterop;
template <typename Runtime, typename TargetAnyClassMetadataVariant>
struct TargetClassMetadata;
template <typename Runtime> struct TargetStructMetadata;
template <typename Runtime> struct TargetOpaqueMetadata;
template <typename Runtime> struct TargetValueMetadata;
template <typename Runtime> struct TargetForeignClassMetadata;
template <typename Runtime> struct TargetContextDescriptor;
template <typename Runtime> class TargetTypeContextDescriptor;
template <typename Runtime> class TargetClassDescriptor;
template <typename Runtime> class TargetValueTypeDescriptor;
template <typename Runtime> class TargetEnumDescriptor;
template <typename Runtime> class TargetStructDescriptor;
template <typename Runtime> struct TargetGenericMetadataPattern;
template <unsigned PointerSize>
struct RuntimeTarget;
@@ -90,6 +108,18 @@ struct InProcess {
using StoredSize = size_t;
using StoredPointerDifference = ptrdiff_t;
#if SWIFT_OBJC_INTEROP
static constexpr bool ObjCInterop = true;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
#else
static constexpr bool ObjCInterop = false;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
#endif
template <typename T>
using TargetClassMetadata = TargetClassMetadata<T, TargetAnyClassMetadata<T>>;
static_assert(sizeof(StoredSize) == sizeof(StoredPointerDifference),
"target uses differently-sized size_t and ptrdiff_t");
@@ -120,14 +150,44 @@ struct ExternalPointer {
StoredPointer PointerValue;
};
/// An external process's runtime target, which may be a different architecture.
template <typename Runtime> struct WithObjCInterop {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSignedPointer = typename Runtime::StoredSignedPointer;
using StoredSize = typename Runtime::StoredSize;
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
static constexpr size_t PointerSize = Runtime::PointerSize;
static constexpr bool ObjCInterop = true;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
};
template <typename Runtime> struct NoObjCInterop {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSignedPointer = typename Runtime::StoredSignedPointer;
using StoredSize = typename Runtime::StoredSize;
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
static constexpr size_t PointerSize = Runtime::PointerSize;
static constexpr bool ObjCInterop = false;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
};
/// An external process's runtime target, which may be a different architecture,
/// and may or may not have Objective-C interoperability.
template <typename Runtime>
struct External {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSignedPointer = typename Runtime::StoredSignedPointer;
using StoredSize = typename Runtime::StoredSize;
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
template <typename T>
using TargetAnyClassMetadata =
typename Runtime::template TargetAnyClassMetadata<T>;
template <typename T>
using TargetClassMetadata = TargetClassMetadata<T, TargetAnyClassMetadata<T>>;
static constexpr size_t PointerSize = Runtime::PointerSize;
static constexpr bool ObjCInterop = Runtime::ObjCInterop;
const StoredPointer PointerValue;
template <typename T>
@@ -478,21 +538,6 @@ namespace {
};
}
template <typename Runtime> struct TargetGenericMetadataInstantiationCache;
template <typename Runtime> struct TargetAnyClassMetadata;
template <typename Runtime> struct TargetClassMetadata;
template <typename Runtime> struct TargetStructMetadata;
template <typename Runtime> struct TargetOpaqueMetadata;
template <typename Runtime> struct TargetValueMetadata;
template <typename Runtime> struct TargetForeignClassMetadata;
template <typename Runtime> struct TargetContextDescriptor;
template <typename Runtime> class TargetTypeContextDescriptor;
template <typename Runtime> class TargetClassDescriptor;
template <typename Runtime> class TargetValueTypeDescriptor;
template <typename Runtime> class TargetEnumDescriptor;
template <typename Runtime> class TargetStructDescriptor;
template <typename Runtime> struct TargetGenericMetadataPattern;
using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
// FIXME: https://bugs.swift.org/browse/SR-1155
@@ -540,7 +585,7 @@ struct TargetMetadata {
#if SWIFT_OBJC_INTEROP
protected:
constexpr TargetMetadata(TargetAnyClassMetadata<Runtime> *isa)
constexpr TargetMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
: Kind(reinterpret_cast<StoredPointer>(isa)) {}
#endif
@@ -559,7 +604,6 @@ public:
Kind = static_cast<StoredPointer>(kind);
}
#if SWIFT_OBJC_INTEROP
protected:
const TargetAnyClassMetadata<Runtime> *getClassISA() const {
return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
@@ -567,7 +611,6 @@ protected:
void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
Kind = reinterpret_cast<StoredPointer>(isa);
}
#endif
public:
/// Is this a class object--the metadata record for a Swift class (which also
@@ -684,12 +727,23 @@ public:
getTypeContextDescriptor() const {
switch (getKind()) {
case MetadataKind::Class: {
const auto cls = static_cast<const TargetClassMetadata<Runtime> *>(this);
if (!cls->isTypeMetadata())
return nullptr;
if (cls->isArtificialSubclass())
return nullptr;
return cls->getDescription();
if (Runtime::ObjCInterop) {
const auto cls = static_cast<const TargetClassMetadata<
Runtime, TargetAnyClassMetadataObjCInterop<Runtime>> *>(this);
if (!cls->isTypeMetadata())
return nullptr;
if (cls->isArtificialSubclass())
return nullptr;
return cls->getDescription();
} else {
const auto cls = static_cast<const TargetClassMetadata<
Runtime, TargetAnyClassMetadata<Runtime>> *>(this);
if (!cls->isTypeMetadata())
return nullptr;
if (cls->isArtificialSubclass())
return nullptr;
return cls->getDescription();
}
}
case MetadataKind::Struct:
case MetadataKind::Enum:
@@ -706,7 +760,8 @@ public:
/// Get the class object for this type if it has one, or return null if the
/// type is not a class (or not a class with a class object).
const TargetClassMetadata<Runtime> *getClassObject() const;
const typename Runtime::template TargetClassMetadata<Runtime> *
getClassObject() const;
/// Retrieve the generic arguments of this type, if it has any.
ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *
@@ -740,8 +795,9 @@ public:
typename std::enable_if<std::is_same<R, InProcess>::value, Class>::type
getObjCClassObject() const {
return reinterpret_cast<Class>(
const_cast<TargetClassMetadata<InProcess>*>(
getClassObject()));
const_cast<TargetClassMetadata<
InProcess, TargetAnyClassMetadataObjCInterop<InProcess>> *>(
getClassObject()));
}
#endif
@@ -777,7 +833,9 @@ template <typename Runtime>
struct TargetHeapMetadataHeaderPrefix {
/// Destroy the object, returning the allocated size of the object
/// or 0 if the object shouldn't be deallocated.
TargetSignedPointer<Runtime, HeapObjectDestroyer *__ptrauth_swift_heap_object_destructor> destroy;
TargetSignedPointer<Runtime, HeapObjectDestroyer *
__ptrauth_swift_heap_object_destructor>
destroy;
};
using HeapMetadataHeaderPrefix =
TargetHeapMetadataHeaderPrefix<InProcess>;
@@ -809,10 +867,8 @@ struct TargetHeapMetadata : TargetMetadata<Runtime> {
TargetHeapMetadata() = default;
constexpr TargetHeapMetadata(MetadataKind kind)
: TargetMetadata<Runtime>(kind) {}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
constexpr TargetHeapMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
: TargetMetadata<Runtime>(isa) {}
#endif
};
using HeapMetadata = TargetHeapMetadata<InProcess>;
@@ -949,6 +1005,8 @@ struct TargetClassMetadataBounds : TargetMetadataBounds<Runtime> {
using TargetMetadataBounds<Runtime>::NegativeSizeInWords;
using TargetMetadataBounds<Runtime>::PositiveSizeInWords;
using TargetClassMetadata =
typename Runtime::template TargetClassMetadata<Runtime>;
/// The offset from the address point of the metadata to the immediate
/// members.
@@ -961,10 +1019,13 @@ struct TargetClassMetadataBounds : TargetMetadataBounds<Runtime> {
: TargetMetadataBounds<Runtime>{negativeSizeInWords, positiveSizeInWords},
ImmediateMembersOffset(immediateMembersOffset) {}
template <typename T>
using TargetClassMetadataT = typename Runtime::template TargetClassMetadata<T>;
/// Return the basic bounds of all Swift class metadata.
/// The immediate members offset will not be meaningful.
static constexpr TargetClassMetadataBounds<Runtime> forSwiftRootClass() {
using Metadata = FullMetadata<TargetClassMetadata<Runtime>>;
using Metadata = FullMetadata<TargetClassMetadataT<Runtime>>;
return forAddressPointAndSize(sizeof(typename Metadata::HeaderType),
sizeof(Metadata));
}
@@ -1007,39 +1068,65 @@ template <typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
using TargetClassMetadata =
typename Runtime::template TargetClassMetadata<Runtime>;
#if SWIFT_OBJC_INTEROP
constexpr TargetAnyClassMetadata(TargetAnyClassMetadata<Runtime> *isa,
TargetClassMetadata<Runtime> *superclass)
: TargetHeapMetadata<Runtime>(isa),
Superclass(superclass),
CacheData{nullptr, nullptr},
Data(SWIFT_CLASS_IS_SWIFT_MASK) {}
#endif
constexpr TargetAnyClassMetadata(TargetClassMetadata<Runtime> *superclass)
: TargetHeapMetadata<Runtime>(MetadataKind::Class),
Superclass(superclass)
#if SWIFT_OBJC_INTEROP
, CacheData{nullptr, nullptr},
Data(SWIFT_CLASS_IS_SWIFT_MASK)
#endif
{}
#if SWIFT_OBJC_INTEROP
// Allow setting the metadata kind to a class ISA on class metadata.
using TargetMetadata<Runtime>::getClassISA;
using TargetMetadata<Runtime>::setClassISA;
#endif
protected:
constexpr TargetAnyClassMetadata(
TargetAnyClassMetadataObjCInterop<Runtime> *isa,
TargetClassMetadata *superclass)
: TargetHeapMetadata<Runtime>(isa), Superclass(superclass) {}
public:
constexpr TargetAnyClassMetadata(TargetClassMetadata *superclass)
: TargetHeapMetadata<Runtime>(MetadataKind::Class),
Superclass(superclass) {}
// Note that ObjC classes do not have a metadata header.
/// The metadata for the superclass. This is null for the root class.
TargetSignedPointer<Runtime, const TargetClassMetadata<Runtime> *
TargetSignedPointer<Runtime, const TargetClassMetadata *
__ptrauth_swift_objc_superclass>
Superclass;
#if SWIFT_OBJC_INTEROP
/// Is this object a valid swift type metadata? That is, can it be
/// safely downcast to ClassMetadata?
bool isTypeMetadata() const {
return true;
}
/// A different perspective on the same bit.
bool isPureObjC() const {
return !isTypeMetadata();
}
};
/// This is the class metadata object for all classes (Swift and ObjC) in a
/// runtime that has Objective-C interoperability.
template <typename Runtime>
struct TargetAnyClassMetadataObjCInterop
: public TargetAnyClassMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
using TargetClassMetadataObjCInterop =
TargetClassMetadata<Runtime, TargetAnyClassMetadataObjCInterop<Runtime>>;
constexpr TargetAnyClassMetadataObjCInterop(
TargetAnyClassMetadataObjCInterop<Runtime> *isa,
TargetClassMetadataObjCInterop *superclass)
: TargetAnyClassMetadata<Runtime>(isa, superclass),
CacheData{nullptr, nullptr},
Data(SWIFT_CLASS_IS_SWIFT_MASK) {}
constexpr TargetAnyClassMetadataObjCInterop(
TargetClassMetadataObjCInterop *superclass)
: TargetAnyClassMetadata<Runtime>(superclass), CacheData{nullptr,
nullptr},
Data(SWIFT_CLASS_IS_SWIFT_MASK) {}
// Allow setting the metadata kind to a class ISA on class metadata.
using TargetMetadata<Runtime>::getClassISA;
using TargetMetadata<Runtime>::setClassISA;
/// The cache data is used for certain dynamic lookups; it is owned
/// by the runtime and generally needs to interoperate with
/// Objective-C's use.
@@ -1052,26 +1139,25 @@ struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
StoredSize Data;
static constexpr StoredPointer offsetToData() {
return offsetof(TargetAnyClassMetadata, Data);
return offsetof(TargetAnyClassMetadataObjCInterop, Data);
}
#endif
/// Is this object a valid swift type metadata? That is, can it be
/// safely downcast to ClassMetadata?
bool isTypeMetadata() const {
#if SWIFT_OBJC_INTEROP
return (Data & SWIFT_CLASS_IS_SWIFT_MASK);
#else
return true;
#endif
}
/// A different perspective on the same bit
bool isPureObjC() const {
return !isTypeMetadata();
}
};
using AnyClassMetadata =
TargetAnyClassMetadata<InProcess>;
#if SWIFT_OBJC_INTEROP
using AnyClassMetadata = TargetAnyClassMetadataObjCInterop<InProcess>;
#else
using AnyClassMetadata = TargetAnyClassMetadata<InProcess>;
#endif
using ClassIVarDestroyer =
SWIFT_CC(swift) void(SWIFT_CONTEXT HeapObject *);
@@ -1082,23 +1168,28 @@ using ClassIVarDestroyer =
///
/// Note that the layout of this type is compatible with the layout of
/// an Objective-C class.
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
///
/// If the Runtime supports Objective-C interoperability, this class inherits
/// from TargetAnyClassMetadataObjCInterop, otherwise it inherits from
/// TargetAnyClassMetadata.
template <typename Runtime, typename TargetAnyClassMetadataVariant>
struct TargetClassMetadata : public TargetAnyClassMetadataVariant {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
TargetClassMetadata() = default;
constexpr TargetClassMetadata(const TargetAnyClassMetadata<Runtime> &base,
ClassFlags flags,
ClassIVarDestroyer *ivarDestroyer,
StoredPointer size, StoredPointer addressPoint,
StoredPointer alignMask,
StoredPointer classSize, StoredPointer classAddressPoint)
: TargetAnyClassMetadata<Runtime>(base),
Flags(flags), InstanceAddressPoint(addressPoint),
InstanceSize(size), InstanceAlignMask(alignMask),
Reserved(0), ClassSize(classSize), ClassAddressPoint(classAddressPoint),
Description(nullptr), IVarDestroyer(ivarDestroyer) {}
constexpr TargetClassMetadata(const TargetAnyClassMetadataVariant &base,
ClassFlags flags,
ClassIVarDestroyer *ivarDestroyer,
StoredPointer size, StoredPointer addressPoint,
StoredPointer alignMask,
StoredPointer classSize,
StoredPointer classAddressPoint)
: TargetAnyClassMetadataVariant(base), Flags(flags),
InstanceAddressPoint(addressPoint), InstanceSize(size),
InstanceAlignMask(alignMask), Reserved(0), ClassSize(classSize),
ClassAddressPoint(classAddressPoint), Description(nullptr),
IVarDestroyer(ivarDestroyer) {}
// The remaining fields are valid only when isTypeMetadata().
// The Objective-C runtime knows the offsets to some of these fields.
@@ -1150,7 +1241,7 @@ public:
// - class variables (if we choose to support these)
// - "tabulated" virtual methods
using TargetAnyClassMetadata<Runtime>::isTypeMetadata;
using TargetAnyClassMetadataVariant::isTypeMetadata;
ConstTargetMetadataPointer<Runtime, TargetClassDescriptor>
getDescription() const {
@@ -1350,7 +1441,18 @@ public:
return metadata->getKind() == MetadataKind::Class;
}
};
using ClassMetadata = TargetClassMetadata<InProcess>;
#if SWIFT_OBJC_INTEROP
using ClassMetadata =
TargetClassMetadata<InProcess,
TargetAnyClassMetadataObjCInterop<InProcess>>;
#else
using ClassMetadata =
TargetClassMetadata<InProcess, TargetAnyClassMetadata<InProcess>>;
#endif
template <typename Runtime>
using TargetClassMetadataObjCInterop =
TargetClassMetadata<Runtime, TargetAnyClassMetadataObjCInterop<Runtime>>;
/// The structure of class metadata that's compatible with dispatch objects.
/// This includes Swift heap metadata, followed by the vtable entries that
@@ -1398,7 +1500,7 @@ using HeapLocalVariableMetadata
/// Swift-compiled.
template <typename Runtime>
struct TargetObjCClassWrapperMetadata : public TargetMetadata<Runtime> {
ConstTargetMetadataPointer<Runtime, TargetClassMetadata> Class;
ConstTargetMetadataPointer<Runtime, TargetClassMetadataObjCInterop> Class;
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::ObjCClassWrapper;
@@ -1832,7 +1934,6 @@ TargetTupleTypeMetadata<Runtime>::getOffsetToNumElements() -> StoredSize {
template <typename Runtime> struct TargetProtocolDescriptor;
#if SWIFT_OBJC_INTEROP
/// Layout of a small prefix of an Objective-C protocol, used only to
/// directly extract the name of the protocol.
template <typename Runtime>
@@ -1843,7 +1944,6 @@ struct TargetObjCProtocolPrefix {
/// The mangled name of the protocol.
TargetPointer<Runtime, const char> Name;
};
#endif
/// A reference to a protocol within the runtime, which may be either
/// a Swift protocol or (when Objective-C interoperability is enabled) an
@@ -1877,13 +1977,14 @@ public:
TargetProtocolDescriptorRef(
ProtocolDescriptorPointer protocol,
ProtocolDispatchStrategy dispatchStrategy) {
#if SWIFT_OBJC_INTEROP
storage = reinterpret_cast<StoredPointer>(protocol)
| (dispatchStrategy == ProtocolDispatchStrategy::ObjC ? IsObjCBit : 0);
#else
assert(dispatchStrategy == ProtocolDispatchStrategy::Swift);
storage = reinterpret_cast<StoredPointer>(protocol);
#endif
if (Runtime::ObjCInterop) {
storage =
reinterpret_cast<StoredPointer>(protocol) |
(dispatchStrategy == ProtocolDispatchStrategy::ObjC ? IsObjCBit : 0);
} else {
assert(dispatchStrategy == ProtocolDispatchStrategy::Swift);
storage = reinterpret_cast<StoredPointer>(protocol);
}
}
const static TargetProtocolDescriptorRef forSwift(
@@ -1917,22 +2018,18 @@ public:
/// Determine what kind of protocol this is, Swift or Objective-C.
ProtocolDispatchStrategy getDispatchStrategy() const {
#if SWIFT_OBJC_INTEROP
if (isObjC()) {
return ProtocolDispatchStrategy::ObjC;
}
#endif
return ProtocolDispatchStrategy::Swift;
}
/// Determine whether this protocol has a 'class' constraint.
ProtocolClassConstraint getClassConstraint() const {
#if SWIFT_OBJC_INTEROP
if (isObjC()) {
return ProtocolClassConstraint::Class;
}
#endif
return getSwiftProtocol()->getProtocolContextDescriptorFlags()
.getClassConstraint();
@@ -1940,21 +2037,17 @@ public:
/// Determine whether this protocol needs a witness table.
bool needsWitnessTable() const {
#if SWIFT_OBJC_INTEROP
if (isObjC()) {
return false;
}
#endif
return true;
}
SpecialProtocol getSpecialProtocol() const {
#if SWIFT_OBJC_INTEROP
if (isObjC()) {
return SpecialProtocol::None;
}
#endif
return getSwiftProtocol()->getProtocolContextDescriptorFlags()
.getSpecialProtocol();
@@ -1962,9 +2055,7 @@ public:
/// Retrieve the Swift protocol descriptor.
ProtocolDescriptorPointer getSwiftProtocol() const {
#if SWIFT_OBJC_INTEROP
assert(!isObjC());
#endif
// NOTE: we explicitly use a C-style cast here because cl objects to the
// reinterpret_cast from a uintptr_t type to an unsigned type which the
@@ -1978,12 +2069,15 @@ public:
return storage;
}
#if SWIFT_OBJC_INTEROP
/// Whether this references an Objective-C protocol.
bool isObjC() const {
return (storage & IsObjCBit) != 0;
if (Runtime::ObjCInterop)
return (storage & IsObjCBit) != 0;
else
return false;
}
#if SWIFT_OBJC_INTEROP
/// Retrieve the Objective-C protocol.
TargetPointer<Runtime, Protocol> getObjCProtocol() const {
assert(isObjC());
@@ -2460,11 +2554,13 @@ class RelativeTargetProtocolDescriptorPointer {
#endif
};
#if SWIFT_OBJC_INTEROP
bool isObjC() const {
return objcPointer.getInt();
}
#if SWIFT_OBJC_INTEROP
if (Runtime::ObjCInterop)
return objcPointer.getInt();
#endif
return false;
}
public:
/// Retrieve a reference to the protocol.
@@ -2472,13 +2568,14 @@ public:
#if SWIFT_OBJC_INTEROP
if (isObjC()) {
return TargetProtocolDescriptorRef<Runtime>::forObjC(
const_cast<Protocol*>(objcPointer.getPointer()));
const_cast<Protocol *>(objcPointer.getPointer()));
}
#endif
return TargetProtocolDescriptorRef<Runtime>::forSwift(
reinterpret_cast<ConstTargetMetadataPointer<
Runtime, TargetProtocolDescriptor>>(swiftPointer.getPointer()));
reinterpret_cast<
ConstTargetMetadataPointer<Runtime, TargetProtocolDescriptor>>(
swiftPointer.getPointer()));
}
operator TargetProtocolDescriptorRef<Runtime>() const {
@@ -2489,6 +2586,9 @@ public:
/// A reference to a type.
template <typename Runtime>
struct TargetTypeReference {
template <typename T>
using TargetClassMetadata = typename T::template TargetClassMetadata<T>;
union {
/// A direct reference to a TypeContextDescriptor or ProtocolDescriptor.
RelativeDirectPointer<TargetContextDescriptor<Runtime>>
@@ -2502,7 +2602,7 @@ struct TargetTypeReference {
/// An indirect reference to an Objective-C class.
RelativeDirectPointer<
ConstTargetMetadataPointer<Runtime, TargetClassMetadata>>
IndirectObjCClass;
IndirectObjCClass;
/// A direct reference to an Objective-C class name.
RelativeDirectPointer<const char>
@@ -2526,14 +2626,12 @@ struct TargetTypeReference {
return nullptr;
}
#if SWIFT_OBJC_INTEROP
/// If this type reference is one of the kinds that supports ObjC
/// references,
const TargetClassMetadata<Runtime> *
const TargetClassMetadataObjCInterop<Runtime> *
getObjCClass(TypeReferenceKind kind) const;
#endif
const TargetClassMetadata<Runtime> * const *
const TargetClassMetadataObjCInterop<Runtime> * const *
getIndirectObjCClass(TypeReferenceKind kind) const {
assert(kind == TypeReferenceKind::IndirectObjCClass);
return IndirectObjCClass.get();
@@ -2615,10 +2713,11 @@ public:
return TypeRef.getDirectObjCClassName(getTypeKind());
}
const TargetClassMetadata<Runtime> * const *getIndirectObjCClass() const {
const TargetClassMetadataObjCInterop<Runtime> *const *
getIndirectObjCClass() const {
return TypeRef.getIndirectObjCClass(getTypeKind());
}
const TargetContextDescriptor<Runtime> *getTypeDescriptor() const {
return TypeRef.getTypeDescriptor(getTypeKind());
}

View File

@@ -168,6 +168,8 @@ public:
using StoredPointer = typename Runtime::StoredPointer;
using StoredSignedPointer = typename Runtime::StoredSignedPointer;
using StoredSize = typename Runtime::StoredSize;
using TargetClassMetadata =
typename Runtime::template TargetClassMetadata<Runtime>;
private:
/// The maximum number of bytes to read when reading metadata. Anything larger
@@ -502,7 +504,7 @@ public:
if (!meta || meta->getKind() != MetadataKind::Class)
return StoredPointer();
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
auto classMeta = cast<TargetClassMetadata>(meta);
return stripSignedPointer(classMeta->Superclass);
}
@@ -514,39 +516,39 @@ public:
if (!meta || meta->getKind() != MetadataKind::Class)
return None;
#if SWIFT_OBJC_INTEROP
// The following algorithm only works on the non-fragile Apple runtime.
if (Runtime::ObjCInterop) {
// The following algorithm only works on the non-fragile Apple runtime.
// Grab the RO-data pointer. This part is not ABI.
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
if (!roDataPtr)
return None;
// Grab the RO-data pointer. This part is not ABI.
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
if (!roDataPtr)
return None;
// Get the address of the InstanceStart field.
auto address = roDataPtr + sizeof(uint32_t) * 1;
// Get the address of the InstanceStart field.
auto address = roDataPtr + sizeof(uint32_t) * 1;
unsigned start;
if (!Reader->readInteger(RemoteAddress(address), &start))
return None;
unsigned start;
if (!Reader->readInteger(RemoteAddress(address), &start))
return None;
return start;
#else
// All swift class instances start with an isa pointer,
// followed by the retain counts (which are the size of a long long).
size_t isaAndRetainCountSize = sizeof(StoredSize) + sizeof(long long);
size_t start = isaAndRetainCountSize;
return start;
} else {
// All swift class instances start with an isa pointer,
// followed by the retain counts (which are the size of a long long).
size_t isaAndRetainCountSize = sizeof(StoredSize) + sizeof(long long);
size_t start = isaAndRetainCountSize;
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
while (stripSignedPointer(classMeta->Superclass)) {
classMeta = cast<TargetClassMetadata<Runtime>>(
readMetadata(stripSignedPointer(classMeta->Superclass)));
auto classMeta = cast<TargetClassMetadata>(meta);
while (stripSignedPointer(classMeta->Superclass)) {
classMeta = cast<TargetClassMetadata>(
readMetadata(stripSignedPointer(classMeta->Superclass)));
// Subtract the size contribution of the isa and retain counts from
// the super class.
start += classMeta->InstanceSize - isaAndRetainCountSize;
// Subtract the size contribution of the isa and retain counts from
// the super class.
start += classMeta->InstanceSize - isaAndRetainCountSize;
}
return start;
}
return start;
#endif
}
/// Given a pointer to the metadata, attempt to read the value
@@ -588,7 +590,7 @@ public:
if (!Meta)
return None;
if (auto ClassMeta = dyn_cast<TargetClassMetadata<Runtime>>(Meta)) {
if (auto ClassMeta = dyn_cast<TargetClassMetadata>(Meta)) {
if (ClassMeta->isPureObjC()) {
// If we can determine the Objective-C class name, this is probably an
// error existential with NSError-compatible layout.
@@ -719,34 +721,36 @@ public:
Demangler &dem,
Resolver resolver) {
#if SWIFT_OBJC_INTEROP
// Check whether we have an Objective-C protocol.
if (ProtocolAddress.isObjC()) {
auto Name = readObjCProtocolName(ProtocolAddress.getObjCProtocol());
StringRef NameStr(Name);
if (Runtime::ObjCInterop) {
// Check whether we have an Objective-C protocol.
if (ProtocolAddress.isObjC()) {
auto Name = readObjCProtocolName(ProtocolAddress.getObjCProtocol());
StringRef NameStr(Name);
// If this is a Swift-defined protocol, demangle it.
if (NameStr.startswith("_TtP")) {
auto Demangled = dem.demangleSymbol(NameStr);
if (!Demangled)
return resolver.failure();
// FIXME: This appears in _swift_buildDemanglingForMetadata().
while (Demangled->getKind() == Node::Kind::Global ||
Demangled->getKind() == Node::Kind::TypeMangling ||
Demangled->getKind() == Node::Kind::Type ||
Demangled->getKind() == Node::Kind::ProtocolList ||
Demangled->getKind() == Node::Kind::TypeList ||
Demangled->getKind() == Node::Kind::Type) {
if (Demangled->getNumChildren() != 1)
// If this is a Swift-defined protocol, demangle it.
if (NameStr.startswith("_TtP")) {
auto Demangled = dem.demangleSymbol(NameStr);
if (!Demangled)
return resolver.failure();
Demangled = Demangled->getFirstChild();
// FIXME: This appears in _swift_buildDemanglingForMetadata().
while (Demangled->getKind() == Node::Kind::Global ||
Demangled->getKind() == Node::Kind::TypeMangling ||
Demangled->getKind() == Node::Kind::Type ||
Demangled->getKind() == Node::Kind::ProtocolList ||
Demangled->getKind() == Node::Kind::TypeList ||
Demangled->getKind() == Node::Kind::Type) {
if (Demangled->getNumChildren() != 1)
return resolver.failure();
Demangled = Demangled->getFirstChild();
}
return resolver.swiftProtocol(Demangled);
}
return resolver.swiftProtocol(Demangled);
// Otherwise, this is an imported protocol.
return resolver.objcProtocol(NameStr);
}
// Otherwise, this is an imported protocol.
return resolver.objcProtocol(NameStr);
}
#endif
@@ -1419,7 +1423,7 @@ public:
return readMetadataBoundsOfSuperclass(superclass);
},
[&](MetadataRef metadata) -> llvm::Optional<ClassMetadataBounds> {
auto cls = dyn_cast<TargetClassMetadata<Runtime>>(metadata);
auto cls = dyn_cast<TargetClassMetadata>(metadata);
if (!cls)
return None;
@@ -1659,6 +1663,10 @@ protected:
return Reader->readString(RemoteAddress(namePtr), className);
}
template <typename T>
using TargetClassMetadataT =
typename Runtime::template TargetClassMetadata<T>;
MetadataRef readMetadata(StoredPointer address) {
auto cached = MetadataCache.find(address);
if (cached != MetadataCache.end())
@@ -1672,7 +1680,9 @@ protected:
switch (getEnumeratedMetadataKind(KindValue)) {
case MetadataKind::Class:
return _readMetadata<TargetClassMetadata>(address);
return _readMetadata<TargetClassMetadataT>(address);
case MetadataKind::Enum:
return _readMetadata<TargetEnumMetadata>(address);
case MetadataKind::ErrorObject:
@@ -1779,7 +1789,7 @@ protected:
bool skipArtificialSubclasses = false) {
switch (metadata->getKind()) {
case MetadataKind::Class: {
auto classMeta = cast<TargetClassMetadata<Runtime>>(metadata);
auto classMeta = cast<TargetClassMetadata>(metadata);
while (true) {
if (!classMeta->isTypeMetadata())
return 0;
@@ -1801,7 +1811,7 @@ protected:
if (!superMeta)
return 0;
auto superclassMeta = dyn_cast<TargetClassMetadata<Runtime>>(superMeta);
auto superclassMeta = dyn_cast<TargetClassMetadata>(superMeta);
if (!superclassMeta)
return 0;
@@ -2692,7 +2702,7 @@ private:
BuiltType readNominalTypeFromClassMetadata(MetadataRef origMetadata,
bool skipArtificialSubclasses = false) {
auto classMeta = cast<TargetClassMetadata<Runtime>>(origMetadata);
auto classMeta = cast<TargetClassMetadata>(origMetadata);
if (classMeta->isTypeMetadata())
return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses);
@@ -2715,6 +2725,10 @@ private:
return BuiltObjCClass;
}
using TargetClassMetadataObjCInterop =
swift::TargetClassMetadata<Runtime,
TargetAnyClassMetadataObjCInterop<Runtime>>;
/// Given that the remote process is running the non-fragile Apple runtime,
/// grab the ro-data from a class pointer.
StoredPointer readObjCRODataPtr(StoredPointer classAddress) {
@@ -2723,9 +2737,10 @@ private:
#if SWIFT_OBJC_INTEROP
StoredPointer dataPtr;
if (!Reader->readInteger(RemoteAddress(classAddress +
TargetClassMetadata<Runtime>::offsetToData()),
&dataPtr))
if (!Reader->readInteger(
RemoteAddress(classAddress +
TargetClassMetadataObjCInterop::offsetToData()),
&dataPtr))
return StoredPointer();
// Apply the data-pointer mask.

View File

@@ -649,13 +649,24 @@ static RemoteASTContextImpl *createImpl(ASTContext &ctx,
std::shared_ptr<MemoryReader> &&reader) {
auto &target = ctx.LangOpts.Target;
assert(target.isArch32Bit() || target.isArch64Bit());
bool objcInterop = ctx.LangOpts.EnableObjCInterop;
if (target.isArch32Bit()) {
using Target = External<RuntimeTarget<4>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
if (objcInterop) {
using Target = External<WithObjCInterop<RuntimeTarget<4>>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
} else {
using Target = External<NoObjCInterop<RuntimeTarget<4>>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
}
} else {
using Target = External<RuntimeTarget<8>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
if (objcInterop) {
using Target = External<WithObjCInterop<RuntimeTarget<8>>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
} else {
using Target = External<NoObjCInterop<RuntimeTarget<8>>>;
return new RemoteASTContextConcreteImpl<Target>(std::move(reader), ctx);
}
}
}

View File

@@ -36,7 +36,11 @@ using namespace swift;
using namespace swift::reflection;
using namespace swift::remote;
using Runtime = External<RuntimeTarget<sizeof(uintptr_t)>>;
#if SWIFT_OBJC_INTEROP
using Runtime = External<WithObjCInterop<RuntimeTarget<sizeof(uintptr_t)>>>;
#else
using Runtime = External<NoObjCInterop<RuntimeTarget<sizeof(uintptr_t)>>>;
#endif
using NativeReflectionContext = swift::reflection::ReflectionContext<Runtime>;
struct SwiftReflectionContext {

View File

@@ -487,19 +487,21 @@ public:
return c;
#endif
}
template<> inline const ClassMetadata *
Metadata::getClassObject() const {
template <>
inline const ClassMetadata *Metadata::getClassObject() const {
switch (getKind()) {
case MetadataKind::Class: {
// Native Swift class metadata is also the class object.
return static_cast<const ClassMetadata *>(this);
}
#if SWIFT_OBJC_INTEROP
case MetadataKind::ObjCClassWrapper: {
// Objective-C class objects are referenced by their Swift metadata wrapper.
auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
return wrapper->Class;
}
#endif
// Other kinds of types don't have class objects.
default:
return nullptr;

View File

@@ -1111,6 +1111,7 @@ static bool isSubclass(const Metadata *subclass, const Metadata *superclass) {
}
}
const ClassMetadata *swiftSubclass = cast<ClassMetadata>(subclass);
#if SWIFT_OBJC_INTEROP
if (auto *objcSuperclass = dyn_cast<ObjCClassWrapperMetadata>(superclass)) {
// Walk up swiftSubclass's ancestors until we get to an ObjC class, then
// kick over to swift_dynamicCastMetatype.
@@ -1123,6 +1124,7 @@ static bool isSubclass(const Metadata *subclass, const Metadata *superclass) {
});
return false;
}
#endif
if (isa<ForeignClassMetadata>(superclass)) {
// superclass is foreign, but subclass is not (if it were, the above
// !isa<ClassMetadata> condition would have been entered). Since it is not

View File

@@ -611,14 +611,25 @@ static ReflectionContextHolder makeReflectionContextForObjectFiles(
uint8_t pointerSize;
Reader->queryDataLayout(DataLayoutQueryType::DLQ_GetPointerSize,
nullptr, &pointerSize);
switch (pointerSize) {
case 4:
return makeReflectionContextForMetadataReader<External<RuntimeTarget<4>>>
(std::move(Reader));
return makeReflectionContextForMetadataReader<
// FIXME: This could be configurable.
#if SWIFT_OBJC_INTEROP
External<WithObjCInterop<RuntimeTarget<4>>>
#else
External<NoObjCInterop<RuntimeTarget<4>>>
#endif
>(std::move(Reader));
case 8:
return makeReflectionContextForMetadataReader<External<RuntimeTarget<8>>>
(std::move(Reader));
return makeReflectionContextForMetadataReader<
// FIXME: This could be configurable.
#if SWIFT_OBJC_INTEROP
External<WithObjCInterop<RuntimeTarget<8>>>
#else
External<NoObjCInterop<RuntimeTarget<8>>>
#endif
>(std::move(Reader));
default:
fputs("unsupported word size in object file\n", stderr);
abort();