Swift-进阶 01:Swift源码编译

Swift-进阶 01:Swift源码编译,第1张

准备工作

第一步:clone swift 源码

swift源码版本需要与 Xcode 版本匹配(Xcode 12.2对应 swift-5.3.1-Release ) swift源码地址

第二步:update-checkout

这步主要是 clone 编译swift 相关的库

第三步:采用ninja编译

第四步:使用VSCode调试Swift

本文不涉及如何使用,仅对齐实现原理作一个记录。

Swift中,一个类实例的内存布局是有规律的:

这方面尚未从官方的资料找到参考,上述规律一些是从网上其他大神的总结中收集,一些从Clang的一些说明文档中挖掘,加上自己的反复验证得到

HandyJSON 是强依赖 metadata 结构的,如果 metadata 有大规模的改动可能直接导致这个库完全不能用。随着Swift语言的版本升级。metadata的结构也有多次变动。

Swift 4.2 对 nominal type descriptor 做了调整,struct 和 class 结构变得有所不同,乍看没有少什么东西,其实对 fieldTypesAccessor 这个函数做了修改,不再符合 c 的 calling convention,因此不可以再从 nominal type descriptor 获取类型信息。

尽管苹果希望我们用 Mirror 来做反射,但是其实 Mirror 至今为止都不包含属性的类型的信息,因此苹果留了一个临时接口 swift_getFieldAt 来帮助我们获取类型信息:

为什么说是临时的呢,因为 Swift 5 的时候就发现这个接口没了。。。。

到了 Swift 5.0 的时候,前面已经说过了获取类型的那个接口没了,那么我们只好翻出 Swift 的源码来找找思路了,

找到 TypeContextDescriptorBuilderBase 类的 layout() 方法:

按源码写出 nominal type descriptor 的结构如下:

虽然 fieldTypesAccessor 还是无法调用,但是我们发现这里多了一个 reflectionFieldDescriptor 指针,直觉告诉我办法应该在这个东西里面,所以先看下这个东西是什么结构:

逻辑基本就是拿到 ReflectionFieldDescriptor 的地址,然后把地址放到相应的内存里,需要注意的是这里放的是一个相对的地址,RelativePointer 的注释中写道:

// A reference can be absolute or relative: // // - An absolute reference is a pointer to the object. // // - A relative reference is a (signed) offset from the address of the // reference to the address of its direct referent.

相对引用指的是相对当前引用指针地址的偏移量,于是我们有了获取 ReflectionFieldDescriptor 地址的方法:

拿到了地址,我们还需要知道 FieldDescriptor 这个结构是什么样子的,我们找到 FieldDescriptor 这个类:

FieldDescriptor 的结构里有一个 FieldRecord 的数组,从名字看里面应该保存了类型信息,我们再翻出 FieldRecord 的源码:

很遗憾 FieldRecord 并没有直接保存类型信息,只有一个 MangledTypeName ,问题不大,我们还有一个叫 swift_getTypeByMangledNameInContext 的函数,这个函数背后调用的 swift_getTypeByMangledName 函数与之前的 getFieldAt 内部调用的是同一个函数,返回是 Any.Type :

参考:

Swift 5 Type Metadata 详解

Metadata官方文档

深度解析HandyJSON

swift之内存布局

Swift内存赋值探索二: 指针在Swift中的使用


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11438841.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-16
下一篇 2023-05-16

发表评论

登录后才能评论

评论列表(0条)

保存