@fraczak/k 6.4.0 → 6.5.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/CHANGELOG.md +17 -0
- package/Examples/arithmetics.k +86 -63
- package/Value.mjs +8 -2
- package/backends/wasm/TECHNICAL-DEBT.md +11 -13
- package/backends/wasm/runtime.wat +375 -2
- package/backends/wasm/src/kvm2wasm.mjs +36 -0
- package/backends/wasm/src/wasm.mjs +48 -4
- package/backends/wasm/tests/test-wasm.mjs +8 -0
- package/browser/vfs-data.mjs +3 -3
- package/codecs/runtime/show-value.mjs +10 -1
- package/package.json +1 -1
|
@@ -159,6 +159,7 @@ export function lowerToWasm(relDef, name, options = {}) {
|
|
|
159
159
|
for (const field of inputProductFields) {
|
|
160
160
|
registers.add(field.local);
|
|
161
161
|
}
|
|
162
|
+
registers.add("tail_loop_mark");
|
|
162
163
|
|
|
163
164
|
let nextUnionId = 0;
|
|
164
165
|
const tailLoopLabel = "$tail_loop";
|
|
@@ -379,6 +380,24 @@ export function lowerToWasm(relDef, name, options = {}) {
|
|
|
379
380
|
);
|
|
380
381
|
lines.push(branchWat);
|
|
381
382
|
}
|
|
383
|
+
lines.push(` ;; compact if arena growth exceeds 1MB`);
|
|
384
|
+
lines.push(` global.get $arena_free`);
|
|
385
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
386
|
+
lines.push(` i32.sub`);
|
|
387
|
+
lines.push(` i32.const 1048576`);
|
|
388
|
+
lines.push(` i32.gt_u`);
|
|
389
|
+
lines.push(` if`);
|
|
390
|
+
lines.push(` call $compact_start`);
|
|
391
|
+
for (let i = 0; i < N; i++) {
|
|
392
|
+
const fieldTmp = `${dest}_f${i}`;
|
|
393
|
+
lines.push(` local.get $${fieldTmp}`);
|
|
394
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
395
|
+
lines.push(` call $compact_obj`);
|
|
396
|
+
lines.push(` local.set $${fieldTmp}`);
|
|
397
|
+
}
|
|
398
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
399
|
+
lines.push(` call $compact_finish`);
|
|
400
|
+
lines.push(` end`);
|
|
382
401
|
for (let i = 0; i < N; i++) {
|
|
383
402
|
const branch = sortedBranches[i];
|
|
384
403
|
const fieldTmp = `${dest}_f${i}`;
|
|
@@ -565,6 +584,21 @@ export function lowerToWasm(relDef, name, options = {}) {
|
|
|
565
584
|
registers.add(callSrc);
|
|
566
585
|
materializeInputProduct(lines, callSrc);
|
|
567
586
|
}
|
|
587
|
+
lines.push(` ;; compact if arena growth exceeds 1MB`);
|
|
588
|
+
lines.push(` global.get $arena_free`);
|
|
589
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
590
|
+
lines.push(` i32.sub`);
|
|
591
|
+
lines.push(` i32.const 1048576`);
|
|
592
|
+
lines.push(` i32.gt_u`);
|
|
593
|
+
lines.push(` if`);
|
|
594
|
+
lines.push(` call $compact_start`);
|
|
595
|
+
lines.push(` local.get $${callSrc}`);
|
|
596
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
597
|
+
lines.push(` call $compact_obj`);
|
|
598
|
+
lines.push(` local.set $${callSrc}`);
|
|
599
|
+
lines.push(` local.get $tail_loop_mark`);
|
|
600
|
+
lines.push(` call $compact_finish`);
|
|
601
|
+
lines.push(` end`);
|
|
568
602
|
lines.push(` local.get $${callSrc}`);
|
|
569
603
|
lines.push(` local.set $in`);
|
|
570
604
|
lines.push(initInputProductLocals());
|
|
@@ -641,6 +675,8 @@ export function lowerToWasm(relDef, name, options = {}) {
|
|
|
641
675
|
const wat = `(func $${name} (export "${name}") (param $in i32) (result i32 i32)
|
|
642
676
|
${localDecls}
|
|
643
677
|
${inputProductLocalInit}
|
|
678
|
+
global.get $arena_free
|
|
679
|
+
local.set $tail_loop_mark
|
|
644
680
|
(loop ${tailLoopLabel}
|
|
645
681
|
${profWat}${bodyWat}
|
|
646
682
|
)
|
|
@@ -31,6 +31,24 @@ const METADATA_SECTION = "k.metadata";
|
|
|
31
31
|
const ARTIFACT_FORMAT = "k-wasm";
|
|
32
32
|
const ARTIFACT_VERSION = 1;
|
|
33
33
|
|
|
34
|
+
class OutOfMemoryError extends Error {
|
|
35
|
+
constructor(message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "OutOfMemoryError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function checkWasmOom(exports) {
|
|
42
|
+
if (exports.oom_flag && exports.oom_flag.value) {
|
|
43
|
+
const size = exports.oom_size ? exports.oom_size.value : 0;
|
|
44
|
+
const max = exports.arena_max ? exports.arena_max.value : 0;
|
|
45
|
+
const free = exports.arena_free ? exports.arena_free.value : 0;
|
|
46
|
+
throw new OutOfMemoryError(
|
|
47
|
+
`WebAssembly Out of Memory: linear memory arena exhausted (failed to allocate ${size} bytes; arena used: ${free >>> 0} bytes, arena max: ${max >>> 0} bytes)`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
const cleanName = (name) => "rel_" + name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
35
53
|
|
|
36
54
|
async function getWabt() {
|
|
@@ -894,9 +912,21 @@ async function instantiateWasmArtifact(wasmBuffer) {
|
|
|
894
912
|
const t1 = process.hrtime.bigint();
|
|
895
913
|
const mark = exports.arena_mark ? exports.arena_mark() : 0;
|
|
896
914
|
const arenaValues = new Map();
|
|
897
|
-
|
|
915
|
+
let ptrIn;
|
|
916
|
+
try {
|
|
917
|
+
ptrIn = writeValueToArena(exports, value, inputPattern, 0, arenaValues, tags, metadata.inputPattern);
|
|
918
|
+
} catch (error) {
|
|
919
|
+
checkWasmOom(exports);
|
|
920
|
+
throw error;
|
|
921
|
+
}
|
|
898
922
|
const t2 = process.hrtime.bigint();
|
|
899
|
-
|
|
923
|
+
let result;
|
|
924
|
+
try {
|
|
925
|
+
result = exports[metadata.entry](ptrIn);
|
|
926
|
+
} catch (error) {
|
|
927
|
+
checkWasmOom(exports);
|
|
928
|
+
throw error;
|
|
929
|
+
}
|
|
900
930
|
if (result[1] !== 1) {
|
|
901
931
|
if (exports.arena_reset) exports.arena_reset(mark);
|
|
902
932
|
throw new Error("Wasm relation execution failed (returned false)");
|
|
@@ -933,9 +963,21 @@ async function instantiateWasmArtifact(wasmBuffer) {
|
|
|
933
963
|
const t1 = process.hrtime.bigint();
|
|
934
964
|
const mark = exports.arena_mark ? exports.arena_mark() : 0;
|
|
935
965
|
const arenaValues = new Map();
|
|
936
|
-
|
|
966
|
+
let ptrIn;
|
|
967
|
+
try {
|
|
968
|
+
ptrIn = writeValueToArena(exports, inputValue, inputPattern, 0, arenaValues, tags, metadata.inputPattern);
|
|
969
|
+
} catch (error) {
|
|
970
|
+
checkWasmOom(exports);
|
|
971
|
+
throw error;
|
|
972
|
+
}
|
|
937
973
|
const t2 = process.hrtime.bigint();
|
|
938
|
-
|
|
974
|
+
let result;
|
|
975
|
+
try {
|
|
976
|
+
result = exports[metadata.entry](ptrIn);
|
|
977
|
+
} catch (error) {
|
|
978
|
+
checkWasmOom(exports);
|
|
979
|
+
throw error;
|
|
980
|
+
}
|
|
939
981
|
if (result[1] !== 1) {
|
|
940
982
|
if (exports.arena_reset) exports.arena_reset(mark);
|
|
941
983
|
return undefined;
|
|
@@ -982,6 +1024,7 @@ export {
|
|
|
982
1024
|
ARTIFACT_FORMAT,
|
|
983
1025
|
ARTIFACT_VERSION,
|
|
984
1026
|
METADATA_SECTION,
|
|
1027
|
+
OutOfMemoryError,
|
|
985
1028
|
appendCustomSection,
|
|
986
1029
|
compileWasmArtifactFromKVM,
|
|
987
1030
|
compileWasmArtifactFromObject,
|
|
@@ -998,6 +1041,7 @@ export default {
|
|
|
998
1041
|
ARTIFACT_FORMAT,
|
|
999
1042
|
ARTIFACT_VERSION,
|
|
1000
1043
|
METADATA_SECTION,
|
|
1044
|
+
OutOfMemoryError,
|
|
1001
1045
|
appendCustomSection,
|
|
1002
1046
|
compileWasmArtifactFromKVM,
|
|
1003
1047
|
compileWasmArtifactFromObject,
|
|
@@ -88,6 +88,14 @@ console.log("==> Running runtime.wat Core Allocator Tests");
|
|
|
88
88
|
const ptr3 = runtimeExports.alloc(70000);
|
|
89
89
|
assert.ok(ptr3 > 1040, "Large allocation must return a valid pointer");
|
|
90
90
|
assert.equal(ptr3 % 8, 0, "Large allocation must be 8-byte aligned");
|
|
91
|
+
|
|
92
|
+
// Test 5: Out of Memory flag recording on overflow
|
|
93
|
+
assert.equal(runtimeExports.oom_flag.value, 0, "OOM flag must be 0 initially");
|
|
94
|
+
assert.throws(() => {
|
|
95
|
+
runtimeExports.alloc(-1);
|
|
96
|
+
}, /unreachable/);
|
|
97
|
+
assert.equal(runtimeExports.oom_flag.value, 1, "OOM flag must be 1 after allocation failure");
|
|
98
|
+
assert.equal(runtimeExports.oom_size.value, -1, "OOM size must record requested size");
|
|
91
99
|
console.log("Core Allocator tests passed successfully!");
|
|
92
100
|
}
|
|
93
101
|
|