Move all examples to a top-level directory (#1286)
* Move all examples to a top-level directory This commit moves all API examples (Rust and C) to a top-level `examples` directory. This is intended to make it more discoverable and conventional as to where examples are located. Additionally all examples are now available in both Rust and C to see how to execute the example in the language you're familiar with. The intention is that as more languages are supported we'd add more languages as examples here too. Each example is also accompanied by either a `*.wat` file which is parsed as input, or a Rust project in a `wasm` folder which is compiled as input. A simple driver crate was also added to `crates/misc` which executes all the examples on CI, ensuring the C and Rust examples all execute successfully.
This commit is contained in:
248
examples/memory.c
Normal file
248
examples/memory.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
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
|
||||
cc examples/memory.c \
|
||||
-I crates/c-api/include \
|
||||
-I crates/c-api/wasm-c-api/include \
|
||||
target/release/libwasmtime.a \
|
||||
-lpthread -ldl -lm \
|
||||
-o memory
|
||||
./memory
|
||||
|
||||
Note that on Windows and macOS the command will be similar, but you'll need
|
||||
to tweak the `-lpthread` and such annotations.
|
||||
|
||||
Also note that this example was taken from
|
||||
https://github.com/WebAssembly/wasm-c-api/blob/master/example/memory.c
|
||||
originally
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wasm.h>
|
||||
#include <wasmtime.h>
|
||||
|
||||
|
||||
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");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void check_call(wasm_func_t* func, wasm_val_t args[], int32_t expected) {
|
||||
wasm_val_t results[1];
|
||||
if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
|
||||
printf("> Error on result\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void check_call0(wasm_func_t* func, int32_t expected) {
|
||||
check_call(func, NULL, expected);
|
||||
}
|
||||
|
||||
void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
|
||||
wasm_val_t args[] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
|
||||
check_call(func, args, expected);
|
||||
}
|
||||
|
||||
void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
|
||||
wasm_val_t args[2] = {
|
||||
{.kind = WASM_I32, .of = {.i32 = arg1}},
|
||||
{.kind = WASM_I32, .of = {.i32 = arg2}}
|
||||
};
|
||||
check_call(func, args, expected);
|
||||
}
|
||||
|
||||
void check_ok(wasm_func_t* func, wasm_val_t args[]) {
|
||||
if (wasm_func_call(func, args, NULL)) {
|
||||
printf("> Error on result, expected empty\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
|
||||
wasm_val_t args[2] = {
|
||||
{.kind = WASM_I32, .of = {.i32 = arg1}},
|
||||
{.kind = WASM_I32, .of = {.i32 = arg2}}
|
||||
};
|
||||
check_ok(func, args);
|
||||
}
|
||||
|
||||
void check_trap(wasm_func_t* func, wasm_val_t args[]) {
|
||||
wasm_val_t results[1];
|
||||
wasm_trap_t* trap = wasm_func_call(func, args, results);
|
||||
if (! trap) {
|
||||
printf("> Error on result, expected trap\n");
|
||||
exit(1);
|
||||
}
|
||||
wasm_trap_delete(trap);
|
||||
}
|
||||
|
||||
void check_trap1(wasm_func_t* func, int32_t arg) {
|
||||
wasm_val_t args[1] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
|
||||
check_trap(func, args);
|
||||
}
|
||||
|
||||
void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
|
||||
wasm_val_t args[2] = {
|
||||
{.kind = WASM_I32, .of = {.i32 = arg1}},
|
||||
{.kind = WASM_I32, .of = {.i32 = arg2}}
|
||||
};
|
||||
check_trap(func, args);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Load our input file to parse it next
|
||||
FILE* file = fopen("examples/memory.wat", "r");
|
||||
if (!file) {
|
||||
printf("> Error loading file!\n");
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
if (fread(wat.data, file_size, 1, file) != 1) {
|
||||
printf("> Error loading module!\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
// Parse the wat into the binary wasm format
|
||||
wasm_byte_vec_t binary, error;
|
||||
if (wasmtime_wat2wasm(engine, &wat, &binary, &error) == 0) {
|
||||
fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data);
|
||||
return 1;
|
||||
}
|
||||
wasm_byte_vec_delete(&wat);
|
||||
|
||||
// Compile.
|
||||
printf("Compiling module...\n");
|
||||
wasm_module_t* module = wasm_module_new(store, &binary);
|
||||
if (!module) {
|
||||
printf("> Error compiling module!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_byte_vec_delete(&binary);
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
wasm_instance_t* instance = wasm_instance_new(store, module, NULL, NULL);
|
||||
if (!instance) {
|
||||
printf("> Error instantiating module!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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);
|
||||
assert(wasm_memory_same(memory, copy));
|
||||
wasm_memory_delete(copy);
|
||||
|
||||
// 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_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);
|
||||
|
||||
// Mutate memory.
|
||||
printf("Mutating memory...\n");
|
||||
wasm_memory_data(memory)[0x1003] = 5;
|
||||
check_ok2(store_func, 0x1002, 6);
|
||||
check_trap2(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);
|
||||
|
||||
// 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);
|
||||
|
||||
check_call1(load_func, 0x20000, 0);
|
||||
check_ok2(store_func, 0x20000, 0);
|
||||
check_trap1(load_func, 0x30000);
|
||||
check_trap2(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);
|
||||
|
||||
// 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));
|
||||
|
||||
wasm_memorytype_delete(memorytype);
|
||||
wasm_memory_delete(memory2);
|
||||
|
||||
// Shut down.
|
||||
printf("Shutting down...\n");
|
||||
wasm_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
|
||||
// All done.
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user