Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/multimemory.c
1685 views
1
/*
2
An example of how to interact with multiple memories.
3
4
You can build using cmake:
5
6
mkdir build && cd build && cmake .. && \
7
cmake --build . --target wasmtime-multimemory
8
*/
9
10
#include <inttypes.h>
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#include <wasm.h>
15
#include <wasmtime.h>
16
17
static void exit_with_error(const char *message, wasmtime_error_t *error,
18
wasm_trap_t *trap);
19
20
void check(bool success) {
21
if (!success) {
22
printf("> Error, expected success\n");
23
exit(1);
24
}
25
}
26
27
void check_call(wasmtime_context_t *store, wasmtime_func_t *func,
28
const wasmtime_val_t *args, size_t nargs, int32_t expected) {
29
wasmtime_val_t results[1];
30
wasm_trap_t *trap = NULL;
31
wasmtime_error_t *error =
32
wasmtime_func_call(store, func, args, nargs, results, 1, &trap);
33
if (error != NULL || trap != NULL)
34
exit_with_error("failed to call function", error, trap);
35
if (results[0].of.i32 != expected) {
36
printf("> Error on result\n");
37
exit(1);
38
}
39
}
40
41
void check_call0(wasmtime_context_t *store, wasmtime_func_t *func,
42
int32_t expected) {
43
check_call(store, func, NULL, 0, expected);
44
}
45
46
void check_call1(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg,
47
int32_t expected) {
48
wasmtime_val_t args[1];
49
args[0].kind = WASMTIME_I32;
50
args[0].of.i32 = arg;
51
check_call(store, func, args, 1, expected);
52
}
53
54
void check_call2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
55
int32_t arg2, int32_t expected) {
56
wasmtime_val_t args[2];
57
args[0].kind = WASMTIME_I32;
58
args[0].of.i32 = arg1;
59
args[1].kind = WASMTIME_I32;
60
args[1].of.i32 = arg2;
61
check_call(store, func, args, 2, expected);
62
}
63
64
void check_ok(wasmtime_context_t *store, wasmtime_func_t *func,
65
const wasmtime_val_t *args, size_t nargs) {
66
wasm_trap_t *trap = NULL;
67
wasmtime_error_t *error =
68
wasmtime_func_call(store, func, args, nargs, NULL, 0, &trap);
69
if (error != NULL || trap != NULL)
70
exit_with_error("failed to call function", error, trap);
71
}
72
73
void check_ok2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
74
int32_t arg2) {
75
wasmtime_val_t args[2];
76
args[0].kind = WASMTIME_I32;
77
args[0].of.i32 = arg1;
78
args[1].kind = WASMTIME_I32;
79
args[1].of.i32 = arg2;
80
check_ok(store, func, args, 2);
81
}
82
83
void check_trap(wasmtime_context_t *store, wasmtime_func_t *func,
84
const wasmtime_val_t *args, size_t nargs, size_t num_results) {
85
assert(num_results <= 1);
86
wasmtime_val_t results[1];
87
wasm_trap_t *trap = NULL;
88
wasmtime_error_t *error =
89
wasmtime_func_call(store, func, args, nargs, results, num_results, &trap);
90
if (error != NULL)
91
exit_with_error("failed to call function", error, NULL);
92
if (trap == NULL) {
93
printf("> Error on result, expected trap\n");
94
exit(1);
95
}
96
wasm_trap_delete(trap);
97
}
98
99
void check_trap1(wasmtime_context_t *store, wasmtime_func_t *func,
100
int32_t arg) {
101
wasmtime_val_t args[1];
102
args[0].kind = WASMTIME_I32;
103
args[0].of.i32 = arg;
104
check_trap(store, func, args, 1, 1);
105
}
106
107
void check_trap2(wasmtime_context_t *store, wasmtime_func_t *func, int32_t arg1,
108
int32_t arg2) {
109
wasmtime_val_t args[2];
110
args[0].kind = WASMTIME_I32;
111
args[0].of.i32 = arg1;
112
args[1].kind = WASMTIME_I32;
113
args[1].of.i32 = arg2;
114
check_trap(store, func, args, 2, 0);
115
}
116
117
int main(int argc, const char *argv[]) {
118
// Initialize.
119
printf("Initializing...\n");
120
121
wasm_config_t *config = wasm_config_new();
122
assert(config != NULL);
123
wasmtime_config_wasm_multi_memory_set(config, true);
124
125
wasm_engine_t *engine = wasm_engine_new_with_config(config);
126
assert(engine != NULL);
127
128
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
129
wasmtime_context_t *context = wasmtime_store_context(store);
130
131
// Load our input file to parse it next
132
FILE *file = fopen("examples/multimemory.wat", "r");
133
if (!file) {
134
printf("> Error loading file!\n");
135
return 1;
136
}
137
fseek(file, 0L, SEEK_END);
138
size_t file_size = ftell(file);
139
fseek(file, 0L, SEEK_SET);
140
wasm_byte_vec_t wat;
141
wasm_byte_vec_new_uninitialized(&wat, file_size);
142
if (fread(wat.data, file_size, 1, file) != 1) {
143
printf("> Error loading module!\n");
144
return 1;
145
}
146
fclose(file);
147
148
// Parse the wat into the binary wasm format
149
wasm_byte_vec_t binary;
150
wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
151
if (error != NULL)
152
exit_with_error("failed to parse wat", error, NULL);
153
wasm_byte_vec_delete(&wat);
154
155
// Compile.
156
printf("Compiling module...\n");
157
wasmtime_module_t *module = NULL;
158
error =
159
wasmtime_module_new(engine, (uint8_t *)binary.data, binary.size, &module);
160
if (error)
161
exit_with_error("failed to compile module", error, NULL);
162
wasm_byte_vec_delete(&binary);
163
164
// Instantiate.
165
printf("Instantiating module...\n");
166
wasmtime_instance_t instance;
167
wasm_trap_t *trap = NULL;
168
error = wasmtime_instance_new(context, module, NULL, 0, &instance, &trap);
169
if (error != NULL || trap != NULL)
170
exit_with_error("failed to instantiate", error, trap);
171
wasmtime_module_delete(module);
172
173
// Extract export.
174
printf("Extracting exports...\n");
175
wasmtime_memory_t memory0, memory1;
176
wasmtime_func_t size0, load0, store0, size1, load1, store1;
177
wasmtime_extern_t item;
178
bool ok;
179
ok = wasmtime_instance_export_get(context, &instance, "memory0",
180
strlen("memory0"), &item);
181
assert(ok && item.kind == WASMTIME_EXTERN_MEMORY);
182
memory0 = item.of.memory;
183
ok = wasmtime_instance_export_get(context, &instance, "size0",
184
strlen("size0"), &item);
185
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
186
size0 = item.of.func;
187
ok = wasmtime_instance_export_get(context, &instance, "load0",
188
strlen("load0"), &item);
189
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
190
load0 = item.of.func;
191
ok = wasmtime_instance_export_get(context, &instance, "store0",
192
strlen("store0"), &item);
193
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
194
store0 = item.of.func;
195
ok = wasmtime_instance_export_get(context, &instance, "memory1",
196
strlen("memory1"), &item);
197
assert(ok && item.kind == WASMTIME_EXTERN_MEMORY);
198
memory1 = item.of.memory;
199
ok = wasmtime_instance_export_get(context, &instance, "size1",
200
strlen("size1"), &item);
201
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
202
size1 = item.of.func;
203
ok = wasmtime_instance_export_get(context, &instance, "load1",
204
strlen("load1"), &item);
205
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
206
load1 = item.of.func;
207
ok = wasmtime_instance_export_get(context, &instance, "store1",
208
strlen("store1"), &item);
209
assert(ok && item.kind == WASMTIME_EXTERN_FUNC);
210
store1 = item.of.func;
211
212
// Check initial memory.
213
printf("Checking memory...\n");
214
check(wasmtime_memory_size(context, &memory0) == 2);
215
check(wasmtime_memory_data_size(context, &memory0) == 0x20000);
216
check(wasmtime_memory_data(context, &memory0)[0] == 0);
217
check(wasmtime_memory_data(context, &memory0)[0x1000] == 1);
218
check(wasmtime_memory_data(context, &memory0)[0x1001] == 2);
219
check(wasmtime_memory_data(context, &memory0)[0x1002] == 3);
220
check(wasmtime_memory_data(context, &memory0)[0x1003] == 4);
221
222
check_call0(context, &size0, 2);
223
check_call1(context, &load0, 0, 0);
224
check_call1(context, &load0, 0x1000, 1);
225
check_call1(context, &load0, 0x1001, 2);
226
check_call1(context, &load0, 0x1002, 3);
227
check_call1(context, &load0, 0x1003, 4);
228
check_call1(context, &load0, 0x1ffff, 0);
229
check_trap1(context, &load0, 0x20000);
230
231
check(wasmtime_memory_size(context, &memory1) == 2);
232
check(wasmtime_memory_data_size(context, &memory1) == 0x20000);
233
check(wasmtime_memory_data(context, &memory1)[0] == 0);
234
check(wasmtime_memory_data(context, &memory1)[0x1000] == 4);
235
check(wasmtime_memory_data(context, &memory1)[0x1001] == 3);
236
check(wasmtime_memory_data(context, &memory1)[0x1002] == 2);
237
check(wasmtime_memory_data(context, &memory1)[0x1003] == 1);
238
239
check_call0(context, &size1, 2);
240
check_call1(context, &load1, 0, 0);
241
check_call1(context, &load1, 0x1000, 4);
242
check_call1(context, &load1, 0x1001, 3);
243
check_call1(context, &load1, 0x1002, 2);
244
check_call1(context, &load1, 0x1003, 1);
245
check_call1(context, &load1, 0x1ffff, 0);
246
check_trap1(context, &load1, 0x20000);
247
248
// Mutate memory.
249
printf("Mutating memory...\n");
250
wasmtime_memory_data(context, &memory0)[0x1003] = 5;
251
check_ok2(context, &store0, 0x1002, 6);
252
check_trap2(context, &store0, 0x20000, 0);
253
254
check(wasmtime_memory_data(context, &memory0)[0x1002] == 6);
255
check(wasmtime_memory_data(context, &memory0)[0x1003] == 5);
256
check_call1(context, &load0, 0x1002, 6);
257
check_call1(context, &load0, 0x1003, 5);
258
259
wasmtime_memory_data(context, &memory1)[0x1003] = 7;
260
check_ok2(context, &store1, 0x1002, 8);
261
check_trap2(context, &store1, 0x20000, 0);
262
263
check(wasmtime_memory_data(context, &memory1)[0x1002] == 8);
264
check(wasmtime_memory_data(context, &memory1)[0x1003] == 7);
265
check_call1(context, &load1, 0x1002, 8);
266
check_call1(context, &load1, 0x1003, 7);
267
268
// Grow memory.
269
printf("Growing memory...\n");
270
uint64_t old_size;
271
error = wasmtime_memory_grow(context, &memory0, 1, &old_size);
272
if (error != NULL)
273
exit_with_error("failed to grow memory", error, trap);
274
check(wasmtime_memory_size(context, &memory0) == 3);
275
check(wasmtime_memory_data_size(context, &memory0) == 0x30000);
276
277
check_call1(context, &load0, 0x20000, 0);
278
check_ok2(context, &store0, 0x20000, 0);
279
check_trap1(context, &load0, 0x30000);
280
check_trap2(context, &store0, 0x30000, 0);
281
282
error = wasmtime_memory_grow(context, &memory0, 1, &old_size);
283
assert(error != NULL);
284
wasmtime_error_delete(error);
285
error = wasmtime_memory_grow(context, &memory0, 0, &old_size);
286
if (error != NULL)
287
exit_with_error("failed to grow memory", error, trap);
288
289
error = wasmtime_memory_grow(context, &memory1, 2, &old_size);
290
if (error != NULL)
291
exit_with_error("failed to grow memory", error, trap);
292
check(wasmtime_memory_size(context, &memory1) == 4);
293
check(wasmtime_memory_data_size(context, &memory1) == 0x40000);
294
295
check_call1(context, &load1, 0x30000, 0);
296
check_ok2(context, &store1, 0x30000, 0);
297
check_trap1(context, &load1, 0x40000);
298
check_trap2(context, &store1, 0x40000, 0);
299
300
error = wasmtime_memory_grow(context, &memory1, 1, &old_size);
301
assert(error != NULL);
302
wasmtime_error_delete(error);
303
error = wasmtime_memory_grow(context, &memory1, 0, &old_size);
304
if (error != NULL)
305
exit_with_error("failed to grow memory", error, trap);
306
307
// Shut down.
308
printf("Shutting down...\n");
309
wasmtime_store_delete(store);
310
wasm_engine_delete(engine);
311
312
// All done.
313
printf("Done.\n");
314
return 0;
315
}
316
317
static void exit_with_error(const char *message, wasmtime_error_t *error,
318
wasm_trap_t *trap) {
319
fprintf(stderr, "error: %s\n", message);
320
wasm_byte_vec_t error_message;
321
if (error != NULL) {
322
wasmtime_error_message(error, &error_message);
323
wasmtime_error_delete(error);
324
} else {
325
wasm_trap_message(trap, &error_message);
326
wasm_trap_delete(trap);
327
}
328
fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
329
wasm_byte_vec_delete(&error_message);
330
exit(1);
331
}
332
333