@amxts/core 0.2.4 → 0.3.0

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 (71) hide show
  1. package/README.md +5 -5
  2. package/README.ru.md +5 -5
  3. package/as/amxts.d.ts +13 -3
  4. package/as/entities.ts +571 -501
  5. package/as/events.ts +3323 -557
  6. package/as/facade.ts +3079 -718
  7. package/as/fetch.ts +2 -2
  8. package/as/fs.ts +352 -59
  9. package/as/hlds.ts +121 -120
  10. package/as/hooks.ts +10585 -5177
  11. package/as/lib/check.ts +3 -2
  12. package/as/natives.ts +856 -1272
  13. package/as/promise.ts +37 -27
  14. package/as/vector.ts +94 -14
  15. package/includes/order.txt +17 -19
  16. package/node_modules/assemblyscript/std/assembly/index.d.ts +1 -1
  17. package/package.json +9 -6
  18. package/runtime/deps/assemblyscript/dist/asc.js +136 -42
  19. package/runtime/deps/assemblyscript/dist/assemblyscript.js +141 -141
  20. package/runtime/licenses/README.md +9 -7
  21. package/runtime/licenses/ReGameDLL-LICENSE +21 -0
  22. package/runtime/licenses/ReHLDS-LICENSE +21 -0
  23. package/runtime/licenses/zlib-LICENSE +22 -0
  24. package/runtime/natives.txt +618 -523
  25. package/runtime/patches/README.md +87 -1
  26. package/runtime/patches/assemblyscript-0.28.20-amxts.patch +4838 -416
  27. package/runtime/patches/wamr-2.4.5-amxts.patch +417 -5
  28. package/scripts/auto-imports.ts +1 -1
  29. package/scripts/build-identity.ts +102 -65
  30. package/scripts/build-wasm.ts +12 -12
  31. package/scripts/check.ts +4 -1
  32. package/scripts/client-messages.ts +73 -1
  33. package/scripts/compile-cache.ts +11 -8
  34. package/scripts/compile-pool.ts +6 -3
  35. package/scripts/compile-worker.ts +23 -23
  36. package/scripts/compile.ts +142 -19
  37. package/scripts/docs/as/amxts.ts +10 -4
  38. package/scripts/docs/as/facade.ts +1779 -275
  39. package/scripts/docs/as/fetch.ts +2 -2
  40. package/scripts/docs/as/fs.ts +190 -6
  41. package/scripts/docs/as/vector.ts +81 -0
  42. package/scripts/docs/entities.ts +12 -0
  43. package/scripts/docs/events.ts +49 -13
  44. package/scripts/docs/game.ts +6 -0
  45. package/scripts/docs/messages.ts +10 -1
  46. package/scripts/hlds-events.ts +11 -11
  47. package/scripts/includes.ts +3 -4
  48. package/scripts/leaf-natives.ts +84 -0
  49. package/scripts/player-fields.ts +1 -1
  50. package/scripts/plugin-natives.ts +1 -1
  51. package/scripts/prebuilt.ts +41 -10
  52. package/scripts/project.ts +2 -3
  53. package/scripts/reapi-events.ts +9 -9
  54. package/scripts/server-env.ts +145 -0
  55. package/scripts/shared-modules.ts +23 -7
  56. package/scripts/system.ts +1 -1
  57. package/scripts/tracked-fs.ts +11 -2
  58. package/scripts/typed-commands.ts +153 -15
  59. package/scripts/upgrade-calls.ts +225 -0
  60. package/scripts/upgrade-names.ts +1 -4
  61. package/scripts/upgrade.ts +26 -11
  62. package/src/cli-api.mjs +3 -2
  63. package/src/system.mjs +21 -11
  64. package/src/testing/compile.ts +31 -8
  65. package/src/testing/coroutines.ts +0 -10
  66. package/src/testing/memory.ts +89 -2
  67. package/src/testing/natives.ts +67 -30
  68. package/src/testing/server.ts +1094 -155
  69. package/src/testing/tables.ts +23 -6
  70. package/src/typecheck.mjs +110 -0
  71. package/runtime/licenses/Bun-LICENSE.md +0 -84
@@ -163,7 +163,7 @@ index 771ef87..7bdb74d 100644
163
163
  }
164
164
  }
165
165
  diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c
166
- index d2621fb..47178c4 100644
166
+ index d2621fb..1538532 100644
167
167
  --- a/core/iwasm/aot/aot_runtime.c
168
168
  +++ b/core/iwasm/aot/aot_runtime.c
169
169
  @@ -2682,9 +2682,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
@@ -192,7 +192,134 @@ index d2621fb..47178c4 100644
192
192
  #endif
193
193
  }
194
194
 
195
- @@ -3414,6 +3414,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
195
+ @@ -2773,6 +2773,126 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
196
+ }
197
+ }
198
+
199
+ +#if WASM_ENABLE_AOT_STACK_FRAME != 0
200
+ +static bool
201
+ +aot_alloc_standard_frame(WASMExecEnv *exec_env, uint32 func_index);
202
+ +#endif
203
+ +
204
+ +/* amxts: a direct call, see wasm_runtime_direct_entry in wasm_export.h */
205
+ +void *
206
+ +wasm_runtime_direct_entry(WASMFunctionInstanceCommon *function)
207
+ +{
208
+ + AOTFunctionInstance *func = (AOTFunctionInstance *)function;
209
+ +
210
+ + return func->is_import_func ? NULL : func->u.func.func_ptr;
211
+ +}
212
+ +
213
+ +/* amxts: see wasm_runtime_memory_view in wasm_export.h */
214
+ +uint8_t *
215
+ +wasm_runtime_memory_view(WASMExecEnv *exec_env, uint64_t *size)
216
+ +{
217
+ + WASMMemoryInstance *memory =
218
+ + wasm_get_default_memory((WASMModuleInstance *)exec_env->module_inst);
219
+ +
220
+ + if (!memory) {
221
+ + *size = 0;
222
+ + return NULL;
223
+ + }
224
+ + *size = memory->memory_data_size;
225
+ + return memory->memory_data;
226
+ +}
227
+ +
228
+ +uint32_t
229
+ +wasm_runtime_direct_frames(WASMModuleInstanceCommon *module_inst)
230
+ +{
231
+ +#if WASM_ENABLE_AOT_STACK_FRAME != 0
232
+ + return (uint32_t)(((AOTModule *)((AOTModuleInstance *)module_inst)->module)
233
+ + ->feature_flags
234
+ + & (WASM_FEATURE_TINY_STACK_FRAME
235
+ + | WASM_FEATURE_FRAME_PER_FUNCTION));
236
+ +#else
237
+ + (void)module_inst;
238
+ + return 0;
239
+ +#endif
240
+ +}
241
+ +
242
+ +/* written into the host's call where the compiler can (link-time code
243
+ + generation, MSVC's and GCC's): it runs before every direct call */
244
+ +#if defined(_MSC_VER)
245
+ +__forceinline
246
+ +#elif defined(__GNUC__)
247
+ +__attribute__((always_inline))
248
+ +#endif
249
+ +bool
250
+ +wasm_runtime_direct_begin(WASMExecEnv *exec_env,
251
+ + WASMFunctionInstanceCommon *function, uint32_t frames,
252
+ + void **mark)
253
+ +{
254
+ + AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
255
+ +
256
+ + /* the thread is the one the exec env first ran on, its stack the same */
257
+ + if (!exec_env->native_stack_boundary)
258
+ + wasm_exec_env_set_thread_info(exec_env);
259
+ +#if WASM_ENABLE_AOT_STACK_FRAME != 0
260
+ + {
261
+ + /* the frames as aot_alloc_frame keeps them; the mark is where they
262
+ + stand, a tiny frame's top or a standard frame, for
263
+ + wasm_runtime_direct_end to put them back */
264
+ + uint32 flags = frames;
265
+ + uint32 func_index = ((AOTFunctionInstance *)function)->func_index;
266
+ +
267
+ + if (flags & WASM_FEATURE_TINY_STACK_FRAME) {
268
+ + AOTTinyFrame *frame = (AOTTinyFrame *)exec_env->wasm_stack.top;
269
+ +
270
+ + *mark = frame;
271
+ + if (!(flags & WASM_FEATURE_FRAME_PER_FUNCTION)) {
272
+ + if ((uint8 *)frame > exec_env->wasm_stack.top_boundary) {
273
+ + aot_set_exception(module_inst,
274
+ + "wasm operand stack overflow");
275
+ + return false;
276
+ + }
277
+ + frame->func_index = func_index;
278
+ + exec_env->wasm_stack.top += sizeof(AOTTinyFrame);
279
+ + }
280
+ + }
281
+ + else {
282
+ + *mark = exec_env->cur_frame;
283
+ + if (!(flags & WASM_FEATURE_FRAME_PER_FUNCTION)
284
+ + && !aot_alloc_standard_frame(exec_env, func_index))
285
+ + return false;
286
+ + }
287
+ + }
288
+ +#else
289
+ + (void)frames;
290
+ + *mark = NULL;
291
+ +#endif
292
+ + module_inst->cur_exec_env = exec_env;
293
+ + return true;
294
+ +}
295
+ +
296
+ +bool
297
+ +wasm_runtime_direct_end(WASMExecEnv *exec_env, uint32_t frames, void *mark)
298
+ +{
299
+ + AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
300
+ + bool ret = module_inst->cur_exception[0] == '\0';
301
+ +
302
+ +#if WASM_ENABLE_DUMP_CALL_STACK != 0
303
+ + if (!ret)
304
+ + aot_create_call_stack(exec_env);
305
+ +#endif
306
+ +#if WASM_ENABLE_AOT_STACK_FRAME != 0
307
+ + /* the frames the call left taken off, down to the mark at once: what
308
+ + aot_free_frame does one at a time */
309
+ + if (frames & WASM_FEATURE_TINY_STACK_FRAME)
310
+ + exec_env->wasm_stack.top = (uint8 *)mark;
311
+ + else
312
+ + exec_env->cur_frame = (struct WASMInterpFrame *)mark;
313
+ +#endif
314
+ + (void)frames;
315
+ + (void)mark;
316
+ + return ret;
317
+ +}
318
+ +
319
+ void
320
+ aot_set_exception(AOTModuleInstance *module_inst, const char *exception)
321
+ {
322
+ @@ -3414,6 +3534,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
196
323
  #endif
197
324
  ret = invoke_native_internal(exec_env, func_ptr, func_type, signature,
198
325
  attachment, argv1, argc, argv);
@@ -204,7 +331,7 @@ index d2621fb..47178c4 100644
204
331
  #if WASM_ENABLE_AOT_STACK_FRAME != 0
205
332
  /* Free all frames allocated, note that some frames
206
333
  may be allocated in AOT code and haven't been
207
- @@ -3474,6 +3479,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
334
+ @@ -3474,6 +3599,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
208
335
  #endif
209
336
  ret = invoke_native_internal(exec_env, func_ptr, func_type, signature,
210
337
  attachment, argv, argc, argv);
@@ -341,11 +468,223 @@ index 82f70ca..ea501fb 100644
341
468
 
342
469
  while (frame_ip < frame_ip_end) {
343
470
  opcode = *frame_ip++;
471
+ diff --git a/core/iwasm/compilation/aot_emit_conversion.c b/core/iwasm/compilation/aot_emit_conversion.c
472
+ index fa5c2ab..0317f29 100644
473
+ --- a/core/iwasm/compilation/aot_emit_conversion.c
474
+ +++ b/core/iwasm/compilation/aot_emit_conversion.c
475
+ @@ -254,6 +254,74 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
476
+ res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic,
477
+ dest_type, &src_type, 1, operand);
478
+ }
479
+ + else if (sign && dest_type == I64_TYPE && src_type == F64_TYPE
480
+ + && !comp_ctx->is_indirect_mode
481
+ + && !strncmp(comp_ctx->target_arch, "i386", 4)) {
482
+ + /* amxts: on i386 a double becomes a 64-bit integer through the
483
+ + x87 - a store, fld, two fldcw and fistp - while one within 32
484
+ + bits, which is nearly every one (a number made a cell is
485
+ + trunc_sat to 64 bits and a wrap), takes SSE2's cvttsd2si. */
486
+ + LLVMBasicBlockRef narrow_block, wide_block, joined_block;
487
+ + LLVMValueRef fits, narrow, wide, branch;
488
+ + LLVMMetadataRef weights[3];
489
+ +
490
+ + fits = LLVMBuildAnd(
491
+ + comp_ctx->builder,
492
+ + LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGT, operand,
493
+ + F64_CONST(-2147483649.0), "above_i32_min"),
494
+ + LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLT, operand,
495
+ + F64_CONST(2147483648.0), "below_i32_max"),
496
+ + "fits_i32");
497
+ + ADD_BASIC_BLOCK(joined_block, "trunc_joined");
498
+ + ADD_BASIC_BLOCK(wide_block, "trunc_wide");
499
+ + ADD_BASIC_BLOCK(narrow_block, "trunc_narrow");
500
+ + if (!fits
501
+ + || !(branch = LLVMBuildCondBr(comp_ctx->builder, fits,
502
+ + narrow_block, wide_block))) {
503
+ + aot_set_last_error("llvm build cond br failed.");
504
+ + goto fail;
505
+ + }
506
+ + /* Weighted as nearly always narrow, or LLVM makes it a select
507
+ + and runs the x87 path every time too. */
508
+ + weights[0] = LLVMMDStringInContext2(comp_ctx->context,
509
+ + "branch_weights", 14);
510
+ + weights[1] = LLVMValueAsMetadata(I32_CONST(2000));
511
+ + weights[2] = LLVMValueAsMetadata(I32_CONST(1));
512
+ + LLVMSetMetadata(
513
+ + branch,
514
+ + LLVMGetMDKindIDInContext(comp_ctx->context, "prof", 4),
515
+ + LLVMMetadataAsValue(comp_ctx->context,
516
+ + LLVMMDNodeInContext2(comp_ctx->context,
517
+ + weights, 3)));
518
+ +
519
+ + LLVMPositionBuilderAtEnd(comp_ctx->builder, narrow_block);
520
+ + narrow = LLVMBuildSExt(
521
+ + comp_ctx->builder,
522
+ + LLVMBuildFPToSI(comp_ctx->builder, operand, I32_TYPE,
523
+ + "trunc_i32"),
524
+ + I64_TYPE, "trunc_i32_wide");
525
+ + if (!narrow || !LLVMBuildBr(comp_ctx->builder, joined_block)) {
526
+ + aot_set_last_error("llvm build br failed.");
527
+ + goto fail;
528
+ + }
529
+ +
530
+ + LLVMPositionBuilderAtEnd(comp_ctx->builder, wide_block);
531
+ + wide = LLVMBuildFPToSI(comp_ctx->builder, operand, I64_TYPE, name);
532
+ + if (!wide || !LLVMBuildBr(comp_ctx->builder, joined_block)) {
533
+ + aot_set_last_error("llvm build br failed.");
534
+ + goto fail;
535
+ + }
536
+ +
537
+ + LLVMPositionBuilderAtEnd(comp_ctx->builder, joined_block);
538
+ + if (!(res = LLVMBuildPhi(comp_ctx->builder, I64_TYPE,
539
+ + "trunc_joined_phi"))) {
540
+ + aot_set_last_error("llvm build phi failed.");
541
+ + goto fail;
542
+ + }
543
+ + LLVMAddIncoming(res, &narrow, &narrow_block, 1);
544
+ + LLVMAddIncoming(res, &wide, &wide_block, 1);
545
+ + check_greater_succ = joined_block;
546
+ + }
547
+ else {
548
+ if (sign) {
549
+ res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type,
550
+ @@ -319,6 +387,83 @@ fail:
551
+ return false;
552
+ }
553
+
554
+ +/* amxts: i32.trunc_sat_f64_s on i386 with SSE2 as cvttsd2si itself, which
555
+ + answers 0x80000000 for NaN and for a number out of i32's range: only that
556
+ + answer, rare, takes the branch that saturates. WAMR's own way tests NaN,
557
+ + the bottom and the top, a branch each, around every conversion: a `%`
558
+ + checks both its numbers are whole this way, and the three branches cost a
559
+ + remainder of two numbers that change in a loop a tenth of its time. */
560
+ +static bool
561
+ +trunc_sat_f64_to_i32_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
562
+ + LLVMValueRef operand)
563
+ +{
564
+ + LLVMBasicBlockRef fast_block, slow_block, res_block;
565
+ + LLVMTypeRef vector_type = LLVMVectorType(F64_TYPE, 2);
566
+ + LLVMValueRef vector, raw, indefinite, branch, nan, positive, slow, phi;
567
+ + LLVMMetadataRef weights[3];
568
+ +
569
+ + if (!(vector = LLVMBuildInsertElement(comp_ctx->builder,
570
+ + LLVMGetUndef(vector_type), operand,
571
+ + I32_ZERO, "cvttsd2si_in"))
572
+ + || !(raw = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
573
+ + "llvm.x86.sse2.cvttsd2si", I32_TYPE,
574
+ + &vector_type, 1, vector))
575
+ + || !(indefinite =
576
+ + LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, raw,
577
+ + I32_CONST(INT32_MIN), "cvttsd2si_indefinite"))) {
578
+ + aot_set_last_error("llvm build conversion failed.");
579
+ + return false;
580
+ + }
581
+ +
582
+ + fast_block = LLVMGetInsertBlock(comp_ctx->builder);
583
+ + ADD_BASIC_BLOCK(res_block, "trunc_sat_done");
584
+ + ADD_BASIC_BLOCK(slow_block, "trunc_sat_edge");
585
+ + if (!(branch = LLVMBuildCondBr(comp_ctx->builder, indefinite, slow_block,
586
+ + res_block))) {
587
+ + aot_set_last_error("llvm build cond br failed.");
588
+ + goto fail;
589
+ + }
590
+ + /* Weighted as nearly never the edge. */
591
+ + weights[0] =
592
+ + LLVMMDStringInContext2(comp_ctx->context, "branch_weights", 14);
593
+ + weights[1] = LLVMValueAsMetadata(I32_CONST(1));
594
+ + weights[2] = LLVMValueAsMetadata(I32_CONST(2000));
595
+ + LLVMSetMetadata(
596
+ + branch, LLVMGetMDKindIDInContext(comp_ctx->context, "prof", 4),
597
+ + LLVMMetadataAsValue(comp_ctx->context,
598
+ + LLVMMDNodeInContext2(comp_ctx->context, weights, 3)));
599
+ +
600
+ + /* NaN is 0, a number above the range INT32_MAX, any other INT32_MIN -
601
+ + -2^31 itself among them. */
602
+ + LLVMPositionBuilderAtEnd(comp_ctx->builder, slow_block);
603
+ + if (!(nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand,
604
+ + operand, "is_nan"))
605
+ + || !(positive = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGT, operand,
606
+ + F64_CONST(0.0), "is_positive"))
607
+ + || !(slow = LLVMBuildSelect(
608
+ + comp_ctx->builder, nan, I32_ZERO,
609
+ + LLVMBuildSelect(comp_ctx->builder, positive,
610
+ + I32_CONST(INT32_MAX), I32_CONST(INT32_MIN),
611
+ + "saturated"),
612
+ + "saturated_or_nan"))
613
+ + || !LLVMBuildBr(comp_ctx->builder, res_block)) {
614
+ + aot_set_last_error("llvm build conversion failed.");
615
+ + goto fail;
616
+ + }
617
+ +
618
+ + LLVMPositionBuilderAtEnd(comp_ctx->builder, res_block);
619
+ + if (!(phi = LLVMBuildPhi(comp_ctx->builder, I32_TYPE, "trunc_sat_phi"))) {
620
+ + aot_set_last_error("llvm build phi failed.");
621
+ + goto fail;
622
+ + }
623
+ + LLVMAddIncoming(phi, &raw, &fast_block, 1);
624
+ + LLVMAddIncoming(phi, &slow, &slow_block, 1);
625
+ + PUSH_I32(phi);
626
+ + return true;
627
+ +fail:
628
+ + return false;
629
+ +}
630
+ +
631
+ bool
632
+ aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
633
+ {
634
+ @@ -438,6 +583,11 @@ aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
635
+ return trunc_float_to_int(
636
+ comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
637
+ sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
638
+ + else if (sign && !comp_ctx->is_indirect_mode
639
+ + && !comp_ctx->disable_llvm_intrinsics
640
+ + && !strncmp(comp_ctx->target_arch, "i386", 4)
641
+ + && aot_target_has_sse2(comp_ctx))
642
+ + return trunc_sat_f64_to_i32_x86(comp_ctx, func_ctx, value);
643
+ else
644
+ return trunc_sat_float_to_int(
645
+ comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
646
+ diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h
647
+ index 9f62f66..b8cb7d3 100644
648
+ --- a/core/iwasm/compilation/aot_llvm.h
649
+ +++ b/core/iwasm/compilation/aot_llvm.h
650
+ @@ -644,6 +644,10 @@ aot_load_const_from_table(AOTCompContext *comp_ctx, LLVMValueRef base,
651
+ bool
652
+ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
653
+
654
+ +/* amxts: whether the machine code is for a CPU with SSE2. */
655
+ +bool
656
+ +aot_target_has_sse2(const AOTCompContext *comp_ctx);
657
+ +
658
+ void
659
+ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module);
660
+
661
+ diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp
662
+ index 35b25c8..f06a36c 100644
663
+ --- a/core/iwasm/compilation/aot_llvm_extra.cpp
664
+ +++ b/core/iwasm/compilation/aot_llvm_extra.cpp
665
+ @@ -145,6 +145,17 @@ ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM)
666
+ return PA;
667
+ }
668
+
669
+ +/* amxts: whether the machine code is for a CPU with SSE2: --cpu=pentium4
670
+ + and every one after it, not a bare --target=i386. */
671
+ +bool
672
+ +aot_target_has_sse2(const AOTCompContext *comp_ctx)
673
+ +{
674
+ + const llvm::MCSubtargetInfo *info =
675
+ + reinterpret_cast<llvm::TargetMachine *>(comp_ctx->target_machine)
676
+ + ->getMCSubtargetInfo();
677
+ + return info != nullptr && info->checkFeatures("+sse2");
678
+ +}
679
+ +
680
+ bool
681
+ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
682
+ {
344
683
  diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h
345
- index 81efb8f..2d80cf2 100644
684
+ index 81efb8f..3a08bbe 100644
346
685
  --- a/core/iwasm/include/wasm_export.h
347
686
  +++ b/core/iwasm/include/wasm_export.h
348
- @@ -2075,6 +2075,20 @@ WASM_RUNTIME_API_EXTERN uint32_t
687
+ @@ -2075,6 +2075,93 @@ WASM_RUNTIME_API_EXTERN uint32_t
349
688
  wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf,
350
689
  uint32_t len);
351
690
 
@@ -362,6 +701,79 @@ index 81efb8f..2d80cf2 100644
362
701
  +WASM_RUNTIME_API_EXTERN uint32_t
363
702
  +wasm_runtime_take_trap_frames(wasm_module_inst_t module_inst,
364
703
  + WASMCApiFrame *buffer, uint32_t length);
704
+ +
705
+ +/**
706
+ + * amxts: the machine code of an AOT function, for a host that calls it
707
+ + * itself, many times, rather than through wasm_runtime_call_wasm: called as
708
+ + * `result fn(wasm_exec_env_t, params...)` with the C types of its wasm ones
709
+ + * (i32 int32_t, i64 int64_t, f32 float, f64 double), between
710
+ + * wasm_runtime_direct_begin and wasm_runtime_direct_end, always on the
711
+ + * thread the exec env first ran on: its native stack's boundary, which the
712
+ + * code checks, is set once.
713
+ + *
714
+ + * @param function the function, of an AOT module
715
+ + *
716
+ + * @return its machine code, or NULL for an imported function
717
+ + */
718
+ +WASM_RUNTIME_API_EXTERN void *
719
+ +wasm_runtime_direct_entry(wasm_function_inst_t function);
720
+ +
721
+ +/**
722
+ + * amxts: the linear memory of the instance an exec env runs, as it is now:
723
+ + * where it starts in the host, and its size. A native reads and writes the
724
+ + * plugin's memory through it without asking for each address; the memory
725
+ + * moves when it grows, so it is asked again after anything that may run the
726
+ + * plugin's code.
727
+ + *
728
+ + * @param exec_env the exec env
729
+ + * @param size where its size in bytes goes
730
+ + *
731
+ + * @return where it starts, or NULL with a size of 0 when it has none
732
+ + */
733
+ +WASM_RUNTIME_API_EXTERN uint8_t *
734
+ +wasm_runtime_memory_view(wasm_exec_env_t exec_env, uint64_t *size);
735
+ +
736
+ +/**
737
+ + * amxts: how an instance's AOT code keeps its frames, for
738
+ + * wasm_runtime_direct_begin and wasm_runtime_direct_end: read once, as the
739
+ + * module was compiled.
740
+ + *
741
+ + * @param module_inst the instance
742
+ + *
743
+ + * @return its frames' kind
744
+ + */
745
+ +WASM_RUNTIME_API_EXTERN uint32_t
746
+ +wasm_runtime_direct_frames(wasm_module_inst_t module_inst);
747
+ +
748
+ +/**
749
+ + * amxts: before a direct call (wasm_runtime_direct_entry): the frame the
750
+ + * call's stack starts with, and the instance's exec env.
751
+ + *
752
+ + * @param exec_env the exec env the call runs in
753
+ + * @param function the function called
754
+ + * @param frames what wasm_runtime_direct_frames gave for its instance
755
+ + * @param mark where the frames stand, for wasm_runtime_direct_end
756
+ + *
757
+ + * @return false, with an exception set, when the call has no room
758
+ + */
759
+ +WASM_RUNTIME_API_EXTERN bool
760
+ +wasm_runtime_direct_begin(wasm_exec_env_t exec_env,
761
+ + wasm_function_inst_t function, uint32_t frames,
762
+ + void **mark);
763
+ +
764
+ +/**
765
+ + * amxts: after a direct call: whether it ended without an exception - a
766
+ + * failed one keeps its frames for wasm_runtime_take_trap_frames - and the
767
+ + * frames it left taken off.
768
+ + *
769
+ + * @param exec_env the exec env the call ran in
770
+ + * @param frames what wasm_runtime_direct_frames gave for its instance
771
+ + * @param mark what wasm_runtime_direct_begin gave
772
+ + *
773
+ + * @return true when the call succeeded
774
+ + */
775
+ +WASM_RUNTIME_API_EXTERN bool
776
+ +wasm_runtime_direct_end(wasm_exec_env_t exec_env, uint32_t frames, void *mark);
365
777
  +
366
778
  /**
367
779
  * Get the size required to store the LLVM PGO profile data
@@ -68,7 +68,7 @@ export const CORE = '@amxts/core';
68
68
  */
69
69
  export const HOOD = new Set([
70
70
  // Cells and raw handlers.
71
- 'Call CellArray CellBuffer Handler WideHandler NoArgument arg argc argString argText cell cellFloat cells cellsToString cmd cmdWide floatCell handled hook hostIndex nativeFn noOrigin out paint playerIds publicFor putCell readText ret setArg setArgText stringToCells swapTeam text TEXT_MAX',
71
+ 'Call CellArray CellBuffer Handler WideHandler NoArgument arg argc argString argText cell cellFloat cells cellsToString cmd cmdWide floatCell handled hook unhook hostIndex nativeFn noOrigin out paint playerIds publicFor putCell readText ret setArg setArgText stringToCells swapTeam text TEXT_MAX',
72
72
  // The kit's.
73
73
  'caller callingPlugin cellArrayRows cellsText colorTags createCellArray defineModule destroyCellArray menuColors onPluginStop PawnCall PawnFunction pushCellArrayRow request RequestErrorKind RequestOptions RequestResult showMenu textCells',
74
74
  // The generated listener and flag tables.
@@ -1,20 +1,12 @@
1
- // The build a module and the compiler beside it on a server are of: the
2
- // version and the commit, as a release's manifest names them -
3
- // `0.2.0+1bf291c0ab`, SemVer's build metadata.
4
- //
5
- // `bun run generate` writes it into the module (runtime/src/embedded.h), and
6
- // `bun run serverkit` builds amxts-compile with the one read back from there,
7
- // so the two agree whenever they come from one build. Before it compiles a
8
- // plugin's source, the module asks the compiler for its build
9
- // (`amxts-compile --version`) and refuses one of another: the module writes
10
- // the API a plugin imports, and a compiler of another release reads it with
11
- // another AssemblyScript, which fails with errors that say nothing of why.
1
+ // The build a module is of: the version and the commit, as a release's
2
+ // manifest names them - `0.2.0+1bf291c0ab`, SemVer's build metadata.
3
+ // `bun run generate` writes it into the module (runtime/src/embedded.h).
12
4
  //
13
5
  // A plugin carries an identity of its own: the ABI it was compiled against,
14
6
  // which the module checks before it loads the plugin (abiIdentity, below).
15
7
  import { spawnSync } from 'node:child_process';
16
8
  import { createHash } from 'node:crypto';
17
- import { existsSync, readFileSync } from 'node:fs';
9
+ import { existsSync } from 'node:fs';
18
10
  import { dirname, join, resolve } from 'node:path';
19
11
  import process from 'node:process';
20
12
  import { fileURLToPath } from 'node:url';
@@ -38,46 +30,44 @@ export function buildIdentity(): string {
38
30
  return commit ? `${coreVersion()}+${commit}` : coreVersion();
39
31
  }
40
32
 
41
- /** A string the generated module carries (`#define <name> "..."`), or null before `bun run generate`. */
42
- function moduleDefine(name: string): string | null {
43
- const header = './runtime/src/embedded.h';
44
- if (!existsSync(header)) return null;
45
- return new RegExp(`^#define ${name} "([^"]*)"$`, 'm').exec(readFileSync(header, 'utf-8'))?.[1] ?? null;
46
- }
47
-
48
- /** The build the generated module carries, or null before `bun run generate`. */
49
- export const moduleBuild = () => moduleDefine('AMXTS_BUILD');
50
-
51
- /** The ABI the generated module loads plugins of, or null before `bun run generate`. */
52
- export const moduleAbi = () => moduleDefine('AMXTS_ABI');
53
-
54
- /** The `--define`s that build amxts-compile as of `build`, stamping plugins with `abi`. */
55
- export function buildDefines(build: string, abi: string): string[] {
56
- return [`--define=AMXTS_BUILD=${JSON.stringify(build)}`, `--define=AMXTS_ABI=${JSON.stringify(abi)}`];
57
- }
58
-
59
33
  // ---------------------------------------------------------------- the ABI
60
34
  //
61
- // What a plugin and the module have to agree on: the imports the hood
62
- // declares (`@external("env", ...)` in as/, by name and by the types they
63
- // take and give) and the natives table wamrc compiles direct calls against
64
- // (runtime/natives.txt). A plugin of another ABI calls an import the module
65
- // does not have, or has with another signature, and the server crashes; so
66
- // the module loads no plugin whose ABI is not its own.
35
+ // What a plugin and the module have to agree on, in two parts.
36
+ //
37
+ // The ground: the machine code's - the WAMR patch, which both wamrc and the
38
+ // module's runtime are built with, and the versions of WAMR and
39
+ // AssemblyScript the patches are for (AssemblyScript lays out the strings the
40
+ // module reads) - and ABI_REVISION. It is the version and a hash of those,
41
+ // `0.3.1+abi.1a2b3c4d`, which the module carries as its own (AMXTS_ABI).
67
42
  //
68
- // It is the version and a hash of those - `0.2.0+abi.1a2b3c4d`. Not the
69
- // commit: a module from a release and the plugins built with the core from
70
- // npm, or a module package's prebuilt plugin, are of one release but not
71
- // built from one checkout. The version tells releases apart; the hash, builds
72
- // of one version whose imports differ. The same release rebuilt is the same
73
- // ABI, and a change that is only the facade's own code needs no rebuilt
74
- // plugins.
43
+ // The imports: every function the plugin imports, each with its shape - its
44
+ // line of the natives table (runtime/natives.txt), which holds every import
45
+ // the module has, the hood's own and Pawn's natives alike: the types wamrc
46
+ // compiles a direct call with, how the module's thunk passes the arguments,
47
+ // and `leaf`. A plugin carries the ground's identity, then the shape of each
48
+ // import it uses (pluginAbi), and the module loads it when the line and the
49
+ // ground are its own and it has every import with the same shape. So a
50
+ // plugin built by any patch of a line loads on any patch's module that has
51
+ // what it uses, and a module package's prebuilt plugin serves the whole line:
52
+ // a patch adds imports, and only what uses them needs it. An import keeps
53
+ // its shape for the line (shapeChanges): a change of shape is a new import.
54
+ //
55
+ // The full version stays in the identity to be read: the release a module
56
+ // is of (src/system.mjs), what a refusal names. Not the commit: a module from
57
+ // a release and the plugins built with the core from npm, or a module
58
+ // package's prebuilt plugin, are of one release but not built from one
59
+ // checkout. Not the facade's code: it is compiled into each plugin, which
60
+ // carries its own, so plugins of two patches talk only through the imports -
61
+ // and, between a module and the plugins that use it, through the module's
62
+ // surface, whose own hash the module checks when a plugin first calls it
63
+ // (scripts/shared-modules.ts).
75
64
 
76
65
  /**
77
66
  * Raised by hand when the module and the facade change how they talk without
78
- * an import changing its name or its types: what a cell of an event means,
79
- * an export the module calls, what names a plugin in a shared module's call
80
- * (2: its run, not its index).
67
+ * an import's shape or the patches changing: what a cell of an event means,
68
+ * an export the module calls, how a value crosses between plugins
69
+ * (as/remote.ts), what names a plugin in a shared module's call (2: its run,
70
+ * not its index). A patch release must not raise it.
81
71
  */
82
72
  const ABI_REVISION = 2;
83
73
 
@@ -86,30 +76,77 @@ export const ABI_SECTION = 'amxts.abi';
86
76
 
87
77
  const CORE = resolve(dirname(fileURLToPath(import.meta.url)), '..');
88
78
 
89
- // One import: `@external("env", "ent_get") declare function _entGet(id: i32, offset: i32): i32;`.
90
- const IMPORT = /@external\("env",\s*"([^"]+)"\)\s*(?:export\s+)?declare\s+function\s+\w+\s*\(([^)]*)\)\s*(?::([^;]+))?;/g;
91
-
92
- /** The imports a file of the hood declares: `ent_get(i32,i32)i32`, the parameters' names left out. */
93
- export function importsOf(code: string): string[] {
94
- return [...code.matchAll(IMPORT)].map(([, name, params, result]) => {
95
- const types = params.split(',').map(param => param.slice(param.indexOf(':') + 1).trim()).filter(Boolean);
96
- return `${name}(${types.join(',')})${result?.trim() ?? 'void'}`;
97
- });
79
+ /** The natives table a compile reads: AMXTS_NATIVES, else the core's. */
80
+ export function nativesFile(): string | undefined {
81
+ return [process.env.AMXTS_NATIVES, join(CORE, 'runtime/natives.txt')].find(each => each && existsSync(each));
98
82
  }
99
83
 
100
- declare const AMXTS_ABI: string;
84
+ /** A natives table's lines, but its comments: `add (iiii)i [a1>,v,s,v leaf`. */
85
+ const tableLines = (text: string) => text.split(/\r?\n/).filter(line => line && !line.startsWith('#'));
86
+
87
+ /** The name of an import's shape: `add` of `add (iiii)i [a1>,v,s,v leaf`. */
88
+ export const importName = (shape: string) => shape.split(' ', 1)[0];
89
+
90
+ /** Every import there is, by name, with its shape. */
91
+ export function importShapes(): Map<string, string> {
92
+ const file = nativesFile();
93
+ const lines = file ? tableLines(tracked.readFileSync(file, 'utf8')) : [];
94
+ return new Map(lines.map(line => [importName(line), line]));
95
+ }
101
96
 
102
97
  /**
103
- * The ABI this core compiles plugins for, which the module it builds loads.
104
- * amxts-compile on a server has the module's own built in; anywhere else it
105
- * is read off the hood's files, through the tracked reads, so a cached
106
- * compile is made again when they change.
98
+ * The ground this core compiles plugins on, which the module it builds loads
99
+ * plugins of: `0.3.1+abi.1a2b3c4d`. It is read off the patches, through the
100
+ * tracked reads, so a cached compile is made again when they change.
107
101
  */
108
102
  export function abiIdentity(): string {
109
- if (typeof AMXTS_ABI === 'string') return AMXTS_ABI;
110
- const plugins = join(CORE, 'as');
111
- const imports = tracked.readdirSync(plugins).filter(file => file.endsWith('.ts')).flatMap(file => importsOf(tracked.readFileSync(join(plugins, file), 'utf8')));
112
- const natives = tracked.readFileSync(join(CORE, 'runtime/natives.txt'), 'utf8').split(/\r?\n/).filter(Boolean);
113
- const hash = createHash('sha256').update([`revision ${ABI_REVISION}`, ...imports.sort(), ...natives.sort()].join('\n')).digest('hex');
103
+ // A patch by its name, which carries the upstream version; WAMR's by its content too.
104
+ const dir = join(CORE, 'runtime/patches');
105
+ const patches = tracked.readdirSync(dir).filter(file => file.endsWith('.patch')).map(file => (file.startsWith('wamr-') ? `${file}\n${tracked.readFileSync(join(dir, file), 'utf8')}` : file));
106
+ const hash = createHash('sha256').update([`revision ${ABI_REVISION}`, ...patches.sort()].join('\n')).digest('hex');
114
107
  return `${coreVersion()}+abi.${hash.slice(0, 8)}`;
115
108
  }
109
+
110
+ /**
111
+ * The ABI section of a plugin that imports `imports` (`env.add`, as a wasm
112
+ * names them): the identity, then the shape of each import, a line each.
113
+ */
114
+ export function pluginAbi(imports: Iterable<string>): string {
115
+ const shapes = importShapes();
116
+ const used = [...imports].filter(each => each.startsWith('env.')).map(each => shapes.get(each.slice(4)) ?? each.slice(4));
117
+ return [abiIdentity(), ...used.sort()].join('\n');
118
+ }
119
+
120
+ /**
121
+ * The imports of the line's last release, each with its shape, relative to
122
+ * the core: `bun run abi:lock` writes it when a version is released.
123
+ */
124
+ export const ABI_LOCK = 'runtime/abi-lock.txt';
125
+
126
+ /**
127
+ * The shapes of a released lock (runtime/abi-lock.txt: the version, then
128
+ * every import of it) that a natives table has no longer, or has otherwise,
129
+ * while the two are of one line: a plugin built for that release would be
130
+ * refused by this one's module. Another line owes the lock nothing.
131
+ */
132
+ export function shapeChanges(lock: string, natives: string, version = coreVersion()): string[] {
133
+ const [released = '', ...shapes] = tableLines(lock);
134
+ if (releaseLine(released) !== releaseLine(version)) return [];
135
+ const now = new Set(tableLines(natives));
136
+ return shapes.filter(shape => !now.has(shape));
137
+ }
138
+
139
+ /** The line of a version, `major.minor`: `0.3` of `0.3.1` and of `0.3.0-rc.1`. */
140
+ export function releaseLine(version: string): string {
141
+ return version.split('.', 2).join('.');
142
+ }
143
+
144
+ /**
145
+ * What the module compares of an identity: its line and its ground's hash,
146
+ * `0.3+abi.1a2b3c4d` of `0.3.1+abi.1a2b3c4d`. The modules of two identities
147
+ * with one abiLine load each other's plugins, of the imports they both have.
148
+ */
149
+ export function abiLine(abi: string): string {
150
+ const at = abi.indexOf('+');
151
+ return at < 0 ? abi : `${releaseLine(abi.slice(0, at))}${abi.slice(at)}`;
152
+ }