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