13c51d3adSAlex Crichton /*
23c51d3adSAlex Crichton Example of instantiating of the WebAssembly module and invoking its exported
33c51d3adSAlex Crichton function.
43c51d3adSAlex Crichton
557ba95e9SMasashi Yoshimura You can build using cmake:
62ba3025eSTheGreatRambler
72ba3025eSTheGreatRambler mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-memory
82ba3025eSTheGreatRambler
93c51d3adSAlex Crichton Also note that this example was taken from
103c51d3adSAlex Crichton https://github.com/WebAssembly/wasm-c-api/blob/master/example/memory.c
113c51d3adSAlex Crichton originally
123c51d3adSAlex Crichton */
133c51d3adSAlex Crichton
143c51d3adSAlex Crichton #include <inttypes.h>
153c51d3adSAlex Crichton #include <stdio.h>
163c51d3adSAlex Crichton #include <stdlib.h>
173c51d3adSAlex Crichton #include <string.h>
183c51d3adSAlex Crichton #include <wasm.h>
193c51d3adSAlex Crichton #include <wasmtime.h>
203c51d3adSAlex Crichton
21f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
22f8fee938STyler Rockwood wasm_trap_t *trap);
233c51d3adSAlex Crichton
check(bool success)243c51d3adSAlex Crichton void check(bool success) {
253c51d3adSAlex Crichton if (!success) {
263c51d3adSAlex Crichton printf("> Error, expected success\n");
273c51d3adSAlex Crichton exit(1);
283c51d3adSAlex Crichton }
293c51d3adSAlex Crichton }
303c51d3adSAlex Crichton
check_call(wasmtime_context_t * store,wasmtime_func_t * func,const wasmtime_val_t * args,size_t nargs,int32_t expected)31f8fee938STyler Rockwood void check_call(wasmtime_context_t *store, wasmtime_func_t *func,
32f8fee938STyler Rockwood const wasmtime_val_t *args, size_t nargs, int32_t expected) {
337a1b7cdfSAlex Crichton wasmtime_val_t results[1];
34bd374fd6SAlex Crichton wasm_trap_t *trap = NULL;
35f8fee938STyler Rockwood wasmtime_error_t *error =
36f8fee938STyler Rockwood wasmtime_func_call(store, func, args, nargs, results, 1, &trap);
37bd374fd6SAlex Crichton if (error != NULL || trap != NULL)
38bd374fd6SAlex Crichton exit_with_error("failed to call function", error, trap);
39bd374fd6SAlex Crichton if (results[0].of.i32 != expected) {
403c51d3adSAlex Crichton printf("> Error on result\n");
413c51d3adSAlex Crichton exit(1);
423c51d3adSAlex Crichton }
433c51d3adSAlex Crichton }
443c51d3adSAlex Crichton
check_call0(wasmtime_context_t * store,wasmtime_func_t * func,int32_t expected)45f8fee938STyler Rockwood void check_call0(wasmtime_context_t *store, wasmtime_func_t *func,
46f8fee938STyler Rockwood int32_t expected) {
477a1b7cdfSAlex Crichton check_call(store, func, NULL, 0, expected);
483c51d3adSAlex Crichton }
493c51d3adSAlex Crichton
check_call1(wasmtime_context_t * store,wasmtime_func_t * func,int32_t arg,int32_t expected)50f8fee938STyler Rockwood void check_call1(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg,
51f8fee938STyler Rockwood int32_t expected) {
527a1b7cdfSAlex Crichton wasmtime_val_t args[1];
537a1b7cdfSAlex Crichton args[0].kind = WASMTIME_I32;
547a1b7cdfSAlex Crichton args[0].of.i32 = arg;
557a1b7cdfSAlex Crichton check_call(store, func, args, 1, expected);
563c51d3adSAlex Crichton }
573c51d3adSAlex Crichton
check_call2(wasmtime_context_t * store,wasmtime_func_t * func,int32_t arg1,int32_t arg2,int32_t expected)58f8fee938STyler Rockwood void check_call2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
59f8fee938STyler Rockwood int32_t arg2, int32_t expected) {
607a1b7cdfSAlex Crichton wasmtime_val_t args[2];
617a1b7cdfSAlex Crichton args[0].kind = WASMTIME_I32;
627a1b7cdfSAlex Crichton args[0].of.i32 = arg1;
637a1b7cdfSAlex Crichton args[1].kind = WASMTIME_I32;
647a1b7cdfSAlex Crichton args[1].of.i32 = arg2;
657a1b7cdfSAlex Crichton check_call(store, func, args, 2, expected);
663c51d3adSAlex Crichton }
673c51d3adSAlex Crichton
check_ok(wasmtime_context_t * store,wasmtime_func_t * func,const wasmtime_val_t * args,size_t nargs)68f8fee938STyler Rockwood void check_ok(wasmtime_context_t *store, wasmtime_func_t *func,
69f8fee938STyler Rockwood const wasmtime_val_t *args, size_t nargs) {
70bd374fd6SAlex Crichton wasm_trap_t *trap = NULL;
71f8fee938STyler Rockwood wasmtime_error_t *error =
72f8fee938STyler Rockwood wasmtime_func_call(store, func, args, nargs, NULL, 0, &trap);
73bd374fd6SAlex Crichton if (error != NULL || trap != NULL)
74bd374fd6SAlex Crichton exit_with_error("failed to call function", error, trap);
753c51d3adSAlex Crichton }
763c51d3adSAlex Crichton
check_ok2(wasmtime_context_t * store,wasmtime_func_t * func,int32_t arg1,int32_t arg2)77f8fee938STyler Rockwood void check_ok2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
78f8fee938STyler Rockwood int32_t arg2) {
797a1b7cdfSAlex Crichton wasmtime_val_t args[2];
807a1b7cdfSAlex Crichton args[0].kind = WASMTIME_I32;
817a1b7cdfSAlex Crichton args[0].of.i32 = arg1;
827a1b7cdfSAlex Crichton args[1].kind = WASMTIME_I32;
837a1b7cdfSAlex Crichton args[1].of.i32 = arg2;
847a1b7cdfSAlex Crichton check_ok(store, func, args, 2);
853c51d3adSAlex Crichton }
863c51d3adSAlex Crichton
check_trap(wasmtime_context_t * store,wasmtime_func_t * func,const wasmtime_val_t * args,size_t nargs,size_t num_results)87f8fee938STyler Rockwood void check_trap(wasmtime_context_t *store, wasmtime_func_t *func,
88f8fee938STyler Rockwood const wasmtime_val_t *args, size_t nargs, size_t num_results) {
89bd374fd6SAlex Crichton assert(num_results <= 1);
907a1b7cdfSAlex Crichton wasmtime_val_t results[1];
91bd374fd6SAlex Crichton wasm_trap_t *trap = NULL;
92f8fee938STyler Rockwood wasmtime_error_t *error =
93f8fee938STyler Rockwood wasmtime_func_call(store, func, args, nargs, results, num_results, &trap);
94bd374fd6SAlex Crichton if (error != NULL)
95bd374fd6SAlex Crichton exit_with_error("failed to call function", error, NULL);
96bd374fd6SAlex Crichton if (trap == NULL) {
973c51d3adSAlex Crichton printf("> Error on result, expected trap\n");
983c51d3adSAlex Crichton exit(1);
993c51d3adSAlex Crichton }
1003c51d3adSAlex Crichton wasm_trap_delete(trap);
1013c51d3adSAlex Crichton }
1023c51d3adSAlex Crichton
check_trap1(wasmtime_context_t * store,wasmtime_func_t * func,int32_t arg)103f8fee938STyler Rockwood void check_trap1(wasmtime_context_t *store, wasmtime_func_t *func,
104f8fee938STyler Rockwood int32_t arg) {
1057a1b7cdfSAlex Crichton wasmtime_val_t args[1];
1067a1b7cdfSAlex Crichton args[0].kind = WASMTIME_I32;
1077a1b7cdfSAlex Crichton args[0].of.i32 = arg;
1087a1b7cdfSAlex Crichton check_trap(store, func, args, 1, 1);
1093c51d3adSAlex Crichton }
1103c51d3adSAlex Crichton
check_trap2(wasmtime_context_t * store,wasmtime_func_t * func,int32_t arg1,int32_t arg2)111f8fee938STyler Rockwood void check_trap2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
112f8fee938STyler Rockwood int32_t arg2) {
1137a1b7cdfSAlex Crichton wasmtime_val_t args[2];
1147a1b7cdfSAlex Crichton args[0].kind = WASMTIME_I32;
1157a1b7cdfSAlex Crichton args[0].of.i32 = arg1;
1167a1b7cdfSAlex Crichton args[1].kind = WASMTIME_I32;
1177a1b7cdfSAlex Crichton args[1].of.i32 = arg2;
1187a1b7cdfSAlex Crichton check_trap(store, func, args, 2, 0);
1193c51d3adSAlex Crichton }
1203c51d3adSAlex Crichton
main()121*adff9d9dSAlex Crichton int main() {
1223c51d3adSAlex Crichton // Initialize.
1233c51d3adSAlex Crichton printf("Initializing...\n");
1243c51d3adSAlex Crichton wasm_engine_t *engine = wasm_engine_new();
1257a1b7cdfSAlex Crichton wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
1267a1b7cdfSAlex Crichton wasmtime_context_t *context = wasmtime_store_context(store);
1273c51d3adSAlex Crichton
1283c51d3adSAlex Crichton // Load our input file to parse it next
1293c51d3adSAlex Crichton FILE *file = fopen("examples/memory.wat", "r");
1303c51d3adSAlex Crichton if (!file) {
1313c51d3adSAlex Crichton printf("> Error loading file!\n");
1323c51d3adSAlex Crichton return 1;
1333c51d3adSAlex Crichton }
1343c51d3adSAlex Crichton fseek(file, 0L, SEEK_END);
1353c51d3adSAlex Crichton size_t file_size = ftell(file);
1363c51d3adSAlex Crichton fseek(file, 0L, SEEK_SET);
1373c51d3adSAlex Crichton wasm_byte_vec_t wat;
1383c51d3adSAlex Crichton wasm_byte_vec_new_uninitialized(&wat, file_size);
1393c51d3adSAlex Crichton if (fread(wat.data, file_size, 1, file) != 1) {
1403c51d3adSAlex Crichton printf("> Error loading module!\n");
1413c51d3adSAlex Crichton return 1;
1423c51d3adSAlex Crichton }
1433c51d3adSAlex Crichton fclose(file);
1443c51d3adSAlex Crichton
1453c51d3adSAlex Crichton // Parse the wat into the binary wasm format
146bd374fd6SAlex Crichton wasm_byte_vec_t binary;
1477a1b7cdfSAlex Crichton wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
148bd374fd6SAlex Crichton if (error != NULL)
149bd374fd6SAlex Crichton exit_with_error("failed to parse wat", error, NULL);
1503c51d3adSAlex Crichton wasm_byte_vec_delete(&wat);
1513c51d3adSAlex Crichton
1523c51d3adSAlex Crichton // Compile.
1533c51d3adSAlex Crichton printf("Compiling module...\n");
1547a1b7cdfSAlex Crichton wasmtime_module_t *module = NULL;
155f8fee938STyler Rockwood error =
156f8fee938STyler Rockwood wasmtime_module_new(engine, (uint8_t *)binary.data, binary.size, &module);
157bd374fd6SAlex Crichton if (error)
158bd374fd6SAlex Crichton exit_with_error("failed to compile module", error, NULL);
1593c51d3adSAlex Crichton wasm_byte_vec_delete(&binary);
1603c51d3adSAlex Crichton
1613c51d3adSAlex Crichton // Instantiate.
1623c51d3adSAlex Crichton printf("Instantiating module...\n");
1637a1b7cdfSAlex Crichton wasmtime_instance_t instance;
164bd374fd6SAlex Crichton wasm_trap_t *trap = NULL;
1657a1b7cdfSAlex Crichton error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
1667a1b7cdfSAlex Crichton if (error != NULL || trap != NULL)
167bd374fd6SAlex Crichton exit_with_error("failed to instantiate", error, trap);
1687a1b7cdfSAlex Crichton wasmtime_module_delete(module);
1693c51d3adSAlex Crichton
1703c51d3adSAlex Crichton // Extract export.
1713c51d3adSAlex Crichton printf("Extracting exports...\n");
1727a1b7cdfSAlex Crichton wasmtime_memory_t memory;
1737a1b7cdfSAlex Crichton wasmtime_func_t size_func, load_func, store_func;
1747a1b7cdfSAlex Crichton wasmtime_extern_t item;
1757a1b7cdfSAlex Crichton bool ok;
176f8fee938STyler Rockwood ok = wasmtime_instance_export_get(context, &instance, "memory",
177f8fee938STyler Rockwood strlen("memory"), &item);
1787a1b7cdfSAlex Crichton assert(ok && item.kind == WASMTIME_EXTERN_MEMORY);
1797a1b7cdfSAlex Crichton memory = item.of.memory;
180f8fee938STyler Rockwood ok = wasmtime_instance_export_get(context, &instance, "size", strlen("size"),
181f8fee938STyler Rockwood &item);
1827a1b7cdfSAlex Crichton assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
1837a1b7cdfSAlex Crichton size_func = item.of.func;
184f8fee938STyler Rockwood ok = wasmtime_instance_export_get(context, &instance, "load", strlen("load"),
185f8fee938STyler Rockwood &item);
1867a1b7cdfSAlex Crichton assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
1877a1b7cdfSAlex Crichton load_func = item.of.func;
188f8fee938STyler Rockwood ok = wasmtime_instance_export_get(context, &instance, "store",
189f8fee938STyler Rockwood strlen("store"), &item);
1907a1b7cdfSAlex Crichton assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
1917a1b7cdfSAlex Crichton store_func = item.of.func;
1923c51d3adSAlex Crichton
1933c51d3adSAlex Crichton // Check initial memory.
1943c51d3adSAlex Crichton printf("Checking memory...\n");
1957a1b7cdfSAlex Crichton check(wasmtime_memory_size(context, &memory) == 2);
1967a1b7cdfSAlex Crichton check(wasmtime_memory_data_size(context, &memory) == 0x20000);
1977a1b7cdfSAlex Crichton check(wasmtime_memory_data(context, &memory)[0] == 0);
1987a1b7cdfSAlex Crichton check(wasmtime_memory_data(context, &memory)[0x1000] == 1);
1997a1b7cdfSAlex Crichton check(wasmtime_memory_data(context, &memory)[0x1003] == 4);
2003c51d3adSAlex Crichton
2017a1b7cdfSAlex Crichton check_call0(context, &size_func, 2);
2027a1b7cdfSAlex Crichton check_call1(context, &load_func, 0, 0);
2037a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x1000, 1);
2047a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x1003, 4);
2057a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x1ffff, 0);
2067a1b7cdfSAlex Crichton check_trap1(context, &load_func, 0x20000);
2073c51d3adSAlex Crichton
2083c51d3adSAlex Crichton // Mutate memory.
2093c51d3adSAlex Crichton printf("Mutating memory...\n");
2107a1b7cdfSAlex Crichton wasmtime_memory_data(context, &memory)[0x1003] = 5;
2117a1b7cdfSAlex Crichton check_ok2(context, &store_func, 0x1002, 6);
2127a1b7cdfSAlex Crichton check_trap2(context, &store_func, 0x20000, 0);
2133c51d3adSAlex Crichton
2147a1b7cdfSAlex Crichton check(wasmtime_memory_data(context, &memory)[0x1002] == 6);
2157a1b7cdfSAlex Crichton check(wasmtime_memory_data(context, &memory)[0x1003] == 5);
2167a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x1002, 6);
2177a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x1003, 5);
2183c51d3adSAlex Crichton
2193c51d3adSAlex Crichton // Grow memory.
2203c51d3adSAlex Crichton printf("Growing memory...\n");
2212ba3025eSTheGreatRambler uint64_t old_size;
2227a1b7cdfSAlex Crichton error = wasmtime_memory_grow(context, &memory, 1, &old_size);
2237a1b7cdfSAlex Crichton if (error != NULL)
2247a1b7cdfSAlex Crichton exit_with_error("failed to grow memory", error, trap);
2257a1b7cdfSAlex Crichton check(wasmtime_memory_size(context, &memory) == 3);
2267a1b7cdfSAlex Crichton check(wasmtime_memory_data_size(context, &memory) == 0x30000);
2273c51d3adSAlex Crichton
2287a1b7cdfSAlex Crichton check_call1(context, &load_func, 0x20000, 0);
2297a1b7cdfSAlex Crichton check_ok2(context, &store_func, 0x20000, 0);
2307a1b7cdfSAlex Crichton check_trap1(context, &load_func, 0x30000);
2317a1b7cdfSAlex Crichton check_trap2(context, &store_func, 0x30000, 0);
2323c51d3adSAlex Crichton
2337a1b7cdfSAlex Crichton error = wasmtime_memory_grow(context, &memory, 1, &old_size);
2347a1b7cdfSAlex Crichton assert(error != NULL);
2357a1b7cdfSAlex Crichton wasmtime_error_delete(error);
2367a1b7cdfSAlex Crichton error = wasmtime_memory_grow(context, &memory, 0, &old_size);
2377a1b7cdfSAlex Crichton if (error != NULL)
2387a1b7cdfSAlex Crichton exit_with_error("failed to grow memory", error, trap);
2393c51d3adSAlex Crichton
2403c51d3adSAlex Crichton // Create stand-alone memory.
2413c51d3adSAlex Crichton printf("Creating stand-alone memory...\n");
2423c51d3adSAlex Crichton wasm_limits_t limits = {5, 5};
2433c51d3adSAlex Crichton wasm_memorytype_t *memorytype = wasm_memorytype_new(&limits);
2447a1b7cdfSAlex Crichton wasmtime_memory_t memory2;
2457a1b7cdfSAlex Crichton error = wasmtime_memory_new(context, memorytype, &memory2);
2467a1b7cdfSAlex Crichton if (error != NULL)
2477a1b7cdfSAlex Crichton exit_with_error("failed to create memory", error, trap);
2483c51d3adSAlex Crichton wasm_memorytype_delete(memorytype);
2497a1b7cdfSAlex Crichton check(wasmtime_memory_size(context, &memory2) == 5);
2503c51d3adSAlex Crichton
2513c51d3adSAlex Crichton // Shut down.
2523c51d3adSAlex Crichton printf("Shutting down...\n");
2537a1b7cdfSAlex Crichton wasmtime_store_delete(store);
2543c51d3adSAlex Crichton wasm_engine_delete(engine);
2553c51d3adSAlex Crichton
2563c51d3adSAlex Crichton // All done.
2573c51d3adSAlex Crichton printf("Done.\n");
2583c51d3adSAlex Crichton return 0;
2593c51d3adSAlex Crichton }
260bd374fd6SAlex Crichton
exit_with_error(const char * message,wasmtime_error_t * error,wasm_trap_t * trap)261f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
262f8fee938STyler Rockwood wasm_trap_t *trap) {
263bd374fd6SAlex Crichton fprintf(stderr, "error: %s\n", message);
264bd374fd6SAlex Crichton wasm_byte_vec_t error_message;
265bd374fd6SAlex Crichton if (error != NULL) {
266bd374fd6SAlex Crichton wasmtime_error_message(error, &error_message);
267bd374fd6SAlex Crichton wasmtime_error_delete(error);
268bd374fd6SAlex Crichton } else {
269bd374fd6SAlex Crichton wasm_trap_message(trap, &error_message);
270bd374fd6SAlex Crichton wasm_trap_delete(trap);
271bd374fd6SAlex Crichton }
272bd374fd6SAlex Crichton fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
273bd374fd6SAlex Crichton wasm_byte_vec_delete(&error_message);
274bd374fd6SAlex Crichton exit(1);
275bd374fd6SAlex Crichton }
276