2017-07-29 16 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; 
} 

JavaScriptでdo_callbackの実装では、実際の関数呼び出しを行うために仲介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.cemcc 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

Emscriptenを使用せずにテーブルとメモリのインポートを生成するclangをどうすればできますか?リンカーレベルでそれを行いますか?例えば、輸入品を含む「空の」モジュールとwasm-link? –

関連する問題