本文将会初次探索Swift
底层,但随着Swift
版本更新,底层结构可能会变更(ABI
已经稳定,即便调整,应该也是微调),因此在这边记录下版本号。c++
Swift
源码版本是5.3.1
,Xcode
版本是12.3
(其实对应的源码版本是5.3.2
,不太小版本,懒的更新了)swift
本文会初步探索Metadata
,详细的底层结构会在文章末尾附上连接。markdown
因为比较深刻底层,会有较多指针类型,若是你不是很熟悉Swift
类型的指针,能够先看下我上一篇写的文章。闭包
Mirror
获取类型的Metadata
虽然Swift
重心在强调静态类型上,但它经过反射Mirror
的API
,容许代码在运行时检查和操做任意值。这边咱们经过Mirror
的源码,看如何获取数据类型的元数据Metadata
的,咱们先以struct
为突入口。app
咱们在源码中运行以下代码post
struct Teacher {var age = 18; var name = "kody"}
let t = Teacher.init()
let mirror = Mirror(reflecting: t)
复制代码
在初始化mirror
前,咱们在init(reflecting subject: Any)
方法中打上断点,随着断点走:
ui
咱们能够看到这些框起来的方法(获取类型,及属性个数)都调用了一个call
,而后拿到了一个impl
变量,而后返回impl
的某个属性就能够了,因此这边call
方法和impl
是什么比较关键,咱们继续往下走:this
先进入call
方法(部分截图,太长了): spa
初步看到impl
是ReflectionMirrorImpl
,这里是一个相似闭包的东西,参数传了一个ReflectionMirrorImpl
类型,接着往下走,看看谁会调用: 指针
咱们发现经过调用type->getKind()
获取数据类型,发现是一个结构体,而后进入switch
的结构体的分支,发现impl
变成了StructImpl
,咱们搜索StructImpl
能够看到
从图中咱们能够发现:StructImpl
是ReflectionMirrorImpl
的子类,Struct
的元数据Metadata
是StructMetadata
。
简单的整理下Mirror
底层的核心逻辑,就是经过getKind()
方法获取该类型的元数据类型,而后根据该类型Metadata
获取相应的属性,好比类型名称、属性名字,属性个数等
MetadataKind
前面在type->getKind()
在switch
中,咱们看到了MetadataKind::Struct
这个类型。
咱们看下MetadataKind
类型:
enum class MetadataKind : uint32_t 复制代码
MetadataKind
是一个Int32
大小的枚举,咱们看下MetadataKind::Struct
系列的对应的枚举值
const unsigned MetadataKindIsNonType = 0x400;
const unsigned MetadataKindIsNonHeap = 0x200;
const unsigned MetadataKindIsRuntimePrivate = 0x100;
LastEnumerated = 0x7FF,
NOMINALTYPEMETADATAKIND(Class, 0)
NOMINALTYPEMETADATAKIND(Struct, 0 | MetadataKindIsNonHeap)
NOMINALTYPEMETADATAKIND(Enum, 1 | MetadataKindIsNonHeap)
NOMINALTYPEMETADATAKIND(Optional, 2 | MetadataKindIsNonHeap)
METADATAKIND(ForeignClass, 3 | MetadataKindIsNonHeap)
METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(Tuple, 1 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(Function, 2 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(Existential, 3 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(Metatype, 4 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(ObjCClassWrapper, 5 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(ExistentialMetatype, 6 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
METADATAKIND(HeapLocalVariable, 0 | MetadataKindIsNonType)
METADATAKIND(HeapGenericLocalVariable, 0 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
METADATAKIND(ErrorObject, 1 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
复制代码
咱们能够把Kind
整理成一张表格
名称 | 枚举值 | 说明 |
---|---|---|
Class | 0x0 | 类 |
Struct | 0x200 | 结构体 |
Enum | 0x201 | 枚举 |
Optional | 0x202 | 可选类型 |
ForeignClass | 0x203 | 外部类,好比CoreFoundation中的类 |
Opaque | 0x300 | 在元数据系统中不公开其值的类型 |
Tuple | 0x301 | 元祖类型 |
Function | 0x302 | A monomorphic function |
Existential | 0x303 | An existential type |
Metatype | 0x304 | A metatype |
ObjCClassWrapper | 0x305 | An ObjC class wrapper |
ExistentialMetatype | 0x306 | An existential metatype |
HeapLocalVariable | 0x400 | 使用静态生成的元数据的堆分配的局部变量 |
HeapGenericLocalVariable | 0x500 | 使用运行时实例化的元数据的堆分配的局部变量 |
ErrorObject | 0x501 | swift原生的错误类型 |
LastEnumerated | 0x7FF | 最大的非isa指针元数据类型值 |
因此咱们前面type
存的是0x200
,对应的枚举值是结构体,咱们能够从源码的断点处能够看到,咱们后面也会用代码实现一遍。
StructMetadata
TargetStructMetadata
StructMetadata
是什么呢?咱们能够全局搜索下,能够找到
using StructMetadata = TargetStructMetadata<InProcess>;
复制代码
StructMetadata
就是TargetStructMetadata
的别名
/// The structure of type metadata for structs.
template <typename Runtime>
struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
using TargetValueMetadata<Runtime>::TargetValueMetadata;
const TargetStructDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}
...
};
复制代码
咱们没有找到有什么属性,咱们看下他的父类TargetValueMetadata
struct TargetValueMetadata : public TargetMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
TargetValueMetadata(MetadataKind Kind,
const TargetTypeContextDescriptor<Runtime> *description)
: TargetMetadata<Runtime>(Kind), Description(description) {}
/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
...
};
复制代码
咱们看到初始化方法中有Kind
和description
两个属性,可是底下只看到一个属性description
,那Kind
应该还在父类中,咱们继续向上探索父类TargetMetadata
/// Bounds for metadata objects.
struct TargetMetadata {
using StoredPointer = typename Runtime::StoredPointer;
/// The basic header type.
typedef TargetTypeMetadataHeader<Runtime> HeaderType;
constexpr TargetMetadata() : Kind(static_cast<StoredPointer>(MetadataKind::Class)) {}
constexpr TargetMetadata(MetadataKind Kind) : Kind(static_cast<StoredPointer>(Kind)) {}
#if SWIFT_OBJC_INTEROP
protected:
constexpr TargetMetadata(TargetAnyClassMetadata<Runtime> *isa) : Kind(reinterpret_cast<StoredPointer>(isa)) {}
#endif
private:
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
public:
/// Get the metadata kind.
MetadataKind getKind() const {
return getEnumeratedMetadataKind(Kind);
}
/// Set the metadata kind.
void setKind(MetadataKind kind) {
Kind = static_cast<StoredPointer>(kind);
}
...
};
复制代码
果不其然,咱们找到了Kind
,不过是StoredPointer
类型的,他是Runtime::StoredPointer
的别名,那Runtime
传进来的是模版,前面咱们看到模版传进来的的是InProcess
,在InProcess
中,咱们看到using StoredPointer = uintptr_t;
,咱们在点开uintptr_t
,看到typedef unsigned long uintptr_t;
,那本质上Kind
就是unsigned long
类型。其实咱们从上面的代码中就能够看出,这个Kind
在与OC的类交互时,传进来的是isa
,否则就是MetadataKind
。
StructMetadata
上面的代码翻看下来,整个StructMetadata
就只有Kind
和Description
2个属性,Kind
咱们知道了是unsigned long
类型,Description
暂时还不知道是啥,不过不要紧,从名称上来看是一个指针,咱们先用一个UnsafeRawPointer
来替代他(后面在详细解析他),这样咱们能够写以下代码
struct Teacher {
var age = 18
var name = "kody"
}
struct StructMetadata {
var kind: Int
var Description: UnsafeRawPointer
}
// 经过源码咱们能够知道Type类型对应的就是Metadata,这里记住要转成Any.Type,否则typesize不一致,不让转
let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
print("0x\(String(ptr.pointee.kind, radix: 16))") //0x200
复制代码
很是棒,输出0x200
,和表格里的一致,换成枚举也能获得对应的值,若是强转Teacher?.self
,那会获得0x202
,这样说明咱们的思路可行的。
Swift
基础类型底层的详细探索在上面搜索StructMetadata
的时候,细心的小伙伴能够发现下面的代码:
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;
复制代码
这里定义了大部分咱们想要的底层Metadata
了,因此咱们只要分析这些类或者结构体,就能获得基础类型的底层结构了。
一开始是想写在一块儿的,可是感受太长了,因此会分文章写
待续...