Swift -- 6.Mirror源码解析

一.元类型、.self和Self

1.AnyObject

AnyObject代表任意类的实例,类的类型,仅类遵循的协议。

//3.仅类遵循的协议
protocol Myprotocol: AnyObject {
    func test()
}

class LGTeacher {
    var age = 18
    var name = "Kody"
    
}

let t = LGTeacher()
//1.代表实例
var t1: AnyObject = t
//2.代表类的类型
var t2: AnyObject = LGTeacher.self

2.T.self

T.self如果T是实例对象,T.self返回的就是实例本身。如果T是类,返回的就是元类型

//实例对象
let t = LGTeacher() //
//实例对象
let t1 = t.self //
//元类型(metadata)
let t2 = LGTeacher.self //(@thick swiftTest.LGTeacher.Type) t2 = swiftTest.LGTeacher

汇编探究swiftTest.LGTeacher

LGTeacher元类型
  • 此时的rax其实就是元类型,也就是LGTeachermetadata

3.self在不同方法里的表现

class LGTeacher {
    var age = 18
    var name = "Kody"
    
    
    func test() {
        //当前实例对象
        print(self)
    }
    
    static func test1() {
        //self是LGTeacher这个类型本身,也就是metadata
        print(self)
    }
}

4.Self

//2.遵循协议的类型
protocol Myprotocol: AnyObject {
    func get() -> Self
}

class LGTeacher: Myprotocol {
    
    static let age = 18
    //3.访问类型属性(Swift5.5已经不能在存储属性上使用Self),但是在函数内访问类型属性是可以的(第4点)。
//    let age1 = Self.age
    
    //1.作为方法的返回类型
    func test() -> Self {
        return self
    }
    
    func get() -> Self {
        return self
    }
    
    static func getAge() -> Int {
        //4.访问类型属性
        return Self.age
    }
    
    func getAge() -> Int {
        //4.访问类型属性
        return Self.age
    }
}

5.Any&AnyClass

Any表示任意类型,包括function类型或者Optional类型(Swift里面函数/可选值也是有metadata的)
AnyClass代表任意实例的类型。AnyObject.Type

class LGTeacher {
    var age = 18
}

//AnyClass: AnyObject.Type(任意实例的类型)
//LGTeacher.self(属于LGTeacher.Type)
//而LGTeacher又属于AnyObject,因此这样的写法是没有问题的
var t: AnyClass = LGTeacher.self

//这样写是不行的,LGTeacher.Type表示LGTeacher.Type.Type,而AnyClass为LGTeacher.Type
//var t1: AnyClass = LGTeacher.Type

6.type(of: T)

获取一个值的动态类型

var age = 10

//Value的静态类型:Any
func test(_ value: Any) {
    print(type(of: value)) // Int
}

//self --> type(of:T)
//在我们使用self时,相当于就是type(of:)获取实际类型
test(age)

例子

protocol Myprotocol: AnyObject {
    func get() -> Self
}
class LGTeacher: Myprotocol {
    var age = 18
    
    //typeof(:self)
    func get() -> Self {
        return self
    }
}

//静态类型为Myprotocol
let t: Myprotocol = LGTeacher()
//打印的是实际类型
print(t.get()) //swiftTest.LGTeacher

7.探究一个在stackoverflow上的一个问题

问题链接

protocol P {
    init()
}

extension P {
    static func createWithBigSelf() -> Self {
        return Self()
    }
    static func createWithLittleSelf() -> Self {
        return self.init()
    }
}

class A : P {
    required init() {}
}

class B : A {}


let x: A.Type = B.self

print(x.createWithBigSelf()) // A
print(x.createWithLittleSelf()) // B

/*
 第一点,要想在函数内使用Self(),必须要实现required init函数。
 
 执行createWithBigSelf时,相当于执行了x的静态类型传入了函数内,Self()中的Self指的是当前类型,
 也就是通过传入的类型创建了一个当前实例,因此x.createWithBigSelf()为A
 
 执行createWithLittleSelf时,执行到self.init()时,其实相当于执行了type(of:T),获取到了真实类型去构造了一个实例,
 因此x.createWithLittleSelf()为B
 
 当然,这里只是个人角度上分析,也可以从SIL或IR的角度上分析可能更直观。
 */

二.Swift Runtime

我们在Swift -- 2.类与结构体(下)探究影响函数的派发方式也说了一些关于在Swift上使用Runtime功能,必须加上@objc dynamic
@objc暴露给Runtime Api。消息不会变为消息调度机制objc_msgSend
dynamic赋予动态性
继承NSObject的类才能在OC中使用

  • 对于纯Swift类来说,方法和属性不加任何修饰符的情况下。这个时候其实已经不具备我们所谓的Runtime特性了
  • 对于纯Swift类来说,方法和属性添加@objc,我们当前可以通过Runtime Api拿到,但是没法进行调度,因为并没有赋予它动态性
  • 对于纯Swift类来说,没有动态性,可以添加dynamic修饰,可获得动态性
  • 对于纯Swift类来说,方法和属性添加@objc dynamic,可以使用Runtime Api进行调度。但是OC代码中不能使用,因为没有继承自NSObject

  • 继承自NSObjectSwift类,如果想要动态获取当前的属性和方法,必须在其声明之前添加@objc关键字,否则也是没有办法通过Runtime Api获取的
  • 继承自NSObjectSwift类,其继承自父类的方法具有动态性,其它自定义方法、属性想要获得动态性,需要添加dynamic修饰

  • 若方法的参数、属性类型为Swift特有、无法映射到Objective-C的类型(如果Character、Tuple),则此方法、属性无法添加dynamic修饰(编译器报错)

总结:简单的来说,如果对于Swift来说如果想使用Runtime Api必须加上@objc,如果想要动态性加上dynamic,如果想要在OC上使用加上NSObject

三.Mirror

所谓反射就是可以动态获取类型、成员信息,在运行时可以调用方法、属性等行为的特性。在使用OC开发时很少强调其反射概念,因为OC的Runtime要比其它语言中的反射强大得多。但是Swift是一门类型安全的语言,不支持我们像OC那样直接操作,它的标准库依然提供了反射机制来让我们访问成员信息。

Swift的反射机制是基于一个叫Mirror的结构体实现的。你为具体的实例创建一个Mirror对象,然后可以通过它查询这个实例

1.基本用法

class LGTeacher {
    var age = 18
    
    func teach() {
        print("teach")
    }
}

//构建一个Mirror实例,传入的参数为Any类型
let mirror = Mirror(reflecting: LGTeacher())

/*
 为什么传入LGTeacher.self,mirror.children是一个空集合?
 因为传入进去的是一个类型(传入进去的是metadata),对于元类型来说是没有属性和方法,因此也不会反射出数据
 
 */

//注意:当前通过Mirror反射是没法反射到函数的
for pro in mirror.children {
    //pro.label,当前的名称
    //pro.value,反射的值
    print("\(pro.label):\(pro.value)") // Optional("age"):18
}

//拿到类名字符串
let className = Mirror(reflecting: LGTeacher()).description.replacingOccurrences(of: "Mirror for", with: "").trimmingCharacters(in: CharacterSet.whitespaces)

2.小案例:将映射中的属性存放字典中

class LGTeacher {
    var age = 18
}

func testMirror(_ obj: Any) -> Any {
    let mirror = Mirror(reflecting: obj)
    guard !mirror.children.isEmpty else {
        return obj
    }
    var dic = [String:Any]()
    for child in mirror.children {
        if let key = child.label {
            dic[key] = testMirror(child.value)
        }else {
            print("No Key")
        }
    }
    return dic
}


let result = testMirror(LGTeacher())
print(result) //["age": 18]

那么如果我们想让所有的类都可以实现这个功能,此时可以用protocol协议实现

class LGTeacher {
    var age = 18
}

protocol JsonMap {
    func testMirror() -> Any
}

extension JsonMap {
    func testMirror() -> Any {
        let mirror = Mirror(reflecting: self)
        guard !mirror.children.isEmpty else {
            return self
        }
        var dic = [String:Any]()
        for child in mirror.children {
            if let value = child.value as? JsonMap {
                if let key = child.label {
                    dic[key] = value.testMirror()
                }else {
                    print("No Key")
                }
            }else {
                print("child.value not comfirm JsonMap Protocol")
            }
        }
        return dic
    }
}

extension LGTeacher: JsonMap{}
extension Int: JsonMap {}

let result = LGTeacher().testMirror()
print(result) //["age": 18]

添加Error优化当前代码的错误信息

class LGTeacher {
    var age = 18
}

enum JsonMapError: Error {
    case emptyKey
    case notComfirmProtocol
}

protocol JsonMap {
    func testMirror() throws -> Any
}

extension JsonMap {
    func testMirror() throws -> Any {
        let mirror = Mirror(reflecting: self)
        guard !mirror.children.isEmpty else {
            return self
        }
        var dic = [String:Any]()
        for child in mirror.children {
            if let value = child.value as? JsonMap {
                if let key = child.label {
                    dic[key] = try value.testMirror()
                }else {
                    throw JsonMapError.emptyKey
                }
            }else {
                throw JsonMapError.notComfirmProtocol
            }
        }
        return dic
    }
}

extension LGTeacher: JsonMap{}
extension Int: JsonMap {}

let result = try? LGTeacher().testMirror()
print(result) //Optional(["age": 18])

关于rethrows

rethrows本身并不抛出异常或处理异常,只是起到了传递异常的作用。通常在闭包中使用

enum ClosureError: Error {
    case lessZero
}

func test(closure: (Int) throws -> Int, num: Int) rethrows -> Int {
    try closure(num)
}

do {
    let result = try test(closure: {
        if $0 < 0 {
            throw ClosureError.lessZero
        }else {
            return $0 + 10
        }
    }, num: 1)
    print(result)
}catch {
    print(error) //lessZero
}

3.Mirror源码解析

进入源文件搜索Mirror.swift,忽略掉一些细节,在源码中找到初始化方法

  public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }
  • 如果subject遵循了CustomReflectable协议self = customized.customMirror
  • 否则self等于内部的反射初始化函数生成的实例

1.关于CustomReflectable

class LGTeacher: CustomReflectable {
    var age = 18
    var name = "Kody"
    
    var customMirror: Mirror {
        //KeyValuePairs,键值对
        let info = KeyValuePairs(dictionaryLiteral: ("currentAge",age), ("currentName", name))
        let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
        return mirror
    }
}

let mirror = Mirror(reflecting: LGTeacher())

for child in mirror.children {
    if let label = child.label {
        print("\(label):\(child.value)")
    }
}

//此时打印的值,就是我们在customMirror中声明的KeyValuePairs
//currentAge:18
//currentName:Kody

//通过LLDB调试时,也能反射出当前的调试信息
//(lldb) po LGTeacher()
//▿ 
//  - currentAge : 18
//  - currentName : "Kody"

2.关于Mirror的内部初始化方法Mirror(internalReflection:subject))

extension Mirror {
  internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
    //获取传进来的subject的类型信息。使用type(of: T)获取真实信息
    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)
    
    ...
  }

关于_getNormalizedType_getChildCount函数

@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType(_: T, type: Any.Type) -> Any.Type

@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount(_: T, type: Any.Type) -> Int
  • @_silgen_nameSwift的一个隐藏符号,作用是将某个C/C++语言函数直接映射为Swift函数

3.关于Swift调用C语言函数

传统思路

1.创建C文件,.h(方法的声明)和.c(方法的实现)文件
//testC.h
int sum(int a, int b);
//testC.c
int sum(int a, int b) {
    return  a + b;
}

2.创建桥接文件,import我们创建的.h文件
//一般在导入C/C++文件时使用include,导入OC文件使用improt
#include "testC.h"

3.在Swift代码中使用

使用@_silgen_name

1.第一步不变

2.使用_silgen_name直接将C函数映射成Swift函数
@_silgen_name("sum")
internal func my_sum(a: Int, b: Int) -> Int

let result = my_sum(a: 10, b: 10)
print(result) //20

访问控制(Access Control)

  • open可以在任意地方被访问、继承和重写
  • public可以在任意地方被访问,在其它模块(module)内不能被继承、重写
  • internal默认。在整个模块内可以访问、继承和重写
  • fileprivaty在同一个文件内(.swift)可以被访问、继承和重写。修饰的函数静态派发
  • privaty私有的。只能在自己的类中访问。修饰的函数静态派发

  • final只能修饰class。意味着该类是最终类,不能被继承。修饰的class中的函数派发方式为静态派发

4.找到C++代码swift_reflectionMirror_normalizedType

// 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; });
}
  • call调用了一个函数,通过回调函数impl->type,返回type的信息
  • 通过注释可以得出Any.Type就是Metadata

5.call的实现

template
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;
  }
  
  //如果不是Class,执行这个call回调函数
  auto call = [&](ReflectionMirrorImpl *impl) {
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
  //如果是Class,执行callClass回调函数
  auto callClass = [&] {
    if (passedType == nullptr) {
      // Get the runtime type of the object.
      const void *obj = *reinterpret_cast(value);
      auto isa = _swift_getClass(obj);

      // Look through artificial subclasses.
      while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
        isa = isa->Superclass;
      }
      passedType = isa;
    }

  #if SWIFT_OBJC_INTEROP
    // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
    // ForeignClass (e.g. CF classes) manifests as a NULL class object.
    auto *classObject = passedType->getClassObject();
    if (classObject == nullptr || !classObject->isTypeMetadata()) {
      ObjCClassImpl impl;
      return call(&impl);
    }
  #endif

    // Otherwise, use the native Swift facilities.
    ClassImpl impl;
    return call(&impl);
  };
  
  //通过MetadataKind来判断类型,执行不同的处理
  switch (type->getKind()) {
    case MetadataKind::Tuple: {
      TupleImpl impl;
      return call(&impl);
    }

    case MetadataKind::Struct: {
      StructImpl impl;
      return call(&impl);
    }
    

    case MetadataKind::Enum:
    case MetadataKind::Optional: {
      EnumImpl impl;
      return call(&impl);
    }
      
    case MetadataKind::ObjCClassWrapper:
    case MetadataKind::ForeignClass:
    case MetadataKind::Class: {
      return callClass();
    }

    case MetadataKind::Metatype:
    case MetadataKind::ExistentialMetatype: {
      MetatypeImpl impl;
      return call(&impl);
    }

    ...
}
  • 关于Call函数,声明了2个回调函数来获取Class非Class的type
  • 这2个回调函数都有一个参数ReflectionMirrorImpl
  • 根据不同的MetadataKind有不同的Impl,例如枚举EnumImpl

6.关于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反射实现的抽象基类

7.关于EnumImpl

// Implementation for enums.
struct EnumImpl : ReflectionMirrorImpl {
  //是否能反射
  bool isReflectable() {
    //做一个metadata的强转
    const auto *Enum = static_cast(type);
    //找到metadata的Description
    const auto &Description = Enum->getDescription();
    //根据Description中的isReflectable字段来判断是否可以反射
    return Description->isReflectable();
  }
  
  const char *getInfo(unsigned *tagPtr = nullptr,
                      const Metadata **payloadTypePtr = nullptr,
                      bool *indirectPtr = nullptr) {
    // 'tag' is in the range [0..NumElements-1].
    unsigned tag = type->vw_getEnumTag(value);

    StringRef name;
    FieldType info;
    //获取FieldDescriptor的信息,也就是属性信息存放的地方
    std::tie(name, info) = getFieldAt(type, tag);
    const Metadata *payloadType = info.getType();
    bool indirect = info.isIndirect();

    if (tagPtr)
      *tagPtr = tag;
    if (payloadTypePtr)
      *payloadTypePtr = payloadType;
    if (indirectPtr)
      *indirectPtr = indirect;
    
    return name.data();
  }

  char displayStyle() override {
    return 'e';
  }
  
  //获取count
  intptr_t count() override {
    if (!isReflectable()) {
      return 0;
    }
    
    // No fields if reflecting the enumeration type instead of a case
    if (!value) {
      return 0;
    }

    const Metadata *payloadType;
    //获取挂载类型,也就是Metadata
    getInfo(nullptr, &payloadType, nullptr);
    return (payloadType != nullptr) ? 1 : 0;
  }

  ...
}

8.关于getFieldAt

static std::pair
getFieldAt(const Metadata *base, unsigned index) {
  using namespace reflection;
  
  // If we failed to find the field descriptor metadata for the type, fall
  // back to returning an empty tuple as a standin.
  auto failedToFindMetadata = [&]() -> std::pair {
    auto typeName = swift_getTypeName(base, /*qualified*/ true);
    missing_reflection_metadata_warning(
      "warning: the Swift runtime found no field metadata for "
      "type '%*s' that claims to be reflectable. Its fields will show up as "
      "'unknown' in Mirrors\n",
      (int)typeName.length, typeName.data);
    return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
  };
  //获取TargetxxxDescriptor信息
  auto *baseDesc = base->getTypeContextDescriptor();
  if (!baseDesc)
    return failedToFindMetadata();

  //获取descriptor里的FieldDescriptor的信息
  auto *fields = baseDesc->Fields.get();
  if (!fields)
    return failedToFindMetadata();
  
  auto &field = fields->getFields()[index];
  // Bounds are always valid as the offset is constant.
  //获取属性的名称
  auto name = field.getFieldName();
  ...
}
  • 此时的逻辑和Swift -- 3.属性通过Mach-O找到我们的属性名称是一致的

Mirror的工作原理:可以看出Mirro是通过Metadata(当前类型的元数据)getDescription(当前类型的描述)FieldDescription(当前类型属性的描述)来实现的。

四.结合源码还原TargetEnumMetaData

在Swift -- 1.类与结构体(上)探究了TargetClassMetadata的数据类型,在寻找的过程中也遇到了TargetEnumMetaData,因此结合源码还原一下TargetEnumMetaData

1.关于MetadataKind

之前我们总结了一张关于MetadataKind的表

name value
Class 0x0
Struct 0x200
Enum 0x201
Optional 0x202
ForeignClass 0x203
Opaque 0x300
Tuple 0x301
Function 0x302
Existential 0x303
Metatype 0x304
ObjCClassWrapper 0x305
ExistentialMetatype 0x306
HeapLocalVariable 0x400
HeapGenericLocalVariable 0x500
ErrorObject 0x501
LastEnumerated 0x7FF

那么这些值是怎么的来的呢?接下来通过源码分析一下

  1. kind的内存大小
//1.在TargetMetaData中找到kind
/// The kind. Only valid for non-class metadata; getKind() must be used to get
/// the kind value.
StoredPointer Kind;

//2.关于StoredPointer
using StoredPointer = typename Runtime::StoredPointer;

//3.关于Runtime
using Runtime = External>;

//4.关于uintptr_t
typedef unsigned long           uintptr_t;
  • 得出kind大小为Int64

2.验证kind

找到MetadataKind

/// Non-type metadata kinds have this bit set.
//没有类型的元数据的kind存放在此位
const unsigned MetadataKindIsNonType = 0x400;

/// Non-heap metadata kinds have this bit set.
//不是堆元数据存放在此位。也就是除了引用类型
const unsigned MetadataKindIsNonHeap = 0x200;

//运行时私有元数据已设置此位
const unsigned MetadataKindIsRuntimePrivate = 0x100;

/// Kinds of Swift metadata records.  Some of these are types, some
/// aren't.
enum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end)                                 \
  name##_Start = start, name##_End = end,
#include "MetadataKind.def"
  
  /// The largest possible non-isa-pointer metadata kind value.
  ///
  /// This is included in the enumeration to prevent against attempts to
  /// exhaustively match metadata kinds. Future Swift runtimes or compilers
  /// may introduce new metadata kinds, so for forward compatibility, the
  /// runtime must tolerate metadata with unknown kinds.
  /// This specific value is not mapped to a valid metadata kind at this time,
  /// however.
  LastEnumerated = 0x7FF,
};

//关于MetadataKind.def

/// A class type.
NOMINALTYPEMETADATAKIND(Class, 0)

/// A struct type.
NOMINALTYPEMETADATAKIND(Struct, 0 | MetadataKindIsNonHeap)

/// An enum type.
/// If we add reference enums, that needs to go here.
NOMINALTYPEMETADATAKIND(Enum, 1 | MetadataKindIsNonHeap)

/// An optional type.
NOMINALTYPEMETADATAKIND(Optional, 2 | MetadataKindIsNonHeap)

/// A foreign class, such as a Core Foundation class.
METADATAKIND(ForeignClass, 3 | MetadataKindIsNonHeap)

/// A type whose value is not exposed in the metadata system.
METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A tuple.
METADATAKIND(Tuple, 1 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A monomorphic function.
METADATAKIND(Function, 2 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An existential type.
METADATAKIND(Existential, 3 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A metatype.
METADATAKIND(Metatype, 4 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An ObjC class wrapper.
METADATAKIND(ObjCClassWrapper, 5 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An existential metatype.
METADATAKIND(ExistentialMetatype, 6 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A heap-allocated local variable using statically-generated metadata.
METADATAKIND(HeapLocalVariable, 0 | MetadataKindIsNonType)

/// A heap-allocated local variable using runtime-instantiated metadata.
METADATAKIND(HeapGenericLocalVariable,
             0 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)

/// A native error object.
METADATAKIND(ErrorObject,
             1 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)

/// A heap-allocated task.
METADATAKIND(Task,
             2 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)

/// A non-task async job.
METADATAKIND(Job,
             3 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)

2.通过源码还原TargetEnumMetadata

1.进入TargetEnumMetadata,里面并没有结构信息

2.进入TargetEnumMetadata父类TargetValueMetadata

  /// An out-of-line description of the type.
  TargetSignedPointer * __ptrauth_swift_type_descriptor> Description;
  • 存在一个Description描述信息

3.进入TargetValueMetadata父类TargetMetadata(最终基类)

StoredPointer Kind;

4.此时我们就能确定TargetEnumMetadata的外层结构结构

struct TargetEnumMetadata {
    var kind: Int
    var descriptor: UnsafePointer
}

struct TargetEnumDescriptor {
    
}

5.进入TargetEnumDescriptor

  /// 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;
  • NumPayloadCasesAndPayloadSizeOffset具有挂载的case数量
  • NumEmptyCases没有挂载的case数量

6.进入TargetEnumDescriptor父类TargetValueTypeDescriptor

template 
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;

  ...
}
  • 存有NameAccessFunctionPtrFields3个变量,并且类型都是TargetRelativeDirectPointer

7.进入TargetTypeContextDescriptor父类TargetContextDescriptor(最终基类)

/// Base class for all context descriptors.
template
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;

  ...
}

using RelativeContextPointerIntPair =
  RelativeIndirectablePointerIntPair, IntTy,
                              /*nullable*/ true, int32_t,
                              TargetSignedContextPointer>;
  • Flags大小为UInt32
  • Parent类型为TargetRelativeContextPointer

8.总结一下TargetEnumMetadata数据结构

TargetEnumMetadata数据结构

9.关于TargetRelativeDirectPointerTargetRelativeContextPointer

相对地址的指针

using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer;

using TargetRelativeContextPointer =
  RelativeIndirectablePointer,
                              /*nullable*/ true, int32_t,
                              TargetSignedContextPointer>;

/// 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;
};
  • 类似于我们在Mach-o中寻找属性时所看到的很多偏移量,在Swift中大量使用相对地址指针

  • 直接寻址,比如我们定义一个var a = 10 ,那么通过a的指针地址0x1000拿到变量10在内存中的地址(比如是0x1004)。此时a通过2步拿到了内存中的10

  • 相对寻址,比如我们定义一个var a = 10 ,那么a指针地址0x1000存放的是offset,这个offset代表着10在内存中的地址(0x1004)与当前a地址的偏移量,也就是4。这样就可以通过offset来获取值。节省大量的地址信息,优化内存空间

翻译为Swift中的相对指针

struct TargetRelativeDirectPointer {
    var offset: Int32
    
    mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer {
        let offset = self.offset
        return withUnsafePointer(to: &self) { p in
            return UnsafeMutableRawPointer(mutating: p.advanced(by: numericCast(offset))).assumingMemoryBound(to: Pointee.self)
        }
    }
}

10.关于mangledTypeName的还原

使用C语言标准库函数swift_getTypeByMangledNameInContext

//方式1:.h文件声明
/*
 typeNameStart,混淆名称的指针地址
 typeNameLength,混淆名称的长度
 context,上下文,Descriptor的指针地址
 genericArgs,如果有泛型参数,泛型参数的指针地址。参考HandyJson,metadata地址再偏移2个原生指针的大小(2个8字节)
 */
const void * _Nullable swift_getTypeByMangledNameInContext(
                        const void * _Nullable typeNameStart,
                        int typeNameLength,
                        const void * _Nullable context,
                        const void * _Nullable const * _Nullable genericArgs);

//这里使用编译器字段@_silgen_name()方式
@_silgen_name("swift_getTypeByMangledNameInContext")
private func getTypeByMangledNameInContext(
    mangledNamePtr: UnsafePointer,
    mangledNameLength: Int,
    genericContext: UnsafeRawPointer?,
    genericArgs: UnsafeRawPointer?) -> Any.Type?

func getTypeByMangleName(
    mangledNamePtr: UnsafePointer,
    genericContext: UnsafeRawPointer?, metadata: UnsafeRawPointer) ->  Any.Type? {
        return getTypeByMangledNameInContext(mangledNamePtr: mangledNamePtr,
                                             mangledNameLength: getMangledTypeNameSize(mangledNamePtr),
                                             genericContext: UnsafeRawPointer(genericContext),
                                             genericArgs: getGenericArgs(metadata))
}

//参考HandyJson,暂时没找到测量mangledName的长度
func getMangledTypeNameSize(_ managedName: UnsafePointer) -> Int {
    // TODO: should find the actually size 
    return 256
}

//获取泛型参数在metadata中的偏移量
func getGenericArgumentOffset() -> Int {
    return 2
}

//如果有泛型参数,需要传入的泛型参数指针。参考HandyJson
func getGenericArgs(_ metadata: UnsafeRawPointer) -> UnsafeRawPointer? {
    let offSetPtr = metadata.advanced(by: getGenericArgumentOffset() * MemoryLayout.size).assumingMemoryBound(to: Int.self)
    if offSetPtr.pointee == 0 {
        return nil
    }
    return UnsafeRawPointer(offSetPtr)
}

11.还原TargetEnumMetadata

TangledTypeName.swift

@_silgen_name("swift_getTypeByMangledNameInContext")
private func getTypeByMangledNameInContext(
    mangledNamePtr: UnsafePointer,
    mangledNameLength: Int,
    genericContext: UnsafeRawPointer?,
    genericArgs: UnsafeRawPointer?) -> Any.Type?

func getTypeByMangleName(
    mangledNamePtr: UnsafePointer,
    genericContext: UnsafeRawPointer?) ->  Any.Type? {
        return getTypeByMangledNameInContext(mangledNamePtr: mangledNamePtr, mangledNameLength: getMangledTypeNameSize(mangleTypeNamePtr), genericContext: UnsafeRawPointer(genericContext), genericArgs: getGenericArgs(mangledNamePtr))
}

//参考HandyJson,暂时没找到测量mangledName的长度
func getMangledTypeNameSize(_ managedName: UnsafePointer) -> Int {
    // TODO: should find the actually size 
    return 256
}

//获取泛型参数在Descriptor中的偏移量
func getGenericArgumentOffset() -> Int {
    return 2
}

//如果有泛型参数,需要传入的泛型参数指针
func getGenericArgs(_ descriptor: UnsafeRawPointer) -> UnsafeRawPointer {
    return UnsafeRawPointer(descriptor.advanced(by: getGenericArgumentOffset() * MemoryLayout.size).assumingMemoryBound(to: Any.Type.self))
}

TargetMetadata.swift

struct TargetEnumMetadata{
    var kind: Int
    var descriptor: UnsafeMutablePointer
}

struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer
    var name: TargetRelativeDirectPointer
    var accessFunctionPtr: TargetRelativeDirectPointer
    var fields: TargetRelativeDirectPointer

    var numPayloadCaseAndPayloadSizeOffset: UInt32
    var numEmptyCases: UInt32
}

struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer
    var superClass: TargetRelativeDirectPointer
    var kind: UInt16
    var fieldRecordSize: UInt16
    var numField: UInt32
    
    //连续的内存空间存放我们的var变量/case的名称
    //UnsafeBufferPointer,连续的内存空间指针
    var fieldRecords: FieldRecordBuffer
    
    /*
     kind: FieldDescriptorKind(枚举值依次递增)
     Struct: 0x1
     Class
     Enum
     MultiPayloadEnum
     Protocol
     ClassProtocol
     ObjCProtocol
     ObjCClass
     */
}


struct FieldRecordBuffer {
    var element: Element
    
    //方式1.返回buffer连续内存空间
    mutating func buffer(count: Int) -> UnsafeMutableBufferPointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
        }
    }
    
    //方式2.根据下标获取数组元素
    mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
        }
    }
}

struct FieldRecord {
    var flags: UInt32
    var mangledTypeName: TargetRelativeDirectPointer
    var fieldName: TargetRelativeDirectPointer
    
    /*
     flags: FieldRecordFlags
     IsIndirectCase = 0x1,
     IsVar = 0x2,
     IsArtificial = 0x4,
     其它情况 = 0
     */
}

struct TargetRelativeDirectPointer {
    var offset: Int32

    mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer {
        let offset = self.offset
        return withUnsafePointer(to: &self) {
            /*
             注意:这里的$0必须转化为UnsafeRawPointer再执行advanced
             如果类型指针advanced会出问题。
             原始是:在介绍指针的时候说过,如果是类型指针的话,
             advanced(x)相当于移动该类型的内存大小*x。
             */
            return UnsafeMutableRawPointer(mutating: UnsafeRawPointer($0).advanced(by: numericCast(offset))).assumingMemoryBound(to: Pointee.self)
        }
    }
}

main.swift

enum Shape {
    case circle(radious:Int)
    case rectangle(Bool)
    case triangle
}

let ptr = unsafeBitCast(Shape.self as Any.Type, to: UnsafeMutablePointer.self)

//错误写法
//var descriptor = ptr.pointee.descriptor.pointee
//let namePtr = descriptor.name.getMeasureRelativeOffset()

//这里只能这样写,值类型赋值会拷贝。执行到getMeasureRelativeOffset会出问题
let namePtr = ptr.pointee.descriptor.pointee.name.getMeasureRelativeOffset()

print("enum kind: ", "0x\(String(ptr.pointee.kind, radix: 16))") //0x201对应Kind表为Enum
//枚举的名称
print("enum name", String(cString: namePtr)) // Shape
//枚举的带有挂载的数量
print("enum numPayloadCaseAndPayloadSizeOffset: ", ptr.pointee.descriptor.pointee.numPayloadCaseAndPayloadSizeOffset) // 1
//枚举的没有带挂载的数量
print("enum numEmptyCases: ", ptr.pointee.descriptor.pointee.numEmptyCases) // 2


let fieldPtr = ptr.pointee.descriptor.pointee.fields.getMeasureRelativeOffset()

//1.关于还原混淆后的TypeName
let mangleTypeNamePtr = fieldPtr.pointee.mangledTypeName.getMeasureRelativeOffset()

let nameType = getTypeByMangleName(mangledNamePtr: mangleTypeNamePtr, genericContext: UnsafeRawPointer(ptr.pointee.descriptor), metadata: ptr)

print("type Name", nameType as Any)

//2.superClass
let superClassPtr = fieldPtr.pointee.superClass.getMeasureRelativeOffset()
print("enum superClass: ", String(cString: superClassPtr)) //枚举并没有superClass

//3.kind
print("enum field kind: ", fieldPtr.pointee.kind)

//4.fieldRecordSize
print("enum fieldRecordSize: ",fieldPtr.pointee.fieldRecordSize)

//5.numField
print("enum numField: ",fieldPtr.pointee.numField)

//6.FieldRecod

//方式1:使用Buffer的方式
let bufferPtr = fieldPtr.pointee.fieldRecords.buffer(count: numericCast(fieldPtr.pointee.numField))
for i in 0..

打印信息

enum kind:  0x201
enum name Shape
enum numPayloadCaseAndPayloadSizeOffset:  2
enum numEmptyCases:  1
type Name Optional(swiftTest.Shape)
enum superClass:  
enum field kind:  3
enum fieldRecordSize:  12
enum numField:  3
type:Optional((radious: Swift.Int)) case值:circle
type:Optional(Swift.Bool) case值:rectangle
type:nil case值:triangle

五.参考HandyJson总结TargetClassMetadata

在Swift -- 4.指针&内存管理通过指针获取了类名属性名称、、vtable及分析了vtable中的函数名称存放位置(符号表及字符串表)

接下来我们需要获取到的是属性类型属性值

fieldOffsetVectorOffset可以理解为属性信息基于metadata的偏移量(value*8字节)。连续的内存空间,每8字节存放属性值内存地址基于metadata的偏移量
可以理解为取出属性值需要拿到2次的offSet,根据内存地址然后获取到最终的值

TargetMetadata.swift

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
}

struct TargetClassDescriptor{
    var flags: UInt32
    var parent: TargetRelativeDirectPointer
    var name: TargetRelativeDirectPointer
    var accessFunctionPointer: TargetRelativeDirectPointer
    var fieldDescriptor: TargetRelativeDirectPointer
    var superClassType: TargetRelativeDirectPointer
    var metadataNegativeSizeInWords: UInt32
    var metadataPositiveSizeInWords: UInt32
    var numImmediateMembers: UInt32
    var numFields: UInt32
    var fieldOffsetVectorOffset: UInt32
    var Offset: UInt32
    //VTable数量
    var size: UInt32
    //VTable
    var firstVtableData: VTableBuffer
}

struct VTableBuffer {
    var element: Element
    
    mutating func buffer(of count: Int) -> UnsafeMutableBufferPointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
        }
    }
}

struct VTable {
    var flags: TargetMethodDescriptor
    //注意此时的相对地址指针的偏移量不能使用Int,因为符号位会影响offset
    var methodImp: TargetRelativeDirectPointerOffsetUint
}

struct TargetMethodDescriptor {
    var flagType: UInt32

    //从源码恢复的
    enum KindType: UInt32 {
        case Method,
        Init,
        Getter,
        Setter,
        ModifyCoroutine,
        ReadCoroutine
    }

    enum FlagTypeMask: UInt32 {
        case  KindMask = 0x0F,                // 16 kinds should be enough for anybody
        IsInstanceMask = 0x10,
        IsDynamicMask = 0x20,
        IsAsyncMask = 0x40,
//        ExtraDiscriminatorShift = 16, //这个16与0x10冲突了
        ExtraDiscriminatorMask = 0xFFFF0000
      }

    func kindType() -> KindType {
        return KindType(rawValue: flagType & FlagTypeMask.KindMask.rawValue)!
    }

}

struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer
    var superClass: TargetRelativeDirectPointer
    var kind: UInt16
    var fieldRecordSize: UInt16
    var numField: UInt32
    
    //连续的内存空间存放我们的var变量/case的名称
    //UnsafeBufferPointer,连续的内存空间指针
    var fieldRecords: FieldRecordBuffer
    
    /*
     kind: FieldDescriptorKind(枚举值依次递增)
     Struct: 0x1
     Class
     Enum
     MultiPayloadEnum
     Protocol
     ClassProtocol
     ObjCProtocol
     ObjCClass
     */
}

struct FieldRecordBuffer {
    var element: Element
    
    //方式1.返回buffer连续内存空间
    mutating func buffer(count: Int) -> UnsafeMutableBufferPointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
        }
    }
    
    //方式2.根据下标获取数组元素
    mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
        }
    }
}

struct FieldRecord {
    var flags: UInt32
    var mangledTypeName: TargetRelativeDirectPointer
    var fieldName: TargetRelativeDirectPointer
    
    /*
     flags: FieldRecordFlags
     IsIndirectCase = 0x1,
     IsVar = 0x2,
     IsArtificial = 0x4,
     其它情况 = 0
     */
}

struct TargetRelativeDirectPointer {
    var offset: Int32

    mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer {
        let offset = self.offset
        return withUnsafePointer(to: &self) {
            /*
             注意:这里的$0必须转化为UnsafeRawPointer再执行advanced
             如果类型指针advanced会出问题。
             原始是:在介绍指针的时候说过,如果是类型指针的话,
             advanced(x)相当于移动该类型的内存大小*x。
             */
            return UnsafeMutableRawPointer(mutating: UnsafeRawPointer($0).advanced(by: numericCast(offset))).assumingMemoryBound(to: Pointee.self)
        }
    }
}

struct TargetRelativeDirectPointerOffsetUint {
    var offset: UInt32

    mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer {
        let offset = self.offset
        return withUnsafePointer(to: &self) {
            /*
             注意:这里的$0必须转化为UnsafeRawPointer再执行advanced
             如果类型指针advanced会出问题。
             原始是:在介绍指针的时候说过,如果是类型指针的话,
             advanced(x)相当于移动该类型的内存大小*x。
             */
            return UnsafeMutableRawPointer(mutating: UnsafeRawPointer($0).advanced(by: numericCast(offset))).assumingMemoryBound(to: Pointee.self)
        }
    }
}

main.swift

class LGTeacher {
    var age = 18
    var name = "Kody"
    
    func teach() {
        print("teach")
    }
    
    func teach1() {
        print("teach1")
    }
    
    func teach2() {
        print("teach2")
    }
}

let ptr = unsafeBitCast(LGTeacher.self as Any.Type, to: UnsafeMutablePointer.self)

let descriptorPtr = ptr.pointee.typeDescriptor

//1.获取类的名称
print("Class Name:", String(cString: descriptorPtr.pointee.name.getMeasureRelativeOffset()))

//2.获取类的类型
let fieldDescriptorPtr = descriptorPtr.pointee.fieldDescriptor.getMeasureRelativeOffset()
print("Class type:", getTypeByMangleName(mangledNamePtr: fieldDescriptorPtr.pointee.mangledTypeName.getMeasureRelativeOffset(), genericContext: descriptorPtr, metadata: ptr) as Any)

//2.获取属性名称

let fieldRecordBuffer = fieldDescriptorPtr.pointee.fieldRecords.buffer(count: numericCast(fieldDescriptorPtr.pointee.numField))

let propertyPtr = UnsafeRawPointer(ptr).advanced(by: numericCast(descriptorPtr.pointee.fieldOffsetVectorOffset))

let t = LGTeacher()
//3.获取t的metadata地址
let tMetadataPtr = Unmanaged.passUnretained(t).toOpaque()

//4.获取属性值的信息
//获取属性值(offset)存放的地址(基于metadata偏移fieldOffsetVectorOffset个8字节,每8字节存放1个属性的偏移信息)
let offsets = UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self).advanced(by: numericCast(descriptorPtr.pointee.fieldOffsetVectorOffset))

protocol AnyExtensions {}

extension AnyExtensions {

    //取数据
    //这里的self指的是当前类型
    static func value(_ pointer: UnsafeRawPointer) -> Any {
        return pointer.assumingMemoryBound(to: self).pointee
    }
}

struct TargetProtocolMetadata {
    var type: Any.Type
    //协议见证表,后续写到协议相关的再谈
    var witness: Int
}

for i in 0..\(type)->\(extensions.value(valuePtr))")

    /*
     方式2:将自定义的结构体(已经是新的metadata)按位转化为Protocol.Type实现对maetadata的更换。
     这里的TargetProtocolMetadata指的是通过源码总结出的metadata数据结构
     一样的原理,也是通过更换了metadata来实现不同数据的取值,这里不同的是转化前metadata就已经是修改后的。
     */
    
    let protocolMetaData = TargetProtocolMetadata(type: type, witness: 0)
    let protocolType = unsafeBitCast(protocolMetaData, to: AnyExtensions.Type.self)
    print("\(fieldName)->\(type)->\(protocolType.value(valuePtr))")
}

//3.获取V-Table,及执行函数方法
let vtableBuffer = descriptorPtr.pointee.firstVtableData.buffer(of: numericCast(descriptorPtr.pointee.size))

typealias Function = @convention(c) ()-> Void

var vmAddressSize = getsegbyname("__PAGEZERO").pointee.vmsize

for i in 0..

打印信息

Class Name: LGTeacher
Class type: Optional(swiftTest.LGTeacher)
age->Int->18
name->String->Kody
teach
teach1
teach2

六.还原TargetStructMetadata

还原结构体名称属性名称属性类型属性值

查看源码路线和TargetEnumMetadata一致,这里由于篇幅问题就不一一还原了。大概逻辑可以看看TargetEnumMetadata

TargetStructMetadata数据结构
  • 可以看出基本上与值类型的TargetEnumMetadata共用一套逻辑

  • Struct是结构体,它的内存地址就是指向的第一个元素。因此它的第一个属性偏移量肯定就为0

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

struct TargetStructDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer
    var name: TargetRelativeDirectPointer
    var accessFunctionPtr: TargetRelativeDirectPointer
    var fields: TargetRelativeDirectPointer

    var numFields: UInt32
    var fieldOffsetVectorOffset: UInt32
}

struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer
    var superClass: TargetRelativeDirectPointer
    var kind: UInt16
    var fieldRecordSize: UInt16
    var numField: UInt32
    
    //连续的内存空间存放我们的var变量/case的名称
    //UnsafeBufferPointer,连续的内存空间指针
    var fieldRecords: FieldRecordBuffer
    
    /*
     kind: FieldDescriptorKind(枚举值依次递增)
     Struct: 0x1
     Class
     Enum
     MultiPayloadEnum
     Protocol
     ClassProtocol
     ObjCProtocol
     ObjCClass
     */
}

struct FieldRecordBuffer {
    var element: Element
    
    //方式1.返回buffer连续内存空间
    mutating func buffer(count: Int) -> UnsafeMutableBufferPointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
        }
    }
    
    //方式2.根据下标获取数组元素
    mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
        }
    }
}

struct FieldRecord {
    var flags: UInt32
    var mangledTypeName: TargetRelativeDirectPointer
    var fieldName: TargetRelativeDirectPointer
    
    /*
     flags: FieldRecordFlags
     IsIndirectCase = 0x1,
     IsVar = 0x2,
     IsArtificial = 0x4,
     其它情况 = 0
     */
}

struct TargetRelativeDirectPointer {
    var offset: Int32

    mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer {
        let offset = self.offset
        return withUnsafePointer(to: &self) {
            /*
             注意:这里的$0必须转化为UnsafeRawPointer再执行advanced
             如果类型指针advanced会出问题。
             原始是:在介绍指针的时候说过,如果是类型指针的话,
             advanced(x)相当于移动该类型的内存大小*x。
             */
            return UnsafeMutableRawPointer(mutating: UnsafeRawPointer($0).advanced(by: numericCast(offset))).assumingMemoryBound(to: Pointee.self)
        }
    }
}

@_silgen_name("swift_getTypeByMangledNameInContext")
private func getTypeByMangledNameInContext(
    mangledNamePtr: UnsafePointer,
    mangledNameLength: Int,
    genericContext: UnsafeRawPointer?,
    genericArgs: UnsafeRawPointer?) -> Any.Type?

func getTypeByMangleName(
    mangledNamePtr: UnsafePointer,
    genericContext: UnsafeRawPointer?, metadata: UnsafeRawPointer) ->  Any.Type? {
        return getTypeByMangledNameInContext(mangledNamePtr: mangledNamePtr,
                                             mangledNameLength: getMangledTypeNameSize(mangledNamePtr),
                                             genericContext: UnsafeRawPointer(genericContext),
                                             genericArgs: getGenericArgs(metadata))
}

//参考HandyJson,暂时没找到测量mangledName的长度
func getMangledTypeNameSize(_ managedName: UnsafePointer) -> Int {
    // TODO: should find the actually size 
    return 256
}

//获取泛型参数在metadata中的偏移量
func getGenericArgumentOffset() -> Int {
    return 2
}

//如果有泛型参数,需要传入的泛型参数指针。参考HandyJson
func getGenericArgs(_ metadata: UnsafeRawPointer) -> UnsafeRawPointer? {
    let offSetPtr = metadata.advanced(by: getGenericArgumentOffset() * MemoryLayout.size).assumingMemoryBound(to: Int.self)
    if offSetPtr.pointee == 0 {
        return nil
    }
    return UnsafeRawPointer(offSetPtr)
}

main.swift

struct LGTeacher {
    var age = 18
    var name = "Kody"
}

protocol AnyExtensions {}

extension AnyExtensions {
    static func value(ptr: UnsafeRawPointer) -> Any {
        print(self)
        return ptr.assumingMemoryBound(to: self).pointee
    }
}

struct TargetProtocolMetadata {
    let type: Any.Type
    let witness: Int
}

var ptr = unsafeBitCast(LGTeacher.self as Any.Type, to: UnsafeMutablePointer.self)

print("Struct Kind: 0x\(String(ptr.pointee.kind, radix: 16))") //0x200 => Struct

let descriptorPtr = ptr.pointee.descriptor

print("Struct Name: \(String(cString: descriptorPtr.pointee.name.getMeasureRelativeOffset()))")

let fieldDescriptor = ptr.pointee.descriptor.pointee.fields.getMeasureRelativeOffset()

print("Struct Type: \(getTypeByMangleName(mangledNamePtr: fieldDescriptor.pointee.mangledTypeName.getMeasureRelativeOffset(), genericContext: descriptorPtr, metadata: ptr) as Any)")

/*
 获取属性偏移信息
 Struct和Class不一致,Class每8字节存放偏移信息。Struct每4字节存放偏移信息
 */
let offSets = UnsafeRawPointer(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self).advanced(by: numericCast(descriptorPtr.pointee.fieldOffsetVectorOffset))).assumingMemoryBound(to: Int32.self)

var t = LGTeacher()

let instanceAddress = withUnsafePointer(to: &t) {$0}

for i in 0..\(fieldType)->\(value)")
}

打印信息

Struct Kind: 0x200
Struct Name: LGTeacher
Struct Type: Optional(swiftTest.LGTeacher)
Int
age->Int->18
String
name->String->Kody

问题1:关于fieldOffsetVectorOffset的值

fieldOffsetVectorOffset表示基于matadata的偏移量。如果没有其它数据的影响的话(比如说继承,继承后fieldOffsetVectorOffset+1),就存放在metadata的后面。

TargetClassMetadata大小就是10x8字节,因此对应的fieldOffsetVectorOffset为10。
TargetStructMetadata大小就是2x8字节,因此对应的fieldOffsetVectorOffset为2。

对于偏移值来说

对于Class来说,第一个偏移信息肯定为16。除去HeapObject内存大小
对于Struct来说,第一个偏移信息肯定为0。值类型数据,空间地址就是第一条数据内存空间

问题2:关于变量偏移信息,Class每8字节存放偏移信息。Struct每4字节存放偏移信息

暂未在源码中找到相应的逻辑

七.关于HandyJson源码理解

待完善

你可能感兴趣的:(Swift -- 6.Mirror源码解析)