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/memory.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 memory 14 ./memory 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 You can also build using cmake: 20 21 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-memory 22 23 Also note that this example was taken from 24 https://github.com/WebAssembly/wasm-c-api/blob/master/example/memory.c 25 originally 26 */ 27 28 #include <inttypes.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <wasm.h> 33 #include <wasmtime.h> 34 35 static void exit_with_error(const char *message, wasmtime_error_t *error, 36 wasm_trap_t *trap); 37 38 void check(bool success) { 39 if (!success) { 40 printf("> Error, expected success\n"); 41 exit(1); 42 } 43 } 44 45 void check_call(wasmtime_context_t *store, wasmtime_func_t *func, 46 const wasmtime_val_t *args, size_t nargs, int32_t expected) { 47 wasmtime_val_t results[1]; 48 wasm_trap_t *trap = NULL; 49 wasmtime_error_t *error = 50 wasmtime_func_call(store, func, args, nargs, results, 1, &trap); 51 if (error != NULL || trap != NULL) 52 exit_with_error("failed to call function", error, trap); 53 if (results[0].of.i32 != expected) { 54 printf("> Error on result\n"); 55 exit(1); 56 } 57 } 58 59 void check_call0(wasmtime_context_t *store, wasmtime_func_t *func, 60 int32_t expected) { 61 check_call(store, func, NULL, 0, expected); 62 } 63 64 void check_call1(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg, 65 int32_t expected) { 66 wasmtime_val_t args[1]; 67 args[0].kind = WASMTIME_I32; 68 args[0].of.i32 = arg; 69 check_call(store, func, args, 1, expected); 70 } 71 72 void check_call2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, 73 int32_t arg2, int32_t expected) { 74 wasmtime_val_t args[2]; 75 args[0].kind = WASMTIME_I32; 76 args[0].of.i32 = arg1; 77 args[1].kind = WASMTIME_I32; 78 args[1].of.i32 = arg2; 79 check_call(store, func, args, 2, expected); 80 } 81 82 void check_ok(wasmtime_context_t *store, wasmtime_func_t *func, 83 const wasmtime_val_t *args, size_t nargs) { 84 wasm_trap_t *trap = NULL; 85 wasmtime_error_t *error = 86 wasmtime_func_call(store, func, args, nargs, NULL, 0, &trap); 87 if (error != NULL || trap != NULL) 88 exit_with_error("failed to call function", error, trap); 89 } 90 91 void check_ok2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, 92 int32_t arg2) { 93 wasmtime_val_t args[2]; 94 args[0].kind = WASMTIME_I32; 95 args[0].of.i32 = arg1; 96 args[1].kind = WASMTIME_I32; 97 args[1].of.i32 = arg2; 98 check_ok(store, func, args, 2); 99 } 100 101 void check_trap(wasmtime_context_t *store, wasmtime_func_t *func, 102 const wasmtime_val_t *args, size_t nargs, size_t num_results) { 103 assert(num_results <= 1); 104 wasmtime_val_t results[1]; 105 wasm_trap_t *trap = NULL; 106 wasmtime_error_t *error = 107 wasmtime_func_call(store, func, args, nargs, results, num_results, &trap); 108 if (error != NULL) 109 exit_with_error("failed to call function", error, NULL); 110 if (trap == NULL) { 111 printf("> Error on result, expected trap\n"); 112 exit(1); 113 } 114 wasm_trap_delete(trap); 115 } 116 117 void check_trap1(wasmtime_context_t *store, wasmtime_func_t *func, 118 int32_t arg) { 119 wasmtime_val_t args[1]; 120 args[0].kind = WASMTIME_I32; 121 args[0].of.i32 = arg; 122 check_trap(store, func, args, 1, 1); 123 } 124 125 void check_trap2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1, 126 int32_t arg2) { 127 wasmtime_val_t args[2]; 128 args[0].kind = WASMTIME_I32; 129 args[0].of.i32 = arg1; 130 args[1].kind = WASMTIME_I32; 131 args[1].of.i32 = arg2; 132 check_trap(store, func, args, 2, 0); 133 } 134 135 int main(int argc, const char *argv[]) { 136 // Initialize. 137 printf("Initializing...\n"); 138 wasm_engine_t *engine = wasm_engine_new(); 139 wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL); 140 wasmtime_context_t *context = wasmtime_store_context(store); 141 142 // Load our input file to parse it next 143 FILE *file = fopen("examples/memory.wat", "r"); 144 if (!file) { 145 printf("> Error loading file!\n"); 146 return 1; 147 } 148 fseek(file, 0L, SEEK_END); 149 size_t file_size = ftell(file); 150 fseek(file, 0L, SEEK_SET); 151 wasm_byte_vec_t wat; 152 wasm_byte_vec_new_uninitialized(&wat, file_size); 153 if (fread(wat.data, file_size, 1, file) != 1) { 154 printf("> Error loading module!\n"); 155 return 1; 156 } 157 fclose(file); 158 159 // Parse the wat into the binary wasm format 160 wasm_byte_vec_t binary; 161 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary); 162 if (error != NULL) 163 exit_with_error("failed to parse wat", error, NULL); 164 wasm_byte_vec_delete(&wat); 165 166 // Compile. 167 printf("Compiling module...\n"); 168 wasmtime_module_t *module = NULL; 169 error = 170 wasmtime_module_new(engine, (uint8_t *)binary.data, binary.size, &module); 171 if (error) 172 exit_with_error("failed to compile module", error, NULL); 173 wasm_byte_vec_delete(&binary); 174 175 // Instantiate. 176 printf("Instantiating module...\n"); 177 wasmtime_instance_t instance; 178 wasm_trap_t *trap = NULL; 179 error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap); 180 if (error != NULL || trap != NULL) 181 exit_with_error("failed to instantiate", error, trap); 182 wasmtime_module_delete(module); 183 184 // Extract export. 185 printf("Extracting exports...\n"); 186 wasmtime_memory_t memory; 187 wasmtime_func_t size_func, load_func, store_func; 188 wasmtime_extern_t item; 189 bool ok; 190 ok = wasmtime_instance_export_get(context, &instance, "memory", 191 strlen("memory"), &item); 192 assert(ok && item.kind == WASMTIME_EXTERN_MEMORY); 193 memory = item.of.memory; 194 ok = wasmtime_instance_export_get(context, &instance, "size", strlen("size"), 195 &item); 196 assert(ok && item.kind == WASMTIME_EXTERN_FUNC); 197 size_func = item.of.func; 198 ok = wasmtime_instance_export_get(context, &instance, "load", strlen("load"), 199 &item); 200 assert(ok && item.kind == WASMTIME_EXTERN_FUNC); 201 load_func = item.of.func; 202 ok = wasmtime_instance_export_get(context, &instance, "store", 203 strlen("store"), &item); 204 assert(ok && item.kind == WASMTIME_EXTERN_FUNC); 205 store_func = item.of.func; 206 207 // Check initial memory. 208 printf("Checking memory...\n"); 209 check(wasmtime_memory_size(context, &memory) == 2); 210 check(wasmtime_memory_data_size(context, &memory) == 0x20000); 211 check(wasmtime_memory_data(context, &memory)[0] == 0); 212 check(wasmtime_memory_data(context, &memory)[0x1000] == 1); 213 check(wasmtime_memory_data(context, &memory)[0x1003] == 4); 214 215 check_call0(context, &size_func, 2); 216 check_call1(context, &load_func, 0, 0); 217 check_call1(context, &load_func, 0x1000, 1); 218 check_call1(context, &load_func, 0x1003, 4); 219 check_call1(context, &load_func, 0x1ffff, 0); 220 check_trap1(context, &load_func, 0x20000); 221 222 // Mutate memory. 223 printf("Mutating memory...\n"); 224 wasmtime_memory_data(context, &memory)[0x1003] = 5; 225 check_ok2(context, &store_func, 0x1002, 6); 226 check_trap2(context, &store_func, 0x20000, 0); 227 228 check(wasmtime_memory_data(context, &memory)[0x1002] == 6); 229 check(wasmtime_memory_data(context, &memory)[0x1003] == 5); 230 check_call1(context, &load_func, 0x1002, 6); 231 check_call1(context, &load_func, 0x1003, 5); 232 233 // Grow memory. 234 printf("Growing memory...\n"); 235 uint64_t old_size; 236 error = wasmtime_memory_grow(context, &memory, 1, &old_size); 237 if (error != NULL) 238 exit_with_error("failed to grow memory", error, trap); 239 check(wasmtime_memory_size(context, &memory) == 3); 240 check(wasmtime_memory_data_size(context, &memory) == 0x30000); 241 242 check_call1(context, &load_func, 0x20000, 0); 243 check_ok2(context, &store_func, 0x20000, 0); 244 check_trap1(context, &load_func, 0x30000); 245 check_trap2(context, &store_func, 0x30000, 0); 246 247 error = wasmtime_memory_grow(context, &memory, 1, &old_size); 248 assert(error != NULL); 249 wasmtime_error_delete(error); 250 error = wasmtime_memory_grow(context, &memory, 0, &old_size); 251 if (error != NULL) 252 exit_with_error("failed to grow memory", error, trap); 253 254 // Create stand-alone memory. 255 printf("Creating stand-alone memory...\n"); 256 wasm_limits_t limits = {5, 5}; 257 wasm_memorytype_t *memorytype = wasm_memorytype_new(&limits); 258 wasmtime_memory_t memory2; 259 error = wasmtime_memory_new(context, memorytype, &memory2); 260 if (error != NULL) 261 exit_with_error("failed to create memory", error, trap); 262 wasm_memorytype_delete(memorytype); 263 check(wasmtime_memory_size(context, &memory2) == 5); 264 265 // Shut down. 266 printf("Shutting down...\n"); 267 wasmtime_store_delete(store); 268 wasm_engine_delete(engine); 269 270 // All done. 271 printf("Done.\n"); 272 return 0; 273 } 274 275 static void exit_with_error(const char *message, wasmtime_error_t *error, 276 wasm_trap_t *trap) { 277 fprintf(stderr, "error: %s\n", message); 278 wasm_byte_vec_t error_message; 279 if (error != NULL) { 280 wasmtime_error_message(error, &error_message); 281 wasmtime_error_delete(error); 282 } else { 283 wasm_trap_message(trap, &error_message); 284 wasm_trap_delete(trap); 285 } 286 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); 287 wasm_byte_vec_delete(&error_message); 288 exit(1); 289 } 290