2017-07-29 79 views
6

有什麼方法可以訪問WebAssembly模塊內部的函數指針嗎?從JavaScript調用WebAssembly中的C風格函數指針

例如,給出下面的「模塊」編譯WebAssembly:

extern void set_callback(void (*callback)(void *arg), void *arg); 

static void callback(void *arg) 
{ 
    /* ... */ 
} 

int main() { 
    set_callback(&callback, 0); 
    return 0; 
} 

do_callback在JavaScript中實現可調用回調函數,而不必依賴中介C函數出口做實際的函數調用?

var instance = new WebAssembly.Instance(module, { 
    memory: /* ... */ 
    env: { 
    set_callback: function set_callback(callbackptr, argptr) { 
     // We only got the pointer, is there any 
    }, 
    }, 
}); 

通過中間函數導出,我的意思是我可以添加一個公共可見性的內部函數。

do_callback(void (*callback)(void *arg), void *arg) 
{ 
    callback(); 
} 

然後JavaScript的set_callback功能可以通過委託do_callback函數調用的函數的指針。

function set_callback(callbackptr, argptr) { 
    instance.exports.do_callback(callbackptr, argptr); 
} 

但是,最好做到這一點,而不必經過明確的間接,是否有可能,功能表也許呢?

回答

0

您可以從Javascript調用函數指針。

函數指針存儲在表中。當一個函數指針傳遞給Javascript時,你正在接收該函數指針表中的整數索引。將該索引傳遞給Table.prototype.get(),您可以調用該函數。

... 

set_callback: function set_callback(callbackptr, argptr) { 
    tbl.get(callbackptr)(argptr); 
}, 

... 

你可以閱讀更多關於這下表一節MDN頁: https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API#Tables

編輯:這裏是我用來測試這個小例子。

第一個文件fptr.c編譯emcc fptr.c -Os -s WASM=1 -s SIDE_MODULE=1 -o fptr.wasm

typedef int (*fptr_type)(void); 

extern void pass_fptr_to_js(fptr_type fptr); 

static int callback_0(void) 
{ 
    return 26; 
} 

static int callback_1(void) 
{ 
    return 42; 
} 

void run_test() 
{ 
    pass_fptr_to_js(callback_0); 
    pass_fptr_to_js(callback_1); 
} 

這裏是fptr.html

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>WebAssembly Experiment</title> 
</head> 
<body> 
    <h3>Check the console.</h3> 
    <script type="text/javascript"> 
     fetch('fptr.wasm').then(function(response) { 
      response.arrayBuffer().then(function(buffer) { 
       WebAssembly.compile(buffer).then(function(module) { 
        var imports = {}; 

        imports.env = {}; 

        imports.env.memoryBase = 0; 
        imports.env.memory = new WebAssembly.Memory({ initial: 256 }); 
        imports.env.tableBase = 0; 
        imports.env.table = new WebAssembly.Table({ initial: 4, element: 'anyfunc' }); 

        imports.env["abort"] = function() { 
         console.error("ABORT"); 
        }; 

        imports.env["_pass_fptr_to_js"] = function(fptr) { 
         console.log("table index: " + fptr + ", return value: " + imports.env.table.get(fptr)()); 
        }; 

        WebAssembly.instantiate(module, imports).then(function(instance) { 
         instance.exports["__post_instantiate"](); 
         instance.exports["_run_test"](); 
        }); 
       }); 
      }); 
     }); 
    </script> 
</body> 
</html> 
+0

嘗試這個已經作爲函數表的描述基本上是讀作「這是一個函數指針表,使用它適用於C風格函數指針「,但將表傳遞給模塊的導入描述符沒有明顯效果,並且表最終爲空? –

+0

@CasperBeyer我編輯了我的文章,包括我用來測試這個工作示例。 – Ghillie

+0

如何讓clang爲沒有Emscripten的表和內存生成導入?在鏈接器級別執行它?例如wasm-link與包含導入的「空」模塊? –