@fraczak/k 6.3.2 → 6.4.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 (156) hide show
  1. package/DOCS/CODECS.md +258 -0
  2. package/DOCS/DICTIONARY.md +1172 -0
  3. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  4. package/DOCS/KIR_V1.md +221 -0
  5. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  6. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  7. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  8. package/DOCS/REPL.md +76 -14
  9. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  10. package/DOCS/dependency-graph.md +144 -0
  11. package/Examples/arithmetics.k +51 -48
  12. package/Examples/bnat.k +1 -1
  13. package/Examples/buda.k +44 -0
  14. package/Examples/ieee.k +300 -8671
  15. package/Examples/poly.k +67 -0
  16. package/README.md +68 -19
  17. package/augmentation.mjs +9 -7
  18. package/backend-api.mjs +11 -2
  19. package/backends/arm64/README.md +104 -0
  20. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  21. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  22. package/backends/arm64/bin/k-arm64.mjs +88 -0
  23. package/backends/arm64/scripts/run-tests.mjs +41 -0
  24. package/backends/arm64/src/arm64.mjs +229 -0
  25. package/backends/arm64/src/cli.mjs +155 -0
  26. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  27. package/backends/arm64/src/runtime.c +728 -0
  28. package/backends/arm64/tests/integration.sh +112 -0
  29. package/backends/arm64/tests/test-arm64.mjs +240 -0
  30. package/backends/llvm/README.md +135 -0
  31. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  32. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  33. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  34. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  35. package/backends/llvm/runtime/krt.c +1508 -0
  36. package/backends/llvm/runtime/krt.h +109 -0
  37. package/backends/llvm/scripts/conformance.mjs +76 -0
  38. package/backends/llvm/scripts/run-tests.mjs +28 -0
  39. package/backends/llvm/src/executable.mjs +562 -0
  40. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  41. package/backends/llvm/src/llvm.mjs +1092 -0
  42. package/backends/llvm/tests/composition-driver.c +22 -0
  43. package/backends/llvm/tests/identity-driver.c +27 -0
  44. package/backends/llvm/tests/integration.sh +153 -0
  45. package/backends/llvm/tests/perf-support.mjs +735 -0
  46. package/backends/llvm/tests/product-driver.c +23 -0
  47. package/backends/llvm/tests/projection-driver.c +19 -0
  48. package/backends/llvm/tests/relation-driver.c +29 -0
  49. package/backends/llvm/tests/test-llvm.mjs +240 -0
  50. package/backends/llvm/tests/union-driver.c +31 -0
  51. package/backends/llvm/tests/variant-driver.c +19 -0
  52. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  53. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  54. package/backends/wasm/README.md +97 -0
  55. package/backends/wasm/TECHNICAL-DEBT.md +60 -0
  56. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  57. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  58. package/backends/wasm/bin/k-wasm.mjs +49 -0
  59. package/backends/wasm/demo_ieee.mjs +319 -0
  60. package/backends/wasm/runtime.wat +102 -0
  61. package/backends/wasm/scripts/run-tests.mjs +41 -0
  62. package/backends/wasm/src/cli.mjs +133 -0
  63. package/backends/wasm/src/kvm2wasm.mjs +661 -0
  64. package/backends/wasm/src/wasm.mjs +1010 -0
  65. package/backends/wasm/tests/integration.sh +182 -0
  66. package/backends/wasm/tests/perf-support.mjs +336 -0
  67. package/backends/wasm/tests/test-wasm.mjs +617 -0
  68. package/browser/repl-browser.mjs +1584 -0
  69. package/browser/shims/assert.mjs +19 -0
  70. package/browser/shims/buffer.mjs +224 -0
  71. package/browser/shims/crypto.mjs +103 -0
  72. package/browser/shims/fs.mjs +159 -0
  73. package/browser/shims/os.mjs +17 -0
  74. package/browser/shims/path.mjs +54 -0
  75. package/browser/shims/process.mjs +44 -0
  76. package/browser/shims/readline.mjs +11 -0
  77. package/browser/shims/url.mjs +12 -0
  78. package/browser/vfs-data.mjs +19 -0
  79. package/codecs/README.md +3 -0
  80. package/codecs/json.mjs +16 -2
  81. package/codecs/runtime/show-value.mjs +2 -2
  82. package/conformance/helper-reuse/case.json +8 -0
  83. package/conformance/helper-reuse/expected.kv +1 -0
  84. package/conformance/helper-reuse/input.kv +1 -0
  85. package/conformance/helper-reuse/program.k +2 -0
  86. package/conformance/identity/case.json +8 -0
  87. package/conformance/identity/expected.kv +1 -0
  88. package/conformance/identity/input.kv +1 -0
  89. package/conformance/identity/program.k +1 -0
  90. package/conformance/product-projection/case.json +8 -0
  91. package/conformance/product-projection/expected.kv +1 -0
  92. package/conformance/product-projection/input.kv +1 -0
  93. package/conformance/product-projection/program.k +1 -0
  94. package/conformance/run.mjs +149 -0
  95. package/conformance/variant-construction/case.json +8 -0
  96. package/conformance/variant-construction/expected.kv +1 -0
  97. package/conformance/variant-construction/input.kv +1 -0
  98. package/conformance/variant-construction/program.k +1 -0
  99. package/harness/adapters/arm64.mjs +105 -0
  100. package/harness/adapters/kvm.mjs +144 -0
  101. package/harness/adapters/llvm.mjs +118 -0
  102. package/harness/adapters/native.mjs +77 -0
  103. package/harness/adapters/wasm.mjs +169 -0
  104. package/harness/backend.mjs +95 -0
  105. package/harness/cli.mjs +130 -0
  106. package/harness/format.mjs +95 -0
  107. package/harness/index.mjs +25 -0
  108. package/harness/persistent.mjs +121 -0
  109. package/harness/registry.mjs +44 -0
  110. package/harness/suite.mjs +257 -0
  111. package/harness/suites/poly.mjs +156 -0
  112. package/harness/trace.mjs +50 -0
  113. package/harness/util.mjs +92 -0
  114. package/intrinsics.mjs +41 -0
  115. package/kir.mjs +399 -0
  116. package/kvm.mjs +585 -81
  117. package/objects/README.md +37 -3
  118. package/objects/compile.mjs +15 -22
  119. package/objects/inspect.mjs +96 -0
  120. package/objects/validate.mjs +415 -0
  121. package/package.json +51 -19
  122. package/repl-codecs.mjs +133 -20
  123. package/repl.mjs +408 -59
  124. package/run.mjs +2 -7
  125. package/scripts/benchmark.mjs +406 -22
  126. package/scripts/build-repl-html.mjs +1784 -0
  127. package/scripts/perf-ieee.mjs +586 -0
  128. package/scripts/perf-int.mjs +531 -0
  129. package/scripts/perf-poly.mjs +945 -0
  130. package/scripts/render-benchmark.mjs +12 -8
  131. package/scripts/run-tests.mjs +6 -0
  132. package/tests/integration.sh +19 -2
  133. package/tests/test-arithmetics.mjs +54 -0
  134. package/tests/test-ieee-arithmetic.mjs +6 -2
  135. package/tests/test-kir.mjs +85 -0
  136. package/tests/test-kvm-polymorphic.mjs +278 -0
  137. package/tests/test-kvm.mjs +25 -6
  138. package/tests/test-poly.mjs +129 -0
  139. package/tests/test-repl-html.mjs +303 -0
  140. package/tests/test-repl.mjs +175 -1
  141. package/tests/test-validate-object.mjs +40 -0
  142. package/a.klib +0 -1
  143. package/a.kvm +0 -142676
  144. package/a.wasm +0 -0
  145. package/benchmark-results.html +0 -532
  146. package/benchmark-results.json +0 -480
  147. package/k-vscode/.vscode/launch.json +0 -14
  148. package/k-vscode/README.md +0 -75
  149. package/k-vscode/extension.js +0 -273
  150. package/k-vscode/language-configuration.json +0 -42
  151. package/k-vscode/package.json +0 -79
  152. package/k-vscode/snippets/k.json +0 -92
  153. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  154. package/k-vscode/test/background-ranges.test.js +0 -50
  155. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  156. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ K_ROOT=${K_ROOT:-../..}
5
+ TMP_DIR=`mktemp -d`
6
+ trap 'rm -rf "$TMP_DIR"' EXIT
7
+
8
+ echo "Running './tests/integration.sh' ..."
9
+
10
+ compare_json_envelope() {
11
+ local name=$1
12
+ local input=$2
13
+ local program=$3
14
+ printf '%s\n' "$input" |
15
+ node "$K_ROOT/codecs/json.mjs" --parse |
16
+ node "$K_ROOT/k.mjs" "$program" > "$TMP_DIR/native.kv"
17
+ printf '%s\n' "$input" |
18
+ node "$K_ROOT/codecs/json.mjs" --parse |
19
+ node "$K_ROOT/kvm.mjs" "$program" > "$TMP_DIR/kvm.kv"
20
+ printf '%s\n' "$input" |
21
+ node "$K_ROOT/codecs/json.mjs" --parse |
22
+ node ./bin/k-wasm.mjs "$program" > "$TMP_DIR/wasm.kv"
23
+
24
+ if ! cmp -s "$TMP_DIR/native.kv" "$TMP_DIR/kvm.kv" ||
25
+ ! cmp -s "$TMP_DIR/native.kv" "$TMP_DIR/wasm.kv"; then
26
+ echo "output envelope mismatch for $name" >&2
27
+ exit 1
28
+ fi
29
+ }
30
+
31
+ node "$K_ROOT/codecs/unit.mjs" --parse |
32
+ node ./bin/k-wasm.mjs '|ok' |
33
+ node "$K_ROOT/codecs/k-print.mjs" |
34
+ grep -qx '"ok"'
35
+
36
+ printf '{"a": {}, "b": {}}\n' |
37
+ node "$K_ROOT/codecs/k-parse.mjs" |
38
+ node ./bin/k-wasm.mjs '|ok' |
39
+ node "$K_ROOT/codecs/k-print.mjs" |
40
+ grep -qx '{"ok":{"a":{},"b":{}}}'
41
+
42
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
43
+ node "$K_ROOT/codecs/json.mjs" --parse |
44
+ node ./bin/k-wasm.mjs '.c' |
45
+ node "$K_ROOT/codecs/json.mjs" --print |
46
+ grep -qx '\[1,2,"alsk"\]'
47
+
48
+ compare_json_envelope "nested array string projection" \
49
+ '{"a":[1,2,"kupa"], "b": 123}' \
50
+ '.a.2'
51
+ compare_json_envelope "projected JSON number" \
52
+ '{"a":[1,2,"kupa"], "b": 123}' \
53
+ '.b'
54
+ compare_json_envelope "closed product filter" \
55
+ '{"a":[1,2,"kupa"], "b": 123}' \
56
+ '?{X a, Y b}'
57
+ printf '{"a":[1,2,"kupa"], "b": 123}\n' |
58
+ node "$K_ROOT/codecs/json.mjs" --parse |
59
+ node ./bin/k-wasm.mjs '{ .a.2 word, .b number }' |
60
+ node "$K_ROOT/codecs/json.mjs" --print |
61
+ grep -qx '{"number":123,"word":"kupa"}'
62
+
63
+ printf 'a\n' |
64
+ node "$K_ROOT/codecs/k-parse.mjs" --input-type '?< {} a, X b, ...>' |
65
+ node ./bin/k-wasm.mjs '{() i, /a o}' |
66
+ node "$K_ROOT/codecs/show.mjs" > "$TMP_DIR/polymorphic-relation.wire" 2> "$TMP_DIR/polymorphic-relation.show"
67
+ grep -Fqx '{{}|a i, {} o} ?{<{}=X0 a, (...) b, ...> i, X0 o}' "$TMP_DIR/polymorphic-relation.show"
68
+ node "$K_ROOT/codecs/k-print.mjs" "$TMP_DIR/polymorphic-relation.wire" |
69
+ grep -qx '{"i":"a","o":{}}'
70
+
71
+ node ./bin/k-wasm-compile.mjs '.c' "$TMP_DIR/dot-c.wasm"
72
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
73
+ node "$K_ROOT/codecs/json.mjs" --parse |
74
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/dot-c.wasm" |
75
+ node "$K_ROOT/codecs/json.mjs" --print |
76
+ grep -qx '\[1,2,"alsk"\]'
77
+
78
+ node "$K_ROOT/objects/compile.mjs" '.c' "$TMP_DIR/dot-c.ko"
79
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
80
+ node "$K_ROOT/codecs/json.mjs" --parse |
81
+ node ./bin/k-wasm.mjs "$TMP_DIR/dot-c.ko" |
82
+ node "$K_ROOT/codecs/json.mjs" --print |
83
+ grep -qx '\[1,2,"alsk"\]'
84
+
85
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
86
+ node "$K_ROOT/codecs/json.mjs" --parse |
87
+ node ./bin/k-wasm.mjs '?{X c, ...}' |
88
+ node "$K_ROOT/codecs/json.mjs" --print |
89
+ grep -qx '{"a":123,"b":true,"c":\[1,2,"alsk"\]}'
90
+
91
+ printf '{"a":123,"b":true}\n' |
92
+ node "$K_ROOT/codecs/json.mjs" --parse |
93
+ node ./bin/k-wasm.mjs '?{...}' |
94
+ node "$K_ROOT/codecs/json.mjs" --print |
95
+ grep -qx '{"a":123,"b":true}'
96
+
97
+ printf '"bar"\n' |
98
+ node "$K_ROOT/codecs/json.mjs" --parse |
99
+ node ./bin/k-wasm.mjs '?<...>' |
100
+ node "$K_ROOT/codecs/json.mjs" --print |
101
+ grep -qx '"bar"'
102
+
103
+ printf '{"c":[1,2,"alsk"]}\n' |
104
+ node "$K_ROOT/codecs/json.mjs" --parse |
105
+ node ./bin/k-wasm.mjs '?{X c}' |
106
+ node "$K_ROOT/codecs/json.mjs" --print |
107
+ grep -qx '{"c":\[1,2,"alsk"\]}'
108
+
109
+ if printf '{"a":123,"c":1}\n' |
110
+ node "$K_ROOT/codecs/json.mjs" --parse |
111
+ node ./bin/k-wasm.mjs '?{X c}' >/dev/null 2>&1; then
112
+ echo "closed product pattern unexpectedly accepted extra fields" >&2
113
+ exit 1
114
+ fi
115
+
116
+ if printf '"bar"\n' |
117
+ node "$K_ROOT/codecs/json.mjs" --parse |
118
+ node ./bin/k-wasm.mjs '?<X cons>' >/dev/null 2>&1; then
119
+ echo "closed union pattern unexpectedly accepted a wider value envelope" >&2
120
+ exit 1
121
+ fi
122
+
123
+ node "$K_ROOT/codecs/unit.mjs" --parse |
124
+ node "$K_ROOT/k.mjs" '|cons' |
125
+ node ./bin/k-wasm.mjs '?<{} cons>' |
126
+ node "$K_ROOT/codecs/k-print.mjs" |
127
+ grep -qx '"cons"'
128
+
129
+ if node ./bin/k-wasm-compile.mjs 'f = .x f; f' "$TMP_DIR/non-converged.wasm" >/dev/null 2>&1; then
130
+ echo "non-converged type derivation unexpectedly compiled" >&2
131
+ exit 1
132
+ fi
133
+
134
+ printf '|ok\n' > "$TMP_DIR/ok.k"
135
+ if node ./bin/k-wasm-compile.mjs -k "$TMP_DIR/ok.k" "$TMP_DIR/old-k.wasm" >/dev/null 2>&1; then
136
+ echo "-k source-file compatibility option unexpectedly worked" >&2
137
+ exit 1
138
+ fi
139
+
140
+ node ./bin/k-wasm-compile.mjs "$TMP_DIR/ok.k" "$TMP_DIR/ok.wasm"
141
+ node "$K_ROOT/codecs/unit.mjs" --parse > "$TMP_DIR/unit.kv"
142
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/ok.wasm" "$TMP_DIR/unit.kv" |
143
+ node "$K_ROOT/codecs/k-print.mjs" |
144
+ grep -qx '"ok"'
145
+
146
+ node ./bin/k-wasm.mjs "$TMP_DIR/ok.k" "$TMP_DIR/unit.kv" |
147
+ node "$K_ROOT/codecs/k-print.mjs" |
148
+ grep -qx '"ok"'
149
+
150
+ node "$K_ROOT/objects/compile.mjs" "$TMP_DIR/ok.k" "$TMP_DIR/ok.ko"
151
+ node ./bin/k-wasm-compile.mjs "$TMP_DIR/ok.ko" "$TMP_DIR/ok-ko.wasm"
152
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/ok-ko.wasm" "$TMP_DIR/unit.kv" |
153
+ node "$K_ROOT/codecs/k-print.mjs" |
154
+ grep -qx '"ok"'
155
+
156
+ node "$K_ROOT/objects/compile.mjs" "$TMP_DIR/ok.k" "$TMP_DIR/ok.kvm"
157
+ node ./bin/k-wasm-compile.mjs "$TMP_DIR/ok.kvm" "$TMP_DIR/ok-kvm.wasm"
158
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/ok-kvm.wasm" "$TMP_DIR/unit.kv" |
159
+ node "$K_ROOT/codecs/k-print.mjs" |
160
+ grep -qx '"ok"'
161
+
162
+ node "$K_ROOT/objects/compile.mjs" --format kvm 'make_prod = { .x x, .y y }; proj_y = make_prod .y; proj_y' > "$TMP_DIR/project.kvm"
163
+ node ./bin/k-wasm-compile.mjs "$TMP_DIR/project.kvm" "$TMP_DIR/project.wasm"
164
+ printf '{"x":{"a":{}},"y":{"b":{}}}\n' |
165
+ node "$K_ROOT/codecs/k-parse.mjs" |
166
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/project.wasm" |
167
+ node "$K_ROOT/codecs/k-print.mjs" |
168
+ grep -qx '"b"'
169
+
170
+ node "$K_ROOT/objects/compile.mjs" "$K_ROOT/Examples/ieee.k" "$TMP_DIR/ieee.klib"
171
+ if node ./bin/k-wasm-compile.mjs --lib "$TMP_DIR/ieee.klib" --lib "$TMP_DIR/ieee.klib" --export mul:times "{()x,()y} times .result" "$TMP_DIR/repeated-lib.wasm" >/dev/null 2>&1; then
172
+ echo "--lib unexpectedly accepted more than once" >&2
173
+ exit 1
174
+ fi
175
+ node ./bin/k-wasm-compile.mjs --lib "$TMP_DIR/ieee.klib" --export mul:times "{()x,()y} times .result" "$TMP_DIR/ieee-mul.wasm"
176
+ echo 0.12 |
177
+ node "$K_ROOT/codecs/ieee.mjs" --parse |
178
+ node ./bin/k-wasm-run.mjs "$TMP_DIR/ieee-mul.wasm" |
179
+ node "$K_ROOT/codecs/ieee.mjs" --print |
180
+ grep -qx '0.0144'
181
+
182
+ echo "Integration tests passed."
@@ -0,0 +1,336 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import {
6
+ isProduct,
7
+ isVariant,
8
+ lowerToKVM,
9
+ Value
10
+ } from "@fraczak/k/backend-api.mjs";
11
+ import { lowerToWasm, getTagId, getTagFromId } from "../src/kvm2wasm.mjs";
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+
15
+ export function loadRuntimeWat() {
16
+ return fs.readFileSync(path.join(__dirname, "../runtime.wat"), "utf8");
17
+ }
18
+
19
+ export const cleanName = (h) => "rel_" + h.replace(/[^a-zA-Z0-9_]/g, "_");
20
+
21
+ function scanCalls(insts, compiled, queue) {
22
+ for (const inst of insts) {
23
+ if (inst.op === "call" && !compiled.has(inst.func) && !queue.includes(inst.func)) {
24
+ queue.push(inst.func);
25
+ }
26
+ if (inst.branches) {
27
+ for (const branch of inst.branches) {
28
+ scanCalls(branch.body, compiled, queue);
29
+ }
30
+ }
31
+ }
32
+ }
33
+
34
+ function cleanInsts(insts) {
35
+ for (const inst of insts) {
36
+ if (inst.op === "call") {
37
+ inst.func = cleanName(inst.func);
38
+ }
39
+ if (inst.branches) {
40
+ for (const branch of inst.branches) {
41
+ cleanInsts(branch.body);
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ export function findAliasForHash(hash, state) {
48
+ if (!state?.relAliases) return hash;
49
+ let best = null;
50
+ for (const [alias, h] of Object.entries(state.relAliases)) {
51
+ if (h === hash) {
52
+ if (!best) {
53
+ best = alias;
54
+ } else {
55
+ const bestIsBench = best.startsWith("bench_");
56
+ const currentIsBench = alias.startsWith("bench_");
57
+ if (bestIsBench && !currentIsBench) {
58
+ best = alias;
59
+ } else if (bestIsBench === currentIsBench && alias.length < best.length) {
60
+ best = alias;
61
+ }
62
+ }
63
+ }
64
+ }
65
+ return best || hash;
66
+ }
67
+
68
+ export function compileMultiModule(mainHashes, state, options = {}) {
69
+ const compiled = new Set();
70
+ const queue = [...mainHashes];
71
+ const wats = [];
72
+ const profileGlobals = [];
73
+ const profileFunctions = [];
74
+
75
+ while (queue.length > 0) {
76
+ const hash = queue.shift();
77
+ if (compiled.has(hash)) continue;
78
+ compiled.add(hash);
79
+
80
+ const relDef = state.rels[hash];
81
+ if (!relDef) {
82
+ throw new Error(`Relation hash ${hash} not found`);
83
+ }
84
+
85
+ const kvmFunc = lowerToKVM(relDef, hash);
86
+ kvmFunc.typePatternGraph = relDef.typePatternGraph;
87
+ scanCalls(kvmFunc.body, compiled, queue);
88
+
89
+ kvmFunc.name = cleanName(hash);
90
+ cleanInsts(kvmFunc.body);
91
+ if (options.profile) {
92
+ const alias = findAliasForHash(hash, state);
93
+ profileFunctions.push({ name: alias, symbolName: kvmFunc.name, hash });
94
+ profileGlobals.push(` (global $prof_${kvmFunc.name} (export "prof_${kvmFunc.name}") (mut i64) (i64.const 0))`);
95
+ }
96
+ wats.push(lowerToWasm(kvmFunc, kvmFunc.name, options));
97
+ }
98
+
99
+ const globalsText = profileGlobals.length > 0 ? profileGlobals.join("\n") + "\n\n" : "";
100
+ return {
101
+ wat: globalsText + wats.join("\n\n"),
102
+ profileFunctions
103
+ };
104
+ }
105
+
106
+ export function compileWat(watText, wabtInstance) {
107
+ const watModule = wabtInstance.parseWat("perf.wat", watText, {
108
+ mutable_globals: true,
109
+ sat_float_to_int: true,
110
+ sign_extension: true,
111
+ multi_value: true,
112
+ bulk_memory: true,
113
+ reference_types: true
114
+ });
115
+ watModule.resolveNames();
116
+ watModule.validate();
117
+ return watModule.toBinary({
118
+ log: false,
119
+ canonicalize_lebs: true,
120
+ relocatable: false,
121
+ write_debug_names: true
122
+ }).buffer;
123
+ }
124
+
125
+ export async function instantiateWasmModule(mainHashes, state, wabtInstance, options = {}) {
126
+ const runtimeWat = loadRuntimeWat();
127
+ const compiled = compileMultiModule(mainHashes, state, options);
128
+ const wats = typeof compiled === "string" ? compiled : compiled.wat;
129
+ const profileFunctions = typeof compiled === "string" ? [] : (compiled.profileFunctions || []);
130
+ const fullWat = runtimeWat.trim().slice(0, -1) + "\n" + wats + "\n)";
131
+ const binary = compileWat(fullWat, wabtInstance);
132
+ const module = await WebAssembly.compile(binary);
133
+ const instance = await WebAssembly.instantiate(module);
134
+ return { instance, exports: instance.exports, module, profileFunctions };
135
+ }
136
+
137
+ export function readWasmProfile(wasmExports, profileFunctions, reset = true) {
138
+ if (!wasmExports || !profileFunctions || profileFunctions.length === 0) return null;
139
+ const result = {};
140
+ for (const f of profileFunctions) {
141
+ const g = wasmExports[`prof_${f.symbolName}`];
142
+ if (g) {
143
+ const val = Number(g.value);
144
+ if (val > 0) {
145
+ result[f.name] = val;
146
+ }
147
+ if (reset) {
148
+ g.value = 0n;
149
+ }
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+
155
+ export function resetWasmProfile(wasmExports, profileFunctions) {
156
+ if (!wasmExports || !profileFunctions) return;
157
+ for (const f of profileFunctions) {
158
+ const g = wasmExports[`prof_${f.symbolName}`];
159
+ if (g) g.value = 0n;
160
+ }
161
+ }
162
+
163
+ export function readArenaValue(exports, rootPtr, pattern, rootPatternNodeId, patternPropertyList) {
164
+ let rootValue;
165
+ const stack = [{
166
+ ptr: rootPtr,
167
+ patternNodeId: rootPatternNodeId,
168
+ assign: (v) => { rootValue = v; }
169
+ }];
170
+
171
+ while (stack.length > 0) {
172
+ const frame = stack.pop();
173
+
174
+ if (frame.finishProduct) {
175
+ const { productObj, assign } = frame;
176
+ assign(Value.product(productObj, patternPropertyList));
177
+ continue;
178
+ }
179
+
180
+ if (frame.finishVariant) {
181
+ const { tag, payloadBox, assign } = frame;
182
+ assign(Value.variant(tag, payloadBox[0], patternPropertyList));
183
+ continue;
184
+ }
185
+
186
+ const { ptr, patternNodeId, assign } = frame;
187
+ const patternNode = pattern.nodes[patternNodeId];
188
+ const view = new DataView(exports.memory.buffer);
189
+
190
+ if (patternNode.kind === 1 || patternNode.kind === 3) {
191
+ const size = view.getUint32(ptr, true);
192
+ const N = view.getUint32(ptr + 4, true);
193
+ const productObj = {};
194
+
195
+ stack.push({
196
+ finishProduct: true,
197
+ productObj,
198
+ assign
199
+ });
200
+
201
+ for (let i = N - 1; i >= 0; i--) {
202
+ const edge = patternNode.edges[i];
203
+ const offsetVal = view.getUint32(ptr + 8 + 4 * i, true);
204
+ const childPtr = view.getUint32(ptr + offsetVal, true);
205
+ const label = edge.label;
206
+ stack.push({
207
+ ptr: childPtr,
208
+ patternNodeId: edge.target,
209
+ assign: (v) => { productObj[label] = v; }
210
+ });
211
+ }
212
+ } else if (patternNode.kind === 2 || patternNode.kind === 4) {
213
+ const size = view.getUint32(ptr, true);
214
+ const tagId = view.getUint32(ptr + 4, true);
215
+ const payloadPtr = view.getUint32(ptr + 8, true);
216
+
217
+ const tag = getTagFromId(tagId);
218
+ const edge = patternNode.edges.find(e => e.label === tag);
219
+ if (!edge) {
220
+ throw new Error(`Variant tag '${tag}' not found in pattern edges`);
221
+ }
222
+ const payloadBox = [null];
223
+
224
+ stack.push({
225
+ finishVariant: true,
226
+ tag,
227
+ payloadBox,
228
+ assign
229
+ });
230
+
231
+ stack.push({
232
+ ptr: payloadPtr,
233
+ patternNodeId: edge.target,
234
+ assign: (v) => { payloadBox[0] = v; }
235
+ });
236
+ } else {
237
+ throw new Error(`Unsupported pattern kind: ${patternNode.kind}`);
238
+ }
239
+ }
240
+
241
+ return rootValue;
242
+ }
243
+
244
+ export function writeValueToArena(exports, rootValue, pattern, rootPatternNodeId) {
245
+ let rootPtr;
246
+ const stack = [{
247
+ value: rootValue,
248
+ patternNodeId: rootPatternNodeId,
249
+ assign: (p) => { rootPtr = p; }
250
+ }];
251
+
252
+ while (stack.length > 0) {
253
+ const frame = stack.pop();
254
+
255
+ if (frame.finishProduct) {
256
+ const { ptr, totalSize, N, childPtrs, assign } = frame;
257
+ const view = new DataView(exports.memory.buffer);
258
+ view.setUint32(ptr, totalSize, true);
259
+ view.setUint32(ptr + 4, N, true);
260
+
261
+ for (let i = 0; i < N; i++) {
262
+ const offsetVal = 8 + 4 * N + 4 * i;
263
+ view.setUint32(ptr + 8 + 4 * i, offsetVal, true);
264
+ view.setUint32(ptr + offsetVal, childPtrs[i], true);
265
+ }
266
+ assign(ptr);
267
+ continue;
268
+ }
269
+
270
+ if (frame.finishVariant) {
271
+ const { tagId, childPtrBox, assign } = frame;
272
+ const ptr = exports.alloc(12);
273
+ const view = new DataView(exports.memory.buffer);
274
+
275
+ view.setUint32(ptr, 12, true);
276
+ view.setUint32(ptr + 4, tagId, true);
277
+ view.setUint32(ptr + 8, childPtrBox[0], true);
278
+ assign(ptr);
279
+ continue;
280
+ }
281
+
282
+ const { value, patternNodeId, assign } = frame;
283
+ const patternNode = pattern.nodes[patternNodeId];
284
+
285
+ if (isProduct(value)) {
286
+ const keys = Object.keys(value.product).sort();
287
+ const N = keys.length;
288
+ const totalSize = 8 + 8 * N;
289
+ const ptr = exports.alloc(totalSize);
290
+
291
+ const childPtrs = new Array(N);
292
+ stack.push({
293
+ finishProduct: true,
294
+ ptr,
295
+ totalSize,
296
+ N,
297
+ childPtrs,
298
+ assign
299
+ });
300
+
301
+ for (let i = N - 1; i >= 0; i--) {
302
+ const label = keys[i];
303
+ const edge = patternNode.edges.find(e => e.label === label);
304
+ const childVal = value.product[label];
305
+ const targetNode = edge ? edge.target : patternNodeId;
306
+ const index = i;
307
+ stack.push({
308
+ value: childVal,
309
+ patternNodeId: targetNode,
310
+ assign: (p) => { childPtrs[index] = p; }
311
+ });
312
+ }
313
+ } else if (isVariant(value)) {
314
+ const tagId = getTagId(value.tag);
315
+ const edge = patternNode.edges.find(e => e.label === value.tag);
316
+ const childPtrBox = [0];
317
+
318
+ stack.push({
319
+ finishVariant: true,
320
+ tagId,
321
+ childPtrBox,
322
+ assign
323
+ });
324
+
325
+ stack.push({
326
+ value: value.value,
327
+ patternNodeId: edge ? edge.target : patternNodeId,
328
+ assign: (p) => { childPtrBox[0] = p; }
329
+ });
330
+ } else {
331
+ throw new Error(`Unsupported value type: ${value}`);
332
+ }
333
+ }
334
+
335
+ return rootPtr;
336
+ }