本文將會初次探索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
了,因此咱們只要分析這些類或者結構體,就能獲得基礎類型的底層結構了。
一開始是想寫在一塊兒的,可是感受太長了,因此會分文章寫
待續...