Swift没有什么?
苹果工程师给我建的唯一一堵墙是:在Swift中没有任何办法获得一个函数的指针:
注意,C函数指针不会导入到Swift中(来自“Using Swift with Cocoa and Objective-C“)
但是我们怎么知道这种情况下钩子的地址和跳到哪呢?让我们深入了解一下,并且看看Swift的func在字节码层面上的是什么。
当你给一个函数传递一个泛型参数时,Swift并没有直接传递它的地址,而是一个指向trampoline函数(见下文)并带有一些函数元数据信息的指针。并且trampoline自己是包装原始函数的结构的一部分。
这是什么意思?
让我们用它来举个例子:
func call_function(f : () -> Int) {
let b = f()
}
func someFunction() -> Int {
return 0
}</div>
在Swift里我们只写 call_function(someFunction).
但是 Swift 编译器处理代码后,性能比调用call_function(&someFunction)好很多
struct swift_func_wrapper *wrapper = ... /* configure wrapper for someFunction() */
struct swift_func_type_metadata *type_metadata = ... /* information about function's arguments and return type */
call_function(wrapper->trampoline, type_metadata);</div>
一个包装器的结构如下:
struct swift_func_wrapper {
uint64_t **trampoline_ptr_ptr; // = &trampoline_ptr
uint64_t *trampoline_ptr;
struct swift_func_object *object;
}</div>
什么是 swift_func_object类型? 为了创建对象,Swift 实时使用了一个全局的叫metadata[N]的的常量(每一个 function调用都是唯一的,似的你的func 作为一个泛型的参数,所以对于如下的代码:
func callf(f: () -> ()) {
f();
}
callf(someFunction);
callf(someFunction);</div>
常量metadata和metadata2会被创建).
一个metadata[N]的结构有点儿像这样this:
struct metadata {
uint64_t *destructor_func;
uint64_t *unknown0;
const char type:1; // I'm not sure about this and padding,
char padding[7]; // maybe it's just a uint64_t too...
uint64_t *self;
}</div>
最初metadataN只有2个字段集合:destructor_func 和 type。前者是一个函数指针,将用作为使用swift_allocObject() 创建的对象分配内存。后者是对象类型识别器(函数或方法的0x40 或者 '@'),并且是(某种形式)被swift_allocObject() 用来创建一个正确的对象给我们的func:
swift_allocObject(&metadata2->type, 0x20, 0x7);
一旦func 对象被创建,它拥有下面的结构:
struct swift_func_object {
uint64_t *original_type_ptr;
uint64_t *unknown0;
uint64_t function_address;
uint64_t *self;
}</div>
第一个字段是一个指针,用来对应metadata[N]->type 的值,第二个字段似乎是 0x4 | 1 << 24(0x100000004) 并且暗示一些可能 (我不知道是什么)。 function_address 是我们实际挂钩感兴趣的地方,并且self 是 (立即) 自己的指针 (如果我们的对象表示一个普通的函数,这个字段是 NULL)。
好,那么这段我从框架开始如何?事实上,我不明白为什么Swift运行时需要它们,但不论如何,这就是它们原生态的样子:
void* someFunction_Trampoline(void *unknown, void *arg, struct swift_func_object *desc)
{
void* target_function = (void *)desc->function_address;
uint64_t *self = desc->self;
swift_retain_noresult(desc->self); // yeah, retaining self is cool!
swift_release(desc);
_swift_Trampoline(unknown, arg, target_function, self);
return unknown;
}
void *_swift_Trampoline(void *unknown, void *arg, void *target_function, void *self)
{
target_function(arg, self);
return unknown;
}</div>
让我们创建它
想象一下,在你的Swift代码中有这些函数:
func takesFunc<T>(f : T) {
...
}
func someFunction() {
...
}</div>
而且你想像这样生成它们:
takesFunc(someFunction)</div>
这一行代码会转换成相当大的C程序:
struct swift_func_wrapper *wrapper = malloc(sizeof(*wrapper));
wrapper->trampoline_ptr = &someFunction_Trampoline;
wrapper->trampoline_ptr_ptr = &(wrapper.trampoline);
wrapper->object = ({
// let's say the metadata for this function is `metadata2`
struct swift_func_object *object = swift_allocObject(&metadata2->type, 0x20, 0x7);
object->function_address = &someFunction;
object->self = NULL;
object;
});
// global constant for the type of someFunction's arguments
const void *arg_type = &kSomeFunctionArgumentsTypeDescription;
// global constant for the return type of someFunction
const void *return_type = &kSomeFunctionReturnTypeDescription;
struct swift_func_type_metadata *type_metadata = swift_getFunctionTypeMetadata(arg_type, return_type);
takesFunc(wrapper->trampoline_ptr, type_metadata);</div>
结构体“sw