space-data-module-sdk 0.5.10 → 0.5.14

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.
@@ -1,1001 +0,0 @@
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
- #define EM_PTHREAD_STACK_OFFSET 52U
65
- #define EM_PTHREAD_STACK_SIZE_OFFSET 56U
66
- #define EM_PTHREAD_EAGAIN 6
67
-
68
- static WasmEdge_Result stub_void(
69
- void *Data,
70
- const WasmEdge_CallingFrameContext *CallFrameCxt,
71
- const WasmEdge_Value *In,
72
- WasmEdge_Value *Out) {
73
- (void)Data;
74
- (void)CallFrameCxt;
75
- (void)In;
76
- (void)Out;
77
- return WasmEdge_Result_Success;
78
- }
79
-
80
- static WasmEdge_Result stub_receive_on_main_thread(
81
- void *Data,
82
- const WasmEdge_CallingFrameContext *CallFrameCxt,
83
- const WasmEdge_Value *In,
84
- WasmEdge_Value *Out) {
85
- (void)Data;
86
- (void)CallFrameCxt;
87
- (void)In;
88
- Out[0] = WasmEdge_ValueGenF64(0.0);
89
- return WasmEdge_Result_Success;
90
- }
91
-
92
- static WasmEdge_Result stub_pthread_create(
93
- void *Data,
94
- const WasmEdge_CallingFrameContext *CallFrameCxt,
95
- const WasmEdge_Value *In,
96
- WasmEdge_Value *Out) {
97
- (void)CallFrameCxt;
98
- RunnerContext *runner = Data;
99
- if (runner == NULL || runner->ast == NULL || runner->store == NULL ||
100
- runner->shared_memory == NULL) {
101
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
102
- return WasmEdge_Result_Success;
103
- }
104
- ThreadLaunchContext *thread_context =
105
- calloc(1, sizeof(ThreadLaunchContext));
106
- if (thread_context == NULL) {
107
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
108
- return WasmEdge_Result_Success;
109
- }
110
- thread_context->runner = runner;
111
- thread_context->pthread_ptr = (uint32_t)WasmEdge_ValueGetI32(In[0]);
112
- thread_context->start_routine = (uint32_t)WasmEdge_ValueGetI32(In[2]);
113
- thread_context->arg = (uint32_t)WasmEdge_ValueGetI32(In[3]);
114
-
115
- thread_context->executor = WasmEdge_ExecutorCreate(runner->conf, NULL);
116
- if (thread_context->executor == NULL) {
117
- free(thread_context);
118
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
119
- return WasmEdge_Result_Success;
120
- }
121
-
122
- pthread_mutex_lock(&runner->store_mutex);
123
- WasmEdge_Result instantiate_result = WasmEdge_ExecutorInstantiate(
124
- thread_context->executor,
125
- &thread_context->module,
126
- runner->store,
127
- runner->ast);
128
- pthread_mutex_unlock(&runner->store_mutex);
129
- if (!WasmEdge_ResultOK(instantiate_result) || thread_context->module == NULL) {
130
- WasmEdge_ExecutorDelete(thread_context->executor);
131
- free(thread_context);
132
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
133
- return WasmEdge_Result_Success;
134
- }
135
-
136
- WasmEdge_String export_name =
137
- WasmEdge_StringCreateByCString("__indirect_function_table");
138
- thread_context->indirect_table =
139
- WasmEdge_ModuleInstanceFindTable(thread_context->module, export_name);
140
- WasmEdge_StringDelete(export_name);
141
-
142
- export_name = WasmEdge_StringCreateByCString("emscripten_stack_set_limits");
143
- thread_context->stack_set_limits =
144
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
145
- WasmEdge_StringDelete(export_name);
146
-
147
- export_name = WasmEdge_StringCreateByCString("_emscripten_stack_restore");
148
- thread_context->stack_restore =
149
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
150
- WasmEdge_StringDelete(export_name);
151
-
152
- export_name = WasmEdge_StringCreateByCString("_emscripten_thread_init");
153
- thread_context->thread_init =
154
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
155
- WasmEdge_StringDelete(export_name);
156
-
157
- export_name = WasmEdge_StringCreateByCString("_emscripten_tls_init");
158
- thread_context->tls_init =
159
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
160
- WasmEdge_StringDelete(export_name);
161
-
162
- export_name = WasmEdge_StringCreateByCString("_emscripten_thread_exit");
163
- thread_context->thread_exit =
164
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
165
- WasmEdge_StringDelete(export_name);
166
-
167
- export_name = WasmEdge_StringCreateByCString("_emscripten_thread_crashed");
168
- thread_context->thread_crashed =
169
- WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
170
- WasmEdge_StringDelete(export_name);
171
-
172
- if (thread_context->indirect_table == NULL ||
173
- thread_context->stack_set_limits == NULL ||
174
- thread_context->stack_restore == NULL ||
175
- thread_context->thread_init == NULL ||
176
- thread_context->tls_init == NULL ||
177
- thread_context->thread_exit == NULL) {
178
- pthread_mutex_lock(&runner->store_mutex);
179
- WasmEdge_ModuleInstanceDelete(thread_context->module);
180
- pthread_mutex_unlock(&runner->store_mutex);
181
- WasmEdge_ExecutorDelete(thread_context->executor);
182
- free(thread_context);
183
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
184
- return WasmEdge_Result_Success;
185
- }
186
-
187
- pthread_t thread;
188
- pthread_attr_t thread_attr;
189
- if (pthread_attr_init(&thread_attr) != 0) {
190
- pthread_mutex_lock(&runner->store_mutex);
191
- WasmEdge_ModuleInstanceDelete(thread_context->module);
192
- pthread_mutex_unlock(&runner->store_mutex);
193
- WasmEdge_ExecutorDelete(thread_context->executor);
194
- free(thread_context);
195
- Out[0] = WasmEdge_ValueGenI32(EM_PTHREAD_EAGAIN);
196
- return WasmEdge_Result_Success;
197
- }
198
- pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
199
-
200
- extern void *run_guest_thread(void *Data);
201
- const int rc = pthread_create(
202
- &thread,
203
- &thread_attr,
204
- run_guest_thread,
205
- thread_context);
206
- pthread_attr_destroy(&thread_attr);
207
- if (rc != 0) {
208
- pthread_mutex_lock(&runner->store_mutex);
209
- WasmEdge_ModuleInstanceDelete(thread_context->module);
210
- pthread_mutex_unlock(&runner->store_mutex);
211
- WasmEdge_ExecutorDelete(thread_context->executor);
212
- free(thread_context);
213
- Out[0] = WasmEdge_ValueGenI32(rc);
214
- return WasmEdge_Result_Success;
215
- }
216
-
217
- (void)CallFrameCxt;
218
- Out[0] = WasmEdge_ValueGenI32(0);
219
- return WasmEdge_Result_Success;
220
- }
221
-
222
- static void add_host_func(
223
- WasmEdge_ModuleInstanceContext *mod,
224
- const char *name,
225
- WasmEdge_HostFunc_t fn,
226
- void *data,
227
- const WasmEdge_ValType *params,
228
- uint32_t param_len,
229
- const WasmEdge_ValType *returns,
230
- uint32_t return_len) {
231
- WasmEdge_FunctionTypeContext *type =
232
- WasmEdge_FunctionTypeCreate(params, param_len, returns, return_len);
233
- WasmEdge_FunctionInstanceContext *func =
234
- WasmEdge_FunctionInstanceCreate(type, fn, data, 0);
235
- WasmEdge_String func_name = WasmEdge_StringCreateByCString(name);
236
- WasmEdge_ModuleInstanceAddFunction(mod, func_name, func);
237
- WasmEdge_StringDelete(func_name);
238
- WasmEdge_FunctionTypeDelete(type);
239
- }
240
-
241
- static bool read_file_bytes(
242
- const char *path,
243
- uint8_t **buffer,
244
- size_t *buffer_len) {
245
- FILE *file = fopen(path, "rb");
246
- if (file == NULL) {
247
- return false;
248
- }
249
- if (fseek(file, 0, SEEK_END) != 0) {
250
- fclose(file);
251
- return false;
252
- }
253
- long file_size = ftell(file);
254
- if (file_size < 0) {
255
- fclose(file);
256
- return false;
257
- }
258
- if (fseek(file, 0, SEEK_SET) != 0) {
259
- fclose(file);
260
- return false;
261
- }
262
- uint8_t *bytes = malloc((size_t)file_size);
263
- if (bytes == NULL) {
264
- fclose(file);
265
- return false;
266
- }
267
- const size_t read_len = fread(bytes, 1, (size_t)file_size, file);
268
- fclose(file);
269
- if (read_len != (size_t)file_size) {
270
- free(bytes);
271
- return false;
272
- }
273
- *buffer = bytes;
274
- *buffer_len = read_len;
275
- return true;
276
- }
277
-
278
- static bool read_u32_leb(
279
- const uint8_t *bytes,
280
- size_t length,
281
- size_t *offset,
282
- uint32_t *value) {
283
- uint32_t result = 0;
284
- uint32_t shift = 0;
285
- while (*offset < length) {
286
- const uint8_t byte = bytes[*offset];
287
- *offset += 1;
288
- result |= (uint32_t)(byte & 0x7F) << shift;
289
- if ((byte & 0x80) == 0) {
290
- *value = result;
291
- return true;
292
- }
293
- shift += 7;
294
- if (shift >= 35) {
295
- return false;
296
- }
297
- }
298
- return false;
299
- }
300
-
301
- static bool skip_bytes(size_t length, size_t *offset, uint32_t byte_count) {
302
- if (*offset + byte_count > length) {
303
- return false;
304
- }
305
- *offset += byte_count;
306
- return true;
307
- }
308
-
309
- static bool read_name_equals(
310
- const uint8_t *bytes,
311
- size_t length,
312
- size_t *offset,
313
- const char *expected) {
314
- uint32_t name_len = 0;
315
- if (!read_u32_leb(bytes, length, offset, &name_len)) {
316
- return false;
317
- }
318
- if (*offset + name_len > length) {
319
- return false;
320
- }
321
- const size_t expected_len = strlen(expected);
322
- const bool equals =
323
- expected_len == (size_t)name_len &&
324
- memcmp(bytes + *offset, expected, expected_len) == 0;
325
- *offset += name_len;
326
- return equals;
327
- }
328
-
329
- static bool skip_limits(
330
- const uint8_t *bytes,
331
- size_t length,
332
- size_t *offset) {
333
- uint32_t flags = 0;
334
- uint32_t ignored = 0;
335
- if (!read_u32_leb(bytes, length, offset, &flags) ||
336
- !read_u32_leb(bytes, length, offset, &ignored)) {
337
- return false;
338
- }
339
- if ((flags & 0x01U) != 0 && !read_u32_leb(bytes, length, offset, &ignored)) {
340
- return false;
341
- }
342
- return true;
343
- }
344
-
345
- static bool read_imported_module_config(
346
- const char *wasm_path,
347
- ImportedModuleConfig *config) {
348
- memset(config, 0, sizeof(*config));
349
-
350
- uint8_t *bytes = NULL;
351
- size_t length = 0;
352
- if (!read_file_bytes(wasm_path, &bytes, &length)) {
353
- return false;
354
- }
355
-
356
- bool ok = false;
357
- FunctionTypeArity *types = NULL;
358
- uint32_t type_count = 0;
359
- size_t offset = 8;
360
- if (length < 8 || memcmp(bytes, "\0asm", 4) != 0) {
361
- goto cleanup;
362
- }
363
-
364
- while (offset < length) {
365
- const uint8_t section_id = bytes[offset];
366
- offset += 1;
367
-
368
- uint32_t section_len = 0;
369
- if (!read_u32_leb(bytes, length, &offset, &section_len)) {
370
- goto cleanup;
371
- }
372
- if (offset + section_len > length) {
373
- goto cleanup;
374
- }
375
-
376
- const size_t section_end = offset + section_len;
377
- if (section_id == 1) {
378
- if (!read_u32_leb(bytes, section_end, &offset, &type_count)) {
379
- goto cleanup;
380
- }
381
- types = calloc(type_count, sizeof(FunctionTypeArity));
382
- if (types == NULL && type_count > 0) {
383
- goto cleanup;
384
- }
385
- for (uint32_t index = 0; index < type_count; index++) {
386
- if (offset >= section_end || bytes[offset] != 0x60) {
387
- goto cleanup;
388
- }
389
- offset += 1;
390
- if (!read_u32_leb(
391
- bytes,
392
- section_end,
393
- &offset,
394
- &types[index].param_count)) {
395
- goto cleanup;
396
- }
397
- if (!skip_bytes(section_end, &offset, types[index].param_count)) {
398
- goto cleanup;
399
- }
400
- if (!read_u32_leb(
401
- bytes,
402
- section_end,
403
- &offset,
404
- &types[index].return_count)) {
405
- goto cleanup;
406
- }
407
- if (!skip_bytes(section_end, &offset, types[index].return_count)) {
408
- goto cleanup;
409
- }
410
- }
411
- offset = section_end;
412
- continue;
413
- }
414
-
415
- if (section_id != 2) {
416
- offset = section_end;
417
- continue;
418
- }
419
-
420
- uint32_t import_count = 0;
421
- if (!read_u32_leb(bytes, section_end, &offset, &import_count)) {
422
- goto cleanup;
423
- }
424
-
425
- for (uint32_t index = 0; index < import_count; index++) {
426
- const bool is_env =
427
- read_name_equals(bytes, section_end, &offset, "env");
428
- size_t field_name_offset = offset;
429
- uint32_t field_name_len = 0;
430
- if (!read_u32_leb(
431
- bytes,
432
- section_end,
433
- &field_name_offset,
434
- &field_name_len)) {
435
- goto cleanup;
436
- }
437
- if (field_name_offset + field_name_len > section_end) {
438
- goto cleanup;
439
- }
440
- const bool is_memory_name =
441
- field_name_len == 6 &&
442
- memcmp(bytes + field_name_offset, "memory", 6) == 0;
443
- const bool is_receive_on_main_thread_name =
444
- field_name_len == 37 &&
445
- memcmp(
446
- bytes + field_name_offset,
447
- "_emscripten_receive_on_main_thread_js",
448
- 37) == 0;
449
- const bool is_notify_mailbox_postmessage_name =
450
- field_name_len == 38 &&
451
- memcmp(
452
- bytes + field_name_offset,
453
- "_emscripten_notify_mailbox_postmessage",
454
- 38) == 0;
455
- offset = field_name_offset + field_name_len;
456
-
457
- if (offset >= section_end) {
458
- goto cleanup;
459
- }
460
- const uint8_t kind = bytes[offset];
461
- offset += 1;
462
-
463
- switch (kind) {
464
- case 0x00: {
465
- uint32_t type_index = 0;
466
- if (!read_u32_leb(bytes, section_end, &offset, &type_index)) {
467
- goto cleanup;
468
- }
469
- if (is_env && is_receive_on_main_thread_name &&
470
- type_index < type_count) {
471
- config->receive_on_main_thread_param_len =
472
- types[type_index].param_count;
473
- }
474
- if (is_env && is_notify_mailbox_postmessage_name &&
475
- type_index < type_count) {
476
- config->notify_mailbox_postmessage_param_len =
477
- types[type_index].param_count;
478
- }
479
- break;
480
- }
481
- case 0x01:
482
- if (!skip_bytes(section_end, &offset, 1) ||
483
- !skip_limits(bytes, section_end, &offset)) {
484
- goto cleanup;
485
- }
486
- break;
487
- case 0x02: {
488
- uint32_t flags = 0;
489
- uint32_t min_pages = 0;
490
- uint32_t max_pages = 0;
491
- if (!read_u32_leb(bytes, section_end, &offset, &flags) ||
492
- !read_u32_leb(bytes, section_end, &offset, &min_pages)) {
493
- goto cleanup;
494
- }
495
- const bool has_max = (flags & 0x01U) != 0;
496
- const bool shared = (flags & 0x02U) != 0;
497
- if (has_max &&
498
- !read_u32_leb(bytes, section_end, &offset, &max_pages)) {
499
- goto cleanup;
500
- }
501
- if (is_env && is_memory_name) {
502
- config->memory.found = true;
503
- config->memory.shared = shared;
504
- config->memory.has_max = has_max;
505
- config->memory.min = min_pages;
506
- config->memory.max = max_pages;
507
- }
508
- break;
509
- }
510
- case 0x03:
511
- if (!skip_bytes(section_end, &offset, 2)) {
512
- goto cleanup;
513
- }
514
- break;
515
- case 0x04: {
516
- uint32_t tag_type = 0;
517
- uint32_t type_index = 0;
518
- if (!read_u32_leb(bytes, section_end, &offset, &tag_type) ||
519
- !read_u32_leb(bytes, section_end, &offset, &type_index)) {
520
- goto cleanup;
521
- }
522
- break;
523
- }
524
- default:
525
- goto cleanup;
526
- }
527
- }
528
-
529
- ok = true;
530
- goto cleanup;
531
- }
532
-
533
- ok = true;
534
-
535
- cleanup:
536
- free(types);
537
- free(bytes);
538
- return ok;
539
- }
540
-
541
- static bool add_imported_env_memory_from_file(
542
- const char *wasm_path,
543
- WasmEdge_ModuleInstanceContext *env,
544
- WasmEdge_MemoryInstanceContext **memory_out) {
545
- ImportedModuleConfig config;
546
- if (!read_imported_module_config(wasm_path, &config)) {
547
- return false;
548
- }
549
- if (!config.memory.found) {
550
- *memory_out = NULL;
551
- return true;
552
- }
553
- if (!config.memory.has_max) {
554
- return false;
555
- }
556
-
557
- WasmEdge_Limit limit = {
558
- .HasMax = config.memory.has_max,
559
- .Shared = config.memory.shared,
560
- .Min = config.memory.min,
561
- .Max = config.memory.max,
562
- };
563
- WasmEdge_MemoryTypeContext *host_memory_type =
564
- WasmEdge_MemoryTypeCreate(limit);
565
- WasmEdge_MemoryInstanceContext *memory =
566
- WasmEdge_MemoryInstanceCreate(host_memory_type);
567
- WasmEdge_String memory_name = WasmEdge_StringCreateByCString("memory");
568
- WasmEdge_ModuleInstanceAddMemory(env, memory_name, memory);
569
- WasmEdge_StringDelete(memory_name);
570
- WasmEdge_MemoryTypeDelete(host_memory_type);
571
- *memory_out = memory;
572
- return true;
573
- }
574
-
575
- static void register_env_host_functions(
576
- WasmEdge_ModuleInstanceContext *env,
577
- RunnerContext *runner,
578
- uint32_t receive_on_main_thread_param_len,
579
- uint32_t notify_mailbox_postmessage_param_len) {
580
- const WasmEdge_ValType i32_param[1] = {WasmEdge_ValTypeGenI32()};
581
- const WasmEdge_ValType two_i32_params[2] = {
582
- WasmEdge_ValTypeGenI32(),
583
- WasmEdge_ValTypeGenI32()};
584
- const WasmEdge_ValType three_i32_params[3] = {
585
- WasmEdge_ValTypeGenI32(),
586
- WasmEdge_ValTypeGenI32(),
587
- WasmEdge_ValTypeGenI32()};
588
- const WasmEdge_ValType four_i32_params[4] = {
589
- WasmEdge_ValTypeGenI32(),
590
- WasmEdge_ValTypeGenI32(),
591
- WasmEdge_ValTypeGenI32(),
592
- WasmEdge_ValTypeGenI32()};
593
- const WasmEdge_ValType five_i32_params[5] = {
594
- WasmEdge_ValTypeGenI32(),
595
- WasmEdge_ValTypeGenI32(),
596
- WasmEdge_ValTypeGenI32(),
597
- WasmEdge_ValTypeGenI32(),
598
- WasmEdge_ValTypeGenI32()};
599
- const WasmEdge_ValType f64_return[1] = {WasmEdge_ValTypeGenF64()};
600
- const WasmEdge_ValType i32_return[1] = {WasmEdge_ValTypeGenI32()};
601
-
602
- add_host_func(
603
- env,
604
- "_emscripten_thread_set_strongref",
605
- stub_void,
606
- runner,
607
- i32_param,
608
- 1,
609
- NULL,
610
- 0);
611
- add_host_func(
612
- env,
613
- "emscripten_exit_with_live_runtime",
614
- stub_void,
615
- runner,
616
- NULL,
617
- 0,
618
- NULL,
619
- 0);
620
- add_host_func(
621
- env,
622
- "_emscripten_init_main_thread_js",
623
- stub_void,
624
- runner,
625
- i32_param,
626
- 1,
627
- NULL,
628
- 0);
629
- add_host_func(
630
- env,
631
- "__emscripten_init_main_thread_js",
632
- stub_void,
633
- runner,
634
- i32_param,
635
- 1,
636
- NULL,
637
- 0);
638
- add_host_func(
639
- env,
640
- "_emscripten_thread_mailbox_await",
641
- stub_void,
642
- runner,
643
- i32_param,
644
- 1,
645
- NULL,
646
- 0);
647
- add_host_func(
648
- env,
649
- "_emscripten_receive_on_main_thread_js",
650
- stub_receive_on_main_thread,
651
- runner,
652
- receive_on_main_thread_param_len == 4 ? four_i32_params : five_i32_params,
653
- receive_on_main_thread_param_len == 4 ? 4 : 5,
654
- f64_return,
655
- 1);
656
- add_host_func(
657
- env,
658
- "emscripten_check_blocking_allowed",
659
- stub_void,
660
- runner,
661
- NULL,
662
- 0,
663
- NULL,
664
- 0);
665
- add_host_func(
666
- env,
667
- "__pthread_create_js",
668
- stub_pthread_create,
669
- runner,
670
- four_i32_params,
671
- 4,
672
- i32_return,
673
- 1);
674
- add_host_func(
675
- env,
676
- "_emscripten_thread_cleanup",
677
- stub_void,
678
- runner,
679
- i32_param,
680
- 1,
681
- NULL,
682
- 0);
683
- add_host_func(
684
- env,
685
- "__emscripten_thread_cleanup",
686
- stub_void,
687
- runner,
688
- i32_param,
689
- 1,
690
- NULL,
691
- 0);
692
- add_host_func(
693
- env,
694
- "_emscripten_notify_mailbox_postmessage",
695
- stub_void,
696
- runner,
697
- notify_mailbox_postmessage_param_len == 3
698
- ? three_i32_params
699
- : two_i32_params,
700
- notify_mailbox_postmessage_param_len == 3 ? 3 : 2,
701
- NULL,
702
- 0);
703
- }
704
-
705
- static bool read_guest_u32(
706
- WasmEdge_MemoryInstanceContext *memory,
707
- uint32_t offset,
708
- uint32_t *value) {
709
- const uint8_t *bytes =
710
- WasmEdge_MemoryInstanceGetPointerConst(memory, offset, 4);
711
- if (bytes == NULL) {
712
- return false;
713
- }
714
- *value = (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
715
- ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
716
- return true;
717
- }
718
-
719
- static bool invoke_function(
720
- WasmEdge_ExecutorContext *executor,
721
- WasmEdge_FunctionInstanceContext *function,
722
- const WasmEdge_Value *params,
723
- uint32_t params_len,
724
- WasmEdge_Value *returns,
725
- uint32_t returns_len,
726
- const char *label) {
727
- const WasmEdge_Result result = WasmEdge_ExecutorInvoke(
728
- executor,
729
- function,
730
- params,
731
- params_len,
732
- returns,
733
- returns_len);
734
- if (WasmEdge_ResultOK(result)) {
735
- return true;
736
- }
737
- fprintf(
738
- stderr,
739
- "%s failed: %s (0x%x)\n",
740
- label,
741
- WasmEdge_ResultGetMessage(result),
742
- WasmEdge_ResultGetCode(result));
743
- return false;
744
- }
745
-
746
- static void destroy_thread_launch_context(ThreadLaunchContext *context) {
747
- if (context == NULL) {
748
- return;
749
- }
750
- if (context->module != NULL) {
751
- pthread_mutex_lock(&context->runner->store_mutex);
752
- WasmEdge_ModuleInstanceDelete(context->module);
753
- pthread_mutex_unlock(&context->runner->store_mutex);
754
- }
755
- if (context->executor != NULL) {
756
- WasmEdge_ExecutorDelete(context->executor);
757
- }
758
- free(context);
759
- }
760
-
761
- void *run_guest_thread(void *Data) {
762
- ThreadLaunchContext *context = Data;
763
- if (context == NULL || context->runner == NULL ||
764
- context->runner->shared_memory == NULL) {
765
- destroy_thread_launch_context(context);
766
- return NULL;
767
- }
768
-
769
- uint32_t stack_high = 0;
770
- uint32_t stack_size = 0;
771
- if (!read_guest_u32(
772
- context->runner->shared_memory,
773
- context->pthread_ptr + EM_PTHREAD_STACK_OFFSET,
774
- &stack_high) ||
775
- !read_guest_u32(
776
- context->runner->shared_memory,
777
- context->pthread_ptr + EM_PTHREAD_STACK_SIZE_OFFSET,
778
- &stack_size)) {
779
- destroy_thread_launch_context(context);
780
- return NULL;
781
- }
782
- const uint32_t stack_low = stack_high - stack_size;
783
-
784
- WasmEdge_Value params[6];
785
- WasmEdge_Value returns[1];
786
-
787
- params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
788
- params[1] = WasmEdge_ValueGenI32((int32_t)stack_low);
789
- if (!invoke_function(
790
- context->executor,
791
- context->stack_set_limits,
792
- params,
793
- 2,
794
- NULL,
795
- 0,
796
- "emscripten_stack_set_limits")) {
797
- goto thread_crashed;
798
- }
799
-
800
- params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
801
- if (!invoke_function(
802
- context->executor,
803
- context->stack_restore,
804
- params,
805
- 1,
806
- NULL,
807
- 0,
808
- "_emscripten_stack_restore")) {
809
- goto thread_crashed;
810
- }
811
-
812
- params[0] = WasmEdge_ValueGenI32((int32_t)context->pthread_ptr);
813
- params[1] = WasmEdge_ValueGenI32(0);
814
- params[2] = WasmEdge_ValueGenI32(0);
815
- params[3] = WasmEdge_ValueGenI32(1);
816
- params[4] = WasmEdge_ValueGenI32(0);
817
- params[5] = WasmEdge_ValueGenI32(0);
818
- if (!invoke_function(
819
- context->executor,
820
- context->thread_init,
821
- params,
822
- 6,
823
- NULL,
824
- 0,
825
- "_emscripten_thread_init")) {
826
- goto thread_crashed;
827
- }
828
-
829
- if (!invoke_function(
830
- context->executor,
831
- context->tls_init,
832
- NULL,
833
- 0,
834
- returns,
835
- 1,
836
- "_emscripten_tls_init")) {
837
- goto thread_crashed;
838
- }
839
-
840
- WasmEdge_Value function_ref;
841
- const WasmEdge_Result table_result = WasmEdge_TableInstanceGetData(
842
- context->indirect_table,
843
- &function_ref,
844
- context->start_routine);
845
- if (!WasmEdge_ResultOK(table_result)) {
846
- fprintf(
847
- stderr,
848
- "table lookup failed: %s (0x%x)\n",
849
- WasmEdge_ResultGetMessage(table_result),
850
- WasmEdge_ResultGetCode(table_result));
851
- goto thread_crashed;
852
- }
853
- const WasmEdge_FunctionInstanceContext *entry_function =
854
- WasmEdge_ValueGetFuncRef(function_ref);
855
- if (entry_function == NULL) {
856
- fprintf(stderr, "thread entry function pointer was null\n");
857
- goto thread_crashed;
858
- }
859
-
860
- params[0] = WasmEdge_ValueGenI32((int32_t)context->arg);
861
- if (!invoke_function(
862
- context->executor,
863
- (WasmEdge_FunctionInstanceContext *)entry_function,
864
- params,
865
- 1,
866
- returns,
867
- 1,
868
- "thread entry")) {
869
- goto thread_crashed;
870
- }
871
-
872
- params[0] = WasmEdge_ValueGenI32(WasmEdge_ValueGetI32(returns[0]));
873
- invoke_function(
874
- context->executor,
875
- context->thread_exit,
876
- params,
877
- 1,
878
- NULL,
879
- 0,
880
- "_emscripten_thread_exit");
881
- destroy_thread_launch_context(context);
882
- return NULL;
883
-
884
- thread_crashed:
885
- if (context->thread_crashed != NULL) {
886
- invoke_function(
887
- context->executor,
888
- context->thread_crashed,
889
- NULL,
890
- 0,
891
- NULL,
892
- 0,
893
- "_emscripten_thread_crashed");
894
- }
895
- destroy_thread_launch_context(context);
896
- return NULL;
897
- }
898
-
899
- int main(int argc, char **argv) {
900
- if (argc < 2) {
901
- fprintf(stderr, "usage: %s module.wasm [module-args...]\n", argv[0]);
902
- return 2;
903
- }
904
-
905
- WasmEdge_ConfigureContext *conf = WasmEdge_ConfigureCreate();
906
- WasmEdge_ConfigureAddProposal(conf, WasmEdge_Proposal_Threads);
907
- WasmEdge_LoaderContext *loader = WasmEdge_LoaderCreate(conf);
908
- WasmEdge_ValidatorContext *validator = WasmEdge_ValidatorCreate(conf);
909
- WasmEdge_ExecutorContext *executor = WasmEdge_ExecutorCreate(conf, NULL);
910
- WasmEdge_StoreContext *store = WasmEdge_StoreCreate();
911
- RunnerContext runner = {
912
- .conf = conf,
913
- .ast = NULL,
914
- .store = store,
915
- .shared_memory = NULL,
916
- };
917
- pthread_mutex_init(&runner.store_mutex, NULL);
918
-
919
- WasmEdge_ASTModuleContext *ast = NULL;
920
- WasmEdge_Result res = WasmEdge_LoaderParseFromFile(loader, &ast, argv[1]);
921
- if (!WasmEdge_ResultOK(res)) {
922
- fail_result("parse", res);
923
- }
924
- runner.ast = ast;
925
- res = WasmEdge_ValidatorValidate(validator, ast);
926
- if (!WasmEdge_ResultOK(res)) {
927
- fail_result("validate", res);
928
- }
929
-
930
- WasmEdge_ModuleInstanceContext *wasi =
931
- WasmEdge_ModuleInstanceCreateWASIWithFds(
932
- (const char *const *)(argv + 1),
933
- (uint32_t)(argc - 1),
934
- NULL,
935
- 0,
936
- NULL,
937
- 0,
938
- STDIN_FILENO,
939
- STDOUT_FILENO,
940
- STDERR_FILENO);
941
- res = WasmEdge_ExecutorRegisterImport(executor, store, wasi);
942
- if (!WasmEdge_ResultOK(res)) {
943
- fail_result("register wasi", res);
944
- }
945
-
946
- WasmEdge_ModuleInstanceContext *env =
947
- WasmEdge_ModuleInstanceCreate(WasmEdge_StringCreateByCString("env"));
948
- ImportedModuleConfig import_config;
949
- if (!read_imported_module_config(argv[1], &import_config)) {
950
- fprintf(stderr, "failed to inspect wasm import contract\n");
951
- return 1;
952
- }
953
- if (!add_imported_env_memory_from_file(argv[1], env, &runner.shared_memory)) {
954
- fprintf(stderr, "failed to create imported env memory\n");
955
- return 1;
956
- }
957
- register_env_host_functions(
958
- env,
959
- &runner,
960
- import_config.receive_on_main_thread_param_len == 4
961
- ? 4
962
- : 5,
963
- import_config.notify_mailbox_postmessage_param_len == 3
964
- ? 3
965
- : 2);
966
- res = WasmEdge_ExecutorRegisterImport(executor, store, env);
967
- if (!WasmEdge_ResultOK(res)) {
968
- fail_result("register env", res);
969
- }
970
-
971
- WasmEdge_ModuleInstanceContext *mod = NULL;
972
- res = WasmEdge_ExecutorInstantiate(executor, &mod, store, ast);
973
- if (!WasmEdge_ResultOK(res)) {
974
- fail_result("instantiate", res);
975
- }
976
-
977
- WasmEdge_String start_name = WasmEdge_StringCreateByCString("_start");
978
- WasmEdge_FunctionInstanceContext *start =
979
- WasmEdge_ModuleInstanceFindFunction(mod, start_name);
980
- WasmEdge_StringDelete(start_name);
981
- if (start == NULL) {
982
- fprintf(stderr, "_start not found\n");
983
- return 3;
984
- }
985
-
986
- res = WasmEdge_ExecutorInvoke(executor, start, NULL, 0, NULL, 0);
987
- if (!WasmEdge_ResultOK(res)) {
988
- fail_result("invoke", res);
989
- }
990
-
991
- const uint32_t exit_code = WasmEdge_ModuleInstanceWASIGetExitCode(wasi);
992
-
993
- WasmEdge_ASTModuleDelete(ast);
994
- WasmEdge_StoreDelete(store);
995
- WasmEdge_ExecutorDelete(executor);
996
- WasmEdge_ValidatorDelete(validator);
997
- WasmEdge_LoaderDelete(loader);
998
- WasmEdge_ConfigureDelete(conf);
999
- pthread_mutex_destroy(&runner.store_mutex);
1000
- return (int)exit_code;
1001
- }