@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.
- package/README.md +5 -5
- package/README.ru.md +5 -5
- package/as/amxts.d.ts +13 -3
- package/as/entities.ts +571 -501
- package/as/events.ts +3323 -557
- package/as/facade.ts +3079 -718
- package/as/fetch.ts +2 -2
- package/as/fs.ts +352 -59
- package/as/hlds.ts +121 -120
- package/as/hooks.ts +10585 -5177
- package/as/lib/check.ts +3 -2
- package/as/natives.ts +856 -1272
- package/as/promise.ts +37 -27
- package/as/vector.ts +94 -14
- package/includes/order.txt +17 -19
- package/node_modules/assemblyscript/std/assembly/index.d.ts +1 -1
- package/package.json +9 -6
- package/runtime/deps/assemblyscript/dist/asc.js +136 -42
- package/runtime/deps/assemblyscript/dist/assemblyscript.js +141 -141
- package/runtime/licenses/README.md +9 -7
- package/runtime/licenses/ReGameDLL-LICENSE +21 -0
- package/runtime/licenses/ReHLDS-LICENSE +21 -0
- package/runtime/licenses/zlib-LICENSE +22 -0
- package/runtime/natives.txt +618 -523
- package/runtime/patches/README.md +87 -1
- package/runtime/patches/assemblyscript-0.28.20-amxts.patch +4838 -416
- package/runtime/patches/wamr-2.4.5-amxts.patch +417 -5
- package/scripts/auto-imports.ts +1 -1
- package/scripts/build-identity.ts +102 -65
- package/scripts/build-wasm.ts +12 -12
- package/scripts/check.ts +4 -1
- package/scripts/client-messages.ts +73 -1
- package/scripts/compile-cache.ts +11 -8
- package/scripts/compile-pool.ts +6 -3
- package/scripts/compile-worker.ts +23 -23
- package/scripts/compile.ts +142 -19
- package/scripts/docs/as/amxts.ts +10 -4
- package/scripts/docs/as/facade.ts +1779 -275
- package/scripts/docs/as/fetch.ts +2 -2
- package/scripts/docs/as/fs.ts +190 -6
- package/scripts/docs/as/vector.ts +81 -0
- package/scripts/docs/entities.ts +12 -0
- package/scripts/docs/events.ts +49 -13
- package/scripts/docs/game.ts +6 -0
- package/scripts/docs/messages.ts +10 -1
- package/scripts/hlds-events.ts +11 -11
- package/scripts/includes.ts +3 -4
- package/scripts/leaf-natives.ts +84 -0
- package/scripts/player-fields.ts +1 -1
- package/scripts/plugin-natives.ts +1 -1
- package/scripts/prebuilt.ts +41 -10
- package/scripts/project.ts +2 -3
- package/scripts/reapi-events.ts +9 -9
- package/scripts/server-env.ts +145 -0
- package/scripts/shared-modules.ts +23 -7
- package/scripts/system.ts +1 -1
- package/scripts/tracked-fs.ts +11 -2
- package/scripts/typed-commands.ts +153 -15
- package/scripts/upgrade-calls.ts +225 -0
- package/scripts/upgrade-names.ts +1 -4
- package/scripts/upgrade.ts +26 -11
- package/src/cli-api.mjs +3 -2
- package/src/system.mjs +21 -11
- package/src/testing/compile.ts +31 -8
- package/src/testing/coroutines.ts +0 -10
- package/src/testing/memory.ts +89 -2
- package/src/testing/natives.ts +67 -30
- package/src/testing/server.ts +1094 -155
- package/src/testing/tables.ts +23 -6
- package/src/typecheck.mjs +110 -0
- 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..
|
|
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
|
-
@@ -
|
|
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 +
|
|
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..
|
|
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,
|
|
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
|
package/scripts/auto-imports.ts
CHANGED
|
@@ -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
|
|
2
|
-
//
|
|
3
|
-
// `
|
|
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
|
|
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
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
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
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
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
|
|
79
|
-
* an export the module calls,
|
|
80
|
-
* (2: its run,
|
|
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
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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
|
|
104
|
-
*
|
|
105
|
-
*
|
|
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
|
-
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
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
|
+
}
|