space-data-module-sdk 0.5.14 → 0.5.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +91 -1
  2. package/package.json +8 -4
  3. package/schemas/HostStorageAbi.fbs +53 -0
  4. package/src/bundle/codec.js +1 -1
  5. package/src/compliance/pluginCompliance.js +0 -130
  6. package/src/generated/orbpro/invoke/plugin-invoke-request.js +1 -1
  7. package/src/generated/orbpro/invoke/plugin-invoke-response.js +1 -1
  8. package/src/generated/orbpro/manifest/accepted-type-set.js +1 -1
  9. package/src/generated/orbpro/manifest/build-artifact.js +1 -1
  10. package/src/generated/orbpro/manifest/host-capability.js +1 -1
  11. package/src/generated/orbpro/manifest/method-manifest.js +1 -1
  12. package/src/generated/orbpro/manifest/plugin-manifest.js +1 -1
  13. package/src/generated/orbpro/manifest/port-manifest.js +1 -1
  14. package/src/generated/orbpro/manifest/protocol-spec.js +1 -1
  15. package/src/generated/orbpro/manifest/timer-spec.js +1 -1
  16. package/src/generated/orbpro/module/canonicalization-rule.js +1 -1
  17. package/src/generated/orbpro/module/module-bundle-entry.js +1 -1
  18. package/src/generated/orbpro/module/module-bundle.js +1 -1
  19. package/src/generated/orbpro/stream/flat-buffer-type-ref.js +1 -1
  20. package/src/generated/orbpro/stream/typed-arena-buffer.js +1 -1
  21. package/src/index.d.ts +157 -1
  22. package/src/index.js +1 -0
  23. package/src/invoke/codec.js +10 -8
  24. package/src/manifest/codec.js +1 -1
  25. package/src/runtime-host/flatsqlRuntimeStore.js +217 -0
  26. package/src/runtime-host/index.js +21 -0
  27. package/src/runtime-host/moduleRegistry.js +92 -0
  28. package/src/runtime-host/runtimeRegionStore.js +245 -0
  29. package/src/testing/buildWasmEdgeRunner.js +253 -0
  30. package/src/testing/index.d.ts +311 -0
  31. package/src/testing/index.js +21 -0
  32. package/src/testing/moduleHarness.js +163 -0
  33. package/src/testing/native/wasmedge_emscripten_pthread_runner.c +3111 -0
  34. package/src/testing/processInvoke.js +467 -0
  35. package/src/testing/publicationProtectionDemo.js +271 -0
  36. package/src/testing/streamInvokeCodec.js +175 -0
  37. package/src/transport/records.js +56 -55
@@ -0,0 +1,3111 @@
1
+ #include <stdbool.h>
2
+ #include <stdint.h>
3
+ #include <pthread.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <unistd.h>
8
+
9
+ #include <wasmedge/wasmedge.h>
10
+
11
+ static void fail_result(const char *step, WasmEdge_Result res) {
12
+ fprintf(
13
+ stderr,
14
+ "%s failed: %s (0x%x)\n",
15
+ step,
16
+ WasmEdge_ResultGetMessage(res),
17
+ WasmEdge_ResultGetCode(res));
18
+ exit(1);
19
+ }
20
+
21
+ typedef struct ImportedMemoryConfig {
22
+ bool found;
23
+ bool shared;
24
+ bool has_max;
25
+ uint32_t min;
26
+ uint32_t max;
27
+ } ImportedMemoryConfig;
28
+
29
+ typedef struct FunctionTypeArity {
30
+ uint32_t param_count;
31
+ uint32_t return_count;
32
+ } FunctionTypeArity;
33
+
34
+ typedef struct ImportedModuleConfig {
35
+ ImportedMemoryConfig memory;
36
+ uint32_t receive_on_main_thread_param_len;
37
+ uint32_t notify_mailbox_postmessage_param_len;
38
+ } ImportedModuleConfig;
39
+
40
+ typedef struct RunnerContext {
41
+ WasmEdge_ConfigureContext *conf;
42
+ WasmEdge_ASTModuleContext *ast;
43
+ WasmEdge_StoreContext *store;
44
+ WasmEdge_MemoryInstanceContext *shared_memory;
45
+ pthread_mutex_t store_mutex;
46
+ } RunnerContext;
47
+
48
+ typedef struct ThreadLaunchContext {
49
+ RunnerContext *runner;
50
+ WasmEdge_ExecutorContext *executor;
51
+ WasmEdge_ModuleInstanceContext *module;
52
+ WasmEdge_TableInstanceContext *indirect_table;
53
+ WasmEdge_FunctionInstanceContext *stack_set_limits;
54
+ WasmEdge_FunctionInstanceContext *stack_restore;
55
+ WasmEdge_FunctionInstanceContext *thread_init;
56
+ WasmEdge_FunctionInstanceContext *tls_init;
57
+ WasmEdge_FunctionInstanceContext *thread_exit;
58
+ WasmEdge_FunctionInstanceContext *thread_crashed;
59
+ uint32_t pthread_ptr;
60
+ uint32_t start_routine;
61
+ uint32_t arg;
62
+ } ThreadLaunchContext;
63
+
64
+ typedef enum HostControlOpcode {
65
+ HOST_CONTROL_WRITE = 1,
66
+ HOST_CONTROL_READ = 2,
67
+ HOST_CONTROL_FREE = 3,
68
+ HOST_CONTROL_INSTALL_MODULE = 16,
69
+ HOST_CONTROL_LIST_MODULES = 17,
70
+ HOST_CONTROL_UNLOAD_MODULE = 18,
71
+ HOST_CONTROL_INVOKE_MODULE = 19,
72
+ HOST_CONTROL_APPEND_ROW = 20,
73
+ HOST_CONTROL_LIST_ROWS = 21,
74
+ HOST_CONTROL_RESOLVE_ROW = 22,
75
+ HOST_CONTROL_ALLOCATE_REGION = 23,
76
+ HOST_CONTROL_DESCRIBE_REGION = 24,
77
+ HOST_CONTROL_RESOLVE_RECORD = 25,
78
+ HOST_CONTROL_QUERY_ROWS = 26,
79
+ } HostControlOpcode;
80
+
81
+ #define EM_PTHREAD_STACK_OFFSET 52U
82
+ #define EM_PTHREAD_STACK_SIZE_OFFSET 56U
83
+ #define EM_PTHREAD_EAGAIN 6
84
+ static const uint8_t HOST_CONTROL_MAGIC[4] = {'O', 'R', 'P', 'W'};
85
+
86
+ typedef struct JsonSlice {
87
+ const char *data;
88
+ size_t length;
89
+ } JsonSlice;
90
+
91
+ typedef struct JsonBuffer {
92
+ char *data;
93
+ size_t length;
94
+ size_t capacity;
95
+ } JsonBuffer;
96
+
97
+ typedef struct RuntimeHostModule {
98
+ char *module_id;
99
+ char *wasm_path;
100
+ char *metadata_json;
101
+ char **method_ids;
102
+ size_t method_id_count;
103
+ WasmEdge_ConfigureContext *conf;
104
+ WasmEdge_LoaderContext *loader;
105
+ WasmEdge_ValidatorContext *validator;
106
+ WasmEdge_ExecutorContext *executor;
107
+ WasmEdge_StoreContext *store;
108
+ WasmEdge_ASTModuleContext *ast;
109
+ WasmEdge_ModuleInstanceContext *module;
110
+ RunnerContext runner;
111
+ bool store_mutex_initialized;
112
+ } RuntimeHostModule;
113
+
114
+ typedef struct RuntimeHostRow {
115
+ char *schema_file_id;
116
+ uint64_t row_id;
117
+ char *payload_json;
118
+ } RuntimeHostRow;
119
+
120
+ typedef struct RuntimeHostRegion {
121
+ uint64_t region_id;
122
+ char *layout_id;
123
+ uint32_t record_byte_length;
124
+ uint16_t alignment;
125
+ uint8_t **records;
126
+ size_t record_count;
127
+ } RuntimeHostRegion;
128
+
129
+ typedef struct RuntimeHostState {
130
+ RuntimeHostModule *modules;
131
+ size_t module_count;
132
+ size_t module_capacity;
133
+ RuntimeHostRow *rows;
134
+ size_t row_count;
135
+ size_t row_capacity;
136
+ uint64_t next_row_id;
137
+ RuntimeHostRegion *regions;
138
+ size_t region_count;
139
+ size_t region_capacity;
140
+ uint64_t next_region_id;
141
+ } RuntimeHostState;
142
+
143
+ static WasmEdge_FunctionInstanceContext *find_first_available_function(
144
+ WasmEdge_ModuleInstanceContext *module,
145
+ const char *const *names,
146
+ size_t name_count);
147
+
148
+ static WasmEdge_Result stub_void(
149
+ void *Data,
150
+ const WasmEdge_CallingFrameContext *CallFrameCxt,
151
+ const WasmEdge_Value *In,
152
+ WasmEdge_Value *Out) {
153
+ (void)Data;
154
+ (void)CallFrameCxt;
155
+ (void)In;
156
+ (void)Out;
157
+ return WasmEdge_Result_Success;
158
+ }
159
+
160
+ static WasmEdge_Result stub_receive_on_main_thread(
161
+ void *Data,
162
+ const WasmEdge_CallingFrameContext *CallFrameCxt,
163
+ const WasmEdge_Value *In,
164
+ WasmEdge_Value *Out) {
165
+ (void)Data;
166
+ (void)CallFrameCxt;
167
+ (void)In;
168
+ Out[0] = WasmEdge_ValueGenF64(0.0);
169
+ return WasmEdge_Result_Success;
170
+ }
171
+
172
+ static WasmEdge_Result stub_pthread_create(
173
+ void *Data,
174
+ const WasmEdge_CallingFrameContext *CallFrameCxt,
175
+ const WasmEdge_Value *In,
176
+ WasmEdge_Value *Out) {
177
+ (void)CallFrameCxt;
178
+ RunnerContext *runner = Data;
179
+ if (runner == NULL || runner->ast == NULL || runner->store == NULL ||
180
+ runner->shared_memory == NULL) {
181
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
182
+ return WasmEdge_Result_Success;
183
+ }
184
+ ThreadLaunchContext *thread_context =
185
+ calloc(1, sizeof(ThreadLaunchContext));
186
+ if (thread_context == NULL) {
187
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
188
+ return WasmEdge_Result_Success;
189
+ }
190
+ thread_context->runner = runner;
191
+ thread_context->pthread_ptr = (uint32_t)WasmEdge_ValueGetI32(In[0]);
192
+ thread_context->start_routine = (uint32_t)WasmEdge_ValueGetI32(In[2]);
193
+ thread_context->arg = (uint32_t)WasmEdge_ValueGetI32(In[3]);
194
+
195
+ thread_context->executor = WasmEdge_ExecutorCreate(runner->conf, NULL);
196
+ if (thread_context->executor == NULL) {
197
+ free(thread_context);
198
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
199
+ return WasmEdge_Result_Success;
200
+ }
201
+
202
+ pthread_mutex_lock(&runner->store_mutex);
203
+ WasmEdge_Result instantiate_result = WasmEdge_ExecutorInstantiate(
204
+ thread_context->executor,
205
+ &thread_context->module,
206
+ runner->store,
207
+ runner->ast);
208
+ pthread_mutex_unlock(&runner->store_mutex);
209
+ if (!WasmEdge_ResultOK(instantiate_result) || thread_context->module == NULL) {
210
+ WasmEdge_ExecutorDelete(thread_context->executor);
211
+ free(thread_context);
212
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
213
+ return WasmEdge_Result_Success;
214
+ }
215
+
216
+ WasmEdge_String export_name =
217
+ WasmEdge_StringCreateByCString("__indirect_function_table");
218
+ thread_context->indirect_table =
219
+ WasmEdge_ModuleInstanceFindTable(thread_context->module, export_name);
220
+ WasmEdge_StringDelete(export_name);
221
+
222
+ export_name = WasmEdge_StringCreateByCString("emscripten_stack_set_limits");
223
+ thread_context->stack_set_limits =
224
+ WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
225
+ WasmEdge_StringDelete(export_name);
226
+
227
+ {
228
+ static const char *const stack_restore_names[] = {
229
+ "_emscripten_stack_restore",
230
+ "stackRestore",
231
+ };
232
+ thread_context->stack_restore = find_first_available_function(
233
+ thread_context->module,
234
+ stack_restore_names,
235
+ sizeof(stack_restore_names) / sizeof(stack_restore_names[0]));
236
+ }
237
+
238
+ export_name = WasmEdge_StringCreateByCString("_emscripten_thread_init");
239
+ thread_context->thread_init =
240
+ WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
241
+ WasmEdge_StringDelete(export_name);
242
+
243
+ export_name = WasmEdge_StringCreateByCString("_emscripten_tls_init");
244
+ thread_context->tls_init =
245
+ WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
246
+ WasmEdge_StringDelete(export_name);
247
+
248
+ export_name = WasmEdge_StringCreateByCString("_emscripten_thread_exit");
249
+ thread_context->thread_exit =
250
+ WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
251
+ WasmEdge_StringDelete(export_name);
252
+
253
+ export_name = WasmEdge_StringCreateByCString("_emscripten_thread_crashed");
254
+ thread_context->thread_crashed =
255
+ WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
256
+ WasmEdge_StringDelete(export_name);
257
+
258
+ if (thread_context->indirect_table == NULL ||
259
+ thread_context->stack_set_limits == NULL ||
260
+ thread_context->stack_restore == NULL ||
261
+ thread_context->thread_init == NULL ||
262
+ thread_context->tls_init == NULL ||
263
+ thread_context->thread_exit == NULL) {
264
+ pthread_mutex_lock(&runner->store_mutex);
265
+ WasmEdge_ModuleInstanceDelete(thread_context->module);
266
+ pthread_mutex_unlock(&runner->store_mutex);
267
+ WasmEdge_ExecutorDelete(thread_context->executor);
268
+ free(thread_context);
269
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
270
+ return WasmEdge_Result_Success;
271
+ }
272
+
273
+ pthread_t thread;
274
+ pthread_attr_t thread_attr;
275
+ if (pthread_attr_init(&thread_attr) != 0) {
276
+ pthread_mutex_lock(&runner->store_mutex);
277
+ WasmEdge_ModuleInstanceDelete(thread_context->module);
278
+ pthread_mutex_unlock(&runner->store_mutex);
279
+ WasmEdge_ExecutorDelete(thread_context->executor);
280
+ free(thread_context);
281
+ Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
282
+ return WasmEdge_Result_Success;
283
+ }
284
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
285
+
286
+ extern void *run_guest_thread(void *Data);
287
+ const int rc = pthread_create(
288
+ &thread,
289
+ &thread_attr,
290
+ run_guest_thread,
291
+ thread_context);
292
+ pthread_attr_destroy(&thread_attr);
293
+ if (rc != 0) {
294
+ pthread_mutex_lock(&runner->store_mutex);
295
+ WasmEdge_ModuleInstanceDelete(thread_context->module);
296
+ pthread_mutex_unlock(&runner->store_mutex);
297
+ WasmEdge_ExecutorDelete(thread_context->executor);
298
+ free(thread_context);
299
+ Out[0] = WasmEdge_ValueGenI32(rc);
300
+ return WasmEdge_Result_Success;
301
+ }
302
+
303
+ (void)CallFrameCxt;
304
+ Out[0] = WasmEdge_ValueGenI32(0);
305
+ return WasmEdge_Result_Success;
306
+ }
307
+
308
+ static void add_host_func(
309
+ WasmEdge_ModuleInstanceContext *mod,
310
+ const char *name,
311
+ WasmEdge_HostFunc_t fn,
312
+ void *data,
313
+ const WasmEdge_ValType *params,
314
+ uint32_t param_len,
315
+ const WasmEdge_ValType *returns,
316
+ uint32_t return_len) {
317
+ WasmEdge_FunctionTypeContext *type =
318
+ WasmEdge_FunctionTypeCreate(params, param_len, returns, return_len);
319
+ WasmEdge_FunctionInstanceContext *func =
320
+ WasmEdge_FunctionInstanceCreate(type, fn, data, 0);
321
+ WasmEdge_String func_name = WasmEdge_StringCreateByCString(name);
322
+ WasmEdge_ModuleInstanceAddFunction(mod, func_name, func);
323
+ WasmEdge_StringDelete(func_name);
324
+ WasmEdge_FunctionTypeDelete(type);
325
+ }
326
+
327
+ static bool read_file_bytes(
328
+ const char *path,
329
+ uint8_t **buffer,
330
+ size_t *buffer_len) {
331
+ FILE *file = fopen(path, "rb");
332
+ if (file == NULL) {
333
+ return false;
334
+ }
335
+ if (fseek(file, 0, SEEK_END) != 0) {
336
+ fclose(file);
337
+ return false;
338
+ }
339
+ long file_size = ftell(file);
340
+ if (file_size < 0) {
341
+ fclose(file);
342
+ return false;
343
+ }
344
+ if (fseek(file, 0, SEEK_SET) != 0) {
345
+ fclose(file);
346
+ return false;
347
+ }
348
+ uint8_t *bytes = malloc((size_t)file_size);
349
+ if (bytes == NULL) {
350
+ fclose(file);
351
+ return false;
352
+ }
353
+ const size_t read_len = fread(bytes, 1, (size_t)file_size, file);
354
+ fclose(file);
355
+ if (read_len != (size_t)file_size) {
356
+ free(bytes);
357
+ return false;
358
+ }
359
+ *buffer = bytes;
360
+ *buffer_len = read_len;
361
+ return true;
362
+ }
363
+
364
+ static bool read_u32_leb(
365
+ const uint8_t *bytes,
366
+ size_t length,
367
+ size_t *offset,
368
+ uint32_t *value) {
369
+ uint32_t result = 0;
370
+ uint32_t shift = 0;
371
+ while (*offset < length) {
372
+ const uint8_t byte = bytes[*offset];
373
+ *offset += 1;
374
+ result |= (uint32_t)(byte & 0x7F) << shift;
375
+ if ((byte & 0x80) == 0) {
376
+ *value = result;
377
+ return true;
378
+ }
379
+ shift += 7;
380
+ if (shift >= 35) {
381
+ return false;
382
+ }
383
+ }
384
+ return false;
385
+ }
386
+
387
+ static bool skip_bytes(size_t length, size_t *offset, uint32_t byte_count) {
388
+ if (*offset + byte_count > length) {
389
+ return false;
390
+ }
391
+ *offset += byte_count;
392
+ return true;
393
+ }
394
+
395
+ static bool read_name_equals(
396
+ const uint8_t *bytes,
397
+ size_t length,
398
+ size_t *offset,
399
+ const char *expected) {
400
+ uint32_t name_len = 0;
401
+ if (!read_u32_leb(bytes, length, offset, &name_len)) {
402
+ return false;
403
+ }
404
+ if (*offset + name_len > length) {
405
+ return false;
406
+ }
407
+ const size_t expected_len = strlen(expected);
408
+ const bool equals =
409
+ expected_len == (size_t)name_len &&
410
+ memcmp(bytes + *offset, expected, expected_len) == 0;
411
+ *offset += name_len;
412
+ return equals;
413
+ }
414
+
415
+ static bool skip_limits(
416
+ const uint8_t *bytes,
417
+ size_t length,
418
+ size_t *offset) {
419
+ uint32_t flags = 0;
420
+ uint32_t ignored = 0;
421
+ if (!read_u32_leb(bytes, length, offset, &flags) ||
422
+ !read_u32_leb(bytes, length, offset, &ignored)) {
423
+ return false;
424
+ }
425
+ if ((flags & 0x01U) != 0 && !read_u32_leb(bytes, length, offset, &ignored)) {
426
+ return false;
427
+ }
428
+ return true;
429
+ }
430
+
431
+ static bool read_imported_module_config(
432
+ const char *wasm_path,
433
+ ImportedModuleConfig *config) {
434
+ memset(config, 0, sizeof(*config));
435
+
436
+ uint8_t *bytes = NULL;
437
+ size_t length = 0;
438
+ if (!read_file_bytes(wasm_path, &bytes, &length)) {
439
+ return false;
440
+ }
441
+
442
+ bool ok = false;
443
+ FunctionTypeArity *types = NULL;
444
+ uint32_t type_count = 0;
445
+ size_t offset = 8;
446
+ if (length < 8 || memcmp(bytes, "\0asm", 4) != 0) {
447
+ goto cleanup;
448
+ }
449
+
450
+ while (offset < length) {
451
+ const uint8_t section_id = bytes[offset];
452
+ offset += 1;
453
+
454
+ uint32_t section_len = 0;
455
+ if (!read_u32_leb(bytes, length, &offset, &section_len)) {
456
+ goto cleanup;
457
+ }
458
+ if (offset + section_len > length) {
459
+ goto cleanup;
460
+ }
461
+
462
+ const size_t section_end = offset + section_len;
463
+ if (section_id == 1) {
464
+ if (!read_u32_leb(bytes, section_end, &offset, &type_count)) {
465
+ goto cleanup;
466
+ }
467
+ types = calloc(type_count, sizeof(FunctionTypeArity));
468
+ if (types == NULL && type_count > 0) {
469
+ goto cleanup;
470
+ }
471
+ for (uint32_t index = 0; index < type_count; index++) {
472
+ if (offset >= section_end || bytes[offset] != 0x60) {
473
+ goto cleanup;
474
+ }
475
+ offset += 1;
476
+ if (!read_u32_leb(
477
+ bytes,
478
+ section_end,
479
+ &offset,
480
+ &types[index].param_count)) {
481
+ goto cleanup;
482
+ }
483
+ if (!skip_bytes(section_end, &offset, types[index].param_count)) {
484
+ goto cleanup;
485
+ }
486
+ if (!read_u32_leb(
487
+ bytes,
488
+ section_end,
489
+ &offset,
490
+ &types[index].return_count)) {
491
+ goto cleanup;
492
+ }
493
+ if (!skip_bytes(section_end, &offset, types[index].return_count)) {
494
+ goto cleanup;
495
+ }
496
+ }
497
+ offset = section_end;
498
+ continue;
499
+ }
500
+
501
+ if (section_id != 2) {
502
+ offset = section_end;
503
+ continue;
504
+ }
505
+
506
+ uint32_t import_count = 0;
507
+ if (!read_u32_leb(bytes, section_end, &offset, &import_count)) {
508
+ goto cleanup;
509
+ }
510
+
511
+ for (uint32_t index = 0; index < import_count; index++) {
512
+ const bool is_env =
513
+ read_name_equals(bytes, section_end, &offset, "env");
514
+ size_t field_name_offset = offset;
515
+ uint32_t field_name_len = 0;
516
+ if (!read_u32_leb(
517
+ bytes,
518
+ section_end,
519
+ &field_name_offset,
520
+ &field_name_len)) {
521
+ goto cleanup;
522
+ }
523
+ if (field_name_offset + field_name_len > section_end) {
524
+ goto cleanup;
525
+ }
526
+ const bool is_memory_name =
527
+ field_name_len == 6 &&
528
+ memcmp(bytes + field_name_offset, "memory", 6) == 0;
529
+ const bool is_receive_on_main_thread_name =
530
+ field_name_len == 37 &&
531
+ memcmp(
532
+ bytes + field_name_offset,
533
+ "_emscripten_receive_on_main_thread_js",
534
+ 37) == 0;
535
+ const bool is_notify_mailbox_postmessage_name =
536
+ field_name_len == 38 &&
537
+ memcmp(
538
+ bytes + field_name_offset,
539
+ "_emscripten_notify_mailbox_postmessage",
540
+ 38) == 0;
541
+ offset = field_name_offset + field_name_len;
542
+
543
+ if (offset >= section_end) {
544
+ goto cleanup;
545
+ }
546
+ const uint8_t kind = bytes[offset];
547
+ offset += 1;
548
+
549
+ switch (kind) {
550
+ case 0x00: {
551
+ uint32_t type_index = 0;
552
+ if (!read_u32_leb(bytes, section_end, &offset, &type_index)) {
553
+ goto cleanup;
554
+ }
555
+ if (is_env && is_receive_on_main_thread_name &&
556
+ type_index < type_count) {
557
+ config->receive_on_main_thread_param_len =
558
+ types[type_index].param_count;
559
+ }
560
+ if (is_env && is_notify_mailbox_postmessage_name &&
561
+ type_index < type_count) {
562
+ config->notify_mailbox_postmessage_param_len =
563
+ types[type_index].param_count;
564
+ }
565
+ break;
566
+ }
567
+ case 0x01:
568
+ if (!skip_bytes(section_end, &offset, 1) ||
569
+ !skip_limits(bytes, section_end, &offset)) {
570
+ goto cleanup;
571
+ }
572
+ break;
573
+ case 0x02: {
574
+ uint32_t flags = 0;
575
+ uint32_t min_pages = 0;
576
+ uint32_t max_pages = 0;
577
+ if (!read_u32_leb(bytes, section_end, &offset, &flags) ||
578
+ !read_u32_leb(bytes, section_end, &offset, &min_pages)) {
579
+ goto cleanup;
580
+ }
581
+ const bool has_max = (flags & 0x01U) != 0;
582
+ const bool shared = (flags & 0x02U) != 0;
583
+ if (has_max &&
584
+ !read_u32_leb(bytes, section_end, &offset, &max_pages)) {
585
+ goto cleanup;
586
+ }
587
+ if (is_env && is_memory_name) {
588
+ config->memory.found = true;
589
+ config->memory.shared = shared;
590
+ config->memory.has_max = has_max;
591
+ config->memory.min = min_pages;
592
+ config->memory.max = max_pages;
593
+ }
594
+ break;
595
+ }
596
+ case 0x03:
597
+ if (!skip_bytes(section_end, &offset, 2)) {
598
+ goto cleanup;
599
+ }
600
+ break;
601
+ case 0x04: {
602
+ uint32_t tag_type = 0;
603
+ uint32_t type_index = 0;
604
+ if (!read_u32_leb(bytes, section_end, &offset, &tag_type) ||
605
+ !read_u32_leb(bytes, section_end, &offset, &type_index)) {
606
+ goto cleanup;
607
+ }
608
+ break;
609
+ }
610
+ default:
611
+ goto cleanup;
612
+ }
613
+ }
614
+
615
+ ok = true;
616
+ goto cleanup;
617
+ }
618
+
619
+ ok = true;
620
+
621
+ cleanup:
622
+ free(types);
623
+ free(bytes);
624
+ return ok;
625
+ }
626
+
627
+ static bool add_imported_env_memory_from_file(
628
+ const char *wasm_path,
629
+ WasmEdge_ModuleInstanceContext *env,
630
+ WasmEdge_MemoryInstanceContext **memory_out) {
631
+ ImportedModuleConfig config;
632
+ if (!read_imported_module_config(wasm_path, &config)) {
633
+ return false;
634
+ }
635
+ if (!config.memory.found) {
636
+ *memory_out = NULL;
637
+ return true;
638
+ }
639
+ if (!config.memory.has_max) {
640
+ return false;
641
+ }
642
+
643
+ WasmEdge_Limit limit = {
644
+ .HasMax = config.memory.has_max,
645
+ .Shared = config.memory.shared,
646
+ .Min = config.memory.min,
647
+ .Max = config.memory.max,
648
+ };
649
+ WasmEdge_MemoryTypeContext *host_memory_type =
650
+ WasmEdge_MemoryTypeCreate(limit);
651
+ WasmEdge_MemoryInstanceContext *memory =
652
+ WasmEdge_MemoryInstanceCreate(host_memory_type);
653
+ WasmEdge_String memory_name = WasmEdge_StringCreateByCString("memory");
654
+ WasmEdge_ModuleInstanceAddMemory(env, memory_name, memory);
655
+ WasmEdge_StringDelete(memory_name);
656
+ WasmEdge_MemoryTypeDelete(host_memory_type);
657
+ *memory_out = memory;
658
+ return true;
659
+ }
660
+
661
+ static void register_env_host_functions(
662
+ WasmEdge_ModuleInstanceContext *env,
663
+ RunnerContext *runner,
664
+ uint32_t receive_on_main_thread_param_len,
665
+ uint32_t notify_mailbox_postmessage_param_len) {
666
+ const WasmEdge_ValType i32_param[1] = {WasmEdge_ValTypeGenI32()};
667
+ const WasmEdge_ValType two_i32_params[2] = {
668
+ WasmEdge_ValTypeGenI32(),
669
+ WasmEdge_ValTypeGenI32()};
670
+ const WasmEdge_ValType three_i32_params[3] = {
671
+ WasmEdge_ValTypeGenI32(),
672
+ WasmEdge_ValTypeGenI32(),
673
+ WasmEdge_ValTypeGenI32()};
674
+ const WasmEdge_ValType four_i32_params[4] = {
675
+ WasmEdge_ValTypeGenI32(),
676
+ WasmEdge_ValTypeGenI32(),
677
+ WasmEdge_ValTypeGenI32(),
678
+ WasmEdge_ValTypeGenI32()};
679
+ const WasmEdge_ValType five_i32_params[5] = {
680
+ WasmEdge_ValTypeGenI32(),
681
+ WasmEdge_ValTypeGenI32(),
682
+ WasmEdge_ValTypeGenI32(),
683
+ WasmEdge_ValTypeGenI32(),
684
+ WasmEdge_ValTypeGenI32()};
685
+ const WasmEdge_ValType f64_return[1] = {WasmEdge_ValTypeGenF64()};
686
+ const WasmEdge_ValType i32_return[1] = {WasmEdge_ValTypeGenI32()};
687
+
688
+ add_host_func(
689
+ env,
690
+ "_emscripten_thread_set_strongref",
691
+ stub_void,
692
+ runner,
693
+ i32_param,
694
+ 1,
695
+ NULL,
696
+ 0);
697
+ add_host_func(
698
+ env,
699
+ "emscripten_exit_with_live_runtime",
700
+ stub_void,
701
+ runner,
702
+ NULL,
703
+ 0,
704
+ NULL,
705
+ 0);
706
+ add_host_func(
707
+ env,
708
+ "_emscripten_init_main_thread_js",
709
+ stub_void,
710
+ runner,
711
+ i32_param,
712
+ 1,
713
+ NULL,
714
+ 0);
715
+ add_host_func(
716
+ env,
717
+ "__emscripten_init_main_thread_js",
718
+ stub_void,
719
+ runner,
720
+ i32_param,
721
+ 1,
722
+ NULL,
723
+ 0);
724
+ add_host_func(
725
+ env,
726
+ "_emscripten_thread_mailbox_await",
727
+ stub_void,
728
+ runner,
729
+ i32_param,
730
+ 1,
731
+ NULL,
732
+ 0);
733
+ add_host_func(
734
+ env,
735
+ "_emscripten_receive_on_main_thread_js",
736
+ stub_receive_on_main_thread,
737
+ runner,
738
+ receive_on_main_thread_param_len == 4 ? four_i32_params : five_i32_params,
739
+ receive_on_main_thread_param_len == 4 ? 4 : 5,
740
+ f64_return,
741
+ 1);
742
+ add_host_func(
743
+ env,
744
+ "emscripten_check_blocking_allowed",
745
+ stub_void,
746
+ runner,
747
+ NULL,
748
+ 0,
749
+ NULL,
750
+ 0);
751
+ add_host_func(
752
+ env,
753
+ "__pthread_create_js",
754
+ stub_pthread_create,
755
+ runner,
756
+ four_i32_params,
757
+ 4,
758
+ i32_return,
759
+ 1);
760
+ add_host_func(
761
+ env,
762
+ "_emscripten_thread_cleanup",
763
+ stub_void,
764
+ runner,
765
+ i32_param,
766
+ 1,
767
+ NULL,
768
+ 0);
769
+ add_host_func(
770
+ env,
771
+ "__emscripten_thread_cleanup",
772
+ stub_void,
773
+ runner,
774
+ i32_param,
775
+ 1,
776
+ NULL,
777
+ 0);
778
+ add_host_func(
779
+ env,
780
+ "_emscripten_notify_mailbox_postmessage",
781
+ stub_void,
782
+ runner,
783
+ notify_mailbox_postmessage_param_len == 3
784
+ ? three_i32_params
785
+ : two_i32_params,
786
+ notify_mailbox_postmessage_param_len == 3 ? 3 : 2,
787
+ NULL,
788
+ 0);
789
+ }
790
+
791
+ static bool read_guest_u32(
792
+ WasmEdge_MemoryInstanceContext *memory,
793
+ uint32_t offset,
794
+ uint32_t *value) {
795
+ const uint8_t *bytes =
796
+ WasmEdge_MemoryInstanceGetPointerConst(memory, offset, 4);
797
+ if (bytes == NULL) {
798
+ return false;
799
+ }
800
+ *value = (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
801
+ ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
802
+ return true;
803
+ }
804
+
805
+ static bool invoke_function(
806
+ WasmEdge_ExecutorContext *executor,
807
+ WasmEdge_FunctionInstanceContext *function,
808
+ const WasmEdge_Value *params,
809
+ uint32_t params_len,
810
+ WasmEdge_Value *returns,
811
+ uint32_t returns_len,
812
+ const char *label) {
813
+ const WasmEdge_Result result = WasmEdge_ExecutorInvoke(
814
+ executor,
815
+ function,
816
+ params,
817
+ params_len,
818
+ returns,
819
+ returns_len);
820
+ if (WasmEdge_ResultOK(result)) {
821
+ return true;
822
+ }
823
+ fprintf(
824
+ stderr,
825
+ "%s failed: %s (0x%x)\n",
826
+ label,
827
+ WasmEdge_ResultGetMessage(result),
828
+ WasmEdge_ResultGetCode(result));
829
+ return false;
830
+ }
831
+
832
+ static WasmEdge_FunctionInstanceContext *find_function(
833
+ WasmEdge_ModuleInstanceContext *module,
834
+ const char *name) {
835
+ WasmEdge_String function_name = WasmEdge_StringCreateByCString(name);
836
+ WasmEdge_FunctionInstanceContext *function =
837
+ WasmEdge_ModuleInstanceFindFunction(module, function_name);
838
+ WasmEdge_StringDelete(function_name);
839
+ return function;
840
+ }
841
+
842
+ static WasmEdge_FunctionInstanceContext *find_first_available_function(
843
+ WasmEdge_ModuleInstanceContext *module,
844
+ const char *const *names,
845
+ size_t name_count) {
846
+ for (size_t index = 0; index < name_count; ++index) {
847
+ WasmEdge_FunctionInstanceContext *function =
848
+ find_function(module, names[index]);
849
+ if (function != NULL) {
850
+ return function;
851
+ }
852
+ }
853
+ return NULL;
854
+ }
855
+
856
+ static WasmEdge_MemoryInstanceContext *resolve_guest_memory(
857
+ WasmEdge_ModuleInstanceContext *module,
858
+ RunnerContext *runner) {
859
+ WasmEdge_String memory_name = WasmEdge_StringCreateByCString("memory");
860
+ WasmEdge_MemoryInstanceContext *memory =
861
+ WasmEdge_ModuleInstanceFindMemory(module, memory_name);
862
+ WasmEdge_StringDelete(memory_name);
863
+ if (memory != NULL) {
864
+ return memory;
865
+ }
866
+ return runner->shared_memory;
867
+ }
868
+
869
+ static bool write_guest_memory(
870
+ WasmEdge_MemoryInstanceContext *memory,
871
+ uint32_t offset,
872
+ const uint8_t *bytes,
873
+ uint32_t length) {
874
+ if (length == 0) {
875
+ return true;
876
+ }
877
+ const WasmEdge_Result result =
878
+ WasmEdge_MemoryInstanceSetData(memory, bytes, offset, length);
879
+ if (WasmEdge_ResultOK(result)) {
880
+ return true;
881
+ }
882
+ fprintf(
883
+ stderr,
884
+ "guest memory write failed: %s (0x%x)\n",
885
+ WasmEdge_ResultGetMessage(result),
886
+ WasmEdge_ResultGetCode(result));
887
+ return false;
888
+ }
889
+
890
+ static bool read_guest_memory(
891
+ const WasmEdge_MemoryInstanceContext *memory,
892
+ uint32_t offset,
893
+ uint8_t *bytes,
894
+ uint32_t length) {
895
+ if (length == 0) {
896
+ return true;
897
+ }
898
+ const WasmEdge_Result result =
899
+ WasmEdge_MemoryInstanceGetData(memory, bytes, offset, length);
900
+ if (WasmEdge_ResultOK(result)) {
901
+ return true;
902
+ }
903
+ fprintf(
904
+ stderr,
905
+ "guest memory read failed: %s (0x%x)\n",
906
+ WasmEdge_ResultGetMessage(result),
907
+ WasmEdge_ResultGetCode(result));
908
+ return false;
909
+ }
910
+
911
+ static bool guest_malloc(
912
+ WasmEdge_ExecutorContext *executor,
913
+ WasmEdge_FunctionInstanceContext *malloc_fn,
914
+ uint32_t length,
915
+ uint32_t *pointer_out) {
916
+ WasmEdge_Value params[1];
917
+ WasmEdge_Value returns[1];
918
+ params[0] = WasmEdge_ValueGenI32((int32_t)length);
919
+ if (!invoke_function(
920
+ executor,
921
+ malloc_fn,
922
+ params,
923
+ 1,
924
+ returns,
925
+ 1,
926
+ "plugin_alloc")) {
927
+ return false;
928
+ }
929
+ *pointer_out = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
930
+ return true;
931
+ }
932
+
933
+ static bool guest_free(
934
+ WasmEdge_ExecutorContext *executor,
935
+ WasmEdge_FunctionInstanceContext *free_fn,
936
+ uint32_t pointer,
937
+ uint32_t length) {
938
+ if (pointer == 0) {
939
+ return true;
940
+ }
941
+ WasmEdge_Value params[2];
942
+ params[0] = WasmEdge_ValueGenI32((int32_t)pointer);
943
+ params[1] = WasmEdge_ValueGenI32((int32_t)length);
944
+ return invoke_function(
945
+ executor,
946
+ free_fn,
947
+ params,
948
+ 2,
949
+ NULL,
950
+ 0,
951
+ "plugin_free");
952
+ }
953
+
954
+ static bool read_exact(FILE *stream, uint8_t *buffer, size_t length) {
955
+ size_t offset = 0;
956
+ while (offset < length) {
957
+ const size_t read_len = fread(buffer + offset, 1, length - offset, stream);
958
+ if (read_len == 0) {
959
+ if (feof(stream)) {
960
+ return false;
961
+ }
962
+ if (ferror(stream)) {
963
+ perror("fread");
964
+ }
965
+ return false;
966
+ }
967
+ offset += read_len;
968
+ }
969
+ return true;
970
+ }
971
+
972
+ static bool write_all(FILE *stream, const uint8_t *buffer, size_t length) {
973
+ size_t offset = 0;
974
+ while (offset < length) {
975
+ const size_t write_len =
976
+ fwrite(buffer + offset, 1, length - offset, stream);
977
+ if (write_len == 0) {
978
+ if (ferror(stream)) {
979
+ perror("fwrite");
980
+ }
981
+ return false;
982
+ }
983
+ offset += write_len;
984
+ }
985
+ return fflush(stream) == 0;
986
+ }
987
+
988
+ static uint32_t read_le_u32_bytes(const uint8_t *bytes) {
989
+ return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
990
+ ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
991
+ }
992
+
993
+ static void runtime_host_state_init(RuntimeHostState *state) {
994
+ memset(state, 0, sizeof(*state));
995
+ state->next_row_id = 1;
996
+ state->next_region_id = 1;
997
+ }
998
+
999
+ static void json_buffer_init(JsonBuffer *buffer) {
1000
+ memset(buffer, 0, sizeof(*buffer));
1001
+ }
1002
+
1003
+ static void json_buffer_free(JsonBuffer *buffer) {
1004
+ free(buffer->data);
1005
+ buffer->data = NULL;
1006
+ buffer->length = 0;
1007
+ buffer->capacity = 0;
1008
+ }
1009
+
1010
+ static bool json_buffer_reserve(JsonBuffer *buffer, size_t additional) {
1011
+ const size_t required = buffer->length + additional + 1;
1012
+ if (required <= buffer->capacity) {
1013
+ return true;
1014
+ }
1015
+ size_t next_capacity = buffer->capacity == 0 ? 256 : buffer->capacity;
1016
+ while (next_capacity < required) {
1017
+ next_capacity *= 2;
1018
+ }
1019
+ char *next = realloc(buffer->data, next_capacity);
1020
+ if (next == NULL) {
1021
+ return false;
1022
+ }
1023
+ buffer->data = next;
1024
+ buffer->capacity = next_capacity;
1025
+ return true;
1026
+ }
1027
+
1028
+ static bool json_buffer_append_bytes(
1029
+ JsonBuffer *buffer,
1030
+ const char *bytes,
1031
+ size_t length) {
1032
+ if (!json_buffer_reserve(buffer, length)) {
1033
+ return false;
1034
+ }
1035
+ memcpy(buffer->data + buffer->length, bytes, length);
1036
+ buffer->length += length;
1037
+ buffer->data[buffer->length] = '\0';
1038
+ return true;
1039
+ }
1040
+
1041
+ static bool json_buffer_append_cstr(JsonBuffer *buffer, const char *value) {
1042
+ return json_buffer_append_bytes(buffer, value, strlen(value));
1043
+ }
1044
+
1045
+ static bool json_buffer_append_char(JsonBuffer *buffer, char value) {
1046
+ return json_buffer_append_bytes(buffer, &value, 1);
1047
+ }
1048
+
1049
+ static bool json_buffer_append_u64(JsonBuffer *buffer, uint64_t value) {
1050
+ char scratch[32];
1051
+ const int written =
1052
+ snprintf(scratch, sizeof(scratch), "%llu", (unsigned long long)value);
1053
+ return written > 0 &&
1054
+ json_buffer_append_bytes(buffer, scratch, (size_t)written);
1055
+ }
1056
+
1057
+ static bool json_buffer_append_u32(JsonBuffer *buffer, uint32_t value) {
1058
+ char scratch[32];
1059
+ const int written = snprintf(scratch, sizeof(scratch), "%u", value);
1060
+ return written > 0 &&
1061
+ json_buffer_append_bytes(buffer, scratch, (size_t)written);
1062
+ }
1063
+
1064
+ static bool json_buffer_append_json_string(
1065
+ JsonBuffer *buffer,
1066
+ const char *value) {
1067
+ if (!json_buffer_append_char(buffer, '"')) {
1068
+ return false;
1069
+ }
1070
+ for (const unsigned char *cursor = (const unsigned char *)value;
1071
+ *cursor != '\0';
1072
+ ++cursor) {
1073
+ switch (*cursor) {
1074
+ case '"':
1075
+ case '\\':
1076
+ if (!json_buffer_append_char(buffer, '\\') ||
1077
+ !json_buffer_append_char(buffer, (char)*cursor)) {
1078
+ return false;
1079
+ }
1080
+ break;
1081
+ case '\b':
1082
+ if (!json_buffer_append_cstr(buffer, "\\b")) {
1083
+ return false;
1084
+ }
1085
+ break;
1086
+ case '\f':
1087
+ if (!json_buffer_append_cstr(buffer, "\\f")) {
1088
+ return false;
1089
+ }
1090
+ break;
1091
+ case '\n':
1092
+ if (!json_buffer_append_cstr(buffer, "\\n")) {
1093
+ return false;
1094
+ }
1095
+ break;
1096
+ case '\r':
1097
+ if (!json_buffer_append_cstr(buffer, "\\r")) {
1098
+ return false;
1099
+ }
1100
+ break;
1101
+ case '\t':
1102
+ if (!json_buffer_append_cstr(buffer, "\\t")) {
1103
+ return false;
1104
+ }
1105
+ break;
1106
+ default:
1107
+ if (*cursor < 0x20U) {
1108
+ char escaped[7];
1109
+ const int written =
1110
+ snprintf(escaped, sizeof(escaped), "\\u%04x", *cursor);
1111
+ if (written <= 0 ||
1112
+ !json_buffer_append_bytes(buffer, escaped, (size_t)written)) {
1113
+ return false;
1114
+ }
1115
+ } else if (!json_buffer_append_char(buffer, (char)*cursor)) {
1116
+ return false;
1117
+ }
1118
+ break;
1119
+ }
1120
+ }
1121
+ return json_buffer_append_char(buffer, '"');
1122
+ }
1123
+
1124
+ static uint8_t *json_buffer_detach(
1125
+ JsonBuffer *buffer,
1126
+ uint32_t *length_out) {
1127
+ uint8_t *bytes = NULL;
1128
+ if (buffer->length > 0) {
1129
+ bytes = malloc(buffer->length);
1130
+ if (bytes == NULL) {
1131
+ return NULL;
1132
+ }
1133
+ memcpy(bytes, buffer->data, buffer->length);
1134
+ }
1135
+ *length_out = (uint32_t)buffer->length;
1136
+ json_buffer_free(buffer);
1137
+ return bytes;
1138
+ }
1139
+
1140
+ static void skip_json_whitespace(
1141
+ const char *json,
1142
+ size_t length,
1143
+ size_t *offset) {
1144
+ while (*offset < length) {
1145
+ const char ch = json[*offset];
1146
+ if (ch != ' ' && ch != '\n' && ch != '\r' && ch != '\t') {
1147
+ return;
1148
+ }
1149
+ *offset += 1;
1150
+ }
1151
+ }
1152
+
1153
+ static bool consume_json_string(
1154
+ const char *json,
1155
+ size_t length,
1156
+ size_t *offset) {
1157
+ if (*offset >= length || json[*offset] != '"') {
1158
+ return false;
1159
+ }
1160
+ *offset += 1;
1161
+ while (*offset < length) {
1162
+ const char ch = json[*offset];
1163
+ *offset += 1;
1164
+ if (ch == '\\') {
1165
+ if (*offset >= length) {
1166
+ return false;
1167
+ }
1168
+ *offset += 1;
1169
+ continue;
1170
+ }
1171
+ if (ch == '"') {
1172
+ return true;
1173
+ }
1174
+ }
1175
+ return false;
1176
+ }
1177
+
1178
+ static bool consume_json_value(
1179
+ const char *json,
1180
+ size_t length,
1181
+ size_t *offset) {
1182
+ skip_json_whitespace(json, length, offset);
1183
+ if (*offset >= length) {
1184
+ return false;
1185
+ }
1186
+ const char ch = json[*offset];
1187
+ if (ch == '"') {
1188
+ return consume_json_string(json, length, offset);
1189
+ }
1190
+ if (ch == '{' || ch == '[') {
1191
+ const char open = ch;
1192
+ const char close = ch == '{' ? '}' : ']';
1193
+ *offset += 1;
1194
+ skip_json_whitespace(json, length, offset);
1195
+ if (*offset < length && json[*offset] == close) {
1196
+ *offset += 1;
1197
+ return true;
1198
+ }
1199
+ for (;;) {
1200
+ if (open == '{') {
1201
+ if (!consume_json_string(json, length, offset)) {
1202
+ return false;
1203
+ }
1204
+ skip_json_whitespace(json, length, offset);
1205
+ if (*offset >= length || json[*offset] != ':') {
1206
+ return false;
1207
+ }
1208
+ *offset += 1;
1209
+ }
1210
+ if (!consume_json_value(json, length, offset)) {
1211
+ return false;
1212
+ }
1213
+ skip_json_whitespace(json, length, offset);
1214
+ if (*offset >= length) {
1215
+ return false;
1216
+ }
1217
+ if (json[*offset] == close) {
1218
+ *offset += 1;
1219
+ return true;
1220
+ }
1221
+ if (json[*offset] != ',') {
1222
+ return false;
1223
+ }
1224
+ *offset += 1;
1225
+ }
1226
+ }
1227
+ while (*offset < length) {
1228
+ const char value_ch = json[*offset];
1229
+ if (value_ch == ',' || value_ch == '}' || value_ch == ']' ||
1230
+ value_ch == ' ' || value_ch == '\n' || value_ch == '\r' ||
1231
+ value_ch == '\t') {
1232
+ return true;
1233
+ }
1234
+ *offset += 1;
1235
+ }
1236
+ return true;
1237
+ }
1238
+
1239
+ static bool duplicate_json_string_value(
1240
+ JsonSlice slice,
1241
+ char **value_out) {
1242
+ if (slice.length < 2 || slice.data[0] != '"' ||
1243
+ slice.data[slice.length - 1] != '"') {
1244
+ return false;
1245
+ }
1246
+ char *value = malloc(slice.length);
1247
+ if (value == NULL) {
1248
+ return false;
1249
+ }
1250
+ size_t write_index = 0;
1251
+ for (size_t index = 1; index + 1 < slice.length; ++index) {
1252
+ char ch = slice.data[index];
1253
+ if (ch == '\\') {
1254
+ if (index + 1 >= slice.length - 1) {
1255
+ free(value);
1256
+ return false;
1257
+ }
1258
+ index += 1;
1259
+ ch = slice.data[index];
1260
+ switch (ch) {
1261
+ case '"':
1262
+ case '\\':
1263
+ case '/':
1264
+ value[write_index++] = ch;
1265
+ break;
1266
+ case 'b':
1267
+ value[write_index++] = '\b';
1268
+ break;
1269
+ case 'f':
1270
+ value[write_index++] = '\f';
1271
+ break;
1272
+ case 'n':
1273
+ value[write_index++] = '\n';
1274
+ break;
1275
+ case 'r':
1276
+ value[write_index++] = '\r';
1277
+ break;
1278
+ case 't':
1279
+ value[write_index++] = '\t';
1280
+ break;
1281
+ default:
1282
+ free(value);
1283
+ return false;
1284
+ }
1285
+ } else {
1286
+ value[write_index++] = ch;
1287
+ }
1288
+ }
1289
+ value[write_index] = '\0';
1290
+ *value_out = value;
1291
+ return true;
1292
+ }
1293
+
1294
+ static bool duplicate_json_slice(JsonSlice slice, char **value_out) {
1295
+ char *value = malloc(slice.length + 1);
1296
+ if (value == NULL) {
1297
+ return false;
1298
+ }
1299
+ memcpy(value, slice.data, slice.length);
1300
+ value[slice.length] = '\0';
1301
+ *value_out = value;
1302
+ return true;
1303
+ }
1304
+
1305
+ static bool json_slice_is_null(JsonSlice slice) {
1306
+ return slice.length == 4 && memcmp(slice.data, "null", 4) == 0;
1307
+ }
1308
+
1309
+ static bool parse_json_u64(JsonSlice slice, uint64_t *value_out) {
1310
+ char scratch[64];
1311
+ if (slice.length == 0 || slice.length >= sizeof(scratch)) {
1312
+ return false;
1313
+ }
1314
+ memcpy(scratch, slice.data, slice.length);
1315
+ scratch[slice.length] = '\0';
1316
+ char *end = NULL;
1317
+ const unsigned long long value = strtoull(scratch, &end, 10);
1318
+ if (end == scratch || *end != '\0') {
1319
+ return false;
1320
+ }
1321
+ *value_out = (uint64_t)value;
1322
+ return true;
1323
+ }
1324
+
1325
+ static bool find_json_object_field(
1326
+ const char *json,
1327
+ size_t length,
1328
+ const char *field_name,
1329
+ JsonSlice *value_out) {
1330
+ size_t offset = 0;
1331
+ skip_json_whitespace(json, length, &offset);
1332
+ if (offset >= length || json[offset] != '{') {
1333
+ return false;
1334
+ }
1335
+ offset += 1;
1336
+ for (;;) {
1337
+ skip_json_whitespace(json, length, &offset);
1338
+ if (offset >= length) {
1339
+ return false;
1340
+ }
1341
+ if (json[offset] == '}') {
1342
+ return false;
1343
+ }
1344
+ const size_t key_start = offset;
1345
+ if (!consume_json_string(json, length, &offset)) {
1346
+ return false;
1347
+ }
1348
+ JsonSlice key_slice = {
1349
+ .data = json + key_start,
1350
+ .length = offset - key_start,
1351
+ };
1352
+ char *key_value = NULL;
1353
+ if (!duplicate_json_string_value(key_slice, &key_value)) {
1354
+ return false;
1355
+ }
1356
+ skip_json_whitespace(json, length, &offset);
1357
+ if (offset >= length || json[offset] != ':') {
1358
+ free(key_value);
1359
+ return false;
1360
+ }
1361
+ offset += 1;
1362
+ skip_json_whitespace(json, length, &offset);
1363
+ const size_t value_start = offset;
1364
+ if (!consume_json_value(json, length, &offset)) {
1365
+ free(key_value);
1366
+ return false;
1367
+ }
1368
+ const bool matched = strcmp(key_value, field_name) == 0;
1369
+ free(key_value);
1370
+ if (matched) {
1371
+ value_out->data = json + value_start;
1372
+ value_out->length = offset - value_start;
1373
+ return true;
1374
+ }
1375
+ skip_json_whitespace(json, length, &offset);
1376
+ if (offset >= length) {
1377
+ return false;
1378
+ }
1379
+ if (json[offset] == '}') {
1380
+ return false;
1381
+ }
1382
+ if (json[offset] != ',') {
1383
+ return false;
1384
+ }
1385
+ offset += 1;
1386
+ }
1387
+ }
1388
+
1389
+ static bool ensure_runtime_host_capacity(
1390
+ void **buffer,
1391
+ size_t *capacity,
1392
+ size_t count,
1393
+ size_t item_size) {
1394
+ if (count < *capacity) {
1395
+ return true;
1396
+ }
1397
+ size_t next_capacity = *capacity == 0 ? 8 : *capacity * 2;
1398
+ while (next_capacity <= count) {
1399
+ next_capacity *= 2;
1400
+ }
1401
+ void *next = realloc(*buffer, next_capacity * item_size);
1402
+ if (next == NULL) {
1403
+ return false;
1404
+ }
1405
+ *buffer = next;
1406
+ *capacity = next_capacity;
1407
+ return true;
1408
+ }
1409
+
1410
+ static void runtime_host_module_init(RuntimeHostModule *module) {
1411
+ memset(module, 0, sizeof(*module));
1412
+ }
1413
+
1414
+ static void destroy_runtime_host_module(RuntimeHostModule *module) {
1415
+ if (module == NULL) {
1416
+ return;
1417
+ }
1418
+ free(module->module_id);
1419
+ free(module->wasm_path);
1420
+ free(module->metadata_json);
1421
+ for (size_t index = 0; index < module->method_id_count; ++index) {
1422
+ free(module->method_ids[index]);
1423
+ }
1424
+ free(module->method_ids);
1425
+ if (module->store != NULL) {
1426
+ WasmEdge_StoreDelete(module->store);
1427
+ }
1428
+ if (module->executor != NULL) {
1429
+ WasmEdge_ExecutorDelete(module->executor);
1430
+ }
1431
+ if (module->validator != NULL) {
1432
+ WasmEdge_ValidatorDelete(module->validator);
1433
+ }
1434
+ if (module->loader != NULL) {
1435
+ WasmEdge_LoaderDelete(module->loader);
1436
+ }
1437
+ if (module->conf != NULL) {
1438
+ WasmEdge_ConfigureDelete(module->conf);
1439
+ }
1440
+ if (module->ast != NULL) {
1441
+ WasmEdge_ASTModuleDelete(module->ast);
1442
+ }
1443
+ if (module->store_mutex_initialized) {
1444
+ pthread_mutex_destroy(&module->runner.store_mutex);
1445
+ }
1446
+ memset(module, 0, sizeof(*module));
1447
+ }
1448
+
1449
+ static void destroy_runtime_host_region(RuntimeHostRegion *region) {
1450
+ if (region == NULL) {
1451
+ return;
1452
+ }
1453
+ for (size_t index = 0; index < region->record_count; ++index) {
1454
+ free(region->records[index]);
1455
+ }
1456
+ free(region->records);
1457
+ free(region->layout_id);
1458
+ memset(region, 0, sizeof(*region));
1459
+ }
1460
+
1461
+ static void runtime_host_state_destroy(RuntimeHostState *state) {
1462
+ for (size_t index = 0; index < state->module_count; ++index) {
1463
+ destroy_runtime_host_module(&state->modules[index]);
1464
+ }
1465
+ free(state->modules);
1466
+ for (size_t index = 0; index < state->row_count; ++index) {
1467
+ free(state->rows[index].schema_file_id);
1468
+ free(state->rows[index].payload_json);
1469
+ }
1470
+ free(state->rows);
1471
+ for (size_t index = 0; index < state->region_count; ++index) {
1472
+ destroy_runtime_host_region(&state->regions[index]);
1473
+ }
1474
+ free(state->regions);
1475
+ memset(state, 0, sizeof(*state));
1476
+ }
1477
+
1478
+ static bool invoke_optional_module_init(
1479
+ WasmEdge_ExecutorContext *executor,
1480
+ WasmEdge_ModuleInstanceContext *module,
1481
+ bool service_mode) {
1482
+ if (service_mode) {
1483
+ WasmEdge_FunctionInstanceContext *ctors =
1484
+ find_function(module, "__wasm_call_ctors");
1485
+ if (ctors != NULL) {
1486
+ return invoke_function(
1487
+ executor,
1488
+ ctors,
1489
+ NULL,
1490
+ 0,
1491
+ NULL,
1492
+ 0,
1493
+ "__wasm_call_ctors");
1494
+ }
1495
+ return true;
1496
+ }
1497
+
1498
+ WasmEdge_FunctionInstanceContext *start = find_function(module, "_start");
1499
+ if (start != NULL) {
1500
+ return invoke_function(executor, start, NULL, 0, NULL, 0, "_start");
1501
+ }
1502
+ WasmEdge_FunctionInstanceContext *ctors =
1503
+ find_function(module, "__wasm_call_ctors");
1504
+ if (ctors != NULL) {
1505
+ return invoke_function(
1506
+ executor,
1507
+ ctors,
1508
+ NULL,
1509
+ 0,
1510
+ NULL,
1511
+ 0,
1512
+ "__wasm_call_ctors");
1513
+ }
1514
+ return true;
1515
+ }
1516
+
1517
+ static bool serve_plugin_invoke_requests(
1518
+ WasmEdge_ExecutorContext *executor,
1519
+ WasmEdge_ModuleInstanceContext *module,
1520
+ RunnerContext *runner) {
1521
+ WasmEdge_MemoryInstanceContext *memory = resolve_guest_memory(module, runner);
1522
+ if (memory == NULL) {
1523
+ fprintf(stderr, "guest memory export/import was not found\n");
1524
+ return false;
1525
+ }
1526
+
1527
+ WasmEdge_FunctionInstanceContext *malloc_fn =
1528
+ find_function(module, "plugin_alloc");
1529
+ WasmEdge_FunctionInstanceContext *free_fn =
1530
+ find_function(module, "plugin_free");
1531
+ WasmEdge_FunctionInstanceContext *invoke_fn =
1532
+ find_function(module, "plugin_invoke_stream");
1533
+ if (malloc_fn == NULL || free_fn == NULL || invoke_fn == NULL) {
1534
+ fprintf(
1535
+ stderr,
1536
+ "guest must export plugin_alloc, plugin_free, and plugin_invoke_stream\n");
1537
+ return false;
1538
+ }
1539
+
1540
+ for (;;) {
1541
+ uint8_t length_bytes[4];
1542
+ const size_t prefix_read = fread(length_bytes, 1, sizeof(length_bytes), stdin);
1543
+ if (prefix_read == 0) {
1544
+ return feof(stdin);
1545
+ }
1546
+ if (prefix_read != sizeof(length_bytes)) {
1547
+ fprintf(stderr, "partial request length prefix\n");
1548
+ return false;
1549
+ }
1550
+ const uint32_t request_size =
1551
+ (uint32_t)length_bytes[0] |
1552
+ ((uint32_t)length_bytes[1] << 8) |
1553
+ ((uint32_t)length_bytes[2] << 16) |
1554
+ ((uint32_t)length_bytes[3] << 24);
1555
+
1556
+ uint8_t *request_bytes = NULL;
1557
+ if (request_size > 0) {
1558
+ request_bytes = malloc(request_size);
1559
+ if (request_bytes == NULL) {
1560
+ fprintf(stderr, "failed to allocate host request buffer\n");
1561
+ return false;
1562
+ }
1563
+ if (!read_exact(stdin, request_bytes, request_size)) {
1564
+ free(request_bytes);
1565
+ fprintf(stderr, "failed to read complete request payload\n");
1566
+ return false;
1567
+ }
1568
+ }
1569
+
1570
+ if (request_size >= 5 &&
1571
+ memcmp(request_bytes, HOST_CONTROL_MAGIC, sizeof(HOST_CONTROL_MAGIC)) == 0) {
1572
+ const uint8_t opcode = request_bytes[4];
1573
+ bool ok = true;
1574
+ uint8_t *response_bytes = NULL;
1575
+ uint32_t response_size = 0;
1576
+
1577
+ if (opcode == HOST_CONTROL_WRITE) {
1578
+ const uint32_t payload_size = request_size - 5;
1579
+ uint32_t guest_ptr = 0;
1580
+ ok = guest_malloc(executor, malloc_fn, payload_size, &guest_ptr) &&
1581
+ (payload_size == 0 || guest_ptr != 0) &&
1582
+ write_guest_memory(memory, guest_ptr, request_bytes + 5, payload_size);
1583
+ if (ok) {
1584
+ response_size = 4;
1585
+ response_bytes = malloc(response_size);
1586
+ if (response_bytes == NULL) {
1587
+ ok = false;
1588
+ } else {
1589
+ response_bytes[0] = (uint8_t)(guest_ptr & 0xFFU);
1590
+ response_bytes[1] = (uint8_t)((guest_ptr >> 8) & 0xFFU);
1591
+ response_bytes[2] = (uint8_t)((guest_ptr >> 16) & 0xFFU);
1592
+ response_bytes[3] = (uint8_t)((guest_ptr >> 24) & 0xFFU);
1593
+ }
1594
+ }
1595
+ } else if (opcode == HOST_CONTROL_READ) {
1596
+ if (request_size != 13) {
1597
+ ok = false;
1598
+ } else {
1599
+ const uint32_t guest_ptr = read_le_u32_bytes(request_bytes + 5);
1600
+ response_size = read_le_u32_bytes(request_bytes + 9);
1601
+ response_bytes = malloc(response_size);
1602
+ if (response_bytes == NULL && response_size > 0) {
1603
+ ok = false;
1604
+ } else {
1605
+ ok = read_guest_memory(memory, guest_ptr, response_bytes, response_size);
1606
+ }
1607
+ }
1608
+ } else if (opcode == HOST_CONTROL_FREE) {
1609
+ if (request_size != 9 && request_size != 13) {
1610
+ ok = false;
1611
+ } else {
1612
+ const uint32_t guest_ptr = read_le_u32_bytes(request_bytes + 5);
1613
+ const uint32_t guest_len =
1614
+ request_size >= 13 ? read_le_u32_bytes(request_bytes + 9) : 0;
1615
+ ok = guest_free(executor, free_fn, guest_ptr, guest_len);
1616
+ }
1617
+ } else {
1618
+ ok = false;
1619
+ }
1620
+
1621
+ free(request_bytes);
1622
+ if (!ok) {
1623
+ free(response_bytes);
1624
+ fprintf(stderr, "invalid WasmEdge host control request\n");
1625
+ return false;
1626
+ }
1627
+
1628
+ uint8_t response_length_bytes[4];
1629
+ response_length_bytes[0] = (uint8_t)(response_size & 0xFFU);
1630
+ response_length_bytes[1] = (uint8_t)((response_size >> 8) & 0xFFU);
1631
+ response_length_bytes[2] = (uint8_t)((response_size >> 16) & 0xFFU);
1632
+ response_length_bytes[3] = (uint8_t)((response_size >> 24) & 0xFFU);
1633
+ ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
1634
+ write_all(stdout, response_bytes, response_size);
1635
+ free(response_bytes);
1636
+ if (!ok) {
1637
+ return false;
1638
+ }
1639
+ continue;
1640
+ }
1641
+
1642
+ uint32_t request_ptr = 0;
1643
+ uint32_t response_size_ptr = 0;
1644
+ uint32_t response_ptr = 0;
1645
+ uint32_t response_size = 0;
1646
+ bool ok = true;
1647
+
1648
+ if (request_size > 0) {
1649
+ ok = guest_malloc(executor, malloc_fn, request_size, &request_ptr) &&
1650
+ request_ptr != 0 &&
1651
+ write_guest_memory(memory, request_ptr, request_bytes, request_size);
1652
+ }
1653
+ if (ok) {
1654
+ ok = guest_malloc(executor, malloc_fn, 4, &response_size_ptr) &&
1655
+ response_size_ptr != 0;
1656
+ }
1657
+ if (ok) {
1658
+ const uint8_t zero_u32[4] = {0, 0, 0, 0};
1659
+ ok = write_guest_memory(memory, response_size_ptr, zero_u32, 4);
1660
+ }
1661
+ if (ok) {
1662
+ WasmEdge_Value params[3];
1663
+ WasmEdge_Value returns[1];
1664
+ params[0] = WasmEdge_ValueGenI32((int32_t)request_ptr);
1665
+ params[1] = WasmEdge_ValueGenI32((int32_t)request_size);
1666
+ params[2] = WasmEdge_ValueGenI32((int32_t)response_size_ptr);
1667
+ ok = invoke_function(
1668
+ executor,
1669
+ invoke_fn,
1670
+ params,
1671
+ 3,
1672
+ returns,
1673
+ 1,
1674
+ "plugin_invoke_stream");
1675
+ if (ok) {
1676
+ response_ptr = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
1677
+ ok = read_guest_u32(memory, response_size_ptr, &response_size);
1678
+ }
1679
+ }
1680
+
1681
+ if (ok && response_size > 0 && response_ptr == 0) {
1682
+ fprintf(stderr, "plugin_invoke_stream returned null response pointer\n");
1683
+ ok = false;
1684
+ }
1685
+
1686
+ uint8_t *response_bytes = NULL;
1687
+ if (ok && response_size > 0) {
1688
+ response_bytes = malloc(response_size);
1689
+ if (response_bytes == NULL) {
1690
+ fprintf(stderr, "failed to allocate host response buffer\n");
1691
+ ok = false;
1692
+ } else {
1693
+ ok = read_guest_memory(memory, response_ptr, response_bytes, response_size);
1694
+ }
1695
+ }
1696
+
1697
+ if (ok) {
1698
+ uint8_t response_length_bytes[4];
1699
+ response_length_bytes[0] = (uint8_t)(response_size & 0xFFU);
1700
+ response_length_bytes[1] = (uint8_t)((response_size >> 8) & 0xFFU);
1701
+ response_length_bytes[2] = (uint8_t)((response_size >> 16) & 0xFFU);
1702
+ response_length_bytes[3] = (uint8_t)((response_size >> 24) & 0xFFU);
1703
+ ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
1704
+ write_all(stdout, response_bytes, response_size);
1705
+ }
1706
+
1707
+ free(response_bytes);
1708
+ free(request_bytes);
1709
+ if (response_ptr != 0) {
1710
+ guest_free(executor, free_fn, response_ptr, response_size);
1711
+ }
1712
+ if (response_size_ptr != 0) {
1713
+ guest_free(executor, free_fn, response_size_ptr, 4);
1714
+ }
1715
+ if (request_ptr != 0) {
1716
+ guest_free(executor, free_fn, request_ptr, request_size);
1717
+ }
1718
+
1719
+ if (!ok) {
1720
+ return false;
1721
+ }
1722
+ }
1723
+ }
1724
+
1725
+ static bool invoke_plugin_stream_once(
1726
+ WasmEdge_ExecutorContext *executor,
1727
+ WasmEdge_ModuleInstanceContext *module,
1728
+ RunnerContext *runner,
1729
+ const uint8_t *request_bytes,
1730
+ uint32_t request_size,
1731
+ uint8_t **response_bytes_out,
1732
+ uint32_t *response_size_out) {
1733
+ WasmEdge_MemoryInstanceContext *memory = resolve_guest_memory(module, runner);
1734
+ if (memory == NULL) {
1735
+ fprintf(stderr, "guest memory export/import was not found\n");
1736
+ return false;
1737
+ }
1738
+
1739
+ WasmEdge_FunctionInstanceContext *malloc_fn =
1740
+ find_function(module, "plugin_alloc");
1741
+ WasmEdge_FunctionInstanceContext *free_fn =
1742
+ find_function(module, "plugin_free");
1743
+ WasmEdge_FunctionInstanceContext *invoke_fn =
1744
+ find_function(module, "plugin_invoke_stream");
1745
+ if (malloc_fn == NULL || free_fn == NULL || invoke_fn == NULL) {
1746
+ fprintf(
1747
+ stderr,
1748
+ "guest must export plugin_alloc, plugin_free, and plugin_invoke_stream\n");
1749
+ return false;
1750
+ }
1751
+
1752
+ uint32_t request_ptr = 0;
1753
+ uint32_t response_size_ptr = 0;
1754
+ uint32_t response_ptr = 0;
1755
+ uint32_t response_size = 0;
1756
+ uint8_t *response_bytes = NULL;
1757
+ bool ok = true;
1758
+
1759
+ if (request_size > 0) {
1760
+ ok = guest_malloc(executor, malloc_fn, request_size, &request_ptr) &&
1761
+ request_ptr != 0 &&
1762
+ write_guest_memory(memory, request_ptr, request_bytes, request_size);
1763
+ }
1764
+ if (ok) {
1765
+ ok = guest_malloc(executor, malloc_fn, 4, &response_size_ptr) &&
1766
+ response_size_ptr != 0;
1767
+ }
1768
+ if (ok) {
1769
+ const uint8_t zero_u32[4] = {0, 0, 0, 0};
1770
+ ok = write_guest_memory(memory, response_size_ptr, zero_u32, 4);
1771
+ }
1772
+ if (ok) {
1773
+ WasmEdge_Value params[3];
1774
+ WasmEdge_Value returns[1];
1775
+ params[0] = WasmEdge_ValueGenI32((int32_t)request_ptr);
1776
+ params[1] = WasmEdge_ValueGenI32((int32_t)request_size);
1777
+ params[2] = WasmEdge_ValueGenI32((int32_t)response_size_ptr);
1778
+ ok = invoke_function(
1779
+ executor,
1780
+ invoke_fn,
1781
+ params,
1782
+ 3,
1783
+ returns,
1784
+ 1,
1785
+ "plugin_invoke_stream");
1786
+ if (ok) {
1787
+ response_ptr = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
1788
+ ok = read_guest_u32(memory, response_size_ptr, &response_size);
1789
+ }
1790
+ }
1791
+ if (ok && response_size > 0 && response_ptr == 0) {
1792
+ fprintf(stderr, "plugin_invoke_stream returned null response pointer\n");
1793
+ ok = false;
1794
+ }
1795
+ if (ok && response_size > 0) {
1796
+ response_bytes = malloc(response_size);
1797
+ if (response_bytes == NULL) {
1798
+ fprintf(stderr, "failed to allocate host response buffer\n");
1799
+ ok = false;
1800
+ } else {
1801
+ ok = read_guest_memory(memory, response_ptr, response_bytes, response_size);
1802
+ }
1803
+ }
1804
+
1805
+ if (response_ptr != 0) {
1806
+ guest_free(executor, free_fn, response_ptr, response_size);
1807
+ }
1808
+ if (response_size_ptr != 0) {
1809
+ guest_free(executor, free_fn, response_size_ptr, 4);
1810
+ }
1811
+ if (request_ptr != 0) {
1812
+ guest_free(executor, free_fn, request_ptr, request_size);
1813
+ }
1814
+ if (!ok) {
1815
+ free(response_bytes);
1816
+ return false;
1817
+ }
1818
+ *response_bytes_out = response_bytes;
1819
+ *response_size_out = response_size;
1820
+ return true;
1821
+ }
1822
+
1823
+ static bool initialize_runtime_host_module(
1824
+ RuntimeHostModule *module,
1825
+ char *module_id,
1826
+ char *wasm_path,
1827
+ char *metadata_json,
1828
+ char **method_ids,
1829
+ size_t method_id_count) {
1830
+ runtime_host_module_init(module);
1831
+ module->module_id = module_id;
1832
+ module->wasm_path = wasm_path;
1833
+ module->metadata_json = metadata_json;
1834
+ module->method_ids = method_ids;
1835
+ module->method_id_count = method_id_count;
1836
+
1837
+ module->conf = WasmEdge_ConfigureCreate();
1838
+ if (module->conf == NULL) {
1839
+ goto fail;
1840
+ }
1841
+ WasmEdge_ConfigureAddProposal(module->conf, WasmEdge_Proposal_Threads);
1842
+ WasmEdge_ConfigureAddProposal(
1843
+ module->conf, WasmEdge_Proposal_ExceptionHandling);
1844
+ module->loader = WasmEdge_LoaderCreate(module->conf);
1845
+ module->validator = WasmEdge_ValidatorCreate(module->conf);
1846
+ module->executor = WasmEdge_ExecutorCreate(module->conf, NULL);
1847
+ module->store = WasmEdge_StoreCreate();
1848
+ if (module->loader == NULL || module->validator == NULL ||
1849
+ module->executor == NULL || module->store == NULL) {
1850
+ goto fail;
1851
+ }
1852
+
1853
+ module->runner.conf = module->conf;
1854
+ module->runner.store = module->store;
1855
+ if (pthread_mutex_init(&module->runner.store_mutex, NULL) != 0) {
1856
+ goto fail;
1857
+ }
1858
+ module->store_mutex_initialized = true;
1859
+
1860
+ WasmEdge_Result res = WasmEdge_LoaderParseFromFile(
1861
+ module->loader,
1862
+ &module->ast,
1863
+ module->wasm_path);
1864
+ if (!WasmEdge_ResultOK(res)) {
1865
+ goto fail;
1866
+ }
1867
+ module->runner.ast = module->ast;
1868
+ res = WasmEdge_ValidatorValidate(module->validator, module->ast);
1869
+ if (!WasmEdge_ResultOK(res)) {
1870
+ goto fail;
1871
+ }
1872
+
1873
+ const char *wasi_args[2] = {module->wasm_path, "--serve-plugin-invoke"};
1874
+ WasmEdge_ModuleInstanceContext *wasi = WasmEdge_ModuleInstanceCreateWASI(
1875
+ wasi_args,
1876
+ 2,
1877
+ NULL,
1878
+ 0,
1879
+ NULL,
1880
+ 0);
1881
+ if (wasi == NULL) {
1882
+ goto fail;
1883
+ }
1884
+ res = WasmEdge_ExecutorRegisterImport(module->executor, module->store, wasi);
1885
+ if (!WasmEdge_ResultOK(res)) {
1886
+ goto fail;
1887
+ }
1888
+
1889
+ WasmEdge_ModuleInstanceContext *env =
1890
+ WasmEdge_ModuleInstanceCreate(WasmEdge_StringCreateByCString("env"));
1891
+ if (env == NULL) {
1892
+ goto fail;
1893
+ }
1894
+ ImportedModuleConfig import_config;
1895
+ if (!read_imported_module_config(module->wasm_path, &import_config) ||
1896
+ !add_imported_env_memory_from_file(
1897
+ module->wasm_path,
1898
+ env,
1899
+ &module->runner.shared_memory)) {
1900
+ goto fail;
1901
+ }
1902
+ register_env_host_functions(
1903
+ env,
1904
+ &module->runner,
1905
+ import_config.receive_on_main_thread_param_len == 4 ? 4 : 5,
1906
+ import_config.notify_mailbox_postmessage_param_len == 3 ? 3 : 2);
1907
+ res = WasmEdge_ExecutorRegisterImport(module->executor, module->store, env);
1908
+ if (!WasmEdge_ResultOK(res)) {
1909
+ goto fail;
1910
+ }
1911
+
1912
+ res = WasmEdge_ExecutorInstantiate(
1913
+ module->executor,
1914
+ &module->module,
1915
+ module->store,
1916
+ module->ast);
1917
+ if (!WasmEdge_ResultOK(res)) {
1918
+ goto fail;
1919
+ }
1920
+
1921
+ if (!invoke_optional_module_init(module->executor, module->module, true)) {
1922
+ goto fail;
1923
+ }
1924
+
1925
+ return true;
1926
+
1927
+ fail:
1928
+ destroy_runtime_host_module(module);
1929
+ return false;
1930
+ }
1931
+
1932
+ static bool invoke_runtime_host_module(
1933
+ RuntimeHostModule *module,
1934
+ const uint8_t *request_bytes,
1935
+ uint32_t request_size,
1936
+ uint8_t **response_bytes_out,
1937
+ uint32_t *response_size_out) {
1938
+ if (module == NULL || module->executor == NULL || module->module == NULL) {
1939
+ return false;
1940
+ }
1941
+ return invoke_plugin_stream_once(
1942
+ module->executor,
1943
+ module->module,
1944
+ &module->runner,
1945
+ request_bytes,
1946
+ request_size,
1947
+ response_bytes_out,
1948
+ response_size_out);
1949
+ }
1950
+
1951
+ static RuntimeHostModule *find_runtime_host_module(
1952
+ RuntimeHostState *state,
1953
+ const char *module_id,
1954
+ size_t *index_out) {
1955
+ for (size_t index = 0; index < state->module_count; ++index) {
1956
+ if (strcmp(state->modules[index].module_id, module_id) == 0) {
1957
+ if (index_out != NULL) {
1958
+ *index_out = index;
1959
+ }
1960
+ return &state->modules[index];
1961
+ }
1962
+ }
1963
+ return NULL;
1964
+ }
1965
+
1966
+ static RuntimeHostRegion *find_runtime_host_region(
1967
+ RuntimeHostState *state,
1968
+ uint64_t region_id) {
1969
+ for (size_t index = 0; index < state->region_count; ++index) {
1970
+ if (state->regions[index].region_id == region_id) {
1971
+ return &state->regions[index];
1972
+ }
1973
+ }
1974
+ return NULL;
1975
+ }
1976
+
1977
+ static RuntimeHostRow *find_runtime_host_row(
1978
+ RuntimeHostState *state,
1979
+ const char *schema_file_id,
1980
+ uint64_t row_id) {
1981
+ for (size_t index = 0; index < state->row_count; ++index) {
1982
+ RuntimeHostRow *row = &state->rows[index];
1983
+ if (row->row_id == row_id &&
1984
+ strcmp(row->schema_file_id, schema_file_id) == 0) {
1985
+ return row;
1986
+ }
1987
+ }
1988
+ return NULL;
1989
+ }
1990
+
1991
+ static uint64_t next_runtime_host_row_id_for_schema(
1992
+ RuntimeHostState *state,
1993
+ const char *schema_file_id) {
1994
+ uint64_t next_row_id = 1;
1995
+ for (size_t index = 0; index < state->row_count; ++index) {
1996
+ RuntimeHostRow *row = &state->rows[index];
1997
+ if (strcmp(row->schema_file_id, schema_file_id) != 0) {
1998
+ continue;
1999
+ }
2000
+ if (row->row_id >= next_row_id) {
2001
+ next_row_id = row->row_id + 1;
2002
+ }
2003
+ }
2004
+ return next_row_id;
2005
+ }
2006
+
2007
+ static bool append_runtime_host_row_query_result_json(
2008
+ JsonBuffer *buffer,
2009
+ RuntimeHostState *state,
2010
+ const char *schema_file_id_filter) {
2011
+ if (!json_buffer_append_cstr(
2012
+ buffer,
2013
+ "{\"columns\":[\"schemaFileId\",\"rowId\"],\"rows\":[")) {
2014
+ return false;
2015
+ }
2016
+ uint64_t row_count = 0;
2017
+ bool first = true;
2018
+ for (size_t index = 0; index < state->row_count; ++index) {
2019
+ RuntimeHostRow *row = &state->rows[index];
2020
+ if (schema_file_id_filter != NULL &&
2021
+ strcmp(row->schema_file_id, schema_file_id_filter) != 0) {
2022
+ continue;
2023
+ }
2024
+ if (!first && !json_buffer_append_char(buffer, ',')) {
2025
+ return false;
2026
+ }
2027
+ first = false;
2028
+ if (!json_buffer_append_char(buffer, '[') ||
2029
+ !json_buffer_append_json_string(buffer, row->schema_file_id) ||
2030
+ !json_buffer_append_char(buffer, ',') ||
2031
+ !json_buffer_append_u64(buffer, row->row_id) ||
2032
+ !json_buffer_append_char(buffer, ']')) {
2033
+ return false;
2034
+ }
2035
+ row_count += 1;
2036
+ }
2037
+ return json_buffer_append_cstr(buffer, "],\"rowCount\":") &&
2038
+ json_buffer_append_u64(buffer, row_count) &&
2039
+ json_buffer_append_char(buffer, '}');
2040
+ }
2041
+
2042
+ static bool append_runtime_host_module_json(
2043
+ JsonBuffer *buffer,
2044
+ const RuntimeHostModule *module) {
2045
+ if (!json_buffer_append_cstr(buffer, "{\"moduleId\":") ||
2046
+ !json_buffer_append_json_string(buffer, module->module_id) ||
2047
+ !json_buffer_append_cstr(buffer, ",\"metadata\":") ||
2048
+ !json_buffer_append_cstr(
2049
+ buffer,
2050
+ module->metadata_json != NULL ? module->metadata_json : "null") ||
2051
+ !json_buffer_append_cstr(buffer, ",\"methodIds\":[")) {
2052
+ return false;
2053
+ }
2054
+ for (size_t index = 0; index < module->method_id_count; ++index) {
2055
+ if ((index > 0 && !json_buffer_append_char(buffer, ',')) ||
2056
+ !json_buffer_append_json_string(buffer, module->method_ids[index])) {
2057
+ return false;
2058
+ }
2059
+ }
2060
+ return json_buffer_append_cstr(buffer, "]}");
2061
+ }
2062
+
2063
+ static bool append_runtime_host_row_json(
2064
+ JsonBuffer *buffer,
2065
+ const RuntimeHostRow *row) {
2066
+ return json_buffer_append_cstr(buffer, "{\"handle\":{\"schemaFileId\":") &&
2067
+ json_buffer_append_json_string(buffer, row->schema_file_id) &&
2068
+ json_buffer_append_cstr(buffer, ",\"rowId\":") &&
2069
+ json_buffer_append_u64(buffer, row->row_id) &&
2070
+ json_buffer_append_cstr(buffer, "},\"payload\":") &&
2071
+ json_buffer_append_cstr(
2072
+ buffer,
2073
+ row->payload_json != NULL ? row->payload_json : "null") &&
2074
+ json_buffer_append_char(buffer, '}');
2075
+ }
2076
+
2077
+ static bool append_runtime_host_region_descriptor_json(
2078
+ JsonBuffer *buffer,
2079
+ const RuntimeHostRegion *region) {
2080
+ return json_buffer_append_cstr(buffer, "{\"regionId\":") &&
2081
+ json_buffer_append_u64(buffer, region->region_id) &&
2082
+ json_buffer_append_cstr(buffer, ",\"layoutId\":") &&
2083
+ json_buffer_append_json_string(buffer, region->layout_id) &&
2084
+ json_buffer_append_cstr(buffer, ",\"recordByteLength\":") &&
2085
+ json_buffer_append_u32(buffer, region->record_byte_length) &&
2086
+ json_buffer_append_cstr(buffer, ",\"alignment\":") &&
2087
+ json_buffer_append_u32(buffer, region->alignment) &&
2088
+ json_buffer_append_cstr(buffer, ",\"recordCount\":") &&
2089
+ json_buffer_append_u64(buffer, (uint64_t)region->record_count) &&
2090
+ json_buffer_append_char(buffer, '}');
2091
+ }
2092
+
2093
+ static bool append_runtime_host_region_record_json(
2094
+ JsonBuffer *buffer,
2095
+ const RuntimeHostRegion *region,
2096
+ uint32_t record_index) {
2097
+ if (!json_buffer_append_cstr(buffer, "{\"regionId\":") ||
2098
+ !json_buffer_append_u64(buffer, region->region_id) ||
2099
+ !json_buffer_append_cstr(buffer, ",\"recordIndex\":") ||
2100
+ !json_buffer_append_u32(buffer, record_index) ||
2101
+ !json_buffer_append_cstr(buffer, ",\"layoutId\":") ||
2102
+ !json_buffer_append_json_string(buffer, region->layout_id) ||
2103
+ !json_buffer_append_cstr(buffer, ",\"recordByteLength\":") ||
2104
+ !json_buffer_append_u32(buffer, region->record_byte_length) ||
2105
+ !json_buffer_append_cstr(buffer, ",\"alignment\":") ||
2106
+ !json_buffer_append_u32(buffer, region->alignment) ||
2107
+ !json_buffer_append_cstr(buffer, ",\"byteLength\":") ||
2108
+ !json_buffer_append_u32(buffer, region->record_byte_length) ||
2109
+ !json_buffer_append_cstr(buffer, ",\"bytes\":[")) {
2110
+ return false;
2111
+ }
2112
+ const uint8_t *record = region->records[record_index];
2113
+ for (uint32_t index = 0; index < region->record_byte_length; ++index) {
2114
+ if (index > 0 && !json_buffer_append_char(buffer, ',')) {
2115
+ return false;
2116
+ }
2117
+ if (!json_buffer_append_u32(buffer, record[index])) {
2118
+ return false;
2119
+ }
2120
+ }
2121
+ return json_buffer_append_cstr(buffer, "]}");
2122
+ }
2123
+
2124
+ static bool parse_json_string_field(
2125
+ const char *json,
2126
+ size_t length,
2127
+ const char *field_name,
2128
+ char **value_out) {
2129
+ JsonSlice slice;
2130
+ return find_json_object_field(json, length, field_name, &slice) &&
2131
+ duplicate_json_string_value(slice, value_out);
2132
+ }
2133
+
2134
+ static bool parse_json_optional_string_field(
2135
+ const char *json,
2136
+ size_t length,
2137
+ const char *field_name,
2138
+ char **value_out) {
2139
+ JsonSlice slice;
2140
+ if (!find_json_object_field(json, length, field_name, &slice)) {
2141
+ *value_out = NULL;
2142
+ return true;
2143
+ }
2144
+ if (json_slice_is_null(slice)) {
2145
+ *value_out = NULL;
2146
+ return true;
2147
+ }
2148
+ return duplicate_json_string_value(slice, value_out);
2149
+ }
2150
+
2151
+ static bool parse_json_string_array_field(
2152
+ const char *json,
2153
+ size_t length,
2154
+ const char *field_name,
2155
+ char ***values_out,
2156
+ size_t *count_out) {
2157
+ JsonSlice slice;
2158
+ if (!find_json_object_field(json, length, field_name, &slice)) {
2159
+ *values_out = NULL;
2160
+ *count_out = 0;
2161
+ return true;
2162
+ }
2163
+ size_t offset = 0;
2164
+ skip_json_whitespace(slice.data, slice.length, &offset);
2165
+ if (offset >= slice.length || slice.data[offset] != '[') {
2166
+ return false;
2167
+ }
2168
+ offset += 1;
2169
+ char **values = NULL;
2170
+ size_t value_count = 0;
2171
+ size_t value_capacity = 0;
2172
+ for (;;) {
2173
+ skip_json_whitespace(slice.data, slice.length, &offset);
2174
+ if (offset >= slice.length) {
2175
+ break;
2176
+ }
2177
+ if (slice.data[offset] == ']') {
2178
+ offset += 1;
2179
+ *values_out = values;
2180
+ *count_out = value_count;
2181
+ return true;
2182
+ }
2183
+ const size_t value_start = offset;
2184
+ if (!consume_json_string(slice.data, slice.length, &offset) ||
2185
+ !ensure_runtime_host_capacity(
2186
+ (void **)&values,
2187
+ &value_capacity,
2188
+ value_count,
2189
+ sizeof(*values)) ||
2190
+ !duplicate_json_string_value(
2191
+ (JsonSlice){
2192
+ .data = slice.data + value_start,
2193
+ .length = offset - value_start,
2194
+ },
2195
+ &values[value_count])) {
2196
+ break;
2197
+ }
2198
+ value_count += 1;
2199
+ skip_json_whitespace(slice.data, slice.length, &offset);
2200
+ if (offset >= slice.length) {
2201
+ break;
2202
+ }
2203
+ if (slice.data[offset] == ']') {
2204
+ offset += 1;
2205
+ *values_out = values;
2206
+ *count_out = value_count;
2207
+ return true;
2208
+ }
2209
+ if (slice.data[offset] != ',') {
2210
+ break;
2211
+ }
2212
+ offset += 1;
2213
+ }
2214
+ for (size_t index = 0; index < value_count; ++index) {
2215
+ free(values[index]);
2216
+ }
2217
+ free(values);
2218
+ return false;
2219
+ }
2220
+
2221
+ static bool parse_json_u64_field(
2222
+ const char *json,
2223
+ size_t length,
2224
+ const char *field_name,
2225
+ uint64_t *value_out) {
2226
+ JsonSlice slice;
2227
+ return find_json_object_field(json, length, field_name, &slice) &&
2228
+ parse_json_u64(slice, value_out);
2229
+ }
2230
+
2231
+ static bool duplicate_json_field_raw(
2232
+ const char *json,
2233
+ size_t length,
2234
+ const char *field_name,
2235
+ char **value_out,
2236
+ const char *fallback_json) {
2237
+ JsonSlice slice;
2238
+ if (!find_json_object_field(json, length, field_name, &slice)) {
2239
+ *value_out = strdup(fallback_json);
2240
+ return *value_out != NULL;
2241
+ }
2242
+ return duplicate_json_slice(slice, value_out);
2243
+ }
2244
+
2245
+ static bool parse_record_bytes_array(
2246
+ JsonSlice slice,
2247
+ uint32_t record_byte_length,
2248
+ uint8_t **record_out) {
2249
+ uint8_t *record = calloc(record_byte_length, 1);
2250
+ if (record == NULL) {
2251
+ return false;
2252
+ }
2253
+ if (json_slice_is_null(slice)) {
2254
+ *record_out = record;
2255
+ return true;
2256
+ }
2257
+ size_t offset = 0;
2258
+ skip_json_whitespace(slice.data, slice.length, &offset);
2259
+ if (offset >= slice.length || slice.data[offset] != '[') {
2260
+ free(record);
2261
+ return false;
2262
+ }
2263
+ offset += 1;
2264
+ size_t write_index = 0;
2265
+ for (;;) {
2266
+ skip_json_whitespace(slice.data, slice.length, &offset);
2267
+ if (offset >= slice.length) {
2268
+ free(record);
2269
+ return false;
2270
+ }
2271
+ if (slice.data[offset] == ']') {
2272
+ offset += 1;
2273
+ *record_out = record;
2274
+ return true;
2275
+ }
2276
+ size_t value_start = offset;
2277
+ if (!consume_json_value(slice.data, slice.length, &offset)) {
2278
+ free(record);
2279
+ return false;
2280
+ }
2281
+ uint64_t value = 0;
2282
+ JsonSlice value_slice = {
2283
+ .data = slice.data + value_start,
2284
+ .length = offset - value_start,
2285
+ };
2286
+ if (!parse_json_u64(value_slice, &value) || value > 255 ||
2287
+ write_index >= record_byte_length) {
2288
+ free(record);
2289
+ return false;
2290
+ }
2291
+ record[write_index++] = (uint8_t)value;
2292
+ skip_json_whitespace(slice.data, slice.length, &offset);
2293
+ if (offset >= slice.length) {
2294
+ free(record);
2295
+ return false;
2296
+ }
2297
+ if (slice.data[offset] == ']') {
2298
+ offset += 1;
2299
+ *record_out = record;
2300
+ return true;
2301
+ }
2302
+ if (slice.data[offset] != ',') {
2303
+ free(record);
2304
+ return false;
2305
+ }
2306
+ offset += 1;
2307
+ }
2308
+ }
2309
+
2310
+ static bool parse_initial_records_field(
2311
+ const char *json,
2312
+ size_t length,
2313
+ uint32_t record_byte_length,
2314
+ uint8_t ***records_out,
2315
+ size_t *record_count_out) {
2316
+ JsonSlice slice;
2317
+ if (!find_json_object_field(json, length, "initialRecords", &slice)) {
2318
+ *records_out = NULL;
2319
+ *record_count_out = 0;
2320
+ return true;
2321
+ }
2322
+ size_t offset = 0;
2323
+ skip_json_whitespace(slice.data, slice.length, &offset);
2324
+ if (offset >= slice.length || slice.data[offset] != '[') {
2325
+ return false;
2326
+ }
2327
+ offset += 1;
2328
+ uint8_t **records = NULL;
2329
+ size_t record_count = 0;
2330
+ size_t record_capacity = 0;
2331
+ for (;;) {
2332
+ skip_json_whitespace(slice.data, slice.length, &offset);
2333
+ if (offset >= slice.length) {
2334
+ break;
2335
+ }
2336
+ if (slice.data[offset] == ']') {
2337
+ offset += 1;
2338
+ *records_out = records;
2339
+ *record_count_out = record_count;
2340
+ return true;
2341
+ }
2342
+ const size_t value_start = offset;
2343
+ if (!consume_json_value(slice.data, slice.length, &offset) ||
2344
+ !ensure_runtime_host_capacity(
2345
+ (void **)&records,
2346
+ &record_capacity,
2347
+ record_count,
2348
+ sizeof(*records))) {
2349
+ break;
2350
+ }
2351
+ JsonSlice value_slice = {
2352
+ .data = slice.data + value_start,
2353
+ .length = offset - value_start,
2354
+ };
2355
+ if (!parse_record_bytes_array(
2356
+ value_slice,
2357
+ record_byte_length,
2358
+ &records[record_count])) {
2359
+ break;
2360
+ }
2361
+ record_count += 1;
2362
+ skip_json_whitespace(slice.data, slice.length, &offset);
2363
+ if (offset < slice.length && slice.data[offset] == ',') {
2364
+ offset += 1;
2365
+ continue;
2366
+ }
2367
+ if (offset < slice.length && slice.data[offset] == ']') {
2368
+ offset += 1;
2369
+ *records_out = records;
2370
+ *record_count_out = record_count;
2371
+ return true;
2372
+ }
2373
+ break;
2374
+ }
2375
+ for (size_t index = 0; index < record_count; ++index) {
2376
+ free(records[index]);
2377
+ }
2378
+ free(records);
2379
+ return false;
2380
+ }
2381
+
2382
+ static bool respond_with_json_buffer(
2383
+ JsonBuffer *buffer,
2384
+ uint8_t **response_bytes_out,
2385
+ uint32_t *response_size_out) {
2386
+ *response_bytes_out = json_buffer_detach(buffer, response_size_out);
2387
+ return *response_bytes_out != NULL || *response_size_out == 0;
2388
+ }
2389
+
2390
+ static bool dispatch_runtime_host_request(
2391
+ RuntimeHostState *state,
2392
+ uint8_t opcode,
2393
+ const uint8_t *payload_bytes,
2394
+ uint32_t payload_size,
2395
+ uint8_t **response_bytes_out,
2396
+ uint32_t *response_size_out) {
2397
+ const char *json = (const char *)payload_bytes;
2398
+ const size_t json_length = payload_size;
2399
+ JsonBuffer response;
2400
+ json_buffer_init(&response);
2401
+
2402
+ if (opcode == HOST_CONTROL_LIST_MODULES) {
2403
+ if (!json_buffer_append_char(&response, '[')) {
2404
+ goto fail;
2405
+ }
2406
+ for (size_t index = 0; index < state->module_count; ++index) {
2407
+ if (index > 0 && !json_buffer_append_char(&response, ',')) {
2408
+ goto fail;
2409
+ }
2410
+ if (!append_runtime_host_module_json(&response, &state->modules[index])) {
2411
+ goto fail;
2412
+ }
2413
+ }
2414
+ if (!json_buffer_append_char(&response, ']')) {
2415
+ goto fail;
2416
+ }
2417
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2418
+ }
2419
+
2420
+ if (opcode == HOST_CONTROL_INSTALL_MODULE) {
2421
+ char *module_id = NULL;
2422
+ char *wasm_path = NULL;
2423
+ char *metadata_json = NULL;
2424
+ char **method_ids = NULL;
2425
+ size_t method_id_count = 0;
2426
+ if (!parse_json_string_field(json, json_length, "moduleId", &module_id) ||
2427
+ !parse_json_string_field(json, json_length, "wasmPath", &wasm_path) ||
2428
+ !parse_json_string_array_field(
2429
+ json,
2430
+ json_length,
2431
+ "methodIds",
2432
+ &method_ids,
2433
+ &method_id_count) ||
2434
+ !duplicate_json_field_raw(
2435
+ json,
2436
+ json_length,
2437
+ "metadata",
2438
+ &metadata_json,
2439
+ "null")) {
2440
+ free(module_id);
2441
+ free(wasm_path);
2442
+ free(metadata_json);
2443
+ for (size_t index = 0; index < method_id_count; ++index) {
2444
+ free(method_ids[index]);
2445
+ }
2446
+ free(method_ids);
2447
+ goto fail;
2448
+ }
2449
+
2450
+ size_t module_index = 0;
2451
+ const bool creating_module =
2452
+ find_runtime_host_module(state, module_id, &module_index) == NULL;
2453
+ RuntimeHostModule *module =
2454
+ creating_module ? NULL : &state->modules[module_index];
2455
+ if (creating_module) {
2456
+ if (!ensure_runtime_host_capacity(
2457
+ (void **)&state->modules,
2458
+ &state->module_capacity,
2459
+ state->module_count,
2460
+ sizeof(*state->modules))) {
2461
+ free(module_id);
2462
+ free(wasm_path);
2463
+ free(metadata_json);
2464
+ for (size_t index = 0; index < method_id_count; ++index) {
2465
+ free(method_ids[index]);
2466
+ }
2467
+ free(method_ids);
2468
+ goto fail;
2469
+ }
2470
+ module = &state->modules[state->module_count++];
2471
+ runtime_host_module_init(module);
2472
+ } else {
2473
+ destroy_runtime_host_module(module);
2474
+ runtime_host_module_init(module);
2475
+ }
2476
+ if (!initialize_runtime_host_module(
2477
+ module,
2478
+ module_id,
2479
+ wasm_path,
2480
+ metadata_json,
2481
+ method_ids,
2482
+ method_id_count)) {
2483
+ if (creating_module) {
2484
+ state->module_count -= 1;
2485
+ }
2486
+ goto fail;
2487
+ }
2488
+ if (!append_runtime_host_module_json(&response, module)) {
2489
+ goto fail;
2490
+ }
2491
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2492
+ }
2493
+
2494
+ if (opcode == HOST_CONTROL_UNLOAD_MODULE) {
2495
+ char *module_id = NULL;
2496
+ bool unloaded = false;
2497
+ if (!parse_json_string_field(json, json_length, "moduleId", &module_id)) {
2498
+ free(module_id);
2499
+ goto fail;
2500
+ }
2501
+ size_t module_index = 0;
2502
+ RuntimeHostModule *module =
2503
+ find_runtime_host_module(state, module_id, &module_index);
2504
+ free(module_id);
2505
+ if (module != NULL) {
2506
+ destroy_runtime_host_module(module);
2507
+ memmove(
2508
+ &state->modules[module_index],
2509
+ &state->modules[module_index + 1],
2510
+ (state->module_count - module_index - 1) * sizeof(*state->modules));
2511
+ state->module_count -= 1;
2512
+ unloaded = true;
2513
+ }
2514
+ if (!json_buffer_append_cstr(&response, unloaded ? "true" : "false")) {
2515
+ goto fail;
2516
+ }
2517
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2518
+ }
2519
+
2520
+ if (opcode == HOST_CONTROL_INVOKE_MODULE) {
2521
+ if (payload_size < 4) {
2522
+ goto fail;
2523
+ }
2524
+ const uint32_t module_id_length = read_le_u32_bytes(payload_bytes);
2525
+ if ((uint64_t)payload_size < 4ULL + (uint64_t)module_id_length) {
2526
+ goto fail;
2527
+ }
2528
+ char *module_id = malloc((size_t)module_id_length + 1);
2529
+ if (module_id == NULL) {
2530
+ goto fail;
2531
+ }
2532
+ memcpy(module_id, payload_bytes + 4, module_id_length);
2533
+ module_id[module_id_length] = '\0';
2534
+ RuntimeHostModule *module =
2535
+ find_runtime_host_module(state, module_id, NULL);
2536
+ free(module_id);
2537
+ if (module == NULL) {
2538
+ goto fail;
2539
+ }
2540
+ return invoke_runtime_host_module(
2541
+ module,
2542
+ payload_bytes + 4 + module_id_length,
2543
+ payload_size - 4 - module_id_length,
2544
+ response_bytes_out,
2545
+ response_size_out);
2546
+ }
2547
+
2548
+ if (opcode == HOST_CONTROL_APPEND_ROW) {
2549
+ char *schema_file_id = NULL;
2550
+ char *payload_json = NULL;
2551
+ if (!parse_json_string_field(
2552
+ json,
2553
+ json_length,
2554
+ "schemaFileId",
2555
+ &schema_file_id) ||
2556
+ !duplicate_json_field_raw(
2557
+ json,
2558
+ json_length,
2559
+ "payload",
2560
+ &payload_json,
2561
+ "null")) {
2562
+ free(schema_file_id);
2563
+ free(payload_json);
2564
+ goto fail;
2565
+ }
2566
+ if (!ensure_runtime_host_capacity(
2567
+ (void **)&state->rows,
2568
+ &state->row_capacity,
2569
+ state->row_count,
2570
+ sizeof(*state->rows))) {
2571
+ free(schema_file_id);
2572
+ free(payload_json);
2573
+ goto fail;
2574
+ }
2575
+ RuntimeHostRow *row = &state->rows[state->row_count++];
2576
+ row->schema_file_id = schema_file_id;
2577
+ row->row_id = next_runtime_host_row_id_for_schema(state, schema_file_id);
2578
+ row->payload_json = payload_json;
2579
+ if (!json_buffer_append_cstr(&response, "{\"schemaFileId\":") ||
2580
+ !json_buffer_append_json_string(&response, row->schema_file_id) ||
2581
+ !json_buffer_append_cstr(&response, ",\"rowId\":") ||
2582
+ !json_buffer_append_u64(&response, row->row_id) ||
2583
+ !json_buffer_append_char(&response, '}')) {
2584
+ goto fail;
2585
+ }
2586
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2587
+ }
2588
+
2589
+ if (opcode == HOST_CONTROL_LIST_ROWS) {
2590
+ char *schema_file_id = NULL;
2591
+ if (!parse_json_optional_string_field(
2592
+ json,
2593
+ json_length,
2594
+ "schemaFileId",
2595
+ &schema_file_id)) {
2596
+ free(schema_file_id);
2597
+ goto fail;
2598
+ }
2599
+ if (!json_buffer_append_char(&response, '[')) {
2600
+ free(schema_file_id);
2601
+ goto fail;
2602
+ }
2603
+ bool first = true;
2604
+ for (size_t index = 0; index < state->row_count; ++index) {
2605
+ RuntimeHostRow *row = &state->rows[index];
2606
+ if (schema_file_id != NULL &&
2607
+ strcmp(row->schema_file_id, schema_file_id) != 0) {
2608
+ continue;
2609
+ }
2610
+ if (!first && !json_buffer_append_char(&response, ',')) {
2611
+ free(schema_file_id);
2612
+ goto fail;
2613
+ }
2614
+ first = false;
2615
+ if (!append_runtime_host_row_json(&response, row)) {
2616
+ free(schema_file_id);
2617
+ goto fail;
2618
+ }
2619
+ }
2620
+ free(schema_file_id);
2621
+ if (!json_buffer_append_char(&response, ']')) {
2622
+ goto fail;
2623
+ }
2624
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2625
+ }
2626
+
2627
+ if (opcode == HOST_CONTROL_RESOLVE_ROW) {
2628
+ char *schema_file_id = NULL;
2629
+ uint64_t row_id = 0;
2630
+ if (!parse_json_string_field(json, json_length, "schemaFileId", &schema_file_id) ||
2631
+ !parse_json_u64_field(json, json_length, "rowId", &row_id)) {
2632
+ free(schema_file_id);
2633
+ goto fail;
2634
+ }
2635
+ RuntimeHostRow *row = find_runtime_host_row(state, schema_file_id, row_id);
2636
+ free(schema_file_id);
2637
+ if (row == NULL) {
2638
+ if (!json_buffer_append_cstr(&response, "null")) {
2639
+ goto fail;
2640
+ }
2641
+ } else if (!append_runtime_host_row_json(&response, row)) {
2642
+ goto fail;
2643
+ }
2644
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2645
+ }
2646
+
2647
+ if (opcode == HOST_CONTROL_QUERY_ROWS) {
2648
+ char *sql = NULL;
2649
+ char *schema_file_id_filter = NULL;
2650
+ if (!parse_json_string_field(json, json_length, "sql", &sql)) {
2651
+ free(sql);
2652
+ goto fail;
2653
+ }
2654
+ const char *runtime_rows_query_prefix =
2655
+ "SELECT schemaFileId, rowId FROM RuntimeHostRow";
2656
+ if (strstr(sql, runtime_rows_query_prefix) != sql) {
2657
+ free(sql);
2658
+ goto fail;
2659
+ }
2660
+ const char *where_prefix = "WHERE schemaFileId = '";
2661
+ const char *where_clause = strstr(sql, where_prefix);
2662
+ if (where_clause != NULL) {
2663
+ const char *schema_start = where_clause + strlen(where_prefix);
2664
+ const char *schema_end = strchr(schema_start, '\'');
2665
+ if (schema_end == NULL) {
2666
+ free(sql);
2667
+ goto fail;
2668
+ }
2669
+ const size_t schema_length = (size_t)(schema_end - schema_start);
2670
+ schema_file_id_filter = malloc(schema_length + 1);
2671
+ if (schema_file_id_filter == NULL) {
2672
+ free(sql);
2673
+ goto fail;
2674
+ }
2675
+ memcpy(schema_file_id_filter, schema_start, schema_length);
2676
+ schema_file_id_filter[schema_length] = '\0';
2677
+ }
2678
+ const bool appended = append_runtime_host_row_query_result_json(
2679
+ &response,
2680
+ state,
2681
+ schema_file_id_filter);
2682
+ free(schema_file_id_filter);
2683
+ free(sql);
2684
+ if (!appended) {
2685
+ goto fail;
2686
+ }
2687
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2688
+ }
2689
+
2690
+ if (opcode == HOST_CONTROL_ALLOCATE_REGION) {
2691
+ char *layout_id = NULL;
2692
+ uint64_t record_byte_length_u64 = 0;
2693
+ uint64_t alignment_u64 = 1;
2694
+ uint8_t **records = NULL;
2695
+ size_t record_count = 0;
2696
+ if (!parse_json_string_field(json, json_length, "layoutId", &layout_id) ||
2697
+ !parse_json_u64_field(
2698
+ json,
2699
+ json_length,
2700
+ "recordByteLength",
2701
+ &record_byte_length_u64)) {
2702
+ free(layout_id);
2703
+ goto fail;
2704
+ }
2705
+ JsonSlice alignment_slice;
2706
+ if (find_json_object_field(json, json_length, "alignment", &alignment_slice) &&
2707
+ !parse_json_u64(alignment_slice, &alignment_u64)) {
2708
+ free(layout_id);
2709
+ goto fail;
2710
+ }
2711
+ if (record_byte_length_u64 == 0 || record_byte_length_u64 > UINT32_MAX ||
2712
+ alignment_u64 == 0 || alignment_u64 > UINT16_MAX ||
2713
+ !parse_initial_records_field(
2714
+ json,
2715
+ json_length,
2716
+ (uint32_t)record_byte_length_u64,
2717
+ &records,
2718
+ &record_count) ||
2719
+ !ensure_runtime_host_capacity(
2720
+ (void **)&state->regions,
2721
+ &state->region_capacity,
2722
+ state->region_count,
2723
+ sizeof(*state->regions))) {
2724
+ free(layout_id);
2725
+ for (size_t index = 0; index < record_count; ++index) {
2726
+ free(records[index]);
2727
+ }
2728
+ free(records);
2729
+ goto fail;
2730
+ }
2731
+ RuntimeHostRegion *region = &state->regions[state->region_count++];
2732
+ memset(region, 0, sizeof(*region));
2733
+ region->region_id = state->next_region_id++;
2734
+ region->layout_id = layout_id;
2735
+ region->record_byte_length = (uint32_t)record_byte_length_u64;
2736
+ region->alignment = (uint16_t)alignment_u64;
2737
+ region->records = records;
2738
+ region->record_count = record_count;
2739
+ if (!append_runtime_host_region_descriptor_json(&response, region)) {
2740
+ goto fail;
2741
+ }
2742
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2743
+ }
2744
+
2745
+ if (opcode == HOST_CONTROL_DESCRIBE_REGION) {
2746
+ uint64_t region_id = 0;
2747
+ if (!parse_json_u64_field(json, json_length, "regionId", &region_id)) {
2748
+ goto fail;
2749
+ }
2750
+ RuntimeHostRegion *region = find_runtime_host_region(state, region_id);
2751
+ if (region == NULL) {
2752
+ if (!json_buffer_append_cstr(&response, "null")) {
2753
+ goto fail;
2754
+ }
2755
+ } else if (!append_runtime_host_region_descriptor_json(&response, region)) {
2756
+ goto fail;
2757
+ }
2758
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2759
+ }
2760
+
2761
+ if (opcode == HOST_CONTROL_RESOLVE_RECORD) {
2762
+ uint64_t region_id = 0;
2763
+ uint64_t record_index_u64 = 0;
2764
+ if (!parse_json_u64_field(json, json_length, "regionId", &region_id) ||
2765
+ !parse_json_u64_field(json, json_length, "recordIndex", &record_index_u64)) {
2766
+ goto fail;
2767
+ }
2768
+ RuntimeHostRegion *region = find_runtime_host_region(state, region_id);
2769
+ if (region == NULL || record_index_u64 >= region->record_count) {
2770
+ if (!json_buffer_append_cstr(&response, "null")) {
2771
+ goto fail;
2772
+ }
2773
+ } else if (!append_runtime_host_region_record_json(
2774
+ &response,
2775
+ region,
2776
+ (uint32_t)record_index_u64)) {
2777
+ goto fail;
2778
+ }
2779
+ return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
2780
+ }
2781
+
2782
+ fail:
2783
+ json_buffer_free(&response);
2784
+ return false;
2785
+ }
2786
+
2787
+ static bool serve_runtime_host_requests(void) {
2788
+ RuntimeHostState state;
2789
+ runtime_host_state_init(&state);
2790
+ bool ok = true;
2791
+
2792
+ for (;;) {
2793
+ uint8_t length_bytes[4];
2794
+ const size_t prefix_read = fread(length_bytes, 1, sizeof(length_bytes), stdin);
2795
+ if (prefix_read == 0) {
2796
+ ok = feof(stdin);
2797
+ break;
2798
+ }
2799
+ if (prefix_read != sizeof(length_bytes)) {
2800
+ ok = false;
2801
+ break;
2802
+ }
2803
+ const uint32_t request_size = read_le_u32_bytes(length_bytes);
2804
+ uint8_t *request_bytes = NULL;
2805
+ if (request_size > 0) {
2806
+ request_bytes = malloc(request_size);
2807
+ if (request_bytes == NULL || !read_exact(stdin, request_bytes, request_size)) {
2808
+ free(request_bytes);
2809
+ ok = false;
2810
+ break;
2811
+ }
2812
+ }
2813
+ if (request_size < 5 ||
2814
+ memcmp(request_bytes, HOST_CONTROL_MAGIC, sizeof(HOST_CONTROL_MAGIC)) != 0) {
2815
+ free(request_bytes);
2816
+ ok = false;
2817
+ break;
2818
+ }
2819
+ uint8_t *response_bytes = NULL;
2820
+ uint32_t response_size = 0;
2821
+ ok = dispatch_runtime_host_request(
2822
+ &state,
2823
+ request_bytes[4],
2824
+ request_bytes + 5,
2825
+ request_size - 5,
2826
+ &response_bytes,
2827
+ &response_size);
2828
+ free(request_bytes);
2829
+ if (!ok) {
2830
+ free(response_bytes);
2831
+ break;
2832
+ }
2833
+ const uint8_t response_length_bytes[4] = {
2834
+ (uint8_t)(response_size & 0xFFU),
2835
+ (uint8_t)((response_size >> 8) & 0xFFU),
2836
+ (uint8_t)((response_size >> 16) & 0xFFU),
2837
+ (uint8_t)((response_size >> 24) & 0xFFU),
2838
+ };
2839
+ ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
2840
+ write_all(stdout, response_bytes, response_size);
2841
+ free(response_bytes);
2842
+ if (!ok) {
2843
+ break;
2844
+ }
2845
+ }
2846
+
2847
+ runtime_host_state_destroy(&state);
2848
+ return ok;
2849
+ }
2850
+
2851
+ static void destroy_thread_launch_context(ThreadLaunchContext *context) {
2852
+ if (context == NULL) {
2853
+ return;
2854
+ }
2855
+ if (context->module != NULL) {
2856
+ pthread_mutex_lock(&context->runner->store_mutex);
2857
+ WasmEdge_ModuleInstanceDelete(context->module);
2858
+ pthread_mutex_unlock(&context->runner->store_mutex);
2859
+ }
2860
+ if (context->executor != NULL) {
2861
+ WasmEdge_ExecutorDelete(context->executor);
2862
+ }
2863
+ free(context);
2864
+ }
2865
+
2866
+ void *run_guest_thread(void *Data) {
2867
+ ThreadLaunchContext *context = Data;
2868
+ if (context == NULL || context->runner == NULL ||
2869
+ context->runner->shared_memory == NULL) {
2870
+ destroy_thread_launch_context(context);
2871
+ return NULL;
2872
+ }
2873
+
2874
+ uint32_t stack_high = 0;
2875
+ uint32_t stack_size = 0;
2876
+ if (!read_guest_u32(
2877
+ context->runner->shared_memory,
2878
+ context->pthread_ptr + EM_PTHREAD_STACK_OFFSET,
2879
+ &stack_high) ||
2880
+ !read_guest_u32(
2881
+ context->runner->shared_memory,
2882
+ context->pthread_ptr + EM_PTHREAD_STACK_SIZE_OFFSET,
2883
+ &stack_size)) {
2884
+ destroy_thread_launch_context(context);
2885
+ return NULL;
2886
+ }
2887
+ const uint32_t stack_low = stack_high - stack_size;
2888
+
2889
+ WasmEdge_Value params[6];
2890
+ WasmEdge_Value returns[1];
2891
+
2892
+ params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
2893
+ params[1] = WasmEdge_ValueGenI32((int32_t)stack_low);
2894
+ if (!invoke_function(
2895
+ context->executor,
2896
+ context->stack_set_limits,
2897
+ params,
2898
+ 2,
2899
+ NULL,
2900
+ 0,
2901
+ "emscripten_stack_set_limits")) {
2902
+ goto thread_crashed;
2903
+ }
2904
+
2905
+ params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
2906
+ if (!invoke_function(
2907
+ context->executor,
2908
+ context->stack_restore,
2909
+ params,
2910
+ 1,
2911
+ NULL,
2912
+ 0,
2913
+ "_emscripten_stack_restore")) {
2914
+ goto thread_crashed;
2915
+ }
2916
+
2917
+ params[0] = WasmEdge_ValueGenI32((int32_t)context->pthread_ptr);
2918
+ params[1] = WasmEdge_ValueGenI32(0);
2919
+ params[2] = WasmEdge_ValueGenI32(0);
2920
+ params[3] = WasmEdge_ValueGenI32(1);
2921
+ params[4] = WasmEdge_ValueGenI32(0);
2922
+ params[5] = WasmEdge_ValueGenI32(0);
2923
+ if (!invoke_function(
2924
+ context->executor,
2925
+ context->thread_init,
2926
+ params,
2927
+ 6,
2928
+ NULL,
2929
+ 0,
2930
+ "_emscripten_thread_init")) {
2931
+ goto thread_crashed;
2932
+ }
2933
+
2934
+ if (!invoke_function(
2935
+ context->executor,
2936
+ context->tls_init,
2937
+ NULL,
2938
+ 0,
2939
+ returns,
2940
+ 1,
2941
+ "_emscripten_tls_init")) {
2942
+ goto thread_crashed;
2943
+ }
2944
+
2945
+ WasmEdge_Value function_ref;
2946
+ const WasmEdge_Result table_result = WasmEdge_TableInstanceGetData(
2947
+ context->indirect_table,
2948
+ &function_ref,
2949
+ context->start_routine);
2950
+ if (!WasmEdge_ResultOK(table_result)) {
2951
+ fprintf(
2952
+ stderr,
2953
+ "table lookup failed: %s (0x%x)\n",
2954
+ WasmEdge_ResultGetMessage(table_result),
2955
+ WasmEdge_ResultGetCode(table_result));
2956
+ goto thread_crashed;
2957
+ }
2958
+ const WasmEdge_FunctionInstanceContext *entry_function =
2959
+ WasmEdge_ValueGetFuncRef(function_ref);
2960
+ if (entry_function == NULL) {
2961
+ fprintf(stderr, "thread entry function pointer was null\n");
2962
+ goto thread_crashed;
2963
+ }
2964
+
2965
+ params[0] = WasmEdge_ValueGenI32((int32_t)context->arg);
2966
+ if (!invoke_function(
2967
+ context->executor,
2968
+ (WasmEdge_FunctionInstanceContext *)entry_function,
2969
+ params,
2970
+ 1,
2971
+ returns,
2972
+ 1,
2973
+ "thread entry")) {
2974
+ goto thread_crashed;
2975
+ }
2976
+
2977
+ params[0] = WasmEdge_ValueGenI32(WasmEdge_ValueGetI32(returns[0]));
2978
+ invoke_function(
2979
+ context->executor,
2980
+ context->thread_exit,
2981
+ params,
2982
+ 1,
2983
+ NULL,
2984
+ 0,
2985
+ "_emscripten_thread_exit");
2986
+ destroy_thread_launch_context(context);
2987
+ return NULL;
2988
+
2989
+ thread_crashed:
2990
+ if (context->thread_crashed != NULL) {
2991
+ invoke_function(
2992
+ context->executor,
2993
+ context->thread_crashed,
2994
+ NULL,
2995
+ 0,
2996
+ NULL,
2997
+ 0,
2998
+ "_emscripten_thread_crashed");
2999
+ }
3000
+ destroy_thread_launch_context(context);
3001
+ return NULL;
3002
+ }
3003
+
3004
+ int main(int argc, char **argv) {
3005
+ if (argc < 2) {
3006
+ fprintf(
3007
+ stderr,
3008
+ "usage: %s module.wasm [module-args...] | %s --serve-runtime-host\n",
3009
+ argv[0],
3010
+ argv[0]);
3011
+ return 2;
3012
+ }
3013
+ const bool serve_runtime_host =
3014
+ argc >= 2 && strcmp(argv[1], "--serve-runtime-host") == 0;
3015
+ if (serve_runtime_host) {
3016
+ return serve_runtime_host_requests() ? 0 : 1;
3017
+ }
3018
+ const bool serve_plugin_invoke =
3019
+ argc >= 3 && strcmp(argv[2], "--serve-plugin-invoke") == 0;
3020
+
3021
+ WasmEdge_ConfigureContext *conf = WasmEdge_ConfigureCreate();
3022
+ WasmEdge_ConfigureAddProposal(conf, WasmEdge_Proposal_Threads);
3023
+ WasmEdge_ConfigureAddProposal(conf, WasmEdge_Proposal_ExceptionHandling);
3024
+ WasmEdge_LoaderContext *loader = WasmEdge_LoaderCreate(conf);
3025
+ WasmEdge_ValidatorContext *validator = WasmEdge_ValidatorCreate(conf);
3026
+ WasmEdge_ExecutorContext *executor = WasmEdge_ExecutorCreate(conf, NULL);
3027
+ WasmEdge_StoreContext *store = WasmEdge_StoreCreate();
3028
+ RunnerContext runner = {
3029
+ .conf = conf,
3030
+ .ast = NULL,
3031
+ .store = store,
3032
+ .shared_memory = NULL,
3033
+ };
3034
+ pthread_mutex_init(&runner.store_mutex, NULL);
3035
+
3036
+ WasmEdge_ASTModuleContext *ast = NULL;
3037
+ WasmEdge_Result res = WasmEdge_LoaderParseFromFile(loader, &ast, argv[1]);
3038
+ if (!WasmEdge_ResultOK(res)) {
3039
+ fail_result("parse", res);
3040
+ }
3041
+ runner.ast = ast;
3042
+ res = WasmEdge_ValidatorValidate(validator, ast);
3043
+ if (!WasmEdge_ResultOK(res)) {
3044
+ fail_result("validate", res);
3045
+ }
3046
+
3047
+ WasmEdge_ModuleInstanceContext *wasi = WasmEdge_ModuleInstanceCreateWASI(
3048
+ (const char *const *)(argv + 1),
3049
+ (uint32_t)(argc - 1),
3050
+ NULL,
3051
+ 0,
3052
+ NULL,
3053
+ 0);
3054
+ res = WasmEdge_ExecutorRegisterImport(executor, store, wasi);
3055
+ if (!WasmEdge_ResultOK(res)) {
3056
+ fail_result("register wasi", res);
3057
+ }
3058
+
3059
+ WasmEdge_ModuleInstanceContext *env =
3060
+ WasmEdge_ModuleInstanceCreate(WasmEdge_StringCreateByCString("env"));
3061
+ ImportedModuleConfig import_config;
3062
+ if (!read_imported_module_config(argv[1], &import_config)) {
3063
+ fprintf(stderr, "failed to inspect wasm import contract\n");
3064
+ return 1;
3065
+ }
3066
+ if (!add_imported_env_memory_from_file(argv[1], env, &runner.shared_memory)) {
3067
+ fprintf(stderr, "failed to create imported env memory\n");
3068
+ return 1;
3069
+ }
3070
+ register_env_host_functions(
3071
+ env,
3072
+ &runner,
3073
+ import_config.receive_on_main_thread_param_len == 4
3074
+ ? 4
3075
+ : 5,
3076
+ import_config.notify_mailbox_postmessage_param_len == 3
3077
+ ? 3
3078
+ : 2);
3079
+ res = WasmEdge_ExecutorRegisterImport(executor, store, env);
3080
+ if (!WasmEdge_ResultOK(res)) {
3081
+ fail_result("register env", res);
3082
+ }
3083
+
3084
+ WasmEdge_ModuleInstanceContext *mod = NULL;
3085
+ res = WasmEdge_ExecutorInstantiate(executor, &mod, store, ast);
3086
+ if (!WasmEdge_ResultOK(res)) {
3087
+ fail_result("instantiate", res);
3088
+ }
3089
+
3090
+ if (!invoke_optional_module_init(executor, mod, serve_plugin_invoke)) {
3091
+ return 3;
3092
+ }
3093
+
3094
+ uint32_t exit_code = WasmEdge_ModuleInstanceWASIGetExitCode(wasi);
3095
+ if (serve_plugin_invoke) {
3096
+ if (!serve_plugin_invoke_requests(executor, mod, &runner)) {
3097
+ exit_code = 1;
3098
+ } else {
3099
+ exit_code = 0;
3100
+ }
3101
+ }
3102
+
3103
+ WasmEdge_ASTModuleDelete(ast);
3104
+ WasmEdge_StoreDelete(store);
3105
+ WasmEdge_ExecutorDelete(executor);
3106
+ WasmEdge_ValidatorDelete(validator);
3107
+ WasmEdge_LoaderDelete(loader);
3108
+ WasmEdge_ConfigureDelete(conf);
3109
+ pthread_mutex_destroy(&runner.store_mutex);
3110
+ return (int)exit_code;
3111
+ }