Swift探索(六): Mirror源码解析

一:元类型和 .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

AnyObject.png

AnyObject汇编.png

可以看见 p1AnyObject 表示的就是一个实例对象,p2AnyObject 表示的就是原类型 Metadata

protocol Myprotocol: AnyObject {

}

class Person: Myprotocol {
    var age: Int = 18
    var name: String = "小明"
}

var p: Myprotocol = Person()

var p1: AnyObject = p

struct protocol.png

此时的协议 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 转换成具体的类型 asas?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.self.png

T.self汇编.png

从上面打印结果和在汇编中的打印结果可以看出:
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.png

在第一个断点处打印 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.png

可以看到 AnyClass 就是 AnyObjectType 类型

class Person {
    var age = 18
}

var t: AnyClass = Person.self

T.TypeT.self 的类型

二:Swift Runtime

我们都知道 Swift 是一门静态语言,但是在之前的文章 Swift探索(二): 类与结构体(下) 中提过 @objcNSObject@Objc dynamic 标识。那么是可以通过这些关键字来实现在 Swift中调用 OCRuntimeAPI 的。

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
添加@objc.png
  • 对于纯 Swift 类,方法和属性添加 @objc 标识时,可以用过 RunTimeApi 拿到,但在 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
  • 对于继承自 NSObjectSwift 类,必须在声明属性和方法前添加 @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")
    }
}

  • 继承自 NSObjectSwift 类,其继承自父类的方法具有动态性,其它自定义方法、属性相应获得动态性,需要添加 dynamic 修饰
    image.png
  • 若方法的参数、属性类型为 Swfit 特有无法映射到 OC的类型(如 CharacterTuple ),则此方法、属性无法添加 @objcdynamic 关键字(编译器报错)

三: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协议.png

实现了CustomReflectable协议.png

回到源码中,如果没有遵循 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 文件的下方可以看到 TupleStructEnumClass 的具体实现。
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探索(二): 类与结构体(下) 当中我们提到过 StructClassEnum 都有自己的 Metadata , 并且 Metadata 中都有与之对应的 TypeDescriptor
通过对 TupleImplEnumImplClassImpl 的分析实现方式基本与 StructImpl 相同,都是通过 Matadata 类型的元数据、 getDescription 类型的描述 、 FieldDescrition 类型的属性的描述去实现。

4. 利用Mirror源码的原理实现解析小工具

首先通过源码分别获取到 EnumStructClass 这三种类型中的 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 NumPayloadCasesAndPayloadSizeOffsetuint32_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 类型的的属性 NameAccessFunctionPtrFields ,并且 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 类型,按位存储着 kindisGenericisUniqueversionkindSpecificFlags等信息。因此最终可以得出 TargetEnumDescriptor 具体的数据结构如下

struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeContextPointer
    var name: TargetRelativeDirectPointer
    var accessFunctionPointer: TargetRelativeDirectPointer
    var fieldDescriptor: TargetRelativeDirectPointer
    var numPayloadCasesAndPayloadSizeOffset: UInt32
    var numEmptyCases: UInt32
}

接下来分析 TargetRelativeContextPointerTargetRelativeDirectPointer 具体是什么

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 类型的属性 MangledTypeNameSuperclassFieldDescriptorKind 类型的属性 Kinduint16_t 类型的属性 FieldRecordSizeuint32_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 类型的 MangledTypeNameFieldName 。因此能够得到 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..

打印结果


Enum的数据打印结果.png
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_tInstanceAddressPointInstanceSizeClassSizeClassAddressPoint 属性和 uint16_t 的 、 InstanceAlignMaskReserved 属性和 DescriptionIVarDestroyer 属性。进入到 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 并且有三个属性 SuperclassCacheDataData 。跳转到 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 并且有 SuperclassTypeMetadataNegativeSizeInWordsMetadataPositiveSizeInWordsNumImmediateMembersNumFieldsFieldOffsetVectorOffset 属性,定位到 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 并且有 NameAccessFunctionPtrFields 属性, 定位到 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;
  ...
};

TargetContextDescriptorFlagsParent 属性。根据在上面对 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)")

打印结果


Class的数据的打印结果.png

再获取属性信息

// 获取偏移量
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
}

打印结果


Class的数据的打印结果.png
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;
  }
};

我们发现TargetStructMetadataTargetEnumMetadata 如出一辙都是继承自 TargetValueMetadata,通过之前对 TargetEnumMetadata 的分析不难得出 TargetStructMetadata 的结构为

struct TargetStructMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer
}

TargetEnumMetadata 不通过的是 TargetSructMetadatatypeDescriptor 的类型是 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 类型的 NumFieldsFieldOffsetVectorOffset 这两个属性在 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) ")
}

打印结果


Struct的数据的打印结果.png

自此通过对Mirror源码的原理实现了对 EnumClassStruct 三种类型的解析小工具

你可能感兴趣的:(Swift探索(六): Mirror源码解析)