Implement RFC 11: Redesigning Wasmtime's APIs (#2897)
Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
@@ -42,8 +42,9 @@ int main() {
|
||||
|
||||
// With an engine we can create a *store* which is a long-lived group of wasm
|
||||
// modules.
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Read our input file, which in this case is a wasm text file.
|
||||
FILE* file = fopen("examples/externref.wat", "r");
|
||||
@@ -58,15 +59,15 @@ int main() {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Now that we've got our binary webassembly we can compile our module.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) wasm.data, wasm.size, &module);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
@@ -74,104 +75,99 @@ int main() {
|
||||
// Instantiate the module.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
wasmtime_instance_t instance;
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
printf("Creating new `externref`...\n");
|
||||
|
||||
// Create a new `externref` value.
|
||||
//
|
||||
// Note that if you need clean up for after the externref is reclaimed, you
|
||||
// can use `wasmtime_externref_new_with_finalizer`.
|
||||
wasm_val_t externref;
|
||||
wasmtime_externref_new("Hello, World!", &externref);
|
||||
assert(externref.kind == WASM_ANYREF);
|
||||
// Note that the NULL here is a finalizer callback, but we don't need one for
|
||||
// this example.
|
||||
wasmtime_externref_t *externref = wasmtime_externref_new("Hello, World!", NULL);
|
||||
|
||||
// The `externref`'s wrapped data should be the string "Hello, World!".
|
||||
void* data = NULL;
|
||||
ok = wasmtime_externref_data(&externref, &data);
|
||||
assert(ok);
|
||||
void* data = wasmtime_externref_data(externref);
|
||||
assert(strcmp((char*)data, "Hello, World!") == 0);
|
||||
|
||||
printf("Touching `externref` table...\n");
|
||||
|
||||
wasmtime_extern_t item;
|
||||
|
||||
// Lookup the `table` export.
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 3);
|
||||
wasm_table_t *table = wasm_extern_as_table(externs.data[0]);
|
||||
assert(table != NULL);
|
||||
ok = wasmtime_instance_export_get(context, &instance, "table", strlen("table"), &item);
|
||||
assert(ok);
|
||||
assert(item.kind == WASMTIME_EXTERN_TABLE);
|
||||
|
||||
// Set `table[3]` to our `externref`.
|
||||
wasm_val_t elem;
|
||||
wasm_val_copy(&elem, &externref);
|
||||
assert(elem.kind == WASM_ANYREF);
|
||||
ok = wasm_table_set(table, 3, elem.of.ref);
|
||||
assert(ok);
|
||||
wasmtime_val_t externref_val;
|
||||
externref_val.kind = WASMTIME_EXTERNREF;
|
||||
externref_val.of.externref = externref;
|
||||
error = wasmtime_table_set(context, &item.of.table, 3, &externref_val);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to set table", error, NULL);
|
||||
|
||||
// `table[3]` should now be our `externref`.
|
||||
wasm_ref_delete(elem.of.ref);
|
||||
elem.of.ref = wasm_table_get(table, 3);
|
||||
assert(elem.of.ref != NULL);
|
||||
assert(wasm_ref_same(elem.of.ref, externref.of.ref));
|
||||
wasmtime_val_t elem;
|
||||
ok = wasmtime_table_get(context, &item.of.table, 3, &elem);
|
||||
assert(ok);
|
||||
assert(elem.kind == WASMTIME_EXTERNREF);
|
||||
assert(strcmp((char*)wasmtime_externref_data(elem.of.externref), "Hello, World!") == 0);
|
||||
wasmtime_val_delete(&elem);
|
||||
|
||||
printf("Touching `externref` global...\n");
|
||||
|
||||
// Lookup the `global` export.
|
||||
wasm_global_t *global = wasm_extern_as_global(externs.data[1]);
|
||||
assert(global != NULL);
|
||||
ok = wasmtime_instance_export_get(context, &instance, "global", strlen("global"), &item);
|
||||
assert(ok);
|
||||
assert(item.kind == WASMTIME_EXTERN_GLOBAL);
|
||||
|
||||
// Set the global to our `externref`.
|
||||
wasm_global_set(global, &externref);
|
||||
error = wasmtime_global_set(context, &item.of.global, &externref_val);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to set global", error, NULL);
|
||||
|
||||
// Get the global, and it should return our `externref` again.
|
||||
wasm_val_t global_val;
|
||||
wasm_global_get(global, &global_val);
|
||||
assert(global_val.kind == WASM_ANYREF);
|
||||
assert(wasm_ref_same(global_val.of.ref, externref.of.ref));
|
||||
wasmtime_val_t global_val;
|
||||
wasmtime_global_get(context, &item.of.global, &global_val);
|
||||
assert(global_val.kind == WASMTIME_EXTERNREF);
|
||||
assert(strcmp((char*)wasmtime_externref_data(elem.of.externref), "Hello, World!") == 0);
|
||||
wasmtime_val_delete(&global_val);
|
||||
|
||||
printf("Calling `externref` func...\n");
|
||||
|
||||
// Lookup the `func` export.
|
||||
wasm_func_t *func = wasm_extern_as_func(externs.data[2]);
|
||||
assert(func != NULL);
|
||||
ok = wasmtime_instance_export_get(context, &instance, "func", strlen("func"), &item);
|
||||
assert(ok);
|
||||
assert(item.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// And call it!
|
||||
wasm_val_t args[1] = { externref };
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
error = wasmtime_func_call(func, &args_vec, &results_vec, &trap);
|
||||
wasmtime_val_t results[1];
|
||||
error = wasmtime_func_call(context, &item.of.func, &externref_val, 1, results, 1, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
|
||||
// `func` returns the same reference we gave it, so `results[0]` should be our
|
||||
// `externref`.
|
||||
assert(results[0].kind == WASM_ANYREF);
|
||||
assert(wasm_ref_same(results[0].of.ref, externref.of.ref));
|
||||
assert(results[0].kind == WASMTIME_EXTERNREF);
|
||||
assert(strcmp((char*)wasmtime_externref_data(results[0].of.externref), "Hello, World!") == 0);
|
||||
wasmtime_val_delete(&results[0]);
|
||||
|
||||
// We can GC any now-unused references to our externref that the store is
|
||||
// holding.
|
||||
printf("GCing within the store...\n");
|
||||
wasmtime_store_gc(store);
|
||||
wasmtime_context_gc(context);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
printf("All finished!\n");
|
||||
ret = 0;
|
||||
|
||||
wasm_val_delete(&results[0]);
|
||||
wasm_val_delete(&global_val);
|
||||
wasm_val_delete(&elem);
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_val_delete(&externref);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_store_delete(store);
|
||||
wasmtime_module_delete(module);
|
||||
wasm_engine_delete(engine);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
|
||||
|
||||
@@ -10,14 +10,13 @@ fn main() -> Result<()> {
|
||||
let mut config = Config::new();
|
||||
config.wasm_reference_types(true);
|
||||
let engine = Engine::new(&config)?;
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
|
||||
println!("Compiling module...");
|
||||
let module = Module::from_file(&engine, "examples/externref.wat")?;
|
||||
|
||||
println!("Instantiating module...");
|
||||
let imports = [];
|
||||
let instance = Instance::new(&store, &module, &imports)?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
println!("Creating new `externref`...");
|
||||
let externref = ExternRef::new("Hello, World!");
|
||||
@@ -28,20 +27,25 @@ fn main() -> Result<()> {
|
||||
);
|
||||
|
||||
println!("Touching `externref` table...");
|
||||
let table = instance.get_table("table").unwrap();
|
||||
table.set(3, Some(externref.clone()).into())?;
|
||||
let elem = table.get(3).unwrap().unwrap_externref().unwrap();
|
||||
let table = instance.get_table(&mut store, "table").unwrap();
|
||||
table.set(&mut store, 3, Some(externref.clone()).into())?;
|
||||
let elem = table
|
||||
.get(&mut store, 3)
|
||||
.unwrap() // assert in bounds
|
||||
.unwrap_externref() // assert it's an externref table
|
||||
.unwrap(); // assert the externref isn't null
|
||||
assert!(elem.ptr_eq(&externref));
|
||||
|
||||
println!("Touching `externref` global...");
|
||||
let global = instance.get_global("global").unwrap();
|
||||
global.set(Some(externref.clone()).into())?;
|
||||
let global_val = global.get().unwrap_externref().unwrap();
|
||||
let global = instance.get_global(&mut store, "global").unwrap();
|
||||
global.set(&mut store, Some(externref.clone()).into())?;
|
||||
let global_val = global.get(&mut store).unwrap_externref().unwrap();
|
||||
assert!(global_val.ptr_eq(&externref));
|
||||
|
||||
println!("Calling `externref` func...");
|
||||
let func = instance.get_typed_func::<Option<ExternRef>, Option<ExternRef>>("func")?;
|
||||
let ret = func.call(Some(externref.clone()))?;
|
||||
let func =
|
||||
instance.get_typed_func::<Option<ExternRef>, Option<ExternRef>, _>(&mut store, "func")?;
|
||||
let ret = func.call(&mut store, Some(externref.clone()))?;
|
||||
assert!(ret.is_some());
|
||||
assert!(ret.unwrap().ptr_eq(&externref));
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <wasm.h>
|
||||
#include "wasmtime.h"
|
||||
#include <wasmtime.h>
|
||||
|
||||
#define own
|
||||
|
||||
@@ -20,7 +19,8 @@ int main(int argc, const char* argv[]) {
|
||||
// Initialize.
|
||||
printf("Initializing...\n");
|
||||
wasm_engine_t* engine = wasm_engine_new_with_config(config);
|
||||
wasm_store_t* store = wasm_store_new(engine);
|
||||
wasmtime_store_t* store = wasmtime_store_new(engine, NULL, NULL);
|
||||
wasmtime_context_t* context = wasmtime_store_context(store);
|
||||
|
||||
// Load binary.
|
||||
printf("Loading binary...\n");
|
||||
@@ -42,75 +42,42 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
// Compile.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
wasmtime_error_t* error = wasmtime_module_new(engine, &binary, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
wasmtime_error_t* error = wasmtime_module_new(engine, (uint8_t*) binary.data, binary.size, &module);
|
||||
if (!module)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
wasm_byte_vec_delete(&binary);
|
||||
|
||||
// Figure out which export is the `fib` export
|
||||
wasm_exporttype_vec_t module_exports;
|
||||
wasm_module_exports(module, &module_exports);
|
||||
int fib_idx = -1;
|
||||
for (int i = 0; i < module_exports.size; i++) {
|
||||
const wasm_name_t *name = wasm_exporttype_name(module_exports.data[i]);
|
||||
if (name->size != 3)
|
||||
continue;
|
||||
if (strncmp("fib", name->data, 3) != 0)
|
||||
continue;
|
||||
fib_idx = i;
|
||||
break;
|
||||
}
|
||||
wasm_exporttype_vec_delete(&module_exports);
|
||||
if (fib_idx == -1) {
|
||||
printf("> Error finding `fib` export!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_instance_t* instance = NULL;
|
||||
wasmtime_instance_t instance;
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
wasm_module_delete(module);
|
||||
wasmtime_module_delete(module);
|
||||
|
||||
// Extract export.
|
||||
printf("Extracting export...\n");
|
||||
own wasm_extern_vec_t exports;
|
||||
wasm_instance_exports(instance, &exports);
|
||||
if (exports.size == 0) {
|
||||
printf("> Error accessing exports!\n");
|
||||
return 1;
|
||||
}
|
||||
// Getting second export (first is memory).
|
||||
wasm_func_t* run_func = wasm_extern_as_func(exports.data[fib_idx]);
|
||||
if (run_func == NULL) {
|
||||
printf("> Error accessing export!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_instance_delete(instance);
|
||||
wasmtime_extern_t fib;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "fib", 3, &fib);
|
||||
assert(ok);
|
||||
|
||||
// Call.
|
||||
printf("Calling fib...\n");
|
||||
wasm_val_t params[1] = { WASM_I32_VAL(6) };
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t params_vec = WASM_ARRAY_VEC(params);
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
error = wasmtime_func_call(run_func, ¶ms_vec, &results_vec, &trap);
|
||||
wasmtime_val_t params[1];
|
||||
params[0].kind = WASMTIME_I32;
|
||||
params[0].of.i32 = 6;
|
||||
wasmtime_val_t results[1];
|
||||
error = wasmtime_func_call(context, &fib.of.func, params, 1, results, 1, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
|
||||
wasm_extern_vec_delete(&exports);
|
||||
|
||||
assert(results[0].kind == WASMTIME_I32);
|
||||
printf("> fib(6) = %d\n", results[0].of.i32);
|
||||
|
||||
// Shut down.
|
||||
printf("Shutting down...\n");
|
||||
wasm_store_delete(store);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
|
||||
// All done.
|
||||
|
||||
@@ -16,12 +16,12 @@ fn main() -> Result<()> {
|
||||
// also ensure that we generate debuginfo so this executable can be
|
||||
// debugged in GDB.
|
||||
let engine = Engine::new(Config::new().debug_info(true))?;
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
let module = Module::from_file(&engine, "target/wasm32-unknown-unknown/debug/fib.wasm")?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
// Invoke `fib` export
|
||||
let fib = instance.get_typed_func::<i32, i32>("fib")?;
|
||||
println!("fib(6) = {}", fib.call(6)?);
|
||||
let fib = instance.get_typed_func::<i32, i32, _>(&mut store, "fib")?;
|
||||
println!("fib(6) = {}", fib.call(&mut store, 6)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ int main() {
|
||||
// Create an *engine*, which is a compilation context, with our configured options.
|
||||
wasm_engine_t *engine = wasm_engine_new_with_config(config);
|
||||
assert(engine != NULL);
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
error = wasmtime_store_add_fuel(store, 10000);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
error = wasmtime_context_add_fuel(context, 10000);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to add fuel", error, NULL);
|
||||
|
||||
@@ -60,60 +62,57 @@ int main() {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Compile and instantiate our module
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) wasm.data, wasm.size, &module);
|
||||
if (module == NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
wasmtime_instance_t instance;
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
// Lookup our `fibonacci` export function
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *fibonacci = wasm_extern_as_func(externs.data[0]);
|
||||
assert(fibonacci != NULL);
|
||||
wasmtime_extern_t fib;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "fibonacci", strlen("fibonacci"), &fib);
|
||||
assert(ok);
|
||||
assert(fib.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// Call it repeatedly until it fails
|
||||
for (int n = 1; ; n++) {
|
||||
uint64_t fuel_before;
|
||||
wasmtime_store_fuel_consumed(store, &fuel_before);
|
||||
wasm_val_t params[1] = { WASM_I32_VAL(n) };
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t params_vec = WASM_ARRAY_VEC(params);
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
error = wasmtime_func_call(fibonacci, ¶ms_vec, &results_vec, &trap);
|
||||
wasmtime_context_fuel_consumed(context, &fuel_before);
|
||||
wasmtime_val_t params[1];
|
||||
params[0].kind = WASMTIME_I32;
|
||||
params[0].of.i32 = n;
|
||||
wasmtime_val_t results[1];
|
||||
error = wasmtime_func_call(context, &fib.of.func, params, 1, results, 1, &trap);
|
||||
if (error != NULL || trap != NULL) {
|
||||
printf("Exhausted fuel computing fib(%d)\n", n);
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t fuel_after;
|
||||
wasmtime_store_fuel_consumed(store, &fuel_after);
|
||||
assert(results[0].kind == WASM_I32);
|
||||
wasmtime_context_fuel_consumed(context, &fuel_after);
|
||||
assert(results[0].kind == WASMTIME_I32);
|
||||
printf("fib(%d) = %d [consumed %lld fuel]\n", n, results[0].of.i32, fuel_after - fuel_before);
|
||||
|
||||
error = wasmtime_store_add_fuel(store, fuel_after - fuel_before);
|
||||
error = wasmtime_context_add_fuel(context, fuel_after - fuel_before);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to add fuel", error, NULL);
|
||||
}
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_module_delete(module);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ fn main() -> Result<()> {
|
||||
let mut config = Config::new();
|
||||
config.consume_fuel(true);
|
||||
let engine = Engine::new(&config)?;
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
store.add_fuel(10_000)?;
|
||||
let module = Module::from_file(store.engine(), "examples/fuel.wat")?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
// Invoke `fibonacci` export with higher and higher numbers until we exhaust our fuel.
|
||||
let fibonacci = instance.get_typed_func::<i32, i32>("fibonacci")?;
|
||||
let fibonacci = instance.get_typed_func::<i32, i32, _>(&mut store, "fibonacci")?;
|
||||
for n in 1.. {
|
||||
let fuel_before = store.fuel_consumed().unwrap();
|
||||
let output = match fibonacci.call(n) {
|
||||
let output = match fibonacci.call(&mut store, n) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
println!("Exhausted fuel computing fib({})", n);
|
||||
|
||||
@@ -30,8 +30,9 @@ int main() {
|
||||
// Set up our context
|
||||
wasm_engine_t *engine = wasm_engine_new();
|
||||
assert(engine != NULL);
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Load our input file to parse it next
|
||||
FILE* file = fopen("examples/gcd.wat", "r");
|
||||
@@ -52,52 +53,51 @@ int main() {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Compile and instantiate our module
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) wasm.data, wasm.size, &module);
|
||||
if (module == NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
wasmtime_instance_t instance;
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
// Lookup our `gcd` export function
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *gcd = wasm_extern_as_func(externs.data[0]);
|
||||
assert(gcd != NULL);
|
||||
wasmtime_extern_t gcd;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "gcd", 3, &gcd);
|
||||
assert(ok);
|
||||
assert(gcd.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// And call it!
|
||||
int a = 6;
|
||||
int b = 27;
|
||||
wasm_val_t params[2] = { WASM_I32_VAL(a), WASM_I32_VAL(b) };
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t params_vec = WASM_ARRAY_VEC(params);
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
error = wasmtime_func_call(gcd, ¶ms_vec, &results_vec, &trap);
|
||||
wasmtime_val_t params[2];
|
||||
params[0].kind = WASMTIME_I32;
|
||||
params[0].of.i32 = a;
|
||||
params[1].kind = WASMTIME_I32;
|
||||
params[1].of.i32 = b;
|
||||
wasmtime_val_t results[1];
|
||||
error = wasmtime_func_call(context, &gcd.of.func, params, 2, results, 1, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call gcd", error, trap);
|
||||
assert(results[0].kind == WASM_I32);
|
||||
assert(results[0].kind == WASMTIME_I32);
|
||||
|
||||
printf("gcd(%d, %d) = %d\n", a, b, results[0].of.i32);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
ret = 0;
|
||||
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_module_delete(module);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ fn main() -> Result<()> {
|
||||
// Load our WebAssembly (parsed WAT in our case), and then load it into a
|
||||
// `Module` which is attached to a `Store` cache. After we've got that we
|
||||
// can instantiate it.
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let module = Module::from_file(store.engine(), "examples/gcd.wat")?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
// Invoke `gcd` export
|
||||
let gcd = instance.get_typed_func::<(i32, i32), i32>("gcd")?;
|
||||
let gcd = instance.get_typed_func::<(i32, i32), i32, _>(&mut store, "gcd")?;
|
||||
|
||||
println!("gcd(6, 27) = {}", gcd.call((6, 27))?);
|
||||
println!("gcd(6, 27) = {}", gcd.call(&mut store, (6, 27))?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -26,7 +26,14 @@ to tweak the `-lpthread` and such annotations as well as the name of the
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||
|
||||
static wasm_trap_t* hello_callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
|
||||
static wasm_trap_t* hello_callback(
|
||||
void *env,
|
||||
wasmtime_caller_t *caller,
|
||||
const wasmtime_val_t *args,
|
||||
size_t nargs,
|
||||
wasmtime_val_t *results,
|
||||
size_t nresults
|
||||
) {
|
||||
printf("Calling back...\n");
|
||||
printf("> Hello World!\n");
|
||||
return NULL;
|
||||
@@ -42,9 +49,11 @@ int main() {
|
||||
assert(engine != NULL);
|
||||
|
||||
// With an engine we can create a *store* which is a long-lived group of wasm
|
||||
// modules.
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
// modules. Note that we allocate some custom data here to live in the store,
|
||||
// but here we skip that and specify NULL.
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Read our input file, which in this case is a wasm text file.
|
||||
FILE* file = fopen("examples/hello.wat", "r");
|
||||
@@ -59,25 +68,27 @@ int main() {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Now that we've got our binary webassembly we can compile our module.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) wasm.data, wasm.size, &module);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
|
||||
// Next up we need to create the function that the wasm module imports. Here
|
||||
// we'll be hooking up a thunk function to the `hello_callback` native
|
||||
// function above.
|
||||
// function above. Note that we can assign custom data, but we just use NULL
|
||||
// for now).
|
||||
printf("Creating callback...\n");
|
||||
wasm_functype_t *hello_ty = wasm_functype_new_0_0();
|
||||
wasm_func_t *hello = wasm_func_new(store, hello_ty, hello_callback);
|
||||
wasmtime_func_t hello;
|
||||
wasmtime_func_new(context, hello_ty, hello_callback, NULL, NULL, &hello);
|
||||
|
||||
// With our callback function we can now instantiate the compiled module,
|
||||
// giving us an instance we can then execute exports from. Note that
|
||||
@@ -85,26 +96,24 @@ int main() {
|
||||
// to handle that here too.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_t* imports[] = { wasm_func_as_extern(hello) };
|
||||
wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
|
||||
error = wasmtime_instance_new(store, module, &imports_vec, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
wasmtime_instance_t instance;
|
||||
wasmtime_extern_t import;
|
||||
import.kind = WASMTIME_EXTERN_FUNC;
|
||||
import.of.func = hello;
|
||||
error = wasmtime_instance_new(context, module, &import, 1, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
// Lookup our `run` export function
|
||||
printf("Extracting export...\n");
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *run = wasm_extern_as_func(externs.data[0]);
|
||||
assert(run != NULL);
|
||||
wasmtime_extern_t run;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "run", 3, &run);
|
||||
assert(ok);
|
||||
assert(run.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// And call it!
|
||||
printf("Calling export...\n");
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(run, &args_vec, &results_vec, &trap);
|
||||
error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
|
||||
@@ -112,10 +121,8 @@ int main() {
|
||||
printf("All finished!\n");
|
||||
ret = 0;
|
||||
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_module_delete(module);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
Example of instantiating of the WebAssembly module and invoking its exported
|
||||
function.
|
||||
|
||||
You can compile and run this example on Linux with:
|
||||
|
||||
cargo build --release -p wasmtime-c-api
|
||||
cc examples/hello.cc \
|
||||
-I crates/c-api/include \
|
||||
-I crates/c-api/wasm-c-api/include \
|
||||
target/release/libwasmtime.a \
|
||||
-lpthread -ldl -lm \
|
||||
-o hello
|
||||
./hello
|
||||
|
||||
Note that on Windows and macOS the command will be similar, but you'll need
|
||||
to tweak the `-lpthread` and such annotations as well as the name of the
|
||||
`libwasmtime.a` file on Windows.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wasm.h>
|
||||
#include <wasmtime.h>
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||
|
||||
static wasm_trap_t* hello_callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
|
||||
printf("Calling back...\n");
|
||||
printf("> Hello World!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int ret = 0;
|
||||
// Set up our compilation context. Note that we could also work with a
|
||||
// `wasm_config_t` here to configure what feature are enabled and various
|
||||
// compilation settings.
|
||||
printf("Initializing...\n");
|
||||
wasm_engine_t *engine = wasm_engine_new();
|
||||
assert(engine != NULL);
|
||||
|
||||
// With an engine we can create a *store* which is a long-lived group of wasm
|
||||
// modules.
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
assert(store != NULL);
|
||||
|
||||
// Read our input file, which in this case is a wasm text file.
|
||||
FILE* file = fopen("examples/hello.wat", "r");
|
||||
assert(file != NULL);
|
||||
fseek(file, 0L, SEEK_END);
|
||||
size_t file_size = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
wasm_byte_vec_t wat;
|
||||
wasm_byte_vec_new_uninitialized(&wat, file_size);
|
||||
assert(fread(wat.data, file_size, 1, file) == 1);
|
||||
fclose(file);
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Now that we've got our binary webassembly we can compile our module.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
|
||||
// Next up we need to create the function that the wasm module imports. Here
|
||||
// we'll be hooking up a thunk function to the `hello_callback` native
|
||||
// function above.
|
||||
printf("Creating callback...\n");
|
||||
wasm_functype_t *hello_ty = wasm_functype_new_0_0();
|
||||
wasm_func_t *hello = wasm_func_new(store, hello_ty, hello_callback);
|
||||
|
||||
// With our callback function we can now instantiate the compiled module,
|
||||
// giving us an instance we can then execute exports from. Note that
|
||||
// instantiation can trap due to execution of the `start` function, so we need
|
||||
// to handle that here too.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_t* imports[] = { wasm_func_as_extern(hello) };
|
||||
wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
|
||||
error = wasmtime_instance_new(store, module, &imports_vec, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
// Lookup our `run` export function
|
||||
printf("Extracting export...\n");
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *run = wasm_extern_as_func(externs.data[0]);
|
||||
assert(run != NULL);
|
||||
|
||||
// And call it!
|
||||
printf("Calling export...\n");
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(run, &args_vec, &results_vec, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
printf("All finished!\n");
|
||||
ret = 0;
|
||||
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
|
||||
fprintf(stderr, "error: %s\n", message);
|
||||
wasm_byte_vec_t error_message;
|
||||
if (error != NULL) {
|
||||
wasmtime_error_message(error, &error_message);
|
||||
wasmtime_error_delete(error);
|
||||
} else {
|
||||
wasm_trap_message(trap, &error_message);
|
||||
wasm_trap_delete(trap);
|
||||
}
|
||||
fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
|
||||
wasm_byte_vec_delete(&error_message);
|
||||
exit(1);
|
||||
}
|
||||
@@ -6,23 +6,42 @@
|
||||
use anyhow::Result;
|
||||
use wasmtime::*;
|
||||
|
||||
struct MyState {
|
||||
name: String,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Configure the initial compilation environment, creating the global
|
||||
// `Store` structure. Note that you can also tweak configuration settings
|
||||
// with a `Config` and an `Engine` if desired.
|
||||
println!("Initializing...");
|
||||
let store = Store::default();
|
||||
|
||||
// Compile the wasm binary into an in-memory instance of a `Module`.
|
||||
// First the wasm module needs to be compiled. This is done with a global
|
||||
// "compilation environment" within an `Engine`. Note that engines can be
|
||||
// further configured through `Config` if desired instead of using the
|
||||
// default like this is here.
|
||||
println!("Compiling module...");
|
||||
let module = Module::from_file(store.engine(), "examples/hello.wat")?;
|
||||
let engine = Engine::default();
|
||||
let module = Module::from_file(&engine, "examples/hello.wat")?;
|
||||
|
||||
// Here we handle the imports of the module, which in this case is our
|
||||
// `HelloCallback` type and its associated implementation of `Callback.
|
||||
// After a module is compiled we create a `Store` which will contain
|
||||
// instantiated modules and other items like host functions. A Store
|
||||
// contains an arbitrary piece of host information, and we use `MyState`
|
||||
// here.
|
||||
println!("Initializing...");
|
||||
let mut store = Store::new(
|
||||
&engine,
|
||||
MyState {
|
||||
name: "hello, world!".to_string(),
|
||||
count: 0,
|
||||
},
|
||||
);
|
||||
|
||||
// Our wasm module we'll be instantiating requires one imported function.
|
||||
// the function takes no parameters and returns no results. We create a host
|
||||
// implementation of that function here, and the `caller` parameter here is
|
||||
// used to get access to our original `MyState` value.
|
||||
println!("Creating callback...");
|
||||
let hello_func = Func::wrap(&store, || {
|
||||
let hello_func = Func::wrap(&mut store, |mut caller: Caller<'_, MyState>| {
|
||||
println!("Calling back...");
|
||||
println!("> Hello World!");
|
||||
println!("> {}", caller.data().name);
|
||||
caller.data_mut().count += 1;
|
||||
});
|
||||
|
||||
// Once we've got that all set up we can then move to the instantiation
|
||||
@@ -30,15 +49,15 @@ fn main() -> Result<()> {
|
||||
// Note that this is where the wasm `start` function, if any, would run.
|
||||
println!("Instantiating module...");
|
||||
let imports = [hello_func.into()];
|
||||
let instance = Instance::new(&store, &module, &imports)?;
|
||||
let instance = Instance::new(&mut store, &module, &imports)?;
|
||||
|
||||
// Next we poke around a bit to extract the `run` function from the module.
|
||||
println!("Extracting export...");
|
||||
let run = instance.get_typed_func::<(), ()>("run")?;
|
||||
let run = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
// And last but not least we can call it!
|
||||
println!("Calling export...");
|
||||
run.call(())?;
|
||||
run.call(&mut store, ())?;
|
||||
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
|
||||
@@ -61,11 +61,12 @@ int main() {
|
||||
wasmtime_config_interruptable_set(config, true);
|
||||
wasm_engine_t *engine = wasm_engine_new_with_config(config);
|
||||
assert(engine != NULL);
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Create our interrupt handle we'll use later
|
||||
wasmtime_interrupt_handle_t *handle = wasmtime_interrupt_handle_new(store);
|
||||
wasmtime_interrupt_handle_t *handle = wasmtime_interrupt_handle_new(context);
|
||||
assert(handle != NULL);
|
||||
|
||||
// Read our input file, which in this case is a wasm text file.
|
||||
@@ -81,50 +82,45 @@ int main() {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Now that we've got our binary webassembly we can compile our module.
|
||||
wasm_module_t *module = NULL;
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) wasm.data, wasm.size, &module);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasmtime_instance_t instance;
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
wasmtime_module_delete(module);
|
||||
|
||||
// Lookup our `run` export function
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *run = wasm_extern_as_func(externs.data[0]);
|
||||
assert(run != NULL);
|
||||
wasmtime_extern_t run;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "run", 3, &run);
|
||||
assert(ok);
|
||||
assert(run.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// Spawn a thread to send us an interrupt after a period of time.
|
||||
spawn_interrupt(handle);
|
||||
|
||||
// And call it!
|
||||
printf("Entering infinite loop...\n");
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(run, &args_vec, &results_vec, &trap);
|
||||
error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
|
||||
assert(error == NULL);
|
||||
assert(trap != NULL);
|
||||
printf("Got a trap!...\n");
|
||||
|
||||
// `trap` can be inspected here to see the trap message has an interrupt in it
|
||||
|
||||
wasm_trap_delete(trap);
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ fn main() -> Result<()> {
|
||||
// Enable interruptable code via `Config` and then create an interrupt
|
||||
// handle which we'll use later to interrupt running code.
|
||||
let engine = Engine::new(Config::new().interruptable(true))?;
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
let interrupt_handle = store.interrupt_handle()?;
|
||||
|
||||
// Compile and instantiate a small example with an infinite loop.
|
||||
let module = Module::from_file(&engine, "examples/interrupt.wat")?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let run = instance.get_typed_func::<(), ()>("run")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let run = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
// Spin up a thread to send us an interrupt in a second
|
||||
std::thread::spawn(move || {
|
||||
@@ -26,7 +26,7 @@ fn main() -> Result<()> {
|
||||
});
|
||||
|
||||
println!("Entering infinite loop ...");
|
||||
let trap = run.call(()).unwrap_err();
|
||||
let trap = run.call(&mut store, ()).unwrap_err();
|
||||
|
||||
println!("trap received...");
|
||||
assert!(trap.to_string().contains("wasm trap: interrupt"));
|
||||
|
||||
@@ -30,12 +30,12 @@ static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_t
|
||||
static void read_wat_file(wasm_engine_t *engine, wasm_byte_vec_t *bytes, const char *file);
|
||||
|
||||
int main() {
|
||||
int ret = 0;
|
||||
// Set up our context
|
||||
wasm_engine_t *engine = wasm_engine_new();
|
||||
assert(engine != NULL);
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
wasm_byte_vec_t linking1_wasm, linking2_wasm;
|
||||
read_wat_file(engine, &linking1_wasm, "examples/linking1.wat");
|
||||
@@ -43,18 +43,18 @@ int main() {
|
||||
|
||||
// Compile our two modules
|
||||
wasmtime_error_t *error;
|
||||
wasm_module_t *linking1_module = NULL;
|
||||
wasm_module_t *linking2_module = NULL;
|
||||
error = wasmtime_module_new(engine, &linking1_wasm, &linking1_module);
|
||||
wasmtime_module_t *linking1_module = NULL;
|
||||
wasmtime_module_t *linking2_module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) linking1_wasm.data, linking1_wasm.size, &linking1_module);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile linking1", error, NULL);
|
||||
error = wasmtime_module_new(engine, &linking2_wasm, &linking2_module);
|
||||
error = wasmtime_module_new(engine, (uint8_t*) linking2_wasm.data, linking2_wasm.size, &linking2_module);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile linking2", error, NULL);
|
||||
wasm_byte_vec_delete(&linking1_wasm);
|
||||
wasm_byte_vec_delete(&linking2_wasm);
|
||||
|
||||
// Instantiate wasi
|
||||
// Configure WASI and store it within our `wasmtime_store_t`
|
||||
wasi_config_t *wasi_config = wasi_config_new();
|
||||
assert(wasi_config);
|
||||
wasi_config_inherit_argv(wasi_config);
|
||||
@@ -63,57 +63,48 @@ int main() {
|
||||
wasi_config_inherit_stdout(wasi_config);
|
||||
wasi_config_inherit_stderr(wasi_config);
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap);
|
||||
if (wasi == NULL)
|
||||
error = wasmtime_context_set_wasi(context, wasi_config);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to instantiate wasi", NULL, trap);
|
||||
|
||||
// Create our linker which will be linking our modules together, and then add
|
||||
// our WASI instance to it.
|
||||
wasmtime_linker_t *linker = wasmtime_linker_new(store);
|
||||
error = wasmtime_linker_define_wasi(linker, wasi);
|
||||
wasmtime_linker_t *linker = wasmtime_linker_new(engine);
|
||||
error = wasmtime_linker_define_wasi(linker);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to link wasi", error, NULL);
|
||||
|
||||
// Instantiate `linking2` with our linker.
|
||||
wasm_instance_t *linking2;
|
||||
error = wasmtime_linker_instantiate(linker, linking2_module, &linking2, &trap);
|
||||
wasmtime_instance_t linking2;
|
||||
error = wasmtime_linker_instantiate(linker, context, linking2_module, &linking2, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate linking2", error, trap);
|
||||
|
||||
// Register our new `linking2` instance with the linker
|
||||
wasm_name_t linking2_name;
|
||||
linking2_name.data = "linking2";
|
||||
linking2_name.size = strlen(linking2_name.data);
|
||||
error = wasmtime_linker_define_instance(linker, &linking2_name, linking2);
|
||||
error = wasmtime_linker_define_instance(linker, context, "linking2", strlen("linking2"), &linking2);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to link linking2", error, NULL);
|
||||
|
||||
// Instantiate `linking1` with the linker now that `linking2` is defined
|
||||
wasm_instance_t *linking1;
|
||||
error = wasmtime_linker_instantiate(linker, linking1_module, &linking1, &trap);
|
||||
wasmtime_instance_t linking1;
|
||||
error = wasmtime_linker_instantiate(linker, context, linking1_module, &linking1, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate linking1", error, trap);
|
||||
|
||||
// Lookup our `run` export function
|
||||
wasm_extern_vec_t linking1_externs;
|
||||
wasm_instance_exports(linking1, &linking1_externs);
|
||||
assert(linking1_externs.size == 1);
|
||||
wasm_func_t *run = wasm_extern_as_func(linking1_externs.data[0]);
|
||||
assert(run != NULL);
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(run, &args_vec, &results_vec, &trap);
|
||||
wasmtime_extern_t run;
|
||||
bool ok = wasmtime_instance_export_get(context, &linking1, "run", 3, &run);
|
||||
assert(ok);
|
||||
assert(run.kind == WASMTIME_EXTERN_FUNC);
|
||||
error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call run", error, trap);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
wasm_extern_vec_delete(&linking1_externs);
|
||||
wasm_instance_delete(linking1);
|
||||
wasm_instance_delete(linking2);
|
||||
wasmtime_linker_delete(linker);
|
||||
wasm_module_delete(linking1_module);
|
||||
wasm_module_delete(linking2_module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_module_delete(linking1_module);
|
||||
wasmtime_module_delete(linking2_module);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -141,7 +132,7 @@ static void read_wat_file(
|
||||
fclose(file);
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, bytes);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, bytes);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
@@ -4,36 +4,35 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use wasmtime::*;
|
||||
use wasmtime_wasi::sync::{Wasi, WasiCtxBuilder};
|
||||
use wasmtime_wasi::sync::WasiCtxBuilder;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let engine = Engine::default();
|
||||
let store = Store::new(&engine);
|
||||
|
||||
// First set up our linker which is going to be linking modules together. We
|
||||
// want our linker to have wasi available, so we set that up here as well.
|
||||
let mut linker = Linker::new(&store);
|
||||
let wasi = Wasi::new(
|
||||
&store,
|
||||
WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.inherit_args()?
|
||||
.build(),
|
||||
);
|
||||
wasi.add_to_linker(&mut linker)?;
|
||||
let mut linker = Linker::new(&engine);
|
||||
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
|
||||
|
||||
// Load and compile our two modules
|
||||
let linking1 = Module::from_file(&engine, "examples/linking1.wat")?;
|
||||
let linking2 = Module::from_file(&engine, "examples/linking2.wat")?;
|
||||
|
||||
// Configure WASI and insert it into a `Store`
|
||||
let wasi = WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.inherit_args()?
|
||||
.build();
|
||||
let mut store = Store::new(&engine, wasi);
|
||||
|
||||
// Instantiate our first module which only uses WASI, then register that
|
||||
// instance with the linker since the next linking will use it.
|
||||
let linking2 = linker.instantiate(&linking2)?;
|
||||
linker.instance("linking2", &linking2)?;
|
||||
let linking2 = linker.instantiate(&mut store, &linking2)?;
|
||||
linker.instance(&mut store, "linking2", linking2)?;
|
||||
|
||||
// And with that we can perform the final link and the execute the module.
|
||||
let linking1 = linker.instantiate(&linking1)?;
|
||||
let run = linking1.get_typed_func::<(), ()>("run")?;
|
||||
run.call(())?;
|
||||
let linking1 = linker.instantiate(&mut store, &linking1)?;
|
||||
let run = linking1.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
run.call(&mut store, ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -30,23 +30,6 @@ originally
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||
|
||||
wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) {
|
||||
if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) {
|
||||
printf("> Error accessing memory export %zu!\n", i);
|
||||
exit(1);
|
||||
}
|
||||
return wasm_extern_as_memory(exports->data[i]);
|
||||
}
|
||||
|
||||
wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
|
||||
if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
|
||||
printf("> Error accessing function export %zu!\n", i);
|
||||
exit(1);
|
||||
}
|
||||
return wasm_extern_as_func(exports->data[i]);
|
||||
}
|
||||
|
||||
|
||||
void check(bool success) {
|
||||
if (!success) {
|
||||
printf("> Error, expected success\n");
|
||||
@@ -54,11 +37,16 @@ void check(bool success) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_call(wasm_func_t* func, const wasm_val_vec_t* args_vec, int32_t expected) {
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
void check_call(wasmtime_context_t *store,
|
||||
wasmtime_func_t *func,
|
||||
const wasmtime_val_t* args,
|
||||
size_t nargs,
|
||||
int32_t expected) {
|
||||
wasmtime_val_t results[1];
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasmtime_error_t *error = wasmtime_func_call(func, args_vec, &results_vec, &trap);
|
||||
wasmtime_error_t *error = wasmtime_func_call(
|
||||
store, func, args, nargs, results, 1, &trap
|
||||
);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
if (results[0].of.i32 != expected) {
|
||||
@@ -67,45 +55,51 @@ void check_call(wasm_func_t* func, const wasm_val_vec_t* args_vec, int32_t expec
|
||||
}
|
||||
}
|
||||
|
||||
void check_call0(wasm_func_t* func, int32_t expected) {
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
check_call(func, &args_vec, expected);
|
||||
void check_call0(wasmtime_context_t *store, wasmtime_func_t *func, int32_t expected) {
|
||||
check_call(store, func, NULL, 0, expected);
|
||||
}
|
||||
|
||||
void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
|
||||
wasm_val_t args[] = { WASM_I32_VAL(arg) };
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
check_call(func, &args_vec, expected);
|
||||
void check_call1(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg, int32_t expected) {
|
||||
wasmtime_val_t args[1];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = arg;
|
||||
check_call(store, func, args, 1, expected);
|
||||
}
|
||||
|
||||
void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
|
||||
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
check_call(func, &args_vec, expected);
|
||||
void check_call2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, int32_t arg2, int32_t expected) {
|
||||
wasmtime_val_t args[2];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = arg1;
|
||||
args[1].kind = WASMTIME_I32;
|
||||
args[1].of.i32 = arg2;
|
||||
check_call(store, func, args, 2, expected);
|
||||
}
|
||||
|
||||
void check_ok(wasm_func_t* func, const wasm_val_vec_t* args_vec) {
|
||||
void check_ok(wasmtime_context_t *store, wasmtime_func_t *func, const wasmtime_val_t* args, size_t nargs) {
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
wasmtime_error_t *error = wasmtime_func_call(func, args_vec, &results_vec, &trap);
|
||||
wasmtime_error_t *error = wasmtime_func_call(store, func, args, nargs, NULL, 0, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
}
|
||||
|
||||
void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
|
||||
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
check_ok(func, &args_vec);
|
||||
void check_ok2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, int32_t arg2) {
|
||||
wasmtime_val_t args[2];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = arg1;
|
||||
args[1].kind = WASMTIME_I32;
|
||||
args[1].of.i32 = arg2;
|
||||
check_ok(store, func, args, 2);
|
||||
}
|
||||
|
||||
void check_trap(wasm_func_t* func, const wasm_val_vec_t* args_vec, size_t num_results) {
|
||||
void check_trap(wasmtime_context_t *store,
|
||||
wasmtime_func_t *func,
|
||||
const wasmtime_val_t *args,
|
||||
size_t nargs,
|
||||
size_t num_results) {
|
||||
assert(num_results <= 1);
|
||||
wasm_val_t results[1];
|
||||
wasm_val_vec_t results_vec;
|
||||
results_vec.data = results;
|
||||
results_vec.size = num_results;
|
||||
wasmtime_val_t results[1];
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasmtime_error_t *error = wasmtime_func_call(func, args_vec, &results_vec, &trap);
|
||||
wasmtime_error_t *error = wasmtime_func_call(store, func, args, nargs, results, num_results, &trap);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to call function", error, NULL);
|
||||
if (trap == NULL) {
|
||||
@@ -115,23 +109,28 @@ void check_trap(wasm_func_t* func, const wasm_val_vec_t* args_vec, size_t num_re
|
||||
wasm_trap_delete(trap);
|
||||
}
|
||||
|
||||
void check_trap1(wasm_func_t* func, int32_t arg) {
|
||||
wasm_val_t args[] = { WASM_I32_VAL(arg) };
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
check_trap(func, &args_vec, 1);
|
||||
void check_trap1(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg) {
|
||||
wasmtime_val_t args[1];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = arg;
|
||||
check_trap(store, func, args, 1, 1);
|
||||
}
|
||||
|
||||
void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
|
||||
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
check_trap(func, &args_vec, 0);
|
||||
void check_trap2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, int32_t arg2) {
|
||||
wasmtime_val_t args[2];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = arg1;
|
||||
args[1].kind = WASMTIME_I32;
|
||||
args[1].of.i32 = arg2;
|
||||
check_trap(store, func, args, 2, 0);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
// Initialize.
|
||||
printf("Initializing...\n");
|
||||
wasm_engine_t* engine = wasm_engine_new();
|
||||
wasm_store_t* store = wasm_store_new(engine);
|
||||
wasmtime_store_t* store = wasmtime_store_new(engine, NULL, NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Load our input file to parse it next
|
||||
FILE* file = fopen("examples/memory.wat", "r");
|
||||
@@ -152,102 +151,108 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t binary;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Compile.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t* module = NULL;
|
||||
error = wasmtime_module_new(engine, &binary, &module);
|
||||
wasmtime_module_t* module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) binary.data, binary.size, &module);
|
||||
if (error)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
wasm_byte_vec_delete(&binary);
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_instance_t* instance = NULL;
|
||||
wasmtime_instance_t instance;
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
|
||||
error = wasmtime_instance_new(store, module, &imports, &instance, &trap);
|
||||
if (!instance)
|
||||
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
wasmtime_module_delete(module);
|
||||
|
||||
// Extract export.
|
||||
printf("Extracting exports...\n");
|
||||
wasm_extern_vec_t exports;
|
||||
wasm_instance_exports(instance, &exports);
|
||||
size_t i = 0;
|
||||
wasm_memory_t* memory = get_export_memory(&exports, i++);
|
||||
wasm_func_t* size_func = get_export_func(&exports, i++);
|
||||
wasm_func_t* load_func = get_export_func(&exports, i++);
|
||||
wasm_func_t* store_func = get_export_func(&exports, i++);
|
||||
|
||||
wasm_module_delete(module);
|
||||
|
||||
// Try cloning.
|
||||
wasm_memory_t* copy = wasm_memory_copy(memory);
|
||||
wasm_memory_delete(copy);
|
||||
wasmtime_memory_t memory;
|
||||
wasmtime_func_t size_func, load_func, store_func;
|
||||
wasmtime_extern_t item;
|
||||
bool ok;
|
||||
ok = wasmtime_instance_export_get(context, &instance, "memory", strlen("memory"), &item);
|
||||
assert(ok && item.kind == WASMTIME_EXTERN_MEMORY);
|
||||
memory = item.of.memory;
|
||||
ok = wasmtime_instance_export_get(context, &instance, "size", strlen("size"), &item);
|
||||
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
|
||||
size_func = item.of.func;
|
||||
ok = wasmtime_instance_export_get(context, &instance, "load", strlen("load"), &item);
|
||||
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
|
||||
load_func = item.of.func;
|
||||
ok = wasmtime_instance_export_get(context, &instance, "store", strlen("store"), &item);
|
||||
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
|
||||
store_func = item.of.func;
|
||||
|
||||
// Check initial memory.
|
||||
printf("Checking memory...\n");
|
||||
check(wasm_memory_size(memory) == 2);
|
||||
check(wasm_memory_data_size(memory) == 0x20000);
|
||||
check(wasm_memory_data(memory)[0] == 0);
|
||||
check(wasm_memory_data(memory)[0x1000] == 1);
|
||||
check(wasm_memory_data(memory)[0x1003] == 4);
|
||||
check(wasmtime_memory_size(context, &memory) == 2);
|
||||
check(wasmtime_memory_data_size(context, &memory) == 0x20000);
|
||||
check(wasmtime_memory_data(context, &memory)[0] == 0);
|
||||
check(wasmtime_memory_data(context, &memory)[0x1000] == 1);
|
||||
check(wasmtime_memory_data(context, &memory)[0x1003] == 4);
|
||||
|
||||
check_call0(size_func, 2);
|
||||
check_call1(load_func, 0, 0);
|
||||
check_call1(load_func, 0x1000, 1);
|
||||
check_call1(load_func, 0x1003, 4);
|
||||
check_call1(load_func, 0x1ffff, 0);
|
||||
check_trap1(load_func, 0x20000);
|
||||
check_call0(context, &size_func, 2);
|
||||
check_call1(context, &load_func, 0, 0);
|
||||
check_call1(context, &load_func, 0x1000, 1);
|
||||
check_call1(context, &load_func, 0x1003, 4);
|
||||
check_call1(context, &load_func, 0x1ffff, 0);
|
||||
check_trap1(context, &load_func, 0x20000);
|
||||
|
||||
// Mutate memory.
|
||||
printf("Mutating memory...\n");
|
||||
wasm_memory_data(memory)[0x1003] = 5;
|
||||
check_ok2(store_func, 0x1002, 6);
|
||||
check_trap2(store_func, 0x20000, 0);
|
||||
wasmtime_memory_data(context, &memory)[0x1003] = 5;
|
||||
check_ok2(context, &store_func, 0x1002, 6);
|
||||
check_trap2(context, &store_func, 0x20000, 0);
|
||||
|
||||
check(wasm_memory_data(memory)[0x1002] == 6);
|
||||
check(wasm_memory_data(memory)[0x1003] == 5);
|
||||
check_call1(load_func, 0x1002, 6);
|
||||
check_call1(load_func, 0x1003, 5);
|
||||
check(wasmtime_memory_data(context, &memory)[0x1002] == 6);
|
||||
check(wasmtime_memory_data(context, &memory)[0x1003] == 5);
|
||||
check_call1(context, &load_func, 0x1002, 6);
|
||||
check_call1(context, &load_func, 0x1003, 5);
|
||||
|
||||
// Grow memory.
|
||||
printf("Growing memory...\n");
|
||||
check(wasm_memory_grow(memory, 1));
|
||||
check(wasm_memory_size(memory) == 3);
|
||||
check(wasm_memory_data_size(memory) == 0x30000);
|
||||
uint32_t old_size;
|
||||
error = wasmtime_memory_grow(context, &memory, 1, &old_size);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to grow memory", error, trap);
|
||||
check(wasmtime_memory_size(context, &memory) == 3);
|
||||
check(wasmtime_memory_data_size(context, &memory) == 0x30000);
|
||||
|
||||
check_call1(load_func, 0x20000, 0);
|
||||
check_ok2(store_func, 0x20000, 0);
|
||||
check_trap1(load_func, 0x30000);
|
||||
check_trap2(store_func, 0x30000, 0);
|
||||
check_call1(context, &load_func, 0x20000, 0);
|
||||
check_ok2(context, &store_func, 0x20000, 0);
|
||||
check_trap1(context, &load_func, 0x30000);
|
||||
check_trap2(context, &store_func, 0x30000, 0);
|
||||
|
||||
check(! wasm_memory_grow(memory, 1));
|
||||
check(wasm_memory_grow(memory, 0));
|
||||
|
||||
wasm_extern_vec_delete(&exports);
|
||||
wasm_instance_delete(instance);
|
||||
error = wasmtime_memory_grow(context, &memory, 1, &old_size);
|
||||
assert(error != NULL);
|
||||
wasmtime_error_delete(error);
|
||||
error = wasmtime_memory_grow(context, &memory, 0, &old_size);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to grow memory", error, trap);
|
||||
|
||||
// Create stand-alone memory.
|
||||
printf("Creating stand-alone memory...\n");
|
||||
wasm_limits_t limits = {5, 5};
|
||||
wasm_memorytype_t* memorytype = wasm_memorytype_new(&limits);
|
||||
wasm_memory_t* memory2 = wasm_memory_new(store, memorytype);
|
||||
check(wasm_memory_size(memory2) == 5);
|
||||
check(! wasm_memory_grow(memory2, 1));
|
||||
check(wasm_memory_grow(memory2, 0));
|
||||
|
||||
wasmtime_memory_t memory2;
|
||||
error = wasmtime_memory_new(context, memorytype, &memory2);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to create memory", error, trap);
|
||||
wasm_memorytype_delete(memorytype);
|
||||
wasm_memory_delete(memory2);
|
||||
check(wasmtime_memory_size(context, &memory2) == 5);
|
||||
|
||||
// Shut down.
|
||||
printf("Shutting down...\n");
|
||||
wasm_store_delete(store);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
|
||||
// All done.
|
||||
|
||||
@@ -10,75 +10,65 @@ use anyhow::Result;
|
||||
use wasmtime::*;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Create our `Store` context and then compile a module and create an
|
||||
// Create our `store_fn` context and then compile a module and create an
|
||||
// instance from the compiled module all in one go.
|
||||
let wasmtime_store = Store::default();
|
||||
let module = Module::from_file(wasmtime_store.engine(), "examples/memory.wat")?;
|
||||
let instance = Instance::new(&wasmtime_store, &module, &[])?;
|
||||
let mut store: Store<()> = Store::default();
|
||||
let module = Module::from_file(store.engine(), "examples/memory.wat")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
// Load up our exports from the instance
|
||||
// load_fn up our exports from the instance
|
||||
let memory = instance
|
||||
.get_memory("memory")
|
||||
.get_memory(&mut store, "memory")
|
||||
.ok_or(anyhow::format_err!("failed to find `memory` export"))?;
|
||||
let size = instance.get_typed_func::<(), i32>("size")?;
|
||||
let load = instance.get_typed_func::<i32, i32>("load")?;
|
||||
let store = instance.get_typed_func::<(i32, i32), ()>("store")?;
|
||||
let size = instance.get_typed_func::<(), i32, _>(&mut store, "size")?;
|
||||
let load_fn = instance.get_typed_func::<i32, i32, _>(&mut store, "load")?;
|
||||
let store_fn = instance.get_typed_func::<(i32, i32), (), _>(&mut store, "store")?;
|
||||
|
||||
// Note that these memory reads are *unsafe* due to unknown knowledge about
|
||||
// aliasing with wasm memory. For more information about the safety
|
||||
// guarantees here and how to use `Memory` safely, see the API
|
||||
// documentation.
|
||||
println!("Checking memory...");
|
||||
assert_eq!(memory.size(), 2);
|
||||
assert_eq!(memory.data_size(), 0x20000);
|
||||
unsafe {
|
||||
assert_eq!(memory.data_unchecked_mut()[0], 0);
|
||||
assert_eq!(memory.data_unchecked_mut()[0x1000], 1);
|
||||
assert_eq!(memory.data_unchecked_mut()[0x1003], 4);
|
||||
}
|
||||
assert_eq!(memory.size(&store), 2);
|
||||
assert_eq!(memory.data_size(&store), 0x20000);
|
||||
assert_eq!(memory.data_mut(&mut store)[0], 0);
|
||||
assert_eq!(memory.data_mut(&mut store)[0x1000], 1);
|
||||
assert_eq!(memory.data_mut(&mut store)[0x1003], 4);
|
||||
|
||||
assert_eq!(size.call(())?, 2);
|
||||
assert_eq!(load.call(0)?, 0);
|
||||
assert_eq!(load.call(0x1000)?, 1);
|
||||
assert_eq!(load.call(0x1003)?, 4);
|
||||
assert_eq!(load.call(0x1ffff)?, 0);
|
||||
assert!(load.call(0x20000).is_err()); // out of bounds trap
|
||||
assert_eq!(size.call(&mut store, ())?, 2);
|
||||
assert_eq!(load_fn.call(&mut store, 0)?, 0);
|
||||
assert_eq!(load_fn.call(&mut store, 0x1000)?, 1);
|
||||
assert_eq!(load_fn.call(&mut store, 0x1003)?, 4);
|
||||
assert_eq!(load_fn.call(&mut store, 0x1ffff)?, 0);
|
||||
assert!(load_fn.call(&mut store, 0x20000).is_err()); // out of bounds trap
|
||||
|
||||
println!("Mutating memory...");
|
||||
unsafe {
|
||||
memory.data_unchecked_mut()[0x1003] = 5;
|
||||
}
|
||||
memory.data_mut(&mut store)[0x1003] = 5;
|
||||
|
||||
store.call((0x1002, 6))?;
|
||||
assert!(store.call((0x20000, 0)).is_err()); // out of bounds trap
|
||||
store_fn.call(&mut store, (0x1002, 6))?;
|
||||
assert!(store_fn.call(&mut store, (0x20000, 0)).is_err()); // out of bounds trap
|
||||
|
||||
unsafe {
|
||||
assert_eq!(memory.data_unchecked_mut()[0x1002], 6);
|
||||
assert_eq!(memory.data_unchecked_mut()[0x1003], 5);
|
||||
}
|
||||
assert_eq!(load.call(0x1002)?, 6);
|
||||
assert_eq!(load.call(0x1003)?, 5);
|
||||
assert_eq!(memory.data(&store)[0x1002], 6);
|
||||
assert_eq!(memory.data(&store)[0x1003], 5);
|
||||
assert_eq!(load_fn.call(&mut store, 0x1002)?, 6);
|
||||
assert_eq!(load_fn.call(&mut store, 0x1003)?, 5);
|
||||
|
||||
// Grow memory.
|
||||
println!("Growing memory...");
|
||||
memory.grow(1)?;
|
||||
assert_eq!(memory.size(), 3);
|
||||
assert_eq!(memory.data_size(), 0x30000);
|
||||
memory.grow(&mut store, 1)?;
|
||||
assert_eq!(memory.size(&store), 3);
|
||||
assert_eq!(memory.data_size(&store), 0x30000);
|
||||
|
||||
assert_eq!(load.call(0x20000)?, 0);
|
||||
store.call((0x20000, 0))?;
|
||||
assert!(load.call(0x30000).is_err());
|
||||
assert!(store.call((0x30000, 0)).is_err());
|
||||
assert_eq!(load_fn.call(&mut store, 0x20000)?, 0);
|
||||
store_fn.call(&mut store, (0x20000, 0))?;
|
||||
assert!(load_fn.call(&mut store, 0x30000).is_err());
|
||||
assert!(store_fn.call(&mut store, (0x30000, 0)).is_err());
|
||||
|
||||
assert!(memory.grow(1).is_err());
|
||||
assert!(memory.grow(0).is_ok());
|
||||
assert!(memory.grow(&mut store, 1).is_err());
|
||||
assert!(memory.grow(&mut store, 0).is_ok());
|
||||
|
||||
println!("Creating stand-alone memory...");
|
||||
let memorytype = MemoryType::new(Limits::new(5, Some(5)));
|
||||
let memory2 = Memory::new(&wasmtime_store, memorytype)?;
|
||||
assert_eq!(memory2.size(), 5);
|
||||
assert!(memory2.grow(1).is_err());
|
||||
assert!(memory2.grow(0).is_ok());
|
||||
let memory2 = Memory::new(&mut store, memorytype)?;
|
||||
assert_eq!(memory2.size(&store), 5);
|
||||
assert!(memory2.grow(&mut store, 1).is_err());
|
||||
assert!(memory2.grow(&mut store, 0).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -32,27 +32,37 @@ static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_t
|
||||
|
||||
// A function to be called from Wasm code.
|
||||
wasm_trap_t* callback(
|
||||
const wasm_val_vec_t* args, wasm_val_vec_t* results
|
||||
void *env,
|
||||
wasmtime_caller_t *caller,
|
||||
const wasmtime_val_t* args,
|
||||
size_t nargs,
|
||||
wasmtime_val_t* results,
|
||||
size_t nresults
|
||||
) {
|
||||
printf("Calling back...\n");
|
||||
printf("> %"PRIu32" %"PRIu64"\n", args->data[0].of.i32, args->data[1].of.i64);
|
||||
printf("> %"PRIu32" %"PRIu64"\n", args[0].of.i32, args[1].of.i64);
|
||||
printf("\n");
|
||||
|
||||
wasm_val_copy(&results->data[0], &args->data[1]);
|
||||
wasm_val_copy(&results->data[1], &args->data[0]);
|
||||
results[0] = args[1];
|
||||
results[1] = args[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// A function closure.
|
||||
wasm_trap_t* closure_callback(
|
||||
void* env, const wasm_val_t args[], wasm_val_t results[]
|
||||
void* env,
|
||||
wasmtime_caller_t *caller,
|
||||
const wasmtime_val_t* args,
|
||||
size_t nargs,
|
||||
wasmtime_val_t* results,
|
||||
size_t nresults
|
||||
) {
|
||||
int i = *(int*)env;
|
||||
printf("Calling back closure...\n");
|
||||
printf("> %d\n", i);
|
||||
|
||||
results[0].kind = WASM_I32;
|
||||
results[0].kind = WASMTIME_I32;
|
||||
results[0].of.i32 = (int32_t)i;
|
||||
return NULL;
|
||||
}
|
||||
@@ -62,7 +72,8 @@ int main(int argc, const char* argv[]) {
|
||||
// Initialize.
|
||||
printf("Initializing...\n");
|
||||
wasm_engine_t* engine = wasm_engine_new();
|
||||
wasm_store_t* store = wasm_store_new(engine);
|
||||
wasmtime_store_t* store = wasmtime_store_new(engine, NULL, NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Load our input file to parse it next
|
||||
FILE* file = fopen("examples/multi.wat", "r");
|
||||
@@ -83,18 +94,17 @@ int main(int argc, const char* argv[]) {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t binary;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Compile.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t* module = NULL;
|
||||
error = wasmtime_module_new(engine, &binary, &module);
|
||||
wasmtime_module_t* module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*) binary.data, binary.size, &module);
|
||||
if (error)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
|
||||
wasm_byte_vec_delete(&binary);
|
||||
|
||||
// Create external print functions.
|
||||
@@ -105,65 +115,54 @@ int main(int argc, const char* argv[]) {
|
||||
wasm_valtype_new_i64(),
|
||||
wasm_valtype_new_i32()
|
||||
);
|
||||
wasm_func_t* callback_func =
|
||||
wasm_func_new(store, callback_type, callback);
|
||||
|
||||
wasmtime_func_t callback_func;
|
||||
wasmtime_func_new(context, callback_type, callback, NULL, NULL, &callback_func);
|
||||
wasm_functype_delete(callback_type);
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
|
||||
wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
|
||||
wasm_instance_t* instance = NULL;
|
||||
wasmtime_extern_t imports[1];
|
||||
imports[0].kind = WASMTIME_EXTERN_FUNC;
|
||||
imports[0].of.func = callback_func;
|
||||
wasmtime_instance_t instance;
|
||||
wasm_trap_t* trap = NULL;
|
||||
error = wasmtime_instance_new(store, module, &imports_vec, &instance, &trap);
|
||||
if (!instance)
|
||||
error = wasmtime_instance_new(context, module, imports, 1, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
|
||||
wasm_func_delete(callback_func);
|
||||
wasmtime_module_delete(module);
|
||||
|
||||
// Extract export.
|
||||
printf("Extracting export...\n");
|
||||
wasm_extern_vec_t exports;
|
||||
wasm_instance_exports(instance, &exports);
|
||||
if (exports.size == 0) {
|
||||
printf("> Error accessing exports!\n");
|
||||
return 1;
|
||||
}
|
||||
wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
|
||||
if (run_func == NULL) {
|
||||
printf("> Error accessing export!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_module_delete(module);
|
||||
wasm_instance_delete(instance);
|
||||
wasmtime_extern_t run;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "g", 1, &run);
|
||||
assert(ok);
|
||||
assert(run.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// Call.
|
||||
printf("Calling export...\n");
|
||||
wasm_val_t args[2] = { WASM_I32_VAL(1), WASM_I64_VAL(2) };
|
||||
wasm_val_t results[2];
|
||||
wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
|
||||
wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
|
||||
error = wasmtime_func_call(run_func, &args_vec, &results_vec, &trap);
|
||||
wasmtime_val_t args[2];
|
||||
args[0].kind = WASMTIME_I32;
|
||||
args[0].of.i32 = 1;
|
||||
args[1].kind = WASMTIME_I64;
|
||||
args[1].of.i64 = 2;
|
||||
wasmtime_val_t results[2];
|
||||
error = wasmtime_func_call(context, &run.of.func, args, 2, results, 2, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call run", error, trap);
|
||||
|
||||
wasm_extern_vec_delete(&exports);
|
||||
|
||||
// Print result.
|
||||
printf("Printing result...\n");
|
||||
printf("> %"PRIu64" %"PRIu32"\n",
|
||||
results[0].of.i64, results[1].of.i32);
|
||||
|
||||
assert(results[0].kind == WASM_I64);
|
||||
assert(results[0].kind == WASMTIME_I64);
|
||||
assert(results[0].of.i64 == 2);
|
||||
assert(results[1].kind == WASM_I32);
|
||||
assert(results[1].kind == WASMTIME_I32);
|
||||
assert(results[1].of.i32 == 1);
|
||||
|
||||
// Shut down.
|
||||
printf("Shutting down...\n");
|
||||
wasm_store_delete(store);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
|
||||
// All done.
|
||||
|
||||
@@ -15,38 +15,30 @@ fn main() -> Result<()> {
|
||||
|
||||
println!("Initializing...");
|
||||
let engine = Engine::default();
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
|
||||
// Compile.
|
||||
println!("Compiling module...");
|
||||
let module = Module::from_file(&engine, "examples/multi.wat")?;
|
||||
|
||||
// Create external print functions.
|
||||
// Create a host function which takes multiple parameters and returns
|
||||
// multiple results.
|
||||
println!("Creating callback...");
|
||||
let callback_type = FuncType::new(
|
||||
[ValType::I32, ValType::I64].iter().cloned(),
|
||||
[ValType::I64, ValType::I32].iter().cloned(),
|
||||
);
|
||||
let callback_func = Func::new(&store, callback_type, |_, args, results| {
|
||||
println!("Calling back...");
|
||||
println!("> {} {}", args[0].unwrap_i32(), args[1].unwrap_i64());
|
||||
|
||||
results[0] = Val::I64(args[1].unwrap_i64() + 1);
|
||||
results[1] = Val::I32(args[0].unwrap_i32() + 1);
|
||||
Ok(())
|
||||
let callback_func = Func::wrap(&mut store, |a: i32, b: i64| -> (i64, i32) {
|
||||
(b + 1, a + 1)
|
||||
});
|
||||
|
||||
// Instantiate.
|
||||
println!("Instantiating module...");
|
||||
let instance = Instance::new(&store, &module, &[callback_func.into()])?;
|
||||
let instance = Instance::new(&mut store, &module, &[callback_func.into()])?;
|
||||
|
||||
// Extract exports.
|
||||
println!("Extracting export...");
|
||||
let g = instance.get_typed_func::<(i32, i64), (i64, i32)>("g")?;
|
||||
let g = instance.get_typed_func::<(i32, i64), (i64, i32), _>(&mut store, "g")?;
|
||||
|
||||
// Call `$g`.
|
||||
println!("Calling export \"g\"...");
|
||||
let (a, b) = g.call((1, 3))?;
|
||||
let (a, b) = g.call(&mut store, (1, 3))?;
|
||||
|
||||
println!("Printing result...");
|
||||
println!("> {} {}", a, b);
|
||||
@@ -60,9 +52,10 @@ fn main() -> Result<()> {
|
||||
.get_typed_func::<
|
||||
(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64),
|
||||
(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64),
|
||||
_,
|
||||
>
|
||||
("round_trip_many")?;
|
||||
let results = round_trip_many.call((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))?;
|
||||
(&mut store, "round_trip_many")?;
|
||||
let results = round_trip_many.call(&mut store, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9))?;
|
||||
|
||||
println!("Printing result...");
|
||||
println!("> {:?}", results);
|
||||
@@ -71,6 +64,9 @@ fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Note that this example is not supported in the off-by-default feature of the
|
||||
// old x86 compiler backend for Cranelift. Wasmtime's default configuration
|
||||
// supports this example, however.
|
||||
#[cfg(feature = "old-x86-backend")]
|
||||
fn main() -> Result<()> {
|
||||
Ok(())
|
||||
|
||||
@@ -26,7 +26,13 @@ to tweak the `-lpthread` and such annotations as well as the name of the
|
||||
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||
|
||||
static wasm_trap_t* hello_callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
|
||||
static wasm_trap_t* hello_callback(
|
||||
void *env,
|
||||
wasmtime_caller_t *caller,
|
||||
const wasmtime_val_t* args,
|
||||
size_t nargs,
|
||||
wasmtime_val_t* results,
|
||||
size_t nresults) {
|
||||
printf("Calling back...\n");
|
||||
printf("> Hello World!\n");
|
||||
return NULL;
|
||||
@@ -53,7 +59,7 @@ int serialize(wasm_byte_vec_t* buffer) {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t wasm;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
@@ -61,13 +67,13 @@ int serialize(wasm_byte_vec_t* buffer) {
|
||||
// Now that we've got our binary webassembly we can compile our module
|
||||
// and serialize into buffer.
|
||||
printf("Compiling and serializing module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*)wasm.data, wasm.size, &module);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
error = wasmtime_module_serialize(module, buffer);
|
||||
wasm_module_delete(module);
|
||||
wasmtime_module_delete(module);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to serialize module", error, NULL);
|
||||
|
||||
@@ -87,13 +93,14 @@ int deserialize(wasm_byte_vec_t* buffer) {
|
||||
|
||||
// With an engine we can create a *store* which is a long-lived group of wasm
|
||||
// modules.
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Deserialize compiled module.
|
||||
printf("Deserialize module...\n");
|
||||
wasm_module_t *module = NULL;
|
||||
wasmtime_error_t *error = wasmtime_module_deserialize(engine, buffer, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
wasmtime_error_t *error = wasmtime_module_deserialize(engine, (uint8_t*) buffer->data, buffer->size, &module);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
|
||||
@@ -102,7 +109,8 @@ int deserialize(wasm_byte_vec_t* buffer) {
|
||||
// function above.
|
||||
printf("Creating callback...\n");
|
||||
wasm_functype_t *hello_ty = wasm_functype_new_0_0();
|
||||
wasm_func_t *hello = wasm_func_new(store, hello_ty, hello_callback);
|
||||
wasmtime_func_t hello;
|
||||
wasmtime_func_new(context, hello_ty, hello_callback, NULL, NULL, &hello);
|
||||
|
||||
// With our callback function we can now instantiate the compiled module,
|
||||
// giving us an instance we can then execute exports from. Note that
|
||||
@@ -110,36 +118,31 @@ int deserialize(wasm_byte_vec_t* buffer) {
|
||||
// to handle that here too.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasm_instance_t *instance = NULL;
|
||||
wasm_extern_t *imports[] = { wasm_func_as_extern(hello) };
|
||||
wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
|
||||
error = wasmtime_instance_new(store, module, &imports_vec, &instance, &trap);
|
||||
if (instance == NULL)
|
||||
wasmtime_instance_t instance;
|
||||
wasmtime_extern_t imports[1];
|
||||
imports[0].kind = WASMTIME_EXTERN_FUNC;
|
||||
imports[0].of.func = hello;
|
||||
error = wasmtime_instance_new(context, module, imports, 1, &instance, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to instantiate", error, trap);
|
||||
wasmtime_module_delete(module);
|
||||
|
||||
// Lookup our `run` export function
|
||||
printf("Extracting export...\n");
|
||||
wasm_extern_vec_t externs;
|
||||
wasm_instance_exports(instance, &externs);
|
||||
assert(externs.size == 1);
|
||||
wasm_func_t *run = wasm_extern_as_func(externs.data[0]);
|
||||
assert(run != NULL);
|
||||
wasmtime_extern_t run;
|
||||
bool ok = wasmtime_instance_export_get(context, &instance, "run", 3, &run);
|
||||
assert(ok);
|
||||
assert(run.kind == WASMTIME_EXTERN_FUNC);
|
||||
|
||||
// And call it!
|
||||
printf("Calling export...\n");
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(run, &args_vec, &results_vec, &trap);
|
||||
error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("failed to call function", error, trap);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
printf("All finished!\n");
|
||||
|
||||
wasm_extern_vec_delete(&externs);
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ fn deserialize(buffer: &[u8]) -> Result<()> {
|
||||
// `Store` structure. Note that you can also tweak configuration settings
|
||||
// with a `Config` and an `Engine` if desired.
|
||||
println!("Initializing...");
|
||||
let store = Store::default();
|
||||
let mut store: Store<()> = Store::default();
|
||||
|
||||
// Compile the wasm binary into an in-memory instance of a `Module`. Note
|
||||
// that this is `unsafe` because it is our responsibility for guaranteeing
|
||||
@@ -39,7 +39,7 @@ fn deserialize(buffer: &[u8]) -> Result<()> {
|
||||
// Here we handle the imports of the module, which in this case is our
|
||||
// `HelloCallback` type and its associated implementation of `Callback.
|
||||
println!("Creating callback...");
|
||||
let hello_func = Func::wrap(&store, || {
|
||||
let hello_func = Func::wrap(&mut store, || {
|
||||
println!("Calling back...");
|
||||
println!("> Hello World!");
|
||||
});
|
||||
@@ -49,15 +49,15 @@ fn deserialize(buffer: &[u8]) -> Result<()> {
|
||||
// Note that this is where the wasm `start` function, if any, would run.
|
||||
println!("Instantiating module...");
|
||||
let imports = [hello_func.into()];
|
||||
let instance = Instance::new(&store, &module, &imports)?;
|
||||
let instance = Instance::new(&mut store, &module, &imports)?;
|
||||
|
||||
// Next we poke around a bit to extract the `run` function from the module.
|
||||
println!("Extracting export...");
|
||||
let run = instance.get_typed_func::<(), ()>("run")?;
|
||||
let run = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
// And last but not least we can call it!
|
||||
println!("Calling export...");
|
||||
run.call(())?;
|
||||
run.call(&mut store, ())?;
|
||||
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
|
||||
@@ -124,11 +124,11 @@ int main(int argc, const char *argv[]) {
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t binary;
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary);
|
||||
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to parse wat", error, NULL);
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
|
||||
// Compile and share.
|
||||
own wasm_store_t* store = wasm_store_new(engine);
|
||||
own wasm_module_t* module = wasm_module_new(store, &binary);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
//! This program is an example of how Wasmtime can be used with multithreaded
|
||||
//! runtimes and how various types and structures can be shared across threads.
|
||||
|
||||
// You can execute this example with `cargo run --example threads`
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use wasmtime::*;
|
||||
@@ -8,57 +12,59 @@ use wasmtime::*;
|
||||
const N_THREADS: i32 = 10;
|
||||
const N_REPS: i32 = 3;
|
||||
|
||||
fn run(engine: &Engine, module: Module, id: i32) -> Result<()> {
|
||||
let store = Store::new(&engine);
|
||||
|
||||
// Create external print functions.
|
||||
println!("Creating callback...");
|
||||
let callback_func = Func::wrap(&store, |arg: i32| {
|
||||
println!("> Thread {} is running", arg);
|
||||
});
|
||||
|
||||
let id_type = GlobalType::new(ValType::I32, Mutability::Const);
|
||||
let id_global = Global::new(&store, id_type, Val::I32(id))?;
|
||||
|
||||
// Instantiate.
|
||||
println!("Instantiating module...");
|
||||
let instance = Instance::new(&store, &module, &[callback_func.into(), id_global.into()])?;
|
||||
|
||||
// Extract exports.
|
||||
println!("Extracting export...");
|
||||
let g = instance.get_typed_func::<(), ()>("run")?;
|
||||
|
||||
for _ in 0..N_REPS {
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
// Call `$run`.
|
||||
drop(g.call(())?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
println!("Initializing...");
|
||||
|
||||
// Initialize global per-process state. This state will be shared amonst all
|
||||
// threads. Notably this includes the compiled module as well as a `Linker`,
|
||||
// which contains all our host functions we want to define.
|
||||
let engine = Engine::default();
|
||||
|
||||
// Compile.
|
||||
println!("Compiling module...");
|
||||
let module = Module::from_file(&engine, "examples/threads.wat")?;
|
||||
let mut linker = Linker::new(&engine);
|
||||
linker.func_wrap("global", "hello", || {
|
||||
println!("> Hello from {:?}", thread::current().id());
|
||||
})?;
|
||||
let linker = Arc::new(linker); // "finalize" the linker
|
||||
|
||||
let mut children = Vec::new();
|
||||
for id in 0..N_THREADS {
|
||||
let engine = engine.clone();
|
||||
let module = module.clone();
|
||||
children.push(thread::spawn(move || {
|
||||
run(&engine, module, id).expect("Success");
|
||||
}));
|
||||
}
|
||||
// Share this global state amongst a set of threads, each of which will
|
||||
// create stores and execute instances.
|
||||
let children = (0..N_THREADS)
|
||||
.map(|_| {
|
||||
let engine = engine.clone();
|
||||
let module = module.clone();
|
||||
let linker = linker.clone();
|
||||
thread::spawn(move || {
|
||||
run(&engine, &module, &linker).expect("Success");
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, child) in children.into_iter().enumerate() {
|
||||
if let Err(_) = child.join() {
|
||||
println!("Thread #{} errors", i);
|
||||
}
|
||||
for child in children {
|
||||
child.join().unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(engine: &Engine, module: &Module, linker: &Linker<()>) -> Result<()> {
|
||||
// Each sub-thread we have starting out by instantiating the `module`
|
||||
// provided into a fresh `Store`.
|
||||
println!("Instantiating module...");
|
||||
let mut store = Store::new(&engine, ());
|
||||
let instance = linker.instantiate(&mut store, module)?;
|
||||
let run = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
println!("Executing...");
|
||||
for _ in 0..N_REPS {
|
||||
run.call(&mut store, ())?;
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
}
|
||||
|
||||
// Also note that that a `Store` can also move between threads:
|
||||
println!("> Moving {:?} to a new thread", thread::current().id());
|
||||
let child = thread::spawn(move || run.call(&mut store, ()));
|
||||
|
||||
child.join().unwrap()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
(module
|
||||
(func $message (import "" "hello") (param i32))
|
||||
(global $id (import "" "id") i32)
|
||||
(func (export "run") (call $message (global.get $id)))
|
||||
(func $hello (import "global" "hello"))
|
||||
(func (export "run") (call $hello))
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use anyhow::{anyhow, Error};
|
||||
use std::future::Future;
|
||||
use anyhow::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::time::Duration;
|
||||
use wasmtime::{Config, Engine, Linker, Module, Store};
|
||||
// For this example we want to use the async version of wasmtime_wasi.
|
||||
// Notably, this version of wasi uses a scheduler that will async yield
|
||||
// when sleeping in `poll_oneoff`.
|
||||
use wasmtime_wasi::tokio::{Wasi, WasiCtxBuilder};
|
||||
use wasmtime_wasi::{tokio::WasiCtxBuilder, WasiCtx};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
@@ -42,6 +42,7 @@ async fn main() -> Result<(), Error> {
|
||||
struct Environment {
|
||||
engine: Engine,
|
||||
module: Module,
|
||||
linker: Arc<Linker<WasiCtx>>,
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
@@ -52,13 +53,21 @@ impl Environment {
|
||||
config.async_support(true);
|
||||
config.consume_fuel(true);
|
||||
|
||||
// Install the host functions for `Wasi`.
|
||||
Wasi::add_to_config(&mut config);
|
||||
|
||||
let engine = Engine::new(&config)?;
|
||||
let module = Module::from_file(&engine, "target/wasm32-wasi/debug/tokio-wasi.wasm")?;
|
||||
|
||||
Ok(Self { engine, module })
|
||||
// A `Linker` is shared in the environment amongst all stores, and this
|
||||
// linker is used to instantiate the `module` above. This example only
|
||||
// adds WASI functions to the linker, notably the async versions built
|
||||
// on tokio.
|
||||
let mut linker = Linker::new(&engine);
|
||||
wasmtime_wasi::tokio::add_to_linker(&mut linker, |cx| cx)?;
|
||||
|
||||
Ok(Self {
|
||||
engine,
|
||||
module,
|
||||
linker: Arc::new(linker),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,87 +85,29 @@ impl Inputs {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_wasm(inputs: Inputs) -> impl Future<Output = Result<(), Error>> {
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
// IMPORTANT: The current wasmtime API is very challenging to use safely
|
||||
// on an async runtime. This RFC describes a redesign of the API that will
|
||||
// resolve these safety issues:
|
||||
// https://github.com/alexcrichton/rfcs-2/blob/new-api/accepted/new-api.md
|
||||
|
||||
// This is a "marker type future" which simply wraps some other future and
|
||||
// the only purpose it serves is to forward the implementation of `Future`
|
||||
// as well as have `unsafe impl Send` for itself, regardless of the
|
||||
// underlying type.
|
||||
//
|
||||
// Note that the qctual safety of this relies on the fact that the inputs
|
||||
// here are `Send`, the outputs (just () in this case) are `Send`, and the
|
||||
// future itself is safe tu resume on other threads.
|
||||
//
|
||||
// For an in-depth discussion of the safety of moving Wasmtime's `Store`
|
||||
// between threads, see
|
||||
// https://docs.wasmtime.dev/examples-rust-multithreading.html.
|
||||
struct UnsafeSend<T>(T);
|
||||
|
||||
// Note the `where` cause specifically ensures the output of the future to
|
||||
// be `Send` is required. We specifically dont require `T` to be `Send`
|
||||
// since that's the whole point of this function, but we require that
|
||||
// everything used to construct `T` is `Send` below.
|
||||
unsafe impl<T> Send for UnsafeSend<T>
|
||||
where
|
||||
T: Future,
|
||||
T::Output: Send,
|
||||
{
|
||||
}
|
||||
impl<T: Future> Future for UnsafeSend<T> {
|
||||
type Output = T::Output;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T::Output> {
|
||||
// Note that this `unsafe` is unrelated to `Send`, it only has to do with "pin
|
||||
// projection" and should be safe since it's all we do with the `Pin`.
|
||||
unsafe { self.map_unchecked_mut(|p| &mut p.0).poll(cx) }
|
||||
}
|
||||
}
|
||||
|
||||
// This is a crucial assertion that needs to be here. The compiler
|
||||
// typically checks this for us, but do to our `UnsafeSend` type the
|
||||
// compiler isn't automatically checking this. The assertion here must
|
||||
// assert that all arguments to this function are indeed `Send` because
|
||||
// we're closing over them and sending them to other threads. It's only
|
||||
// everything *internal* to the computation of this function which doesn't
|
||||
// have to be `Send`.
|
||||
fn assert_send<T: Send>(_t: &T) {}
|
||||
assert_send(&inputs);
|
||||
|
||||
// Wrap up the `_run_wasm` function, which is *not* `Send`, but is safe to
|
||||
// resume on other threads.
|
||||
UnsafeSend(_run_wasm(inputs))
|
||||
}
|
||||
|
||||
async fn _run_wasm(inputs: Inputs) -> Result<(), Error> {
|
||||
let store = Store::new(&inputs.env.engine);
|
||||
async fn run_wasm(inputs: Inputs) -> Result<(), Error> {
|
||||
let wasi = WasiCtxBuilder::new()
|
||||
// Let wasi print to this process's stdout.
|
||||
.inherit_stdout()
|
||||
// Set an environment variable so the wasm knows its name.
|
||||
.env("NAME", &inputs.name)?
|
||||
.build();
|
||||
let mut store = Store::new(&inputs.env.engine, wasi);
|
||||
|
||||
// WebAssembly execution will be paused for an async yield every time it
|
||||
// consumes 10000 fuel. Fuel will be refilled u32::MAX times.
|
||||
store.out_of_fuel_async_yield(u32::MAX, 10000);
|
||||
|
||||
Wasi::set_context(
|
||||
&store,
|
||||
WasiCtxBuilder::new()
|
||||
// Let wasi print to this process's stdout.
|
||||
.inherit_stdout()
|
||||
// Set an environment variable so the wasm knows its name.
|
||||
.env("NAME", &inputs.name)?
|
||||
.build(),
|
||||
)
|
||||
.map_err(|_| anyhow!("setting wasi context"))?;
|
||||
|
||||
let linker = Linker::new(&store);
|
||||
|
||||
// Instantiate
|
||||
let instance = linker.instantiate_async(&inputs.env.module).await?;
|
||||
// Instantiate into our own unique store using the shared linker, afterwards
|
||||
// acquiring the `_start` function for the module and executing it.
|
||||
let instance = inputs
|
||||
.env
|
||||
.linker
|
||||
.instantiate_async(&mut store, &inputs.env.module)
|
||||
.await?;
|
||||
instance
|
||||
.get_typed_func::<(), ()>("_start")?
|
||||
.call_async(())
|
||||
.get_typed_func::<(), (), _>(&mut store, "_start")?
|
||||
.call_async(&mut store, ())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -28,12 +28,18 @@ to tweak the `-lpthread` and such annotations.
|
||||
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||
|
||||
int main() {
|
||||
int ret = 0;
|
||||
// Set up our context
|
||||
wasm_engine_t *engine = wasm_engine_new();
|
||||
assert(engine != NULL);
|
||||
wasm_store_t *store = wasm_store_new(engine);
|
||||
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
|
||||
assert(store != NULL);
|
||||
wasmtime_context_t *context = wasmtime_store_context(store);
|
||||
|
||||
// Create a linker with WASI functions defined
|
||||
wasmtime_linker_t *linker = wasmtime_linker_new(engine);
|
||||
wasmtime_error_t *error = wasmtime_linker_define_wasi(linker);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to link wasi", error, NULL);
|
||||
|
||||
wasm_byte_vec_t wasm;
|
||||
// Load our input file to parse it next
|
||||
@@ -53,8 +59,8 @@ int main() {
|
||||
fclose(file);
|
||||
|
||||
// Compile our modules
|
||||
wasm_module_t *module = NULL;
|
||||
wasmtime_error_t *error = wasmtime_module_new(engine, &wasm, &module);
|
||||
wasmtime_module_t *module = NULL;
|
||||
error = wasmtime_module_new(engine, (uint8_t*)wasm.data, wasm.size, &module);
|
||||
if (!module)
|
||||
exit_with_error("failed to compile module", error, NULL);
|
||||
wasm_byte_vec_delete(&wasm);
|
||||
@@ -68,39 +74,28 @@ int main() {
|
||||
wasi_config_inherit_stdout(wasi_config);
|
||||
wasi_config_inherit_stderr(wasi_config);
|
||||
wasm_trap_t *trap = NULL;
|
||||
wasi_instance_t *wasi = wasi_instance_new(store, "wasi_snapshot_preview1", wasi_config, &trap);
|
||||
if (wasi == NULL)
|
||||
exit_with_error("failed to instantiate WASI", NULL, trap);
|
||||
|
||||
wasmtime_linker_t *linker = wasmtime_linker_new(store);
|
||||
error = wasmtime_linker_define_wasi(linker, wasi);
|
||||
error = wasmtime_context_set_wasi(context, wasi_config);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to link wasi", error, NULL);
|
||||
exit_with_error("failed to instantiate WASI", error, NULL);
|
||||
|
||||
// Instantiate the module
|
||||
wasm_name_t empty;
|
||||
wasm_name_new_from_string(&empty, "");
|
||||
wasm_instance_t *instance = NULL;
|
||||
error = wasmtime_linker_module(linker, &empty, module);
|
||||
error = wasmtime_linker_module(linker, context, "", 0, module);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to instantiate module", error, NULL);
|
||||
|
||||
// Run it.
|
||||
wasm_func_t* func;
|
||||
wasmtime_linker_get_default(linker, &empty, &func);
|
||||
wasmtime_func_t func;
|
||||
error = wasmtime_linker_get_default(linker, context, "", 0, &func);
|
||||
if (error != NULL)
|
||||
exit_with_error("failed to locate default export for module", error, NULL);
|
||||
|
||||
wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
|
||||
wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
|
||||
error = wasmtime_func_call(func, &args_vec, &results_vec, &trap);
|
||||
if (error != NULL)
|
||||
error = wasmtime_func_call(context, &func, NULL, 0, NULL, 0, &trap);
|
||||
if (error != NULL || trap != NULL)
|
||||
exit_with_error("error calling default export", error, trap);
|
||||
|
||||
// Clean up after ourselves at this point
|
||||
wasm_name_delete(&empty);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasmtime_module_delete(module);
|
||||
wasmtime_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,38 +5,30 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use wasmtime::*;
|
||||
use wasmtime_wasi::sync::{Wasi, WasiCtxBuilder};
|
||||
use wasmtime_wasi::sync::WasiCtxBuilder;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
tracing_subscriber::FmtSubscriber::builder()
|
||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||
.with_ansi(true)
|
||||
.init();
|
||||
|
||||
// Define the WASI functions globally on the `Config`.
|
||||
let mut config = Config::default();
|
||||
Wasi::add_to_config(&mut config);
|
||||
let engine = Engine::default();
|
||||
let mut linker = Linker::new(&engine);
|
||||
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
|
||||
|
||||
let store = Store::new(&Engine::new(&config)?);
|
||||
|
||||
// Set the WASI context in the store; all instances in the store share this context.
|
||||
// `WasiCtxBuilder` provides a number of ways to configure what the target program
|
||||
// will have access to.
|
||||
assert!(Wasi::set_context(
|
||||
&store,
|
||||
WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.inherit_args()?
|
||||
.build()
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
let mut linker = Linker::new(&store);
|
||||
// Create a WASI context and put it in a Store; all instances in the store
|
||||
// share this context. `WasiCtxBuilder` provides a number of ways to
|
||||
// configure what the target program will have access to.
|
||||
let wasi = WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.inherit_args()?
|
||||
.build();
|
||||
let mut store = Store::new(&engine, wasi);
|
||||
|
||||
// Instantiate our module with the imports we've created, and run it.
|
||||
let module = Module::from_file(store.engine(), "target/wasm32-wasi/debug/wasi.wasm")?;
|
||||
linker.module("", &module)?;
|
||||
linker.get_default("")?.typed::<(), ()>()?.call(())?;
|
||||
let module = Module::from_file(&engine, "target/wasm32-wasi/debug/wasi.wasm")?;
|
||||
linker.module(&mut store, "", &module)?;
|
||||
linker
|
||||
.get_default(&mut store, "")?
|
||||
.typed::<(), (), _>(&store)?
|
||||
.call(&mut store, ())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user