Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/memory.c
1685 views
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(int argc, const char *argv[]) {
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
277