一.元类型、.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() //<LGTeacher: 0x101334100>
//实例对象
let t1 = t.self //<LGTeacher: 0x101334100>
//元类型(metadata)
let t2 = LGTeacher.self //(@thick swiftTest.LGTeacher.Type) t2 = swiftTest.LGTeacher
汇编探究swiftTest.LGTeacher
- 此时的
rax
其实就是元类型,也就是LGTeacher
的metadata
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
- 继承自
NSObject
的Swift
类,如果想要动态获取当前的属性和方法,必须在其声明之前添加@objc
关键字,否则也是没有办法通过Runtime Api
获取的 - 继承自
NSObject
的Swift
类,其继承自父类的方法具有动态性,其它自定义方法、属性想要获得动态性,需要添加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<String,Any>(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()
//▿ <LGTeacher: 0x10b156b70>
// - 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>(_: T, type: Any.Type) -> Any.Type
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
-
@_silgen_name
是Swift
的一个隐藏符号
,作用是将某个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>(_: 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<typename F>
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<const void * const *>(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<const EnumMetadata *>(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<StringRef /*name*/, FieldType /*fieldInfo*/>
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<StringRef, FieldType> {
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 |
那么这些值是怎么的来的呢?接下来通过源码分析一下
-
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<RuntimeTarget<sizeof(uintptr_t)>>;
//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<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
- 存在一个
Description
描述信息
3.进入TargetValueMetadata
父类TargetMetadata
(最终基类)
StoredPointer Kind;
4.此时我们就能确定TargetEnumMetadata
的外层结构结构
struct TargetEnumMetadata {
var kind: Int
var descriptor: UnsafePointer<TargetEnumDescriptor>
}
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 <typename Runtime>
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;
...
}
- 存有
Name
、AccessFunctionPtr
、Fields
3个变量,并且类型都是TargetRelativeDirectPointer
7.进入TargetTypeContextDescriptor
父类TargetContextDescriptor
(最终基类)
/// Base class for all context descriptors.
template<typename Runtime>
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;
...
}
using RelativeContextPointerIntPair =
RelativeIndirectablePointerIntPair<const Context<Runtime>, IntTy,
/*nullable*/ true, int32_t,
TargetSignedContextPointer<Runtime, Context>>;
-
Flags
大小为UInt32 -
Parent
类型为TargetRelativeContextPointer
8.总结一下TargetEnumMetadata
数据结构
9.关于TargetRelativeDirectPointer
和TargetRelativeContextPointer
相对地址的指针
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
using TargetRelativeContextPointer =
RelativeIndirectablePointer<const Context<Runtime>,
/*nullable*/ true, int32_t,
TargetSignedContextPointer<Runtime, Context>>;
/// 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;
};
-
类似于我们在
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<Pointee> {
var offset: Int32
mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
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<UInt8>,
mangledNameLength: Int,
genericContext: UnsafeRawPointer?,
genericArgs: UnsafeRawPointer?) -> Any.Type?
func getTypeByMangleName(
mangledNamePtr: UnsafePointer<UInt8>,
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<UInt8>) -> 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<UnsafeRawPointer>.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<UInt8>,
mangledNameLength: Int,
genericContext: UnsafeRawPointer?,
genericArgs: UnsafeRawPointer?) -> Any.Type?
func getTypeByMangleName(
mangledNamePtr: UnsafePointer<UInt8>,
genericContext: UnsafeRawPointer?) -> Any.Type? {
return getTypeByMangledNameInContext(mangledNamePtr: mangledNamePtr, mangledNameLength: getMangledTypeNameSize(mangleTypeNamePtr), genericContext: UnsafeRawPointer(genericContext), genericArgs: getGenericArgs(mangledNamePtr))
}
//参考HandyJson,暂时没找到测量mangledName的长度
func getMangledTypeNameSize(_ managedName: UnsafePointer<UInt8>) -> 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<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self))
}
TargetMetadata.swift
struct TargetEnumMetadata{
var kind: Int
var descriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}
struct TargetEnumDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPtr: TargetRelativeDirectPointer<UnsafeRawPointer>
var fields: TargetRelativeDirectPointer<FieldDescriptor>
var numPayloadCaseAndPayloadSizeOffset: UInt32
var numEmptyCases: UInt32
}
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<UInt8>
var superClass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: UInt16
var numField: UInt32
//连续的内存空间存放我们的var变量/case的名称
//UnsafeBufferPointer,连续的内存空间指针
var fieldRecords: FieldRecordBuffer<FieldRecord>
/*
kind: FieldDescriptorKind(枚举值依次递增)
Struct: 0x1
Class
Enum
MultiPayloadEnum
Protocol
ClassProtocol
ObjCProtocol
ObjCClass
*/
}
struct FieldRecordBuffer<Element> {
var element: Element
//方式1.返回buffer连续内存空间
mutating func buffer(count: Int) -> UnsafeMutableBufferPointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
}
}
//方式2.根据下标获取数组元素
mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
}
}
}
struct FieldRecord {
var flags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<UInt8>
var fieldName: TargetRelativeDirectPointer<CChar>
/*
flags: FieldRecordFlags
IsIndirectCase = 0x1,
IsVar = 0x2,
IsArtificial = 0x4,
其它情况 = 0
*/
}
struct TargetRelativeDirectPointer<Pointee> {
var offset: Int32
mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
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<TargetEnumMetadata>.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..<bufferPtr.count {
print("type:\(getTypeByMangleName(mangledNamePtr: bufferPtr[i].mangledTypeName.getMeasureRelativeOffset(), genericContext: ptr.pointee.descriptor, metadata: ptr) as Any) case值:\(String(cString: bufferPtr[i].fieldName.getMeasureRelativeOffset()))")
}
//方式2:使用指针位移的方式
//for i in 0..<fieldPtr.pointee.numField {
// let filedRecord = fieldPtr.pointee.fieldRecords.getFieldRecord(index: numericCast(i))
// //这里的flags为0
//
// print("type:\(getTypeByMangleName(mangledNamePtr: filedRecord.pointee.mangledTypeName.getMeasureRelativeOffset(), genericContext: ptr.pointee.descriptor) as Any) case值:\(String(cString: filedRecord.pointee.fieldName.getMeasureRelativeOffset()))")
//}
打印信息
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<TargetClassDescriptor>
var iVarDestroyer: UnsafeRawPointer
}
struct TargetClassDescriptor{
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
var superClassType: TargetRelativeDirectPointer<CChar>
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<VTable>
}
struct VTableBuffer<Element> {
var element: Element
mutating func buffer(of count: Int) -> UnsafeMutableBufferPointer<Element> {
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<UnsafeRawPointer>
}
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<UInt8>
var superClass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: UInt16
var numField: UInt32
//连续的内存空间存放我们的var变量/case的名称
//UnsafeBufferPointer,连续的内存空间指针
var fieldRecords: FieldRecordBuffer<FieldRecord>
/*
kind: FieldDescriptorKind(枚举值依次递增)
Struct: 0x1
Class
Enum
MultiPayloadEnum
Protocol
ClassProtocol
ObjCProtocol
ObjCClass
*/
}
struct FieldRecordBuffer<Element> {
var element: Element
//方式1.返回buffer连续内存空间
mutating func buffer(count: Int) -> UnsafeMutableBufferPointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
}
}
//方式2.根据下标获取数组元素
mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
}
}
}
struct FieldRecord {
var flags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<UInt8>
var fieldName: TargetRelativeDirectPointer<CChar>
/*
flags: FieldRecordFlags
IsIndirectCase = 0x1,
IsVar = 0x2,
IsArtificial = 0x4,
其它情况 = 0
*/
}
struct TargetRelativeDirectPointer<Pointee> {
var offset: Int32
mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
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<Pointee> {
var offset: UInt32
mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
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<TargetClassMetadata>.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..<fieldRecordBuffer.count {
let type = getTypeByMangleName(mangledNamePtr: fieldRecordBuffer[i].mangledTypeName.getMeasureRelativeOffset(), genericContext: descriptorPtr, metadata: ptr)!
let fieldName = String(cString: fieldRecordBuffer[i].fieldName.getMeasureRelativeOffset())
//获取属性偏移信息
let valueOffset = offsets[i]
/*
属性在内存中的实际地址
其实如果能够联想到前面的metadata,
此时的2个属性肯定是放在heapObject(16字节)后
大胆可以猜测一下这里的偏移量一个是16一个是24
*/
let valuePtr = tMetadataPtr.advanced(by: valueOffset)
//疑问:现在有了type怎么取出不同的值?
/*
方式1:根据HandyJson源码,利用协议里self/Self获取实际类型的特性。
将声明的Extensions的metadata更换为我们得知的metadata,利用协议方法内self/Self能够获取真实类型的特性,完成取值操作。
*/
//获取结构体的元数据,静态类型为AnyExtensions,动态类型为Extensions
struct Extensions: AnyExtensions {}
var extensions: AnyExtensions.Type = Extensions.self
//拿到extension的地址更换metadata
withUnsafePointer(to: &extensions) {
UnsafeMutableRawPointer(mutating: $0).assumingMemoryBound(to: Any.Type.self).pointee = type
}
//取值
// let value = extensions.value(valuePtr)
// print("\(fieldName)->\(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..<vtableBuffer.count {
if vtableBuffer[i].flags.kindType() == .Method {
let impOffsetPtr = vtableBuffer[i].methodImp.getMeasureRelativeOffset()
//当然,这里的减去虚拟内存基地址逻辑,还可以添加一个func在相对指针内部偏移时实现
let imp_Decimal = numericCast(Int(bitPattern: impOffsetPtr)) - vmAddressSize
let impPtr = UnsafeRawPointer(bitPattern: UInt(imp_Decimal))
let function = unsafeBitCast(impPtr, to: Function.self)
function()
}
}
打印信息
Class Name: LGTeacher
Class type: Optional(swiftTest.LGTeacher)
age->Int->18
name->String->Kody
teach
teach1
teach2
六.还原TargetStructMetadata
还原结构体名称
、属性名称
、属性类型
、属性值
查看源码路线和TargetEnumMetadata
一致,这里由于篇幅问题就不一一还原了。大概逻辑可以看看TargetEnumMetadata
-
可以看出基本上与值类型的
TargetEnumMetadata
共用一套逻辑 -
Struct
是结构体,它的内存地址就是指向的第一个元素。因此它的第一个属性偏移量肯定就为0
struct TargetStructMetadata {
var kind: Int
var descriptor: UnsafeMutablePointer<TargetStructDescriptor>
}
struct TargetStructDescriptor {
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var name: TargetRelativeDirectPointer<CChar>
var accessFunctionPtr: TargetRelativeDirectPointer<UnsafeRawPointer>
var fields: TargetRelativeDirectPointer<FieldDescriptor>
var numFields: UInt32
var fieldOffsetVectorOffset: UInt32
}
struct FieldDescriptor {
var mangledTypeName: TargetRelativeDirectPointer<UInt8>
var superClass: TargetRelativeDirectPointer<CChar>
var kind: UInt16
var fieldRecordSize: UInt16
var numField: UInt32
//连续的内存空间存放我们的var变量/case的名称
//UnsafeBufferPointer,连续的内存空间指针
var fieldRecords: FieldRecordBuffer<FieldRecord>
/*
kind: FieldDescriptorKind(枚举值依次递增)
Struct: 0x1
Class
Enum
MultiPayloadEnum
Protocol
ClassProtocol
ObjCProtocol
ObjCClass
*/
}
struct FieldRecordBuffer<Element> {
var element: Element
//方式1.返回buffer连续内存空间
mutating func buffer(count: Int) -> UnsafeMutableBufferPointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count))
}
}
//方式2.根据下标获取数组元素
mutating func getFieldRecord(index: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self))
}
}
}
struct FieldRecord {
var flags: UInt32
var mangledTypeName: TargetRelativeDirectPointer<UInt8>
var fieldName: TargetRelativeDirectPointer<CChar>
/*
flags: FieldRecordFlags
IsIndirectCase = 0x1,
IsVar = 0x2,
IsArtificial = 0x4,
其它情况 = 0
*/
}
struct TargetRelativeDirectPointer<Pointee> {
var offset: Int32
mutating func getMeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
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<UInt8>,
mangledNameLength: Int,
genericContext: UnsafeRawPointer?,
genericArgs: UnsafeRawPointer?) -> Any.Type?
func getTypeByMangleName(
mangledNamePtr: UnsafePointer<UInt8>,
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<UInt8>) -> 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<UnsafeRawPointer>.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<TargetStructMetadata>.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..<descriptorPtr.pointee.numFields {
let fieldRecordPtr = fieldDescriptor.pointee.fieldRecords.getFieldRecord(index: numericCast(i))
let fieldType = getTypeByMangleName(mangledNamePtr: fieldRecordPtr.pointee.mangledTypeName.getMeasureRelativeOffset(), genericContext: descriptorPtr, metadata: ptr)!
let fieldName = String(cString: fieldRecordPtr.pointee.fieldName.getMeasureRelativeOffset())
//方式1:
// struct Extensions: AnyExtensions {}
// var extensions: AnyExtensions.Type = Extensions.self
// withUnsafePointer(to: &extensions) {
// UnsafeMutableRawPointer(mutating: $0).assumingMemoryBound(to: Any.Type.self).pointee = fieldType
// }
// let value = extensions.value(ptr: UnsafeRawPointer(instanceAddress).advanced(by: Int(offSets[numericCast(i)])))
//
//方式2:
let structMetadata = TargetProtocolMetadata(type: fieldType, witness: 0)
let protocolType = unsafeBitCast(structMetadata, to: AnyExtensions.Type.self)
let value = protocolType.value(ptr: UnsafeRawPointer(instanceAddress).advanced(by: Int(offSets[numericCast(i)])))
print("\(fieldName)->\(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源码理解
待完善
网友评论