==> src/imports.c <==1/* LaneData and the mesh::* imports (mesh-host/src/wasm.rs `LaneData`, `linker`). */
2#include "mesh/exec_wasm_imports.h"
3
4#include "mesh/abi/control_block.h"
5#include "mesh/abi/exchange.h"
6#include "mesh/abi/ext.h"
7#include "mesh/abi/fault.h"
8#include "mesh/abi/header.h"
9#include "mesh/abi/input_queue.h"
10#include "mesh/abi/pipe.h"
11#include "mesh/abi/program_table.h"
12#include "mesh/abi/wasm.h"
13#include "mesh/lease.h"
14
15#include <string.h>
16
17static size_t ctl(const mesh_wasm_lane_data *d, size_t off) { return mesh_prog_ctl(d->slot) + off; }
18
19void mesh_wasm_lane_data_init(mesh_wasm_lane_data *d, mesh_mailbox mb, uint32_t slot, uint32_t node, uint32_t nodes,
20 uint32_t task_ms, const _Atomic uint64_t *epoch) {
21 memset(d, 0, sizeof *d);
22 size_t e = mesh_prog_entry(slot);
23 d->mb = mb;
24 d->slot = slot;
25 d->node = node;
26 d->nodes = nodes;
27 d->view_off = mesh_mailbox_get(mb, e + MESH_PT_VIEW_OFF);
28 d->view_len = mesh_mailbox_get(mb, e + MESH_PT_VIEW_BYTES);
29 d->req_off = mesh_mailbox_get(mb, e + MESH_PT_REQ_OFF);
30 d->req_max = mesh_mailbox_get(mb, e + MESH_PT_REQ_MAX);
31 d->resp_off = mesh_mailbox_get(mb, e + MESH_PT_RESP_OFF);
32 d->resp_max = mesh_mailbox_get(mb, e + MESH_PT_RESP_MAX);
33 d->input_off = mesh_mailbox_get(mb, e + MESH_PT_INPUT_OFF);
34 d->input_len = mesh_mailbox_get(mb, e + MESH_PT_INPUT_LEN);
35 d->lockstep = mesh_mailbox_get(mb, e + MESH_PT_PEER) == MESH_PEER_MODE_LOCKSTEP;
36 d->ticks = task_ms;
37 d->epoch = epoch;
38}
39
40void mesh_wasm_lane_data_task(mesh_wasm_lane_data *d, uint32_t ticket) {
41 d->ticket = ticket;
42 memset(d->peer_set, 0, sizeof d->peer_set);
43}
44
45void mesh_wasm_lane_fault(const mesh_wasm_lane_data *d, uint32_t code) {
46 if (mesh_mailbox_get(d->mb, ctl(d, MESH_P_FAULT)) == 0) mesh_mailbox_cas(d->mb, ctl(d, MESH_P_FAULT), 0, code);
47}
48
49static bool window(const mesh_wasm_lane_data *d, uint32_t h, size_t *base, uint32_t *len) {
50 if (h == MESH_WASM_W_VIEW) {
51 *base = d->view_off;
52 *len = d->view_len;
53 return true;
54 }
55 if (h == MESH_WASM_W_EXCHANGE && d->lockstep) {
56 *base = MESH_EX_BASE;
57 *len = MESH_EX_BYTES;
58 return true;
59 }
60 if (h >= MESH_WASM_W_PEER && h < MESH_WASM_W_PEER + MESH_PROG_SLOTS && d->peer_set[h - MESH_WASM_W_PEER]) {
61 *base = d->peer_off[h - MESH_WASM_W_PEER];
62 *len = d->peer_len[h - MESH_WASM_W_PEER];
63 return true;
64 }
65 return false;
66}
67
68bool mesh_wasm_lane_at(const mesh_wasm_lane_data *d, uint32_t h, uint32_t off, uint32_t n, size_t align, size_t *at) {
69 size_t base;
70 uint32_t len;
71 if (!window(d, h, &base, &len)) {
72 mesh_wasm_lane_fault(d, h >= MESH_WASM_W_PEER ? MESH_FAULT_PEER_VIEW | (h - MESH_WASM_W_PEER) << 8
73 : MESH_FAULT_VIEW_BOUNDS | off << 8);
74 return false;
75 }
76 size_t a = base + off;
77 if ((uint64_t)off + n > len || a % align != 0) {
78 mesh_wasm_lane_fault(d, MESH_FAULT_VIEW_BOUNDS | off << 8);
79 return false;
80 }
81 *at = a;
82 return true;
83}
84
85uint32_t mesh_wasm_lane_reads_mask(const mesh_wasm_lane_data *d) {
86 size_t e = mesh_prog_entry(d->slot);
87 for (;;) {
88 uint32_t g = mesh_mailbox_get(d->mb, e + MESH_PT_GEN);
89 if (g & 1) continue;
90 uint32_t m = mesh_mailbox_get(d->mb, e + MESH_PT_READS_MASK);
91 atomic_thread_fence(memory_order_seq_cst);
92 if (mesh_mailbox_get(d->mb, e + MESH_PT_GEN) == g) return m;
93 }
94}
95
96int32_t mesh_wasm_lane_peer(mesh_wasm_lane_data *d, uint32_t s) {
97 if (s >= MESH_PROG_SLOTS) return -1;
98 if ((mesh_wasm_lane_reads_mask(d) & (1u << s)) == 0) {
99 mesh_wasm_lane_fault(d, MESH_FAULT_PEER_VIEW | s << 8);
100 return -1;
101 }
102 size_t e = mesh_prog_entry(s);
103 uint32_t st, off, len;
104 for (;;) {
105 uint32_t g = mesh_mailbox_get(d->mb, e + MESH_PT_GEN);
106 if (g & 1) continue;
107 st = mesh_mailbox_get(d->mb, e + MESH_PT_STATE);
108 off = mesh_mailbox_get(d->mb, e + MESH_PT_VIEW_OFF);
109 len = mesh_mailbox_get(d->mb, e + MESH_PT_VIEW_BYTES);
110 atomic_thread_fence(memory_order_seq_cst);
111 if (mesh_mailbox_get(d->mb, e + MESH_PT_GEN) == g) break;
112 }
113 if (st == MESH_ST_EMPTY || st == MESH_ST_FAILED) {
114 d->peer_set[s] = false;
115 return -1;
116 }
117 d->peer_set[s] = true;
118 d->peer_off[s] = off;
119 d->peer_len[s] = len;
120 return (int32_t)len;
121}
122
123void mesh_wasm_copy_out(mesh_mailbox mb, size_t a, uint8_t *dst, size_t n) {
124 if (a % 4 == 0 && n % 4 == 0) {
125 for (size_t i = 0; i < n / 4; i++) {
126 uint32_t w = mesh_mailbox_get(mb, a + 4 * i);
127 memcpy(dst + 4 * i, &w, 4); /* little-endian hosts only, as the mailbox */
128 }
129 } else {
130 for (size_t i = 0; i < n; i++) dst[i] = mesh_mailbox_get8(mb, a + i);
131 }
132}
133
134void mesh_wasm_copy_in(mesh_mailbox mb, size_t a, const uint8_t *src, size_t n) {
135 if (a % 4 == 0 && n % 4 == 0) {
136 for (size_t i = 0; i < n / 4; i++) {
137 uint32_t w;
138 memcpy(&w, src + 4 * i, 4);
139 mesh_mailbox_publish(mb, a + 4 * i, w);
140 }
141 } else {
142 for (size_t i = 0; i < n; i++) mesh_mailbox_set8(mb, a + i, src[i]);
143 }
144}
145
146/* ---- the imports ------------------------------------------------------------------------ */
147
148#define D mesh_wasm_lane_data *d = wasm_instance_user(inst)
149#define A(i) ((uint32_t)io[i])
150#define UNUSED (void)ctx
151
152/* Linear memory [ptr, ptr + len) of the instance, or NULL. */
153static uint8_t *span(wasm_instance *inst, uint32_t ptr, uint32_t len) {
154 uint64_t size;
155 uint8_t *mem = wasm_memory(inst, &size);
156 if (!mem || (uint64_t)ptr + len > size) return NULL;
157 return mem + ptr;
158}
159
160static int info(wasm_instance *inst, void *ctx, uint64_t *io) {
161 UNUSED;
162 D;
163 mesh_mailbox mb = d->mb;
164 uint32_t v;
165 switch (A(0)) {
166 case MESH_WASM_I_SLOT: v = d->slot; break;
167 case MESH_WASM_I_NODE: v = d->node; break;
168 case MESH_WASM_I_NODES: v = d->nodes; break;
169 case MESH_WASM_I_TICKET: v = d->ticket; break;
170 case MESH_WASM_I_SYSTEM: v = mesh_mailbox_get(mb, MESH_H_PEER); break;
171 case MESH_WASM_I_SYSTEMS: v = mesh_mailbox_get(mb, MESH_H_SYSTEMS); break;
172 case MESH_WASM_I_GROUP_RANK: v = mesh_mailbox_get(mb, MESH_H_GROUP_RANK); break;
173 case MESH_WASM_I_GROUP_N: v = mesh_mailbox_get(mb, MESH_H_GROUP_N); break;
174 case MESH_WASM_I_PARAM: v = mesh_mailbox_get(mb, mesh_prog_ext(d->slot) + MESH_PX_PARAM); break;
175 case MESH_WASM_I_SMS: v = mesh_mailbox_get(mb, MESH_H_SMS); break;
176 case MESH_WASM_I_VIEW_BYTES: v = d->view_len; break;
177 case MESH_WASM_I_REQ_LEN: {
178 uint32_t n = mesh_mailbox_get(mb, ctl(d, MESH_P_REQ_LEN));
179 v = n < d->req_max ? n : d->req_max;
180 break;
181 }
182 case MESH_WASM_I_REQ_OFF: v = d->req_off; break;
183 case MESH_WASM_I_RESP_OFF: v = d->resp_off; break;
184 case MESH_WASM_I_RESP_MAX: v = d->resp_max; break;
185 case MESH_WASM_I_INPUT_LEN: v = d->input_len; break;
186 case MESH_WASM_I_LOCKSTEP: v = d->lockstep; break;
187 case MESH_WASM_I_READS_MASK: v = mesh_wasm_lane_reads_mask(d); break;
188 default: v = 0; break;
189 }
190 io[0] = v;
191 return WASM_NUM_OK;
192}
193
194static int ld8(wasm_instance *inst, void *ctx, uint64_t *io) {
195 UNUSED;
196 D;
197 size_t a;
198 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 1, 1, &a) ? mesh_mailbox_get8(d->mb, a) : 0;
199 return WASM_NUM_OK;
200}
201
202static int ld32(wasm_instance *inst, void *ctx, uint64_t *io) {
203 UNUSED;
204 D;
205 size_t a;
206 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 4, 4, &a) ? mesh_mailbox_get(d->mb, a) : 0;
207 return WASM_NUM_OK;
208}
209
210static int ld64(wasm_instance *inst, void *ctx, uint64_t *io) {
211 UNUSED;
212 D;
213 size_t a;
214 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 8, 8, &a) ? mesh_mailbox_get64(d->mb, a) : 0;
215 return WASM_NUM_OK;
216}
217
218static int st8(wasm_instance *inst, void *ctx, uint64_t *io) {
219 UNUSED;
220 D;
221 size_t a;
222 if (mesh_wasm_lane_at(d, A(0), A(1), 1, 1, &a)) mesh_mailbox_set8(d->mb, a, (uint8_t)A(2));
223 return WASM_NUM_OK;
224}
225
226static int st32(wasm_instance *inst, void *ctx, uint64_t *io) {
227 UNUSED;
228 D;
229 size_t a;
230 if (mesh_wasm_lane_at(d, A(0), A(1), 4, 4, &a)) mesh_mailbox_publish(d->mb, a, A(2));
231 return WASM_NUM_OK;
232}
233
234static int st64(wasm_instance *inst, void *ctx, uint64_t *io) {
235 UNUSED;
236 D;
237 size_t a;
238 if (mesh_wasm_lane_at(d, A(0), A(1), 8, 8, &a)) mesh_mailbox_publish64(d->mb, a, io[2]);
239 return WASM_NUM_OK;
240}
241
242static int cas32(wasm_instance *inst, void *ctx, uint64_t *io) {
243 UNUSED;
244 D;
245 size_t a;
246 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 4, 4, &a) ? mesh_mailbox_cas(d->mb, a, A(2), A(3)) : 0;
247 return WASM_NUM_OK;
248}
249
250static int add32(wasm_instance *inst, void *ctx, uint64_t *io) {
251 UNUSED;
252 D;
253 size_t a;
254 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 4, 4, &a) ? mesh_mailbox_fetch_add(d->mb, a, A(2)) : 0;
255 return WASM_NUM_OK;
256}
257
258static int add64(wasm_instance *inst, void *ctx, uint64_t *io) {
259 UNUSED;
260 D;
261 size_t a;
262 io[0] = mesh_wasm_lane_at(d, A(0), A(1), 8, 8, &a) ? mesh_mailbox_fetch_add64(d->mb, a, io[2]) : 0;
263 return WASM_NUM_OK;
264}
265
266static int read_(wasm_instance *inst, void *ctx, uint64_t *io) {
267 UNUSED;
268 D;
269 uint64_t size;
270 if (!wasm_memory(inst, &size)) return WASM_NUM_OK;
271 size_t a;
272 if (!mesh_wasm_lane_at(d, A(0), A(1), A(3), 1, &a)) return WASM_NUM_OK;
273 uint8_t *dst = span(inst, A(2), A(3));
274 if (!dst) {
275 mesh_wasm_lane_fault(d, MESH_FAULT_VIEW_BOUNDS | A(1) << 8);
276 return WASM_NUM_OK;
277 }
278 mesh_wasm_copy_out(d->mb, a, dst, A(3));
279 return WASM_NUM_OK;
280}
281
282static int write_(wasm_instance *inst, void *ctx, uint64_t *io) {
283 UNUSED;
284 D;
285 uint64_t size;
286 if (!wasm_memory(inst, &size)) return WASM_NUM_OK;
287 size_t a;
288 if (!mesh_wasm_lane_at(d, A(0), A(1), A(3), 1, &a)) return WASM_NUM_OK;
289 const uint8_t *src = span(inst, A(2), A(3));
290 if (!src) {
291 mesh_wasm_lane_fault(d, MESH_FAULT_VIEW_BOUNDS | A(1) << 8);
292 return WASM_NUM_OK;
293 }
294 mesh_wasm_copy_in(d->mb, a, src, A(3));
295 return WASM_NUM_OK;
296}
297
298static int peer(wasm_instance *inst, void *ctx, uint64_t *io) {
299 UNUSED;
300 D;
301 io[0] = (uint32_t)mesh_wasm_lane_peer(d, A(0));
302 return WASM_NUM_OK;
303}
304
305static int find(wasm_instance *inst, void *ctx, uint64_t *io) {
306 UNUSED;
307 D;
308 int32_t found = -1;
309 uint64_t size;
310 const uint8_t *name = wasm_memory(inst, &size) ? span(inst, A(0), A(1)) : NULL;
311 uint32_t len = A(1);
312 if (name && len <= MESH_NAME_MAX) {
313 for (uint32_t s = 0; s < MESH_PROG_SLOTS && found < 0; s++) {
314 size_t e = mesh_prog_entry(s);
315 if (mesh_mailbox_get(d->mb, e + MESH_PT_STATE) == MESH_ST_EMPTY) continue;
316 bool same = true;
317 for (uint32_t i = 0; i < MESH_NAME_BYTES && same; i++)
318 same = mesh_mailbox_get8(d->mb, e + MESH_PT_NAME + i) == (i < len ? name[i] : 0);
319 if (same) found = (int32_t)s;
320 }
321 }
322 io[0] = (uint32_t)found;
323 return WASM_NUM_OK;
324}
325
326static int prog_state(wasm_instance *inst, void *ctx, uint64_t *io) {
327 UNUSED;
328 D;
329 io[0] = A(0) < MESH_PROG_SLOTS ? mesh_mailbox_get(d->mb, mesh_prog_entry(A(0)) + MESH_PT_STATE) : MESH_ST_EMPTY;
330 return WASM_NUM_OK;
331}
332
333static int count(wasm_instance *inst, void *ctx, uint64_t *io) {
334 UNUSED;
335 D;
336 if (A(0) < MESH_COUNTERS) mesh_mailbox_fetch_add(d->mb, ctl(d, MESH_P_COUNTERS + 4 * (size_t)A(0)), A(1));
337 return WASM_NUM_OK;
338}
339
340static int counter(wasm_instance *inst, void *ctx, uint64_t *io) {
341 UNUSED;
342 D;
343 io[0] = A(0) < MESH_COUNTERS ? mesh_mailbox_get(d->mb, ctl(d, MESH_P_COUNTERS + 4 * (size_t)A(0))) : 0;
344 return WASM_NUM_OK;
345}
346
347static int input_pending(wasm_instance *inst, void *ctx, uint64_t *io) {
348 UNUSED;
349 D;
350 if (d->input_len == 0) {
351 io[0] = 0;
352 return WASM_NUM_OK;
353 }
354 size_t q = d->view_off + d->input_off;
355 io[0] = (uint32_t)(mesh_mailbox_get(d->mb, q + MESH_IQ_HEAD) - mesh_mailbox_get(d->mb, q + MESH_IQ_TAIL));
356 return WASM_NUM_OK;
357}
358
359static int input_pop(wasm_instance *inst, void *ctx, uint64_t *io) {
360 UNUSED;
361 D;
362 io[0] = (uint32_t)-1;
363 if (d->input_len == 0) return WASM_NUM_OK;
364 size_t q = d->view_off + d->input_off;
365 uint32_t tail = mesh_mailbox_get(d->mb, q + MESH_IQ_TAIL);
366 if (mesh_mailbox_get(d->mb, q + MESH_IQ_HEAD) == tail) return WASM_NUM_OK;
367 uint8_t b = mesh_mailbox_get8(d->mb, q + MESH_IQ_DATA + (tail & (d->input_len - 1)));
368 mesh_mailbox_publish(d->mb, q + MESH_IQ_TAIL, tail + 1u);
369 io[0] = b;
370 return WASM_NUM_OK;
371}
372
373static int respond(wasm_instance *inst, void *ctx, uint64_t *io) {
374 UNUSED;
375 D;
376 uint32_t len = A(0);
377 if (len > d->resp_max) {
378 mesh_wasm_lane_fault(d, MESH_FAULT_RESP_BOUNDS | len << 8);
379 len = d->resp_max;
380 }
381 mesh_mailbox_set(d->mb, ctl(d, MESH_P_RESP_LEN), len);
382 mesh_mailbox_publish64(d->mb, ctl(d, MESH_P_RESP_SEQ), mesh_mailbox_get64(d->mb, ctl(d, MESH_P_REQ_SEQ)));
383 return WASM_NUM_OK;
384}
385
386static int exchange(wasm_instance *inst, void *ctx, uint64_t *io) {
387 UNUSED;
388 D;
389 if (!d->lockstep) {
390 mesh_wasm_lane_fault(d, MESH_FAULT_PEER_VIEW | 0xffu << 8);
391 io[0] = MESH_ROUND_TIMEOUT;
392 return WASM_NUM_OK;
393 }
394 io[0] = mesh_round(d->mb, io[0], NULL);
395 /* The wait is the cluster's, not the program's: the task's budget starts over. */
396 if (d->epoch) wasm_set_deadline(inst, atomic_load(d->epoch) + d->ticks);
397 return WASM_NUM_OK;
398}
399
400/* Pipes (mesh-abi pipe): records straight between linear memory and the ring. */
401static int pipe_push(wasm_instance *inst, void *ctx, uint64_t *io) {
402 UNUSED;
403 D;
404 uint32_t to = A(0), ptr = A(1), len = A(2);
405 uint64_t size;
406 if (!wasm_memory(inst, &size)) {
407 io[0] = (uint32_t)MESH_PIPE_SIZE;
408 return WASM_NUM_OK;
409 }
410 const uint8_t *rec = span(inst, ptr, len);
411 if (!rec) {
412 mesh_wasm_lane_fault(d, MESH_FAULT_VIEW_BOUNDS | ptr << 8);
413 io[0] = (uint32_t)MESH_PIPE_SIZE;
414 return WASM_NUM_OK;
415 }
416 mesh_words w = mesh_mailbox_words(d->mb);
417 int r = mesh_pipe_push(&w, d->slot, to, rec, len);
418 if (r == -MESH_PIPE_ERR_NOT_CONNECTED || r == -MESH_PIPE_ERR_SIZE) mesh_wasm_lane_fault(d, MESH_FAULT_PIPE | to << 8);
419 io[0] = (uint32_t)mesh_pipe_code(r);
420 return WASM_NUM_OK;
421}
422
423static int pipe_pop(wasm_instance *inst, void *ctx, uint64_t *io) {
424 UNUSED;
425 D;
426 uint32_t ptr = A(0), len = A(1);
427 uint64_t size;
428 if (!wasm_memory(inst, &size)) {
429 io[0] = (uint32_t)MESH_PIPE_SIZE;
430 return WASM_NUM_OK;
431 }
432 uint8_t *out = span(inst, ptr, len);
433 if (!out) {
434 mesh_wasm_lane_fault(d, MESH_FAULT_VIEW_BOUNDS | ptr << 8);
435 io[0] = (uint32_t)MESH_PIPE_SIZE;
436 return WASM_NUM_OK;
437 }
438 mesh_words w = mesh_mailbox_words(d->mb);
439 int r = mesh_pipe_pop(&w, d->slot, out, len);
440 if (r == -MESH_PIPE_ERR_NOT_CONNECTED || r == -MESH_PIPE_ERR_SIZE) mesh_wasm_lane_fault(d, MESH_FAULT_PIPE | d->slot << 8);
441 io[0] = (uint32_t)mesh_pipe_code(r);
442 return WASM_NUM_OK;
443}
444
445static int pipe_len(wasm_instance *inst, void *ctx, uint64_t *io) {
446 UNUSED;
447 D;
448 mesh_words w = mesh_mailbox_words(d->mb);
449 mesh_pipe_inbox in;
450 int r = mesh_pipe_target(&w, d->slot, A(0), &in);
451 io[0] = r == 0 ? (uint32_t)(int32_t)mesh_pipe_inbox_len(&in, &w) : (uint32_t)mesh_pipe_code(r);
452 return WASM_NUM_OK;
453}
454
455static int host_ns(wasm_instance *inst, void *ctx, uint64_t *io) {
456 (void)inst, (void)ctx;
457 io[0] = mesh_host_ns();
458 return WASM_NUM_OK;
459}
460
461static int fault(wasm_instance *inst, void *ctx, uint64_t *io) {
462 UNUSED;
463 D;
464 mesh_wasm_lane_fault(d, A(0));
465 return WASM_NUM_OK;
466}
467
468static const wasm_host_func IMPORTS[] = {
469 {MESH_WASM_MODULE, "info", "i>i", info, NULL},
470 {MESH_WASM_MODULE, "ld8", "ii>i", ld8, NULL},
471 {MESH_WASM_MODULE, "ld32", "ii>i", ld32, NULL},
472 {MESH_WASM_MODULE, "ld64", "ii>l", ld64, NULL},
473 {MESH_WASM_MODULE, "st8", "iii>", st8, NULL},
474 {MESH_WASM_MODULE, "st32", "iii>", st32, NULL},
475 {MESH_WASM_MODULE, "st64", "iil>", st64, NULL},
476 {MESH_WASM_MODULE, "cas32", "iiii>i", cas32, NULL},
477 {MESH_WASM_MODULE, "add32", "iii>i", add32, NULL},
478 {MESH_WASM_MODULE, "add64", "iil>l", add64, NULL},
479 {MESH_WASM_MODULE, "read", "iiii>", read_, NULL},
480 {MESH_WASM_MODULE, "write", "iiii>", write_, NULL},
481 {MESH_WASM_MODULE, "peer", "i>i", peer, NULL},
482 {MESH_WASM_MODULE, "find", "ii>i", find, NULL},
483 {MESH_WASM_MODULE, "prog_state", "i>i", prog_state, NULL},
484 {MESH_WASM_MODULE, "count", "ii>", count, NULL},
485 {MESH_WASM_MODULE, "counter", "i>i", counter, NULL},
486 {MESH_WASM_MODULE, "input_pending", ">i", input_pending, NULL},
487 {MESH_WASM_MODULE, "input_pop", ">i", input_pop, NULL},
488 {MESH_WASM_MODULE, "respond", "i>", respond, NULL},
489 {MESH_WASM_MODULE, "exchange", "l>i", exchange, NULL},
490 {MESH_WASM_MODULE, "pipe_push", "iii>i", pipe_push, NULL},
491 {MESH_WASM_MODULE, "pipe_pop", "ii>i", pipe_pop, NULL},
492 {MESH_WASM_MODULE, "pipe_len", "i>i", pipe_len, NULL},
493 {MESH_WASM_MODULE, "host_ns", ">l", host_ns, NULL},
494 {MESH_WASM_MODULE, "fault", "i>", fault, NULL},
495};
496
497const wasm_host_func *mesh_wasm_imports(size_t *n) {
498 *n = sizeof IMPORTS / sizeof IMPORTS[0];
499 return IMPORTS;
500}