1 /* 2 Example of using `anyref` values. 3 4 You can compile and run this example on Linux with: 5 6 cargo build --release -p wasmtime-c-api 7 cc examples/anyref.c \ 8 -I crates/c-api/include \ 9 -I crates/c-api/wasm-c-api/include \ 10 target/release/libwasmtime.a \ 11 -lpthread -ldl -lm \ 12 -o anyref 13 ./anyref 14 15 Note that on Windows and macOS the command will be similar, but you'll need 16 to tweak the `-lpthread` and such annotations as well as the name of the 17 `libwasmtime.a` file on Windows. 18 19 You can also build using cmake: 20 21 mkdir build && cd build && cmake .. && \ 22 cmake --build . --target wasmtime-anyref 23 */ 24 25 #include <assert.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <wasm.h> 30 #include <wasmtime.h> 31 32 static void exit_with_error(const char *message, wasmtime_error_t *error, 33 wasm_trap_t *trap); 34 35 int main() { 36 bool ok = true; 37 // Create a new configuration with Wasm GC enabled. 38 printf("Initializing...\n"); 39 wasm_config_t *config = wasm_config_new(); 40 assert(config != NULL); 41 wasmtime_config_wasm_reference_types_set(config, true); 42 wasmtime_config_wasm_function_references_set(config, true); 43 wasmtime_config_wasm_gc_set(config, true); 44 45 // Create an *engine*, which is a compilation context, with our configured 46 // options. 47 wasm_engine_t *engine = wasm_engine_new_with_config(config); 48 assert(engine != NULL); 49 50 // With an engine we can create a *store* which is a group of wasm instances 51 // that can interact with each other. 52 wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL); 53 assert(store != NULL); 54 wasmtime_context_t *context = wasmtime_store_context(store); 55 56 // Read our input file, which in this case is a wasm text file. 57 FILE *file = fopen("examples/anyref.wat", "r"); 58 assert(file != NULL); 59 fseek(file, 0L, SEEK_END); 60 size_t file_size = ftell(file); 61 fseek(file, 0L, SEEK_SET); 62 wasm_byte_vec_t wat; 63 wasm_byte_vec_new_uninitialized(&wat, file_size); 64 if (fread(wat.data, file_size, 1, file) != 1) { 65 printf("> Error loading module!\n"); 66 return 1; 67 } 68 fclose(file); 69 70 // Parse the wat into the binary wasm format 71 wasm_byte_vec_t wasm; 72 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &wasm); 73 if (error != NULL) 74 exit_with_error("failed to parse wat", error, NULL); 75 wasm_byte_vec_delete(&wat); 76 77 // Now that we've got our binary webassembly we can compile our module. 78 printf("Compiling module...\n"); 79 wasmtime_module_t *module = NULL; 80 error = wasmtime_module_new(engine, (uint8_t *)wasm.data, wasm.size, &module); 81 wasm_byte_vec_delete(&wasm); 82 if (error != NULL) 83 exit_with_error("failed to compile module", error, NULL); 84 85 // Instantiate the module. 86 printf("Instantiating module...\n"); 87 wasm_trap_t *trap = NULL; 88 wasmtime_instance_t instance; 89 error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap); 90 if (error != NULL || trap != NULL) 91 exit_with_error("failed to instantiate", error, trap); 92 93 printf("Creating new `anyref` from i31...\n"); 94 95 // Create a new `anyref` value from an i31 (`i31ref` is a subtype of 96 // `anyref`). 97 wasmtime_anyref_t anyref; 98 wasmtime_anyref_from_i31(context, 1234, &anyref); 99 assert(!wasmtime_anyref_is_null(&anyref)); 100 101 // The `anyref`'s inner i31 value should be 1234. 102 uint32_t i31val = 0; 103 bool is_i31 = wasmtime_anyref_i31_get_u(context, &anyref, &i31val); 104 assert(is_i31); 105 assert(i31val == 1234); 106 107 printf("Touching `anyref` table...\n"); 108 109 wasmtime_extern_t item; 110 111 // Lookup the `table` export. 112 ok = wasmtime_instance_export_get(context, &instance, "table", 113 strlen("table"), &item); 114 assert(ok); 115 assert(item.kind == WASMTIME_EXTERN_TABLE); 116 117 // Set `table[3]` to our `anyref`. 118 wasmtime_val_t anyref_val; 119 anyref_val.kind = WASMTIME_ANYREF; 120 anyref_val.of.anyref = anyref; 121 error = wasmtime_table_set(context, &item.of.table, 3, &anyref_val); 122 if (error != NULL) 123 exit_with_error("failed to set table", error, NULL); 124 125 // `table[3]` should now be our `anyref`. 126 wasmtime_val_t elem; 127 ok = wasmtime_table_get(context, &item.of.table, 3, &elem); 128 assert(ok); 129 assert(elem.kind == WASMTIME_ANYREF); 130 is_i31 = false; 131 i31val = 0; 132 is_i31 = wasmtime_anyref_i31_get_u(context, &elem.of.anyref, &i31val); 133 assert(is_i31); 134 assert(i31val == 1234); 135 wasmtime_val_unroot(context, &elem); 136 137 printf("Touching `anyref` global...\n"); 138 139 // Lookup the `global` export. 140 ok = wasmtime_instance_export_get(context, &instance, "global", 141 strlen("global"), &item); 142 assert(ok); 143 assert(item.kind == WASMTIME_EXTERN_GLOBAL); 144 145 // Set the global to our `anyref`. 146 error = wasmtime_global_set(context, &item.of.global, &anyref_val); 147 if (error != NULL) 148 exit_with_error("failed to set global", error, NULL); 149 150 // Get the global, and it should return our `anyref` again. 151 wasmtime_val_t global_val; 152 wasmtime_global_get(context, &item.of.global, &global_val); 153 assert(global_val.kind == WASMTIME_ANYREF); 154 is_i31 = false; 155 i31val = 0; 156 is_i31 = wasmtime_anyref_i31_get_u(context, &global_val.of.anyref, &i31val); 157 assert(is_i31); 158 assert(i31val == 1234); 159 wasmtime_val_unroot(context, &global_val); 160 161 printf("Passing `anyref` into func...\n"); 162 163 // Lookup the `take_anyref` export. 164 ok = wasmtime_instance_export_get(context, &instance, "take_anyref", 165 strlen("take_anyref"), &item); 166 assert(ok); 167 assert(item.kind == WASMTIME_EXTERN_FUNC); 168 169 // And call it! 170 error = wasmtime_func_call(context, &item.of.func, &anyref_val, 1, NULL, 0, 171 &trap); 172 if (error != NULL || trap != NULL) 173 exit_with_error("failed to call function", error, trap); 174 175 printf("Getting `anyref` from func...\n"); 176 177 // Lookup the `return_anyref` export. 178 ok = wasmtime_instance_export_get(context, &instance, "return_anyref", 179 strlen("return_anyref"), &item); 180 assert(ok); 181 assert(item.kind == WASMTIME_EXTERN_FUNC); 182 183 // And call it! 184 wasmtime_val_t results[1]; 185 error = 186 wasmtime_func_call(context, &item.of.func, NULL, 0, results, 1, &trap); 187 if (error != NULL || trap != NULL) 188 exit_with_error("failed to call function", error, trap); 189 190 // `return_anyfunc` returns an `i31ref` that wraps `42`. 191 assert(results[0].kind == WASMTIME_ANYREF); 192 is_i31 = false; 193 i31val = 0; 194 is_i31 = wasmtime_anyref_i31_get_u(context, &results[0].of.anyref, &i31val); 195 assert(is_i31); 196 assert(i31val == 42); 197 wasmtime_val_unroot(context, &results[0]); 198 wasmtime_val_unroot(context, &anyref_val); 199 200 // We can GC any now-unused references to our anyref that the store is 201 // holding. 202 printf("GCing within the store...\n"); 203 wasmtime_context_gc(context); 204 205 // Clean up after ourselves at this point 206 printf("All finished!\n"); 207 208 wasmtime_store_delete(store); 209 wasmtime_module_delete(module); 210 wasm_engine_delete(engine); 211 return 0; 212 } 213 214 static void exit_with_error(const char *message, wasmtime_error_t *error, 215 wasm_trap_t *trap) { 216 fprintf(stderr, "error: %s\n", message); 217 wasm_byte_vec_t error_message; 218 if (error != NULL) { 219 wasmtime_error_message(error, &error_message); 220 wasmtime_error_delete(error); 221 } else { 222 wasm_trap_message(trap, &error_message); 223 wasm_trap_delete(trap); 224 } 225 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); 226 wasm_byte_vec_delete(&error_message); 227 exit(1); 228 } 229