一:元类型和 .self
1. AnyObject
AnyObject
代表任意类的实例,类的类型,仅类遵守的协议。
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var p1: AnyObject = p
var p2: AnyObject = Person.self
可以看见
p1
的 AnyObject
表示的就是一个实例对象,p2
的 AnyObject
表示的就是原类型 Metadata
protocol Myprotocol: AnyObject {
}
class Person: Myprotocol {
var age: Int = 18
var name: String = "小明"
}
var p: Myprotocol = Person()
var p1: AnyObject = p
此时的协议
Myprotocol
后面的 AnyObject
就表示的遵守的协议,如果将 Class
换成 Struct
编译器就会报错,因此 AnyObject
是能代表仅类遵守的协议。
在编写代码的过程中,有时候不知道具体的类型,用 AnyObject
来表示
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var a: AnyObject = p.age as NSNumber
print(type(of: a))
// 打印结果
__NSCFNumber
如果确定了类型,使用三个关键字将 AnyObject
转换成具体的类型 as
、 as?
、 as!
class Person {
var age: Int = 18
var name: String = "小明"
}
class SubPerson: Person {
var height: Double = 185.5
}
var p: AnyObject = SubPerson()
if let p1 = p as? Person {
print("\(p1) 是 Person")
}
// 打印结果
LJLSwiftSimpleTest.SubPerson 是 Person
2. T.self
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var p1 = p.self
var p2 = p.self.self
var p3 = Person.self
从上面打印结果和在汇编中的打印结果可以看出:
T
是实例对象,则 T.self
返回的就是他本身, T
是类,则 T.self
返回的就是元类型
class Person {
var age: Int = 18
var name: String = "小明"
func test() {
// self只当前实例对象
print(self)
}
// 类方法
static func test1() {
// self 是 Person 这个类型本身
print(self)
}
}
var p = Person()
p.test()
Person.test1()
在第一个断点处打印
self
得到当前实例对象,在第二个断点处打印 self
得到 Person
类本身。
3. Self
Self
类型不是特定的类型,而是方便地引用当前类型,而无需重复或知道该类型的名称。
- 作为方法返回类型:
Self
指代当前实例对象的类型
class Person {
static let age = 18
func test() -> Self{
return self
}
}
- 作为协议中方法的返回类型:
Self
指代遵循这个协议的类型
protocol MyProtocol {
func get() -> Self
}
class Person: MyProtocol {
func get() -> Self {
return self
}
}
4. Any
Any
代表任意类型,包括 function
类型或者 Optional
类型
var array: [Any] = [1, "小明", 3, false]
这里不能替换成 AnyObject
,因为 Int
类型在 Swift
中是值类型,无法用 AnyObject
表示
5. AnyClass
AnyClass
代表任意实例的类型
可以看到
AnyClass
就是 AnyObject
的 Type
类型
class Person {
var age = 18
}
var t: AnyClass = Person.self
T.Type
是 T.self
的类型
二:Swift Runtime
我们都知道 Swift
是一门静态语言,但是在之前的文章 Swift探索(二): 类与结构体(下) 中提过 @objc
、NSObject
、@Objc dynamic
标识。那么是可以通过这些关键字来实现在 Swift
中调用 OC
中 Runtime
的 API
的。
func test(_ cls: AnyClass){
var methodCount: UInt32 = 0
let methodlist = class_copyMethodList(cls, &methodCount)
for i in 0..
使用以上代码获取一个类的属性和方法
class Person {
var age: Int = 18
func play() {
print("play")
}
}
test(Person.self)
// 打印结果
空
- 对于纯
Swift
类来说,方法和属性不加任何修饰符时。不具备Runtime
特性。
class Person {
@objc var age: Int = 18
@objc func play() {
print("play")
}
}
test(Person.self)
// 打印结果
方法列表 :play
方法列表 :age
方法列表 :setAge:
属性成员属性:age
- 对于纯
Swift
类,方法和属性添加@objc
标识时,可以用过RunTime
的Api
拿到,但在OC
中无法进行调度(LJLSwiftSimpleTest-Swift.h
中没有任何Person
这个信息)。
class Person: NSObject {
var age: Int = 18
func play() {
print("play")
}
}
test(Person.self)
// 打印结果
方法列表 :init
class Person: NSObject {
@objc var age: Int = 18
@objc func play() {
print("play")
}
}
test(Person.self)
// 打印结果
方法列表 :init
方法列表 :play
方法列表 :age
方法列表 :setAge:
属性成员属性:age
- 对于继承自
NSObject
的Swift
类,必须在声明属性和方法前添加@objc
关键字才能动态的获取当前的属性和方法。
class Person {
dynamic var age: Int = 18
dynamic func play() {
print("play")
}
}
extension Person {
@_dynamicReplacement(for: play) // 用play1()替代play()函数
func play1() {
print("play1")
}
}
Person().play()
- 纯
Swfit
没有动态性,但方法、属性前添加dynamic
关键字,可获得动态性
class Person: NSObject {
var age: Int = 18
func play() {
print("play")
}
}
class SubPerson: Person {
dynamic var name: String = "小明"
dynamic func play2() {
print("play2")
}
}
- 继承自
NSObject
的Swift
类,其继承自父类的方法具有动态性,其它自定义方法、属性相应获得动态性,需要添加dynamic
修饰
- 若方法的参数、属性类型为
Swfit
特有无法映射到OC
的类型(如Character
、Tuple
),则此方法、属性无法添加@objc
和dynamic
关键字(编译器报错)
三:Mirror
1. Mirror的基本用法
反射:就是动态获取类型、成员信息、在运行时可以调用方法、属性等行为的特性。
Swift
的反射机制是基于 Mirror
的结构体来实现的。可以为具体的实例创建一个 Mirror
对象,通过它来查询这个实例的属性、方法等。
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
// 首先通过构造方法创建一个Mirror实例, 传入的参数是:Any, 也就意味着当前可以是类、结构体、枚举等
let mirror = Mirror(reflecting: p)
// 遍历 children 属性
for pro in mirror.children{
// 通过 label 输出当前的名称, value 输出当前反射的值
print("\(pro.label):\(pro.value)")
}
// 打印反射对象的类型
print("subjectType:\(mirror.subjectType)")
// 打印反射的类型
print("displayStyle:\(mirror.displayStyle))")
// 打印结果
Optional("age"):18
Optional("name"):小明
subjectType:Person
displayStyle:Optional(Swift.Mirror.DisplayStyle.class))
如果将 Person
换成 Stuct
那么最后 displayStyle
的打印结果是
displayStyle:Optional(Swift.Mirror.DisplayStyle.struct))
2. Mirror的实际使用案例
func test(_ mirrorObj: Any) -> Any {
let mirror = Mirror(reflecting: mirrorObj)
// 如果当前实例对象的子属性为空 着返回当前实例
guard !mirror.children.isEmpty else {
return mirrorObj;
}
var result: [String: Any] = [:]
// 遍历 children 属性
for child in mirror.children{
if let key = child.label {
// 递归调用test方法, 直到当前的属性已经没有子属性了
result[key] = test(child.value)
} else {
print("no key")
}
}
return result
}
class Person {
var age: Int = 18
var name: String = "小明"
}
var p = Person()
var result = test(p)
print(result)
// 打印结果
["age": 18, "name": "小明"]
这个例子只是简单的一个将实例对象的属性转换成字典。接下来编写一个功能完善的简易的模型转字典案例
// 定义一个协议
protocol LJLJsonMap {
// 声明一个模型转字典的方法
func jsonMap() throws -> Any
}
// 定义一个 错误枚举
enum JsonMapError: Error {
case emptyKey // 没有属性名称
case noProtocol // 没有遵守协议
}
// 定义一个扩展 实现 错误具体的返回
extension JsonMapError: LocalizedError {
var errorDescription: String? {
switch self {
case .emptyKey:
return "当前实例对象没有属性"
case .noProtocol:
return "当前实例对象的类型或属性的类型没有遵守协议"
}
}
}
// 定义一个扩展 具体实现 jsonMap()
extension LJLJsonMap {
func jsonMap() throws -> Any {
let mirror = Mirror(reflecting: self)
// 如果当前实例对象的子属性为空 着返回当前实例
guard !mirror.children.isEmpty else {
return self;
}
var result: [String: Any] = [:]
// 遍历 children 属性
for child in mirror.children {
if let value = child.value as? LJLJsonMap {
if let key = child.label {
// 递归调用jsonMap方法, 直到当前的属性已经没有子属性了
result[key] = try value.jsonMap()
} else {
throw JsonMapError.emptyKey
}
} else {
throw JsonMapError.noProtocol
}
}
return result
}
}
class PersonClass {
var age: Int = 18
}
class PersonClass2 {
var name: String = "小明"
}
struct PersonStruct {
var weight: Double = 55.5
}
extension PersonClass: LJLJsonMap {}
extension PersonClass2: LJLJsonMap {}
extension PersonStruct: LJLJsonMap {}
// 因为 jsonMap 方法中递归调用 jsonMap 所以这几个类型都需要遵守 LJLJsonMap 协议
extension Int: LJLJsonMap{}
extension Double: LJLJsonMap{}
在上述代码的基础上执行一下代码
var pClass = PersonClass()
do {
let resultClass = try pClass.jsonMap()
print(resultClass)
} catch {
print(error.localizedDescription.description)
}
// 打印结果
["age": 18]
// 注意 Person2 中的 name 属性为 String 并且 String 没有遵守 LJLJsonMap 协议
var pClass = PersonClass2()
do {
let result = try pClass.jsonMap()
print(result)
} catch {
print(error.localizedDescription.description)
}
// 打印结果
当前实例对象的类型或属性的类型没有遵守协议
var pStruct = PersonStruct()
do {
let result = try pStruct.jsonMap()
print(result)
} catch {
print(error.localizedDescription.description)
}
// 打印结果
["weight": 55.5]
3. Mirror源码窥探
首先在 Swift源码 中找到 Mirror.Swift
文件。在源码中我们可以看到 Mirror
是由结构体实现的
public struct Mirror {
找到初始化方法 init()
public init(reflecting subject: Any) {
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
self = Mirror(internalReflecting: subject)
}
}
可以发现这里接收的是一个 Any
类型的参数。在方法体里有一个 if case
的判断语句,判断传入的 subject
是否遵循了 CustomReflectable
协议,如果是则直接调用 customMirror
对于 CustomReflectable
的用法如下
class Person: CustomReflectable {
var age: Int
var name: String
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
var customMirror: Mirror {
let info = KeyValuePairs.init(dictionaryLiteral: ("age", age), ("name", name))
let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
return mirror
}
}
实现这个 CustomReflectable
最直观的区别在 LLDB
调试时。
回到源码中,如果没有遵循
CustomReflectable
协议就进行下级的函数调用 Mirror(internalReflecting: subject)
。通过这个函数可以定位到 ReflectionMirror.swift
文件中的 init(internalReflecting subject: Any, subjectType: Any.Type? = nil, customAncestor: Mirror? = nil)
方法
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
let childCount = _getChildCount(subject, type: subjectType)
let children = (0 ..< childCount).lazy.map({
getChild(of: subject, type: subjectType, index: $0)
})
self.children = Children(children)
self._makeSuperclassMirror = {
guard let subjectClass = subjectType as? AnyClass,
let superclass = _getSuperclass(subjectClass) else {
return nil
}
// Handle custom ancestors. If we've hit the custom ancestor's subject type,
// or descendants are suppressed, return it. Otherwise continue reflecting.
if let customAncestor = customAncestor {
if superclass == customAncestor.subjectType {
return customAncestor
}
if customAncestor._defaultDescendantRepresentation == .suppressed {
return customAncestor
}
}
return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
}
let rawDisplayStyle = _getDisplayStyle(subject)
switch UnicodeScalar(Int(rawDisplayStyle)) {
case "c": self.displayStyle = .class
case "e": self.displayStyle = .enum
case "s": self.displayStyle = .struct
case "t": self.displayStyle = .tuple
case "\0": self.displayStyle = nil
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
}
self.subjectType = subjectType
self._defaultDescendantRepresentation = .generated
}
首先第一步
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
这里是获取 subject
的类型,前面调用这个函数的时候没有传入 subjectType
所以 subject
的类型是通过后面的 _getNormalizedType(subject, type: type(of: subject))
的函数去获取的。
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType(_: T, type: Any.Type) -> Any.Type
定位到 _getNormalizedType()
函数可以发现这里其实是调用的 C++
的方法 swift_reflectionMirror_normalizedType
。前面的 @_silgen_name
是编译器字段,是 Swift
一个隐藏的符号,作用是将 C/C++
的函数直接映射为 Swift
函数。
// func _getNormalizedType(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
找到 swift_reflectionMirror_normalizedType
函数是在 ReflectionMirror.cpp
文件中,发现这里返回的是 call
函数的调用,那么定位到 call
函数的实现,
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
{
const Metadata *type;
OpaqueValue *value;
std::tie(type, value) = unwrapExistential(T, passedValue);
if (passedType != nullptr) {
type = passedType;
}
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
...
}
发现这就是一个回调函数,回调的具体数据都是由 ReflectionMirrorImpl
结构体来实现的。定位到 ReflectionMirrorImpl
结构体
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type;
OpaqueValue *value;
virtual char displayStyle() = 0;
virtual intptr_t count() = 0;
virtual intptr_t childOffset(intptr_t index) = 0;
virtual const FieldType childMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
virtual id quickLookObject() { return nil; }
#endif
// For class types, traverse through superclasses when providing field
// information. The base implementations call through to their local-only
// counterparts.
virtual intptr_t recursiveCount() {
return count();
}
virtual intptr_t recursiveChildOffset(intptr_t index) {
return childOffset(index);
}
virtual const FieldType recursiveChildMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *))
{
return childMetadata(index, outName, outFreeFunc);
}
virtual ~ReflectionMirrorImpl() {}
};
可以发现 ReflectionMirrorImpl
是一个抽象类,也就意味着不同类型的反射都需要实现 ReflectionMirrorImpl
并且在 ReflectionMirror.cpp
文件的下方可以看到 Tuple
、 Struct
、 Enum
、 Class
的具体实现。
StructImpl
的实现
// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Struct = static_cast(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
char displayStyle() override {
return 's';
}
intptr_t count() override {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast(type);
return Struct->getDescription()->NumFields;
}
intptr_t childOffset(intptr_t i) override {
auto *Struct = static_cast(type);
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
return Struct->getFieldOffsets()[i];
}
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
};
bool isReflectable() {
const auto *Struct = static_cast(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
获取是否可以反射,可以看到这里面首先将 StructMetadata
进行强制转换,然后获取到 Matadata
中的 Description
再获取到 Description
中的 isRelectable
字段。
intptr_t count() override {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast(type);
return Struct->getDescription()->NumFields;
}
获取属性的数量,可以看到首先判断是否可以反射,不可以就返回 0
,可以就还是将 StructMetadata
进行强制转换,然后获取到 Description
中的 NumFields
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
可以看到 fieldInfo
是通过 childMetadata()
获取
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) override {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
可以看到 std::tie(name, fieldInfo) = getFieldAt(type, i);
这句代码中调用了 getFieldAt
getFieldAt(const Metadata *base, unsigned index) {
...
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return failedToFindMetadata();
auto *fields = baseDesc->Fields.get();
...
}
主要看这里,获取描述文件 Descriptor
,然后获取 Fieilds
,在获取到 Fieilds
中的属性的信息。在前面的文章 Swift探索(一): 类与结构体(上)和 Swift探索(二): 类与结构体(下) 当中我们提到过 Struct
、 Class
、 Enum
都有自己的 Metadata
, 并且 Metadata
中都有与之对应的 TypeDescriptor
。
通过对 TupleImpl
、 EnumImpl
、 ClassImpl
的分析实现方式基本与 StructImpl
相同,都是通过 Matadata
类型的元数据、 getDescription
类型的描述 、 FieldDescrition
类型的属性的描述去实现。
4. 利用Mirror源码的原理实现解析小工具
首先通过源码分别获取到 Enum
、 Struct
、 Class
这三种类型中的 Metadata
。
4.1 Enum 的实现
4.1.1 还原TargetEnumMetadata
首先定位到源码中的 Metadata.h
文件中,找到 TargetEnumMetadata
代码如下
struct TargetEnumMetadata : public TargetValueMetadata {
// 全是方法
...
}
我们发现这里面全是方法,并且 TargetEnumMetadata
继承自 TargetValueMetadata
,那么进入到 TargetValueMetadata
中
struct TargetValueMetadata : public TargetMetadata {
...
/// An out-of-line description of the type.
TargetSignedPointer * __ptrauth_swift_type_descriptor> Description;
...
};
发现有一个属性 Description
并且 TargetValueMetadata
继承自 TargetMetadata
,进入到 TargetMetadata
struct TargetMetadata {
...
private:
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
...
};
发现有一个属性 Kind
由此可以推测出 TargetEnumMetadata
的结构为
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer
}
4.1.2 还原typeDescriptor
其中 typeDescriptor
就是枚举 metadata
的描述信息,回到源码的 TargetEnumMetadata
中
struct TargetEnumMetadata : public TargetValueMetadata {
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
using TargetValueMetadata::TargetValueMetadata;
const TargetEnumDescriptor *getDescription() const {
return llvm::cast>(this->Description);
}
...
};
可以看到这里进行了一个类型转换,转换成了 TargetEnumDescriptor
,定位到 TargetEnumDescriptor
class TargetEnumDescriptor final
: public TargetValueTypeDescriptor,
public TrailingGenericContextObjects,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects*/
TargetForeignMetadataInitialization,
TargetSingletonMetadataInitialization,
TargetCanonicalSpecializedMetadatasListCount,
TargetCanonicalSpecializedMetadatasListEntry,
TargetCanonicalSpecializedMetadatasCachingOnceToken> {
...
/// The number of non-empty cases in the enum are in the low 24 bits;
/// the offset of the payload size in the metadata record in words,
/// if any, is stored in the high 8 bits.
uint32_t NumPayloadCasesAndPayloadSizeOffset;
/// The number of empty cases in the enum.
uint32_t NumEmptyCases;
...
};
发现 TargetEnumDescriptor
中有两个属性 uint32_t NumPayloadCasesAndPayloadSizeOffset
和 uint32_t NumEmptyCases
并且继承自 TargetValueTypeDescriptor
,定位到 TargetValueTypeDescriptor
class TargetValueTypeDescriptor
: public TargetTypeContextDescriptor {
public:
static bool classof(const TargetContextDescriptor *cd) {
return cd->getKind() == ContextDescriptorKind::Struct ||
cd->getKind() == ContextDescriptorKind::Enum;
}
};
没有属性,继承自 TargetTypeContextDescriptor
, 定位到 TargetTypeContextDescriptor
class TargetTypeContextDescriptor
: public TargetContextDescriptor {
public:
/// The name of the type.
TargetRelativeDirectPointer Name;
/// A pointer to the metadata access function for this type.
///
/// The function type here is a stand-in. You should use getAccessFunction()
/// to wrap the function pointer in an accessor that uses the proper calling
/// convention for a given number of arguments.
TargetRelativeDirectPointer AccessFunctionPtr;
/// A pointer to the field descriptor for the type, if any.
TargetRelativeDirectPointer Fields;
...
};
发现有三个 TargetRelativeDirectPointer
类型的的属性 Name
、 AccessFunctionPtr
、 Fields
,并且 TargetTypeContextDescriptor
继承自 TargetContextDescriptor
,定位到 TargetContextDescriptor
struct TargetContextDescriptor {
/// Flags describing the context, including its kind and format version.
ContextDescriptorFlags Flags;
/// The parent context, or null if this is a top-level context.
TargetRelativeContextPointer Parent;
...
};
发现 TargetContextDescriptor
是个基类,并且有两个属性 ContextDescriptorFlags
类型的 Flags
,和 TargetRelativeContextPointer
类型的 Parent
, 定位到 ContextDescriptorFlags
中
struct ContextDescriptorFlags {
private:
uint32_t Value;
explicit constexpr ContextDescriptorFlags(uint32_t Value)
: Value(Value) {}
public:
constexpr ContextDescriptorFlags() : Value(0) {}
constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
bool isGeneric,
bool isUnique,
uint8_t version,
uint16_t kindSpecificFlags)
: ContextDescriptorFlags(ContextDescriptorFlags()
.withKind(kind)
.withGeneric(isGeneric)
.withUnique(isUnique)
.withVersion(version)
.withKindSpecificFlags(kindSpecificFlags))
{}
...
};
发现 Flags
其实就是 uint32_t
类型,按位存储着 kind
、 isGeneric
、 isUnique
、 version
、 kindSpecificFlags
等信息。因此最终可以得出 TargetEnumDescriptor
具体的数据结构如下
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeContextPointer
var name: TargetRelativeDirectPointer
var accessFunctionPointer: TargetRelativeDirectPointer
var fieldDescriptor: TargetRelativeDirectPointer
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
接下来分析 TargetRelativeContextPointer
和 TargetRelativeDirectPointer
具体是什么
4.1.3 TargetRelativeContextPointer
定位到 TargetRelativeContextPointer
template class Context = TargetContextDescriptor>
using TargetRelativeContextPointer =
RelativeIndirectablePointer,
/*nullable*/ true, int32_t,
TargetSignedContextPointer>;
可以看到这是一个别名的定义给 RelativeIndirectablePointer
取了一个别名 TargetRelativeContextPointer
, 定位到 RelativeIndirectablePointer
/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template
class RelativeIndirectablePointer {
private:
static_assert(std::is_integral::value &&
std::is_signed::value,
"offset type should be signed integer");
/// The relative offset of the pointer's memory from the `this` pointer.
/// If the low bit is clear, this is a direct reference; otherwise, it is
/// an indirect reference.
Offset RelativeOffsetPlusIndirect;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeIndirectablePointer() = delete;
RelativeIndirectablePointer(RelativeIndirectablePointer &&) = delete;
RelativeIndirectablePointer(const RelativeIndirectablePointer &) = delete;
RelativeIndirectablePointer &operator=(RelativeIndirectablePointer &&)
= delete;
RelativeIndirectablePointer &operator=(const RelativeIndirectablePointer &)
= delete;
public:
/// Allow construction and reassignment from an absolute pointer.
/// These always produce a direct relative offset.
RelativeIndirectablePointer(ValueTy *absolute)
: RelativeOffsetPlusIndirect(
Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset(absolute, this)) {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
}
RelativeIndirectablePointer &operator=(ValueTy *absolute) & {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
RelativeOffsetPlusIndirect = Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset(absolute, this);
return *this;
}
const ValueTy *get() const & {
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
"alignment of value and offset must be at least 2 to "
"make room for indirectable flag");
// Check for null.
if (Nullable && RelativeOffsetPlusIndirect == 0)
return nullptr;
Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
uintptr_t address = detail::applyRelativeOffset(this,
offsetPlusIndirect & ~1);
// If the low bit is set, then this is an indirect address. Otherwise,
// it's direct.
if (offsetPlusIndirect & 1) {
return *reinterpret_cast(address);
} else {
return reinterpret_cast(address);
}
}
/// A zero relative offset encodes a null reference.
bool isNull() const & {
return RelativeOffsetPlusIndirect == 0;
}
operator const ValueTy* () const & {
return get();
}
const ValueTy *operator->() const & {
return get();
}
};
这个类主要作用是存储在内存中的对象的相对引用(相对引用指的是当前引用的内存地址,到当前对象的内存地址的距离)。通过 RelativeOffsetPlusIndirect
属性存储相对的地址偏移量,再通过 get()
方法获取。
const ValueTy *get() const & {
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
"alignment of value and offset must be at least 2 to "
"make room for indirectable flag");
// Check for null.
if (Nullable && RelativeOffsetPlusIndirect == 0)
return nullptr;
Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
uintptr_t address = detail::applyRelativeOffset(this,
offsetPlusIndirect & ~1);
// If the low bit is set, then this is an indirect address. Otherwise,
// it's direct.
if (offsetPlusIndirect & 1) {
return *reinterpret_cast(address);
} else {
return reinterpret_cast(address);
}
}
在 get()
函数中,会调用 applyRelativeOffset
函数,进行地址的偏移
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
static_assert(std::is_integral::value &&
std::is_signed::value,
"offset type should be signed integer");
auto base = reinterpret_cast(basePtr);
// We want to do wrapping arithmetic, but with a sign-extended
// offset. To do this in C, we need to do signed promotion to get
// the sign extension, but we need to perform arithmetic on unsigned values,
// since signed overflow is undefined behavior.
auto extendOffset = (uintptr_t)(intptr_t)offset;
return base + extendOffset;
}
在 applyRelativeOffset
中的返回可以发现返回的是 base + extendOffset
基地址加上偏移的值。因此 TargetRelativeContextPointer
可以通过 Swift
代码还原
// 传入指针
struct TargetRelativeContextPointer {
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 获取指针地址 偏移offset后 重新绑定为传入的指针的类型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
4.1.4 还原TargetRelativeDirectPointer
定位到 TargetRelativeDirectPointer
template
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer;
可以发现这里跟 TargetRelativeContextPointer
一样也是给 RelativeDirectPointer
取了一个别名 TargetRelativeDirectPointer
, 定位到 RelativeDirectPointer
/// A direct relative reference to an object that is not a function pointer.
template
class RelativeDirectPointer::value>::type>
: private RelativeDirectPointerImpl
{
using super = RelativeDirectPointerImpl;
public:
using super::get;
using super::super;
RelativeDirectPointer &operator=(T *absolute) & {
super::operator=(absolute);
return *this;
}
operator typename super::PointerTy() const & {
return this->get();
}
const typename super::ValueTy *operator->() const & {
return this->get();
}
using super::isNull;
};
发现这里调用的其实是 RelativeDirectPointerImpl
中的函数, 定位到 RelativeDirectPointerImpl
/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template
class RelativeDirectPointerImpl {
private:
/// The relative offset of the function's entry point from *this.
Offset RelativeOffset;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeDirectPointerImpl() = delete;
/// RelativePointers should appear in statically-generated metadata. They
/// shouldn't be constructed or copied.
RelativeDirectPointerImpl(RelativeDirectPointerImpl &&) = delete;
RelativeDirectPointerImpl(const RelativeDirectPointerImpl &) = delete;
RelativeDirectPointerImpl &operator=(RelativeDirectPointerImpl &&)
= delete;
RelativeDirectPointerImpl &operator=(const RelativeDirectPointerImpl &)
= delete;
public:
using ValueTy = T;
using PointerTy = T*;
// Allow construction and reassignment from an absolute pointer.
RelativeDirectPointerImpl(PointerTy absolute)
: RelativeOffset(Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset(absolute, this))
{
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
}
explicit constexpr RelativeDirectPointerImpl(std::nullptr_t)
: RelativeOffset (0) {
static_assert(Nullable, "can't construct non-nullable pointer from null");
}
RelativeDirectPointerImpl &operator=(PointerTy absolute) & {
if (!Nullable)
assert(absolute != nullptr &&
"constructing non-nullable relative pointer from null");
RelativeOffset = Nullable && absolute == nullptr
? 0
: detail::measureRelativeOffset(absolute, this);
return *this;
}
PointerTy get() const & {
// Check for null.
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `this`.
uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
return reinterpret_cast(absolute);
}
/// A zero relative offset encodes a null reference.
bool isNull() const & {
return RelativeOffset == 0;
}
};
发现这里跟 TargetRelativeContextPointer
基本一样,都是存储在内存中的对象的相对引用,于是优化一下已经还原的 EnumMetadata
的结构体如下
// 传入指针
struct TargetRelativeDirectPointer{
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 获取指针地址 偏移offset后 重新绑定为传入的指针的类型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer
}
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer
var name: TargetRelativeDirectPointer
var accessFunctionPointer: TargetRelativeDirectPointer
var fieldDescriptor: TargetRelativeDirectPointer
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
4.1.5 还原fieldDescriptor
在源码中
class TargetTypeContextDescriptor
: public TargetContextDescriptor {
public:
...
/// A pointer to the field descriptor for the type, if any.
TargetRelativeDirectPointer Fields;
...
};
注意到这里使用的命名空间中的 FieldDescriptor
,进入 FieldDescriptor
class FieldDescriptor {
const FieldRecord *getFieldRecordBuffer() const {
return reinterpret_cast(this + 1);
}
public:
const RelativeDirectPointer MangledTypeName;
const RelativeDirectPointer Superclass;
FieldDescriptor() = delete;
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
using const_iterator = FieldRecordIterator;
bool isEnum() const {
return (Kind == FieldDescriptorKind::Enum ||
Kind == FieldDescriptorKind::MultiPayloadEnum);
}
bool isClass() const {
return (Kind == FieldDescriptorKind::Class ||
Kind == FieldDescriptorKind::ObjCClass);
}
bool isProtocol() const {
return (Kind == FieldDescriptorKind::Protocol ||
Kind == FieldDescriptorKind::ClassProtocol ||
Kind == FieldDescriptorKind::ObjCProtocol);
}
bool isStruct() const {
return Kind == FieldDescriptorKind::Struct;
}
const_iterator begin() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { Begin, End };
}
const_iterator end() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { End, End };
}
llvm::ArrayRef getFields() const {
return {getFieldRecordBuffer(), NumFields};
}
bool hasMangledTypeName() const {
return MangledTypeName;
}
StringRef getMangledTypeName() const {
return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
}
bool hasSuperclass() const {
return Superclass;
}
StringRef getSuperclass() const {
return Demangle::makeSymbolicMangledNameStringRef(Superclass.get());
}
};
可以发现有 RelativeDirectPointer
类型的属性 MangledTypeName
和 Superclass
、FieldDescriptorKind
类型的属性 Kind
、 uint16_t
类型的属性 FieldRecordSize
、 uint32_t
类型的属性 NumFields
, 并且发现第一行代码中调用了一个方法通过 this+1
的方式一个一个的访问属性,所以这是一块连续的内存空间。进入 FieldRecord
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer MangledTypeName;
const RelativeDirectPointer FieldName;
FieldRecord() = delete;
bool hasMangledTypeName() const {
return MangledTypeName;
}
StringRef getMangledTypeName() const {
return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
}
StringRef getFieldName() const {
return FieldName.get();
}
bool isIndirectCase() const {
return Flags.isIndirectCase();
}
bool isVar() const {
return Flags.isVar();
}
};
发现 FieldRecord
有三个属性 FieldRecordFlags
类型的 Flags
也就是 uint32_t
类型、 RelativeDirectPointer
类型的 MangledTypeName
和 FieldName
。因此能够得到 fieldDescriptor
的结构体如下
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer
var superclass: TargetRelativeDirectPointer
var kind: UInt16
var fieldRecordSize: Int16
var numFields: Int32
var fields: FiledRecordBuffer
}
struct FieldRecord {
var fieldRecordFlags: Int32
var mangledTypeName: TargetRelativeDirectPointer
var fieldName: TargetRelativeDirectPointer
}
struct FiledRecordBuffer{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
4.1.6 TargetEnumMetadata 最终数据结构
通过以上分析最终得到的 TargetEnumMetadata
数据结构如下
// 传入指针
struct TargetRelativeDirectPointer{
var offset: Int32
mutating func getApplyRelativeOffset() -> UnsafeMutablePointer{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
// 获取指针地址 偏移offset后 重新绑定为传入的指针的类型
let pointer = UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
struct TargetEnumMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer
}
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer
var name: TargetRelativeDirectPointer
var accessFunctionPointer: TargetRelativeDirectPointer
var fieldDescriptor: TargetRelativeDirectPointer
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer
var superclass: TargetRelativeDirectPointer
var kind: UInt16
var fieldRecordSize: Int16
var numFields: Int32
var fields: FiledRecordBuffer
}
struct FieldRecord {
var fieldRecordFlags: UInt32
var mangledTypeName: TargetRelativeDirectPointer
var fieldName: TargetRelativeDirectPointer
}
struct FiledRecordBuffer{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
4.1.7 解析Enum的数据
enum Week {
case Mon
case Tue
case Wed
case Thu
case Fri
case Sat
case Sun
}
// 按位转换内存指针
let ptr = unsafeBitCast(Week.self as Any.Type, to: UnsafeMutablePointer.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
// 打印枚举的名称
print(String(cString: namePtr))
let field = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset()
for i in 0..
打印结果
4.2 Class 的实现
4.2.1 还原TargetClassMetadata
首先定位到源码中的 Metadata.h
文件中,找到 TargetClassMetadata
代码如下
struct TargetClassMetadata : public TargetAnyClassMetadata {
...
/// Swift-specific class flags.
ClassFlags Flags;
/// The address point of instances of this type.
uint32_t InstanceAddressPoint;
/// The required size of instances of this type.
/// 'InstanceAddressPoint' bytes go before the address point;
/// 'InstanceSize - InstanceAddressPoint' bytes go after it.
uint32_t InstanceSize;
/// The alignment mask of the address point of instances of this type.
uint16_t InstanceAlignMask;
/// Reserved for runtime use.
uint16_t Reserved;
/// The total size of the class object, including prefix and suffix
/// extents.
uint32_t ClassSize;
/// The offset of the address point within the class object.
uint32_t ClassAddressPoint;
// Description is by far the most likely field for a client to try
// to access directly, so we force access to go through accessors.
private:
/// An out-of-line Swift-specific description of the type, or null
/// if this is an artificial subclass. We currently provide no
/// supported mechanism for making a non-artificial subclass
/// dynamically.
TargetSignedPointer * __ptrauth_swift_type_descriptor> Description;
public:
/// A function for destroying instance variables, used to clean up after an
/// early return from a constructor. If null, no clean up will be performed
/// and all ivars must be trivial.
TargetSignedPointer IVarDestroyer;
...
};
可以看到有 TargetClassMetadata
继承自 TargetAnyClassMetadata
并且有 ClassFlags
类型的 Flags
属性和 uint32_t
的 InstanceAddressPoint
、 InstanceSize
、 ClassSize
、 ClassAddressPoint
属性和 uint16_t
的 、 InstanceAlignMask
、 Reserved
属性和 Description
、 IVarDestroyer
属性。进入到 TargetAnyClassMetadata
struct TargetAnyClassMetadata : public TargetHeapMetadata {
...
// Note that ObjC classes do not have a metadata header.
/// The metadata for the superclass. This is null for the root class.
TargetSignedPointer *
__ptrauth_swift_objc_superclass>
Superclass;
#if SWIFT_OBJC_INTEROP
/// 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.
TargetPointer CacheData[2];
/// The data pointer is used for out-of-line metadata and is
/// generally opaque, except that the compiler sets the low bit in
/// order to indicate that this is a Swift metatype and therefore
/// that the type metadata header is present.
StoredSize Data;
...
};
发现 TargetAnyClassMetadata
继承自 TargetHeapMetadata
并且有三个属性 Superclass
、 CacheData
、 Data
。跳转到 TargetHeapMetadata
中
struct TargetHeapMetadata : TargetMetadata {
using HeaderType = TargetHeapMetadataHeader;
TargetHeapMetadata() = default;
constexpr TargetHeapMetadata(MetadataKind kind)
: TargetMetadata(kind) {}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata(TargetAnyClassMetadata *isa)
: TargetMetadata(isa) {}
#endif
};
没有属性并且继承自 TargetMetadata
跳转至 TargetMetadata
struct TargetMetadata {
...
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;
...
};
有一个属性 Kind
, 根据以上源码分析可以得出 TargetClassMetadata
的数据结构
struct TargetClassMetadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutablePointer
var iVarDestroyer: UnsafeRawPointer
}
4.2.2 还原typeDescriptor
其中的 typeDescriptor
就是 class
的描述信息,回到源码中的 TargetClassMetadata
struct TargetClassMetadata : public TargetAnyClassMetadata {
...
/// An out-of-line Swift-specific description of the type, or null
/// if this is an artificial subclass. We currently provide no
/// supported mechanism for making a non-artificial subclass
/// dynamically.
TargetSignedPointer * __ptrauth_swift_type_descriptor> Description;
...
};
定位到 TargetClassDescriptor
class TargetClassDescriptor final
: public TargetTypeContextDescriptor,
public TrailingGenericContextObjects,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects:*/
TargetResilientSuperclass,
TargetForeignMetadataInitialization,
TargetSingletonMetadataInitialization,
TargetVTableDescriptorHeader,
TargetMethodDescriptor,
TargetOverrideTableHeader,
TargetMethodOverrideDescriptor,
TargetObjCResilientClassStubInfo,
TargetCanonicalSpecializedMetadatasListCount,
TargetCanonicalSpecializedMetadatasListEntry,
TargetCanonicalSpecializedMetadataAccessorsListEntry,
TargetCanonicalSpecializedMetadatasCachingOnceToken> {
...
/// The type of the superclass, expressed as a mangled type name that can
/// refer to the generic arguments of the subclass type.
TargetRelativeDirectPointer SuperclassType;
union {
/// If this descriptor does not have a resilient superclass, this is the
/// negative size of metadata objects of this class (in words).
uint32_t MetadataNegativeSizeInWords;
/// If this descriptor has a resilient superclass, this is a reference
/// to a cache holding the metadata's extents.
TargetRelativeDirectPointer>
ResilientMetadataBounds;
};
union {
/// If this descriptor does not have a resilient superclass, this is the
/// positive size of metadata objects of this class (in words).
uint32_t MetadataPositiveSizeInWords;
/// Otherwise, these flags are used to do things like indicating
/// the presence of an Objective-C resilient class stub.
ExtraClassDescriptorFlags ExtraClassFlags;
};
/// The number of additional members added by this class to the class
/// metadata. This data is opaque by default to the runtime, other than
/// as exposed in other members; it's really just
/// NumImmediateMembers * sizeof(void*) bytes of data.
///
/// Whether those bytes are added before or after the address point
/// depends on areImmediateMembersNegative().
uint32_t NumImmediateMembers; // ABI: could be uint16_t?
StoredSize getImmediateMembersSize() const {
return StoredSize(NumImmediateMembers) * sizeof(StoredPointer);
}
/// Are the immediate members of the class metadata allocated at negative
/// offsets instead of positive?
bool areImmediateMembersNegative() const {
return getTypeContextDescriptorFlags().class_areImmediateMembersNegative();
}
/// The number of stored properties in the class, not including its
/// superclasses. If there is a field offset vector, this is its length.
uint32_t NumFields;
private:
/// The offset of the field offset vector for this class's stored
/// properties in its metadata, in words. 0 means there is no field offset
/// vector.
///
/// If this class has a resilient superclass, this offset is relative to
/// the size of the resilient superclass metadata. Otherwise, it is
/// absolute.
uint32_t FieldOffsetVectorOffset;
...
};
TargetClassDescriptor
继承自 TargetTypeContextDescriptor
并且有 SuperclassType
、 MetadataNegativeSizeInWords
、 MetadataPositiveSizeInWords
、 NumImmediateMembers
、 NumFields
、 FieldOffsetVectorOffset
属性,定位到 TargetTypeContextDescriptor
class TargetTypeContextDescriptor
: public TargetContextDescriptor {
public:
/// The name of the type.
TargetRelativeDirectPointer Name;
/// A pointer to the metadata access function for this type.
///
/// The function type here is a stand-in. You should use getAccessFunction()
/// to wrap the function pointer in an accessor that uses the proper calling
/// convention for a given number of arguments.
TargetRelativeDirectPointer AccessFunctionPtr;
/// A pointer to the field descriptor for the type, if any.
TargetRelativeDirectPointer Fields;
...
};
TargetTypeContextDescriptor
继承自 TargetContextDescriptor
并且有 Name
、 AccessFunctionPtr
、 Fields
属性, 定位到 TargetContextDescriptor
struct TargetContextDescriptor {
/// Flags describing the context, including its kind and format version.
ContextDescriptorFlags Flags;
/// The parent context, or null if this is a top-level context.
TargetRelativeContextPointer Parent;
...
};
TargetContextDescriptor
有 Flags
、 Parent
属性。根据在上面对 Enum
数据结构的分析和 TargetClassMetadata
的源码分析,最后得出 TargetClassMetadata
的最终数据结构为
struct TargetClassDescriptor{
var flags: Int32
var parent: Int32
var name: TargetRelativeDirectPointer
var accessFunctionPointer: TargetRelativeDirectPointer
var fieldDescriptor: TargetRelativeDirectPointer
var superClassType: TargetRelativeDirectPointer
var metadataNegativeSizeInWords: Int32
var metadataPositiveSizeInWords: Int32
var numImmediateMembers: Int32
var numFields: Int32
// 每一个属性值距离当前实例对象地址的偏移量
var fieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer{
return metadata.assumingMemoryBound(to: Int.self).advanced(by: numericCast(self.fieldOffsetVectorOffset))
}
var genericArgumentOffset: Int {
return 2
}
}
struct TargetClassMetadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutablePointer
var iVarDestroyer: UnsafeRawPointer
}
4.2.3 解析Class的数据
class Teacher {
var age: Int = 18
var name: String = "小明"
}
var t = Teacher()
let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("当前类的名称: \(String(cString: namePtr))")
let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("当前类属性的个数: \(numFileds)")
打印结果
再获取属性信息
// 获取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))
for i in 0...size).assumingMemoryBound(to: Any.Type.self)
// 标准C语言函数库
let fieldType = swift_getTypeByMangledNameInContext(
typeMangleName,
256,
UnsafeRawPointer(ptr.pointee.typeDescriptor),
UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional.self))
// 将fieldType转换成Any类型
let type = unsafeBitCast(fieldType, to: Any.Type.self)
// 获取首地址
let instanceAddress = Unmanaged.passUnretained(t as AnyObject).toOpaque()
// 将属性的类型信息绑定到协议的类型信息
let valueType = customCast(type: type)
// 获取属性值的地址的值
let valueValue = valueType.get(from: instanceAddress.advanced(by: fieldOffset))
print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}
其中 swift_getTypeByMangledNameInContext
是调用的C语言的标准函数这里通过swift桥接的形式进行
//typeNameStart 地址信息
//typeNameLength 名称混写长度信息
//context 上下文
//genericArgs 泛型参数
const void * _Nullable swift_getTypeByMangledNameInContext(
const char * _Nullable typeNameStart,
int typeNameLength,
const void * _Nullable context,
const void * _Nullable const * _Nullable genericArgs);
customCast(type: type)
具体内容为
protocol BrigeProtocol {}
extension BrigeProtocol {
// 属性值的地址传入进来 后 返回属性值
static func get(from pointer: UnsafeRawPointer) -> Any {
pointer.assumingMemoryBound(to: Self.self).pointee
}
}
// 协议的metadata
struct BrigeProtocolMetadata {
let type: Any.Type
let witness: Int
}
func customCast(type: Any.Type) -> BrigeProtocol.Type {
let container = BrigeProtocolMetadata(type: type, witness: 0)
let protocolType = BrigeProtocol.Type.self
// 按位强制转换成protocolType
let cast = unsafeBitCast(container, to: protocolType)
return cast
}
打印结果
4.3 Struct 的实现
4.3.1 还原TargetStructMetadata
首先定位到源码中的 Metadata.h
文件中,找到 TargetStructMetadata
代码如下
struct TargetStructMetadata : public TargetValueMetadata {
using StoredPointer = typename Runtime::StoredPointer;
using TargetValueMetadata::TargetValueMetadata;
const TargetStructDescriptor *getDescription() const {
return llvm::cast>(this->Description);
}
// The first trailing field of struct metadata is always the generic
// argument array.
/// Get a pointer to the field offset vector, if present, or null.
const uint32_t *getFieldOffsets() const {
auto offset = getDescription()->FieldOffsetVectorOffset;
if (offset == 0)
return nullptr;
auto asWords = reinterpret_cast(this);
return reinterpret_cast(asWords + offset);
}
bool isStaticallySpecializedGenericMetadata() const {
auto *description = getDescription();
if (!description->isGeneric())
return false;
auto *trailingFlags = getTrailingFlags();
if (trailingFlags == nullptr)
return false;
return trailingFlags->isStaticSpecialization();
}
bool isCanonicalStaticallySpecializedGenericMetadata() const {
auto *description = getDescription();
if (!description->isGeneric())
return false;
auto *trailingFlags = getTrailingFlags();
if (trailingFlags == nullptr)
return false;
return trailingFlags->isCanonicalStaticSpecialization();
}
const MetadataTrailingFlags *getTrailingFlags() const {
auto description = getDescription();
auto flags = description->getFullGenericContextHeader()
.DefaultInstantiationPattern->PatternFlags;
if (!flags.hasTrailingFlags())
return nullptr;
auto fieldOffset = description->FieldOffsetVectorOffset;
auto offset =
fieldOffset +
// Pad to the nearest pointer.
((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
sizeof(void *));
auto asWords = reinterpret_cast(this);
return reinterpret_cast(asWords + offset);
}
static constexpr int32_t getGenericArgumentOffset() {
return sizeof(TargetStructMetadata) / sizeof(StoredPointer);
}
static bool classof(const TargetMetadata *metadata) {
return metadata->getKind() == MetadataKind::Struct;
}
};
我们发现TargetStructMetadata
和 TargetEnumMetadata
如出一辙都是继承自 TargetValueMetadata,通过之前对 TargetEnumMetadata
的分析不难得出 TargetStructMetadata
的结构为
struct TargetStructMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer
}
与 TargetEnumMetadata
不通过的是 TargetSructMetadata
的 typeDescriptor
的类型是 TargetStructDescriptor
定位到 TargetStructDescriptor
class TargetStructDescriptor final
: public TargetValueTypeDescriptor,
public TrailingGenericContextObjects,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects*/
TargetForeignMetadataInitialization,
TargetSingletonMetadataInitialization,
TargetCanonicalSpecializedMetadatasListCount,
TargetCanonicalSpecializedMetadatasListEntry,
TargetCanonicalSpecializedMetadatasCachingOnceToken> {
...
/// The number of stored properties in the struct.
/// If there is a field offset vector, this is its length.
uint32_t NumFields;
/// The offset of the field offset vector for this struct's stored
/// properties in its metadata, if any. 0 means there is no field offset
/// vector.
uint32_t FieldOffsetVectorOffset;
...
};
发现跟 TargetEnumDescriptor
也差不太多都是继承自 TargetValueTypeDescriptor
,只是属性不一样是 两个 uint32_t
类型的 NumFields
和 FieldOffsetVectorOffset
这两个属性在 TargetClassDescriptor
中有
所以最后能够得到 TargetSructMetadata
的最终数据结构为
struct TargetStructMetadata {
var kind: Int
var typeDescriptor: UnsafeMutablePointer
}
struct TargetStructDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer
var name: TargetRelativeDirectPointer
var accessFunctionPointer: TargetRelativeDirectPointer
var fieldDescriptor: TargetRelativeDirectPointer
var numFields: Int32
// 每一个属性值距离当前实例对象地址的偏移量
var fieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer{
return metadata.assumingMemoryBound(to: Int32.self).advanced(by: numericCast(self.fieldOffsetVectorOffset) * 2)
}
var genericArgumentOffset: Int {
return 2
}
}
4.3.2 解析Struct的数据
struct Person {
var age: Int = 18
var name: String = "小明"
}
var person = Person()
let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer.self)
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getApplyRelativeOffset()
print("当前结构体的名称: \(String(cString: namePtr))")
let numFileds = ptr.pointee.typeDescriptor.pointee.numFields
print("当前结构体属性的个数: \(numFileds)")
// 获取偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))
for i in 0...size).assumingMemoryBound(to: Any.Type.self)
// 标准C语言函数库
let fieldType = swift_getTypeByMangledNameInContext(
typeMangleName,
256,
UnsafeRawPointer(ptr.pointee.typeDescriptor),
UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional.self))
// 将fieldType转换成Any类型
let type = unsafeBitCast(fieldType, to: Any.Type.self)
// 获取实例对象p的指针 需要转换成UnsafeRawPointer 并且绑定成1字节即Int8类型,
// 因为后面是按字节计算偏移量的,不转换,会以结构体的长度偏移
let instanceAddress = withUnsafePointer(to: &person){
return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)
}
// 将属性的类型信息绑定到协议的类型信息
let valueType = customCast(type: type)
// 获取属性值的地址的值
let valueValue = valueType.get(from: instanceAddress.advanced(by: Int(fieldOffset)))
print("fieldType:\(type) \nfieldValue:\(valueValue) ")
}
打印结果
自此通过对Mirror源码的原理实现了对 Enum
、 Class
、 Struct
三种类型的解析小工具