@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.
@@ -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
- const ptrIn = writeValueToArena(exports, value, inputPattern, 0, arenaValues, tags, metadata.inputPattern);
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
- const result = exports[metadata.entry](ptrIn);
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
- const ptrIn = writeValueToArena(exports, inputValue, inputPattern, 0, arenaValues, tags, metadata.inputPattern);
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
- const result = exports[metadata.entry](ptrIn);
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