美文网首页Swift探索
Swift探索(六): Mirror源码解析

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

作者: Lee_Toto | 来源:发表于2022-02-25 14:18 被阅读0次

    一:元类型和 .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..<numericCast(methodCount) {
            if let method = methodlist?[i]{
                let methodName = method_getName(method)
                print("方法列表 :\(String(describing: methodName))")
            } else{
                print("not found method")
            }
        }
        var count: UInt32 = 0
        let proList = class_copyPropertyList(cls, &count)
        for  i in 0..<numericCast(count) {
            if let property = proList?[i] {
                let propertyName = property_getName(property)
                print("属性成员属性:\(String(utf8String: propertyName)!)")
            } else {
                print("not fount property")
            }
        }
    }
    

    使用以上代码获取一个类的属性和方法

    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<String, Any>.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>(_: T, type: Any.Type) -> Any.Type
    

    定位到 _getNormalizedType() 函数可以发现这里其实是调用的 C++ 的方法 swift_reflectionMirror_normalizedType。前面的 @_silgen_name 是编译器字段,是 Swift 一个隐藏的符号,作用是将 C/C++ 的函数直接映射为 Swift 函数。

    // func _getNormalizedType<T>(_: 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<const StructMetadata *>(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<const StructMetadata *>(type);
        return Struct->getDescription()->NumFields;
      }
    
      intptr_t childOffset(intptr_t i) override {
        auto *Struct = static_cast<const StructMetadata *>(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<char*>(value);
        auto fieldOffset = childOffset(i);
        auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
    
        return copyFieldContents(fieldData, fieldInfo);
      }
    };
    
      bool isReflectable() {
        const auto *Struct = static_cast<const StructMetadata *>(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<const StructMetadata *>(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<char*>(value);
        auto fieldOffset = childOffset(i);
        auto *fieldData = reinterpret_cast<OpaqueValue *>(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<Runtime> {
    // 全是方法
    ...
    }
    

    我们发现这里面全是方法,并且 TargetEnumMetadata 继承自 TargetValueMetadata ,那么进入到 TargetValueMetadata

    struct TargetValueMetadata : public TargetMetadata<Runtime> {
      ...
      /// An out-of-line description of the type.
      TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __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<Any>
    }
    
    4.1.2 还原typeDescriptor

    其中 typeDescriptor 就是枚举 metadata 的描述信息,回到源码的 TargetEnumMetadata

    struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      using StoredSize = typename Runtime::StoredSize;
      using TargetValueMetadata<Runtime>::TargetValueMetadata;
    
      const TargetEnumDescriptor<Runtime> *getDescription() const {
        return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
      }
    ...
    };
    

    可以看到这里进行了一个类型转换,转换成了 TargetEnumDescriptor ,定位到 TargetEnumDescriptor

    class TargetEnumDescriptor final
        : public TargetValueTypeDescriptor<Runtime>,
          public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
                                TargetTypeGenericContextDescriptorHeader,
                                /*additional trailing objects*/
                                TargetForeignMetadataInitialization<Runtime>,
                                TargetSingletonMetadataInitialization<Runtime>,
                                TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                                TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                                TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
      ...
      /// 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<Runtime> {
    public:
      static bool classof(const TargetContextDescriptor<Runtime> *cd) {
        return cd->getKind() == ContextDescriptorKind::Struct ||
               cd->getKind() == ContextDescriptorKind::Enum;
      }
    };
    

    没有属性,继承自 TargetTypeContextDescriptor , 定位到 TargetTypeContextDescriptor

    class TargetTypeContextDescriptor
        : public TargetContextDescriptor<Runtime> {
    public:
      /// The name of the type.
      TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> 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<Runtime, MetadataResponse(...),
                                  /*Nullable*/ true> AccessFunctionPtr;
      
      /// A pointer to the field descriptor for the type, if any.
      TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                                  /*nullable*/ true> 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<Runtime> 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<UnsafeRawPointer>
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
        var numPayloadCasesAndPayloadSizeOffset: UInt32
        var numEmptyCases: UInt32
    }
    

    接下来分析 TargetRelativeContextPointerTargetRelativeDirectPointer 具体是什么

    4.1.3 TargetRelativeContextPointer

    定位到 TargetRelativeContextPointer

    template<typename Runtime,
             template<typename _Runtime> class Context = TargetContextDescriptor>
    using TargetRelativeContextPointer =
      RelativeIndirectablePointer<const Context<Runtime>,
                                  /*nullable*/ true, int32_t,
                                  TargetSignedContextPointer<Runtime, Context>>;
    

    可以看到这是一个别名的定义给 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<typename ValueTy, bool Nullable = false, typename Offset = int32_t, typename IndirectType = const ValueTy *>
    class RelativeIndirectablePointer {
    private:
      static_assert(std::is_integral<Offset>::value &&
                    std::is_signed<Offset>::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<Offset>(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<Offset>(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<IndirectType const *>(address);
        } else {
          return reinterpret_cast<const ValueTy *>(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<IndirectType const *>(address);
        } else {
          return reinterpret_cast<const ValueTy *>(address);
        }
      }
    

    get() 函数中,会调用 applyRelativeOffset 函数,进行地址的偏移

    static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
      static_assert(std::is_integral<Offset>::value &&
                    std::is_signed<Offset>::value,
                    "offset type should be signed integer");
    
      auto base = reinterpret_cast<uintptr_t>(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 <Pointee>{
        var offset: Int32
        
        mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
            
            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 <typename Runtime, typename Pointee, bool Nullable = true>
    using TargetRelativeDirectPointer
      = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
    

    可以发现这里跟 TargetRelativeContextPointer 一样也是给 RelativeDirectPointer 取了一个别名 TargetRelativeDirectPointer , 定位到 RelativeDirectPointer

    /// A direct relative reference to an object that is not a function pointer.
    template <typename T, bool Nullable, typename Offset>
    class RelativeDirectPointer<T, Nullable, Offset,
        typename std::enable_if<!std::is_function<T>::value>::type>
        : private RelativeDirectPointerImpl<T, Nullable, Offset>
    {
      using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
    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<typename T, bool Nullable, typename Offset>
    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<Offset>(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<Offset>(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<PointerTy>(absolute);
      }
    
      /// A zero relative offset encodes a null reference.
      bool isNull() const & {
        return RelativeOffset == 0;
      }
    };
    

    发现这里跟 TargetRelativeContextPointer 基本一样,都是存储在内存中的对象的相对引用,于是优化一下已经还原的 EnumMetadata 的结构体如下

    // 传入指针
    struct TargetRelativeDirectPointer<Pointee>{
        var offset: Int32
        
        mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
            
            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<TargetEnumDescriptor>
    }
    
    struct TargetEnumDescriptor {
        var flags: UInt32
        var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<UnsafeRawPointer>
        var numPayloadCasesAndPayloadSizeOffset: UInt32
        var numEmptyCases: UInt32
    }
    
    4.1.5 还原fieldDescriptor

    在源码中

    class TargetTypeContextDescriptor
        : public TargetContextDescriptor<Runtime> {
    public:
      ...
      /// A pointer to the field descriptor for the type, if any.
      TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                                  /*nullable*/ true> Fields;
      ...
    };
    

    注意到这里使用的命名空间中的 FieldDescriptor ,进入 FieldDescriptor

    class FieldDescriptor {
      const FieldRecord *getFieldRecordBuffer() const {
        return reinterpret_cast<const FieldRecord *>(this + 1);
      }
    
    public:
      const RelativeDirectPointer<const char> MangledTypeName;
      const RelativeDirectPointer<const char> 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<FieldRecord> 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<const char> MangledTypeName;
      const RelativeDirectPointer<const char> 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<CChar>
        var superclass: TargetRelativeDirectPointer<CChar>
        var kind: UInt16
        var fieldRecordSize: Int16
        var numFields: Int32
        var fields: FiledRecordBuffer<FieldRecord>
    }
    
    struct FieldRecord {
        var fieldRecordFlags: Int32
        var mangledTypeName: TargetRelativeDirectPointer<CChar>
        var fieldName: TargetRelativeDirectPointer<UInt8>
    }
    
    struct FiledRecordBuffer<Element>{
        var element: Element
        
        mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
            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<Element> {
            return withUnsafePointer(to: &self) {
                return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
            }
        }
    }
    
    4.1.6 TargetEnumMetadata 最终数据结构

    通过以上分析最终得到的 TargetEnumMetadata 数据结构如下

    // 传入指针
    struct TargetRelativeDirectPointer<Pointee>{
        var offset: Int32
        
        mutating func getApplyRelativeOffset() -> UnsafeMutablePointer<Pointee>{
            
            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<TargetEnumDescriptor>
    }
    
    struct TargetEnumDescriptor {
        var flags: UInt32
        var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
        var numPayloadCasesAndPayloadSizeOffset: UInt32
        var numEmptyCases: UInt32
    }
    
    struct FieldDescriptor {
        var mangledTypeName: TargetRelativeDirectPointer<CChar>
        var superclass: TargetRelativeDirectPointer<CChar>
        var kind: UInt16
        var fieldRecordSize: Int16
        var numFields: Int32
        var fields: FiledRecordBuffer<FieldRecord>
    }
    
    struct FieldRecord {
        var fieldRecordFlags: UInt32
        var mangledTypeName: TargetRelativeDirectPointer<CChar>
        var fieldName: TargetRelativeDirectPointer<UInt8>
    }
    
    struct FiledRecordBuffer<Element>{
        var element: Element
        
        mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
            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<Element> {
            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<TargetEnumMetadata>.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..<field.pointee.numFields {
        let fieldRecord = field.pointee.fields.index(of: Int(i))
        let fieldName = fieldRecord.pointee.fieldName.getApplyRelativeOffset()
        // 打印枚举元素值的名称
        print(String(cString: fieldName))
    }
    

    打印结果


    Enum的数据打印结果.png
    4.2 Class 的实现
    4.2.1 还原TargetClassMetadata

    首先定位到源码中的 Metadata.h 文件中,找到 TargetClassMetadata 代码如下

    struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
      ...
      /// 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<Runtime, const TargetClassDescriptor<Runtime> * __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<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;
       ...
    };
    
    

    可以看到有 TargetClassMetadata 继承自 TargetAnyClassMetadata 并且有 ClassFlags 类型的 Flags 属性和 uint32_tInstanceAddressPointInstanceSizeClassSizeClassAddressPoint 属性和 uint16_t 的 、 InstanceAlignMaskReserved 属性和 DescriptionIVarDestroyer 属性。进入到 TargetAnyClassMetadata

    struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
     ...
    
      // Note that ObjC classes do not have a metadata header.
    
      /// The metadata for the superclass.  This is null for the root class.
      TargetSignedPointer<Runtime, const TargetClassMetadata<Runtime> *
                                       __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<Runtime, void> 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<Runtime> {
      using HeaderType = TargetHeapMetadataHeader<Runtime>;
    
      TargetHeapMetadata() = default;
      constexpr TargetHeapMetadata(MetadataKind kind)
        : TargetMetadata<Runtime>(kind) {}
    #if SWIFT_OBJC_INTEROP
      constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
        : TargetMetadata<Runtime>(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<Any>
        var iVarDestroyer: UnsafeRawPointer
    }
    
    4.2.2 还原typeDescriptor

    其中的 typeDescriptor 就是 class的描述信息,回到源码中的 TargetClassMetadata

    struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
      ...
      /// 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<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
    ...
    };
    

    定位到 TargetClassDescriptor

    class TargetClassDescriptor final
        : public TargetTypeContextDescriptor<Runtime>,
          public TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
                                  TargetTypeGenericContextDescriptorHeader,
                                  /*additional trailing objects:*/
                                  TargetResilientSuperclass<Runtime>,
                                  TargetForeignMetadataInitialization<Runtime>,
                                  TargetSingletonMetadataInitialization<Runtime>,
                                  TargetVTableDescriptorHeader<Runtime>,
                                  TargetMethodDescriptor<Runtime>,
                                  TargetOverrideTableHeader<Runtime>,
                                  TargetMethodOverrideDescriptor<Runtime>,
                                  TargetObjCResilientClassStubInfo<Runtime>,
                                  TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                                  TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                                  TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
                                  TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
    ...
      /// The type of the superclass, expressed as a mangled type name that can
      /// refer to the generic arguments of the subclass type.
      TargetRelativeDirectPointer<Runtime, const char> 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<Runtime,
                                    TargetStoredClassMetadataBounds<Runtime>>
          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<Runtime> {
    public:
      /// The name of the type.
      TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> 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<Runtime, MetadataResponse(...),
                                  /*Nullable*/ true> AccessFunctionPtr;
      
      /// A pointer to the field descriptor for the type, if any.
      TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                                  /*nullable*/ true> 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<Runtime> Parent;
      ...
    };
    

    TargetContextDescriptorFlagsParent 属性。根据在上面对 Enum 数据结构的分析和 TargetClassMetadata 的源码分析,最后得出 TargetClassMetadata 的最终数据结构为

    struct TargetClassDescriptor{
        var flags: Int32
        var parent: Int32
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
        var superClassType: TargetRelativeDirectPointer<CChar>
        var metadataNegativeSizeInWords: Int32
        var metadataPositiveSizeInWords: Int32
        var numImmediateMembers: Int32
        var numFields: Int32
        // 每一个属性值距离当前实例对象地址的偏移量
        var fieldOffsetVectorOffset: Int32
        
        func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int>{
          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<TargetClassDescriptor>
        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<TargetClassMetadata>.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..<numFileds{
    
        let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
        print("fieldDespritor: \(String(cString: fieldDespritor))")
    
        let fieldOffset = offsets[Int(i)]
    
        let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()
    
        // 获取泛型参数
        let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
    
        // 标准C语言函数库
        let fieldType = swift_getTypeByMangledNameInContext(
            typeMangleName,
            256,
            UnsafeRawPointer(ptr.pointee.typeDescriptor),
            UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.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<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      using TargetValueMetadata<Runtime>::TargetValueMetadata;
    
      const TargetStructDescriptor<Runtime> *getDescription() const {
        return llvm::cast<TargetStructDescriptor<Runtime>>(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<const void * const*>(this);
        return reinterpret_cast<const uint32_t *>(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<const void *const *>(this);
        return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
      }
    
      static constexpr int32_t getGenericArgumentOffset() {
        return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
      }
    
      static bool classof(const TargetMetadata<Runtime> *metadata) {
        return metadata->getKind() == MetadataKind::Struct;
      }
    };
    

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

    struct TargetStructMetadata {
        var kind: Int
        var typeDescriptor: UnsafeMutablePointer<Any>
    }
    

    TargetEnumMetadata 不通过的是 TargetSructMetadatatypeDescriptor 的类型是 TargetStructDescriptor 定位到 TargetStructDescriptor

    class TargetStructDescriptor final
        : public TargetValueTypeDescriptor<Runtime>,
          public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
                                TargetTypeGenericContextDescriptorHeader,
                                /*additional trailing objects*/
                                TargetForeignMetadataInitialization<Runtime>,
                                TargetSingletonMetadataInitialization<Runtime>,
                                TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                                TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                                TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
    ...
      /// 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<TargetStructDescriptor>
    }
    
    struct TargetStructDescriptor {
        var flags: UInt32
        var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
        var numFields: Int32
        // 每一个属性值距离当前实例对象地址的偏移量
        var fieldOffsetVectorOffset: Int32
        
        func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32>{
          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<TargetStructMetadata>.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..<numFileds{
    
        let fieldDespritor = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getApplyRelativeOffset()
        print("fieldDespritor: \(String(cString: fieldDespritor))")
    
        let fieldOffset = offsets[Int(i)]
    
        let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getApplyRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getApplyRelativeOffset()
    
        // 获取泛型参数
        let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
    
        // 标准C语言函数库
        let fieldType = swift_getTypeByMangledNameInContext(
            typeMangleName,
            256,
            UnsafeRawPointer(ptr.pointee.typeDescriptor),
            UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.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源码解析

        本文链接:https://www.haomeiwen.com/subject/jmchhrtx.html