2017-07-29 54 views
6

Czy istnieje sposób na uzyskanie dostępu do wskaźników funkcji znajdujących się w module WebAssembly?Wywołanie wskaźnika funkcji stylu C w zespole WebAssembly z JavaScript

Na przykład, biorąc pod uwagę następujące „module” skompilowany do WebAssembly:

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

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

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

Czy implementacja do_callback w JavaScript powołać się na oddzwanianie bez konieczności polegania na pośredniczącego eksportu funkcji C zrobić rzeczywiste wywołanie funkcji ?

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

Przez eksport funkcji pośrednika, mam na myśli, że mogę dodać funkcję wewnętrzną z widocznością publiczną.

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

Następnie funkcja JavaScript set_callback może wywołać wskaźnik funkcji za pośrednictwem delegata do_callback funkcji.

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

Ale lepiej jest to zrobić bez konieczności przechodzenia przez ten wyraźnej zadnie, czy to możliwe, ze stołami funkcyjnych może być?

Odpowiedz

0

Możesz wywołać wskaźniki funkcji z Javascript.

Wskaźniki funkcji są przechowywane w tabeli. Kiedy wskaźnik funkcji jest przekazywany do Javascript, otrzymujesz indeks liczby całkowitej do tabeli dla tego wskaźnika funkcji. Przekaż ten indeks do Table.prototype.get() i możesz wywołać funkcję.

... 

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

... 

Możesz przeczytać więcej na ten temat na tej stronie MDN ramach sekcji tabelach: https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API#Tables

Edycja: Oto minimalne przykład kiedyś przetestować.

Pierwszy plik jest fptr.c skompilowany z 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); 
} 

A oto 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

Tried to już jako opis tabel funkcyjnych w zasadzie brzmi „to jest stół wskaźnik funkcji, wykorzystanie to jest dla wskaźników funkcyjnych w stylu C ", ale przekazywanie tabel do deskryptora importu modułu nie ma zauważalnego efektu, a tabela kończy się być pusta? –

+0

@CasperBeyer Edytowałem swój wpis, aby uwzględnić przykład pracy, którego użyłem do przetestowania tego. – Ghillie

+0

Jak uzyskać clang do generowania importu dla tabeli i pamięci bez Emscripten? Zrób to na poziomie linkera? np. wasm-link z "pustym" modułem zawierającym import? –