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