xref: /wasmtime-44.0.1/examples/memory.c (revision 3b7cb6ee)
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
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 Also note that this example was taken from
20 https://github.com/WebAssembly/wasm-c-api/blob/master/example/memory.c
21 originally
22 */
23 
24 #include <inttypes.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <wasm.h>
29 #include <wasmtime.h>
30 
31 
32 wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) {
33   if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) {
34     printf("> Error accessing memory export %zu!\n", i);
35     exit(1);
36   }
37   return wasm_extern_as_memory(exports->data[i]);
38 }
39 
40 wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
41   if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
42     printf("> Error accessing function export %zu!\n", i);
43     exit(1);
44   }
45   return wasm_extern_as_func(exports->data[i]);
46 }
47 
48 
49 void check(bool success) {
50   if (!success) {
51     printf("> Error, expected success\n");
52     exit(1);
53   }
54 }
55 
56 void check_call(wasm_func_t* func, wasm_val_t args[], int32_t expected) {
57   wasm_val_t results[1];
58   if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
59     printf("> Error on result\n");
60     exit(1);
61   }
62 }
63 
64 void check_call0(wasm_func_t* func, int32_t expected) {
65   check_call(func, NULL, expected);
66 }
67 
68 void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
69   wasm_val_t args[] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
70   check_call(func, args, expected);
71 }
72 
73 void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
74   wasm_val_t args[2] = {
75     {.kind = WASM_I32, .of = {.i32 = arg1}},
76     {.kind = WASM_I32, .of = {.i32 = arg2}}
77   };
78   check_call(func, args, expected);
79 }
80 
81 void check_ok(wasm_func_t* func, wasm_val_t args[]) {
82   if (wasm_func_call(func, args, NULL)) {
83     printf("> Error on result, expected empty\n");
84     exit(1);
85   }
86 }
87 
88 void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
89   wasm_val_t args[2] = {
90     {.kind = WASM_I32, .of = {.i32 = arg1}},
91     {.kind = WASM_I32, .of = {.i32 = arg2}}
92   };
93   check_ok(func, args);
94 }
95 
96 void check_trap(wasm_func_t* func, wasm_val_t args[]) {
97   wasm_val_t results[1];
98   wasm_trap_t* trap = wasm_func_call(func, args, results);
99   if (! trap) {
100     printf("> Error on result, expected trap\n");
101     exit(1);
102   }
103   wasm_trap_delete(trap);
104 }
105 
106 void check_trap1(wasm_func_t* func, int32_t arg) {
107   wasm_val_t args[1] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
108   check_trap(func, args);
109 }
110 
111 void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
112   wasm_val_t args[2] = {
113     {.kind = WASM_I32, .of = {.i32 = arg1}},
114     {.kind = WASM_I32, .of = {.i32 = arg2}}
115   };
116   check_trap(func, args);
117 }
118 
119 int main(int argc, const char* argv[]) {
120   // Initialize.
121   printf("Initializing...\n");
122   wasm_engine_t* engine = wasm_engine_new();
123   wasm_store_t* store = wasm_store_new(engine);
124 
125   // Load our input file to parse it next
126   FILE* file = fopen("examples/memory.wat", "r");
127   if (!file) {
128     printf("> Error loading file!\n");
129     return 1;
130   }
131   fseek(file, 0L, SEEK_END);
132   size_t file_size = ftell(file);
133   fseek(file, 0L, SEEK_SET);
134   wasm_byte_vec_t wat;
135   wasm_byte_vec_new_uninitialized(&wat, file_size);
136   if (fread(wat.data, file_size, 1, file) != 1) {
137     printf("> Error loading module!\n");
138     return 1;
139   }
140   fclose(file);
141 
142   // Parse the wat into the binary wasm format
143   wasm_byte_vec_t binary, error;
144   if (wasmtime_wat2wasm(engine, &wat, &binary, &error) == 0) {
145     fprintf(stderr, "failed to parse wat %.*s\n", (int) error.size, error.data);
146     return 1;
147   }
148   wasm_byte_vec_delete(&wat);
149 
150   // Compile.
151   printf("Compiling module...\n");
152   wasm_module_t* module = wasm_module_new(store, &binary);
153   if (!module) {
154     printf("> Error compiling module!\n");
155     return 1;
156   }
157 
158   wasm_byte_vec_delete(&binary);
159 
160   // Instantiate.
161   printf("Instantiating module...\n");
162   wasm_instance_t* instance = wasm_instance_new(store, module, NULL, NULL);
163   if (!instance) {
164     printf("> Error instantiating module!\n");
165     return 1;
166   }
167 
168   // Extract export.
169   printf("Extracting exports...\n");
170   wasm_extern_vec_t exports;
171   wasm_instance_exports(instance, &exports);
172   size_t i = 0;
173   wasm_memory_t* memory = get_export_memory(&exports, i++);
174   wasm_func_t* size_func = get_export_func(&exports, i++);
175   wasm_func_t* load_func = get_export_func(&exports, i++);
176   wasm_func_t* store_func = get_export_func(&exports, i++);
177 
178   wasm_module_delete(module);
179 
180   // Try cloning.
181   wasm_memory_t* copy = wasm_memory_copy(memory);
182   assert(wasm_memory_same(memory, copy));
183   wasm_memory_delete(copy);
184 
185   // Check initial memory.
186   printf("Checking memory...\n");
187   check(wasm_memory_size(memory) == 2);
188   check(wasm_memory_data_size(memory) == 0x20000);
189   check(wasm_memory_data(memory)[0] == 0);
190   check(wasm_memory_data(memory)[0x1000] == 1);
191   check(wasm_memory_data(memory)[0x1003] == 4);
192 
193   check_call0(size_func, 2);
194   check_call1(load_func, 0, 0);
195   check_call1(load_func, 0x1000, 1);
196   check_call1(load_func, 0x1003, 4);
197   check_call1(load_func, 0x1ffff, 0);
198   check_trap1(load_func, 0x20000);
199 
200   // Mutate memory.
201   printf("Mutating memory...\n");
202   wasm_memory_data(memory)[0x1003] = 5;
203   check_ok2(store_func, 0x1002, 6);
204   check_trap2(store_func, 0x20000, 0);
205 
206   check(wasm_memory_data(memory)[0x1002] == 6);
207   check(wasm_memory_data(memory)[0x1003] == 5);
208   check_call1(load_func, 0x1002, 6);
209   check_call1(load_func, 0x1003, 5);
210 
211   // Grow memory.
212   printf("Growing memory...\n");
213   check(wasm_memory_grow(memory, 1));
214   check(wasm_memory_size(memory) == 3);
215   check(wasm_memory_data_size(memory) == 0x30000);
216 
217   check_call1(load_func, 0x20000, 0);
218   check_ok2(store_func, 0x20000, 0);
219   check_trap1(load_func, 0x30000);
220   check_trap2(store_func, 0x30000, 0);
221 
222   check(! wasm_memory_grow(memory, 1));
223   check(wasm_memory_grow(memory, 0));
224 
225   wasm_extern_vec_delete(&exports);
226   wasm_instance_delete(instance);
227 
228   // Create stand-alone memory.
229   printf("Creating stand-alone memory...\n");
230   wasm_limits_t limits = {5, 5};
231   wasm_memorytype_t* memorytype = wasm_memorytype_new(&limits);
232   wasm_memory_t* memory2 = wasm_memory_new(store, memorytype);
233   check(wasm_memory_size(memory2) == 5);
234   check(! wasm_memory_grow(memory2, 1));
235   check(wasm_memory_grow(memory2, 0));
236 
237   wasm_memorytype_delete(memorytype);
238   wasm_memory_delete(memory2);
239 
240   // Shut down.
241   printf("Shutting down...\n");
242   wasm_store_delete(store);
243   wasm_engine_delete(engine);
244 
245   // All done.
246   printf("Done.\n");
247   return 0;
248 }
249