xref: /wasmtime-44.0.1/examples/multi.c (revision f94db655)
1 /*
2 Example of instantiating of the WebAssembly module and invoking its exported
3 function.
4 
5 You can compile and run this example on Linux with:
6 
7    cargo build --release -p wasmtime-c-api
8    cc examples/multi.c \
9        -I crates/c-api/include \
10        -I crates/c-api/wasm-c-api/include \
11        target/release/libwasmtime.a \
12        -lpthread -ldl -lm \
13        -o multi
14    ./multi
15 
16 Note that on Windows and macOS the command will be similar, but you'll need
17 to tweak the `-lpthread` and such annotations.
18 
19 Also note that this example was taken from
20 https://github.com/WebAssembly/wasm-c-api/blob/master/example/multi.c
21 originally
22 */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <inttypes.h>
28 #include <wasm.h>
29 #include <wasmtime.h>
30 
31 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
32 
33 // A function to be called from Wasm code.
34 wasm_trap_t* callback(
35   const wasm_val_vec_t* args, wasm_val_vec_t* results
36 ) {
37   printf("Calling back...\n");
38   printf("> %"PRIu32" %"PRIu64"\n", args->data[0].of.i32, args->data[1].of.i64);
39   printf("\n");
40 
41   wasm_val_copy(&results->data[0], &args->data[1]);
42   wasm_val_copy(&results->data[1], &args->data[0]);
43   return NULL;
44 }
45 
46 
47 // A function closure.
48 wasm_trap_t* closure_callback(
49   void* env, const wasm_val_t args[], wasm_val_t results[]
50 ) {
51   int i = *(int*)env;
52   printf("Calling back closure...\n");
53   printf("> %d\n", i);
54 
55   results[0].kind = WASM_I32;
56   results[0].of.i32 = (int32_t)i;
57   return NULL;
58 }
59 
60 
61 int main(int argc, const char* argv[]) {
62   // Initialize.
63   printf("Initializing...\n");
64   wasm_engine_t* engine = wasm_engine_new();
65   wasm_store_t* store = wasm_store_new(engine);
66 
67   // Load our input file to parse it next
68   FILE* file = fopen("examples/multi.wat", "r");
69   if (!file) {
70     printf("> Error loading file!\n");
71     return 1;
72   }
73   fseek(file, 0L, SEEK_END);
74   size_t file_size = ftell(file);
75   fseek(file, 0L, SEEK_SET);
76   wasm_byte_vec_t wat;
77   wasm_byte_vec_new_uninitialized(&wat, file_size);
78   if (fread(wat.data, file_size, 1, file) != 1) {
79     printf("> Error loading module!\n");
80     return 1;
81   }
82   fclose(file);
83 
84   // Parse the wat into the binary wasm format
85   wasm_byte_vec_t binary;
86   wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary);
87   if (error != NULL)
88     exit_with_error("failed to parse wat", error, NULL);
89   wasm_byte_vec_delete(&wat);
90 
91   // Compile.
92   printf("Compiling module...\n");
93   wasm_module_t* module = NULL;
94   error = wasmtime_module_new(engine, &binary, &module);
95   if (error)
96     exit_with_error("failed to compile module", error, NULL);
97 
98   wasm_byte_vec_delete(&binary);
99 
100   // Create external print functions.
101   printf("Creating callback...\n");
102   wasm_functype_t* callback_type = wasm_functype_new_2_2(
103       wasm_valtype_new_i32(),
104       wasm_valtype_new_i64(),
105       wasm_valtype_new_i64(),
106       wasm_valtype_new_i32()
107   );
108   wasm_func_t* callback_func =
109     wasm_func_new(store, callback_type, callback);
110 
111   wasm_functype_delete(callback_type);
112 
113   // Instantiate.
114   printf("Instantiating module...\n");
115   wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
116   wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
117   wasm_instance_t* instance = NULL;
118   wasm_trap_t* trap = NULL;
119   error = wasmtime_instance_new(store, module, &imports_vec, &instance, &trap);
120   if (!instance)
121     exit_with_error("failed to instantiate", error, trap);
122 
123   wasm_func_delete(callback_func);
124 
125   // Extract export.
126   printf("Extracting export...\n");
127   wasm_extern_vec_t exports;
128   wasm_instance_exports(instance, &exports);
129   if (exports.size == 0) {
130     printf("> Error accessing exports!\n");
131     return 1;
132   }
133   wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
134   if (run_func == NULL) {
135     printf("> Error accessing export!\n");
136     return 1;
137   }
138 
139   wasm_module_delete(module);
140   wasm_instance_delete(instance);
141 
142   // Call.
143   printf("Calling export...\n");
144   wasm_val_t args[2] = { WASM_I32_VAL(1), WASM_I64_VAL(2) };
145   wasm_val_t results[2];
146   wasm_val_vec_t args_vec = WASM_ARRAY_VEC(args);
147   wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results);
148   error = wasmtime_func_call(run_func, &args_vec, &results_vec, &trap);
149   if (error != NULL || trap != NULL)
150     exit_with_error("failed to call run", error, trap);
151 
152   wasm_extern_vec_delete(&exports);
153 
154   // Print result.
155   printf("Printing result...\n");
156   printf("> %"PRIu64" %"PRIu32"\n",
157     results[0].of.i64, results[1].of.i32);
158 
159   assert(results[0].kind == WASM_I64);
160   assert(results[0].of.i64 == 2);
161   assert(results[1].kind == WASM_I32);
162   assert(results[1].of.i32 == 1);
163 
164   // Shut down.
165   printf("Shutting down...\n");
166   wasm_store_delete(store);
167   wasm_engine_delete(engine);
168 
169   // All done.
170   printf("Done.\n");
171   return 0;
172 }
173 
174 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
175   fprintf(stderr, "error: %s\n", message);
176   wasm_byte_vec_t error_message;
177   if (error != NULL) {
178     wasmtime_error_message(error, &error_message);
179     wasmtime_error_delete(error);
180   } else {
181     wasm_trap_message(trap, &error_message);
182     wasm_trap_delete(trap);
183   }
184   fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
185   wasm_byte_vec_delete(&error_message);
186   exit(1);
187 }
188