欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談在Swift中關(guān)于函數(shù)指針的實現(xiàn)

 更新時間:2015年07月16日 10:32:02   投稿:goldensun  
這篇文章主要介紹了淺談在Swift中關(guān)于函數(shù)指針的實現(xiàn),是作者根據(jù)C語言的指針特性在Swifft中做出的一個實驗,需要的朋友可以參考下

Swift沒有什么?

蘋果工程師給我建的唯一一堵墻是:在Swift中沒有任何辦法獲得一個函數(shù)的指針:

    注意,C函數(shù)指針不會導(dǎo)入到Swift中(來自“Using Swift with Cocoa and Objective-C“)

但是我們怎么知道這種情況下鉤子的地址和跳到哪呢?讓我們深入了解一下,并且看看Swift的func在字節(jié)碼層面上的是什么。

當(dāng)你給一個函數(shù)傳遞一個泛型參數(shù)時,Swift并沒有直接傳遞它的地址,而是一個指向trampoline函數(shù)(見下文)并帶有一些函數(shù)元數(shù)據(jù)信息的指針。并且trampoline自己是包裝原始函數(shù)的結(jié)構(gòu)的一部分。

這是什么意思?

讓我們用它來舉個例子:
 

復(fù)制代碼 代碼如下:

func call_function(f : () -> Int) {
    let b = f()
}
 
func someFunction() -> Int {
    return 0
}

在Swift里我們只寫 call_function(someFunction).
但是 Swift 編譯器處理代碼后,性能比調(diào)用call_function(&someFunction)好很多
 

復(fù)制代碼 代碼如下:

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

一個包裝器的結(jié)構(gòu)如下:  
 

復(fù)制代碼 代碼如下:

struct swift_func_wrapper {
    uint64_t **trampoline_ptr_ptr; // = &trampoline_ptr
    uint64_t *trampoline_ptr;
    struct swift_func_object *object;
}

什么是 swift_func_object類型? 為了創(chuàng)建對象,Swift 實時使用了一個全局的叫metadata[N]的的常量(每一個 function調(diào)用都是唯一的,似的你的func 作為一個泛型的參數(shù),所以對于如下的代碼:  
 

復(fù)制代碼 代碼如下:

func callf(f: () -> ()) {
    f();
}
callf(someFunction);
callf(someFunction);

常量metadata和metadata2會被創(chuàng)建).

一個metadata[N]的結(jié)構(gòu)有點兒像這樣this:
 

復(fù)制代碼 代碼如下:

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

最初metadataN只有2個字段集合:destructor_func 和 type。前者是一個函數(shù)指針,將用作為使用swift_allocObject() 創(chuàng)建的對象分配內(nèi)存。后者是對象類型識別器(函數(shù)或方法的0x40 或者 '@'),并且是(某種形式)被swift_allocObject() 用來創(chuàng)建一個正確的對象給我們的func: 
 
swift_allocObject(&metadata2->type, 0x20, 0x7);

一旦func 對象被創(chuàng)建,它擁有下面的結(jié)構(gòu):
 

復(fù)制代碼 代碼如下:

struct swift_func_object {
    uint64_t *original_type_ptr;
    uint64_t *unknown0;
    uint64_t function_address;
    uint64_t *self;
}

第一個字段是一個指針,用來對應(yīng)metadata[N]->type 的值,第二個字段似乎是 0x4 | 1 << 24(0x100000004) 并且暗示一些可能 (我不知道是什么)。  function_address 是我們實際掛鉤感興趣的地方,并且self 是 (立即) 自己的指針 (如果我們的對象表示一個普通的函數(shù),這個字段是 NULL)。


好,那么這段我從框架開始如何?事實上,我不明白為什么Swift運行時需要它們,但不論如何,這就是它們原生態(tài)的樣子:
 

復(fù)制代碼 代碼如下:

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

讓我們創(chuàng)建它

想象一下,在你的Swift代碼中有這些函數(shù):

 

復(fù)制代碼 代碼如下:

func takesFunc<T>(f : T) {
    ...
}
func someFunction() {
    ...
}

而且你想像這樣生成它們:
 

復(fù)制代碼 代碼如下:

takesFunc(someFunction)

這一行代碼會轉(zhuǎn)換成相當(dāng)大的C程序:
 

復(fù)制代碼 代碼如下:

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

結(jié)構(gòu)體“swift_func_type_metadata”很不透明,因此我也沒太多可以說的。

回到函數(shù)指針

既然我們已經(jīng)知道函數(shù)怎樣作為一個泛型類型參數(shù)表示,讓我們借助這個打到你的目的:獲取一個真正指向函數(shù)的指針!

我們要做的只是需要注意,我們已經(jīng)擁有一個作為第一個參數(shù)傳遞的trampoline_ptr指針域地址,所以object域的偏移量只是0x8。其他的所有都很容易組合:
 

復(fù)制代碼 代碼如下:

uint64_t _rd_get_func_impl(void *trampoline_ptr)
{
    struct swift_func_object *obj = (struct swift_func_object *)*(uint64_t *)(trampoline_ptr + 0x8);
 
    return obj->function_address;
}

看起來是時候?qū)憣?/p>

 

復(fù)制代碼 代碼如下:

rd_route(
    _rd_get_func_impl(firstFunction),
    _rd_get_func_impl(secondFunction),
    nil
)

但我們怎樣從Swift中調(diào)用這些C函數(shù)呢?

為此,我們將使用Swift非公開的特性:允許我們提供給C函數(shù)一個Swift接口的@asmname屬性。用法如下:
 

復(fù)制代碼 代碼如下:

@asmname("_rd_get_func_impl")
    func rd_get_func_impl<Q>(Q) -> UInt64; 
 
@asmname("rd_route")
    func rd_route(UInt64, UInt64, CMutablePointer<UInt64>) -> CInt;

這就是我們在Swift中使用rd_route()需要的一切。

但是它不能處理任何函數(shù)!

也就是說,你不能用rd_route()鉤住任何帶有泛型參數(shù)的函數(shù)(這可能是Swift的bug,也可能不是,我還沒弄清楚)。但是你可以使用extensions輕松的覆蓋它們,直接指定參數(shù)的類型:
 

復(fù)制代碼 代碼如下:

class DemoClass {
    class func template <T : CVarArg>(arg : T, _ num: Int) -> String {
        return "\(arg) and \(num)";
    }
}
 
DemoClass.template("Test", 5) // "Test and 5"
 
extension DemoClass {
    class func template(arg : String, _ num: Int) -> String {
        return "{String}";
    }
    class func template(arg : Int, _ num: Int) -> String {
        return "{Int}";
    }
}
 
-- Your extension's methods for String and Int will be preferred over the original ones */
DemoClass.template("Test", 5) -- "{String}"
DemoClass.template(42, 5) -- "{Int}"
-- But for other types `template(T, Int)` will be used
DemoClass.template(["Array", "Item"], 5) --- "[Array, Item] and 5"

SWRoute

為了在Swift里輕松地勾住函數(shù),我創(chuàng)建了一個名為SWRoute的封裝體—它只是一個小類和一個我們之前寫過的C函數(shù):

復(fù)制代碼 代碼如下:
_rd_get_func_impl():
 
class SwiftRoute {
    class func replace<MethodT>(function targetMethod : MethodT, with replacement : MethodT) -> Int
    {
        return Int(rd_route(rd_get_func_impl(targetMethod), rd_get_func_impl(replacement), nil));
    }
}

注意,我們無償進(jìn)行類型檢查因為Swift需要目標(biāo)方法和替換具有相同的MethoT類型。

而且我們也無法使用一個復(fù)制的原始實現(xiàn),因此我只能把nil作為另一個參數(shù)傳給函數(shù)rd_route()。如果你對如何把這個指針集成到Swift代碼有自己的看法,麻煩告訴我!

你可以在資源庫中找到大量SWRoute的實例。

這就是所有的了。

相關(guān)文章

  • Combine中錯誤處理和Scheduler使用詳解

    Combine中錯誤處理和Scheduler使用詳解

    這篇文章主要為大家介紹了Combine中錯誤處理和Scheduler使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • iOS Swift讀取本地json文件報錯的解決方法

    iOS Swift讀取本地json文件報錯的解決方法

    只要是app開發(fā)者都知道,從服務(wù)器端獲得的數(shù)據(jù)要不就是json格式的數(shù)據(jù),要么就是xml格式的數(shù)據(jù),而這篇文章主要給大家介紹了關(guān)于iOS Swift讀取本地json文件報錯的解決方法,需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • Swift仿選擇電影票的效果并實現(xiàn)無限/自動輪播的方法

    Swift仿選擇電影票的效果并實現(xiàn)無限/自動輪播的方法

    這篇文章主要給大家介紹了關(guān)于Swift仿選擇電影票的效果并實現(xiàn)無限/自動輪播的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Swift中swift中的switch 語句

    Swift中swift中的switch 語句

    本文給大家介紹了swift中的swift語句,以及和c語音中的寫法區(qū)別,本文介紹的非常詳細(xì),需要的朋友參考下
    2016-12-12
  • 詳解Swift面向?qū)ο缶幊讨械姆椒?method)

    詳解Swift面向?qū)ο缶幊讨械姆椒?method)

    既然面向?qū)ο竽蔷鸵欢〞衜ethod,方法和面向過程語言中的function函數(shù)并沒什么區(qū)別,只不過方法在面向?qū)ο笳Z言中可以被類來約束作用域,這里我們就來詳解Swift面向?qū)ο缶幊讨械姆椒?method)
    2016-07-07
  • swift中可選值?和!使用的方法示例

    swift中可選值?和!使用的方法示例

    這篇文章主要給大家介紹了關(guān)于swift中可選值?和!使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • 詳談swift內(nèi)存管理中的引用計數(shù)

    詳談swift內(nèi)存管理中的引用計數(shù)

    下面小編就為大家?guī)硪黄斦剆wift內(nèi)存管理中的引用計數(shù)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Swift UILable 設(shè)置內(nèi)邊距實例代碼

    Swift UILable 設(shè)置內(nèi)邊距實例代碼

    本文主要介紹Swift UILable 設(shè)置內(nèi)邊距,這里提供示例代碼供大家參考,有需要的小伙伴可以看下
    2016-07-07
  • SpringBoot3.0集成Redis緩存的實現(xiàn)示例

    SpringBoot3.0集成Redis緩存的實現(xiàn)示例

    緩存就是一個存儲器,常用 Redis作為緩存數(shù)據(jù)庫,本文主要介紹了SpringBoot3.0集成Redis緩存的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • Swift源碼解析之弱引用

    Swift源碼解析之弱引用

    這篇文章主要給大家介紹了關(guān)于Swift源碼解析之弱引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評論