@fraczak/k 6.3.3 → 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/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +61 -4
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +108 -82
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/Value.mjs +8 -2
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +58 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +475 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +697 -0
- package/backends/wasm/src/wasm.mjs +1054 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +625 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/runtime/show-value.mjs +12 -3
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +105 -6
- package/repl.mjs +335 -49
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +4 -0
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +144 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- package/scripts/git-hooks/pre-commit +0 -10
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
(module
|
|
2
|
+
(memory (export "memory") 1)
|
|
3
|
+
|
|
4
|
+
;; Start allocation at byte offset 1024 to leave a safety margin and avoid returning 0 (nullptr)
|
|
5
|
+
(global $arena_free (export "arena_free") (mut i32) (i32.const 1024))
|
|
6
|
+
;; Maximum address of the currently allocated pages (1 page = 64KB)
|
|
7
|
+
(global $arena_max (export "arena_max") (mut i32) (i32.const 65536))
|
|
8
|
+
;; Out-of-memory status flags
|
|
9
|
+
(global $oom_flag (export "oom_flag") (mut i32) (i32.const 0))
|
|
10
|
+
(global $oom_size (export "oom_size") (mut i32) (i32.const 0))
|
|
11
|
+
|
|
12
|
+
;; Bump allocator function: aligns allocation size to 8 bytes, grows memory if needed, and returns the pointer
|
|
13
|
+
(func $alloc (export "alloc") (param $size i32) (result i32)
|
|
14
|
+
(local $old_free i32)
|
|
15
|
+
(local $new_free i32)
|
|
16
|
+
(local $pages_needed i32)
|
|
17
|
+
(local $grow_res i32)
|
|
18
|
+
|
|
19
|
+
;; Check if size exceeds maximum allocatable size
|
|
20
|
+
local.get $size
|
|
21
|
+
i32.const -8
|
|
22
|
+
i32.gt_u
|
|
23
|
+
if
|
|
24
|
+
i32.const 1
|
|
25
|
+
global.set $oom_flag
|
|
26
|
+
local.get $size
|
|
27
|
+
global.set $oom_size
|
|
28
|
+
unreachable
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
;; 1. Align size to 8 bytes: size = (size + 7) & ~8
|
|
32
|
+
local.get $size
|
|
33
|
+
i32.const 7
|
|
34
|
+
i32.add
|
|
35
|
+
i32.const -8
|
|
36
|
+
i32.and
|
|
37
|
+
local.set $size
|
|
38
|
+
|
|
39
|
+
;; Get current free pointer
|
|
40
|
+
global.get $arena_free
|
|
41
|
+
local.set $old_free
|
|
42
|
+
|
|
43
|
+
;; Calculate proposed new free pointer
|
|
44
|
+
local.get $old_free
|
|
45
|
+
local.get $size
|
|
46
|
+
i32.add
|
|
47
|
+
local.set $new_free
|
|
48
|
+
|
|
49
|
+
;; Check for 32-bit unsigned overflow
|
|
50
|
+
local.get $new_free
|
|
51
|
+
local.get $old_free
|
|
52
|
+
i32.lt_u
|
|
53
|
+
if
|
|
54
|
+
i32.const 1
|
|
55
|
+
global.set $oom_flag
|
|
56
|
+
local.get $size
|
|
57
|
+
global.set $oom_size
|
|
58
|
+
unreachable
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
;; 2. Check if we exceed current memory size
|
|
62
|
+
local.get $new_free
|
|
63
|
+
global.get $arena_max
|
|
64
|
+
i32.gt_u
|
|
65
|
+
if
|
|
66
|
+
;; Calculate how many additional pages we need to grow
|
|
67
|
+
local.get $new_free
|
|
68
|
+
global.get $arena_max
|
|
69
|
+
i32.sub
|
|
70
|
+
i32.const 65535
|
|
71
|
+
i32.add
|
|
72
|
+
i32.const 65536
|
|
73
|
+
i32.div_u
|
|
74
|
+
local.set $pages_needed
|
|
75
|
+
|
|
76
|
+
;; Try to grow memory by $pages_needed
|
|
77
|
+
local.get $pages_needed
|
|
78
|
+
memory.grow
|
|
79
|
+
local.set $grow_res
|
|
80
|
+
|
|
81
|
+
;; If grow returns -1, we are out of memory
|
|
82
|
+
local.get $grow_res
|
|
83
|
+
i32.const -1
|
|
84
|
+
i32.eq
|
|
85
|
+
if
|
|
86
|
+
i32.const 1
|
|
87
|
+
global.set $oom_flag
|
|
88
|
+
local.get $size
|
|
89
|
+
global.set $oom_size
|
|
90
|
+
unreachable
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
;; Update arena_max: arena_max = arena_max + pages_needed * 65536
|
|
94
|
+
global.get $arena_max
|
|
95
|
+
local.get $pages_needed
|
|
96
|
+
i32.const 65536
|
|
97
|
+
i32.mul
|
|
98
|
+
i32.add
|
|
99
|
+
global.set $arena_max
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
;; 3. Perform the allocation
|
|
103
|
+
local.get $new_free
|
|
104
|
+
global.set $arena_free
|
|
105
|
+
|
|
106
|
+
local.get $old_free
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
;; Return a checkpoint that can be restored after a temporary result is consumed.
|
|
110
|
+
(func $arena_mark (export "arena_mark") (result i32)
|
|
111
|
+
global.get $arena_free
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
;; Bulk-free allocations made after a checkpoint. Memory pages remain available for reuse.
|
|
115
|
+
(func $arena_reset (export "arena_reset") (param $mark i32)
|
|
116
|
+
local.get $mark
|
|
117
|
+
i32.const 1024
|
|
118
|
+
i32.lt_u
|
|
119
|
+
if
|
|
120
|
+
unreachable
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
local.get $mark
|
|
124
|
+
global.get $arena_free
|
|
125
|
+
i32.gt_u
|
|
126
|
+
if
|
|
127
|
+
unreachable
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
local.get $mark
|
|
131
|
+
global.set $arena_free
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
;; Compaction staging globals
|
|
135
|
+
(global $compact_buf_start (mut i32) (i32.const 0))
|
|
136
|
+
(global $compact_buf_free (mut i32) (i32.const 0))
|
|
137
|
+
|
|
138
|
+
;; Ensure memory capacity in staging buffer
|
|
139
|
+
(func $ensure_buf_capacity (param $size i32)
|
|
140
|
+
(local $needed i32)
|
|
141
|
+
(local $pages i32)
|
|
142
|
+
(local $grow_res i32)
|
|
143
|
+
|
|
144
|
+
global.get $compact_buf_free
|
|
145
|
+
local.get $size
|
|
146
|
+
i32.add
|
|
147
|
+
local.set $needed
|
|
148
|
+
|
|
149
|
+
;; Check for 32-bit overflow
|
|
150
|
+
local.get $needed
|
|
151
|
+
global.get $compact_buf_free
|
|
152
|
+
i32.lt_u
|
|
153
|
+
if
|
|
154
|
+
i32.const 1
|
|
155
|
+
global.set $oom_flag
|
|
156
|
+
local.get $size
|
|
157
|
+
global.set $oom_size
|
|
158
|
+
unreachable
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
local.get $needed
|
|
162
|
+
global.get $arena_max
|
|
163
|
+
i32.gt_u
|
|
164
|
+
if
|
|
165
|
+
local.get $needed
|
|
166
|
+
global.get $arena_max
|
|
167
|
+
i32.sub
|
|
168
|
+
i32.const 65535
|
|
169
|
+
i32.add
|
|
170
|
+
i32.const 65536
|
|
171
|
+
i32.div_u
|
|
172
|
+
local.set $pages
|
|
173
|
+
|
|
174
|
+
local.get $pages
|
|
175
|
+
memory.grow
|
|
176
|
+
local.set $grow_res
|
|
177
|
+
|
|
178
|
+
local.get $grow_res
|
|
179
|
+
i32.const -1
|
|
180
|
+
i32.eq
|
|
181
|
+
if
|
|
182
|
+
i32.const 1
|
|
183
|
+
global.set $oom_flag
|
|
184
|
+
local.get $size
|
|
185
|
+
global.set $oom_size
|
|
186
|
+
unreachable
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
global.get $arena_max
|
|
190
|
+
local.get $pages
|
|
191
|
+
i32.const 65536
|
|
192
|
+
i32.mul
|
|
193
|
+
i32.add
|
|
194
|
+
global.set $arena_max
|
|
195
|
+
end
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
;; Initialize compaction staging buffer at current arena top
|
|
199
|
+
(func $compact_start (export "compact_start")
|
|
200
|
+
global.get $arena_free
|
|
201
|
+
global.set $compact_buf_start
|
|
202
|
+
global.get $arena_free
|
|
203
|
+
global.set $compact_buf_free
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
;; Compact an object graph reachable from $root down toward $mark
|
|
207
|
+
(func $compact_obj (export "compact_obj") (param $root i32) (param $mark i32) (result i32)
|
|
208
|
+
(local $curr i32)
|
|
209
|
+
(local $first_final i32)
|
|
210
|
+
(local $prev_dest i32)
|
|
211
|
+
(local $dest i32)
|
|
212
|
+
(local $final_ptr i32)
|
|
213
|
+
(local $tag i32)
|
|
214
|
+
(local $payload i32)
|
|
215
|
+
(local $size i32)
|
|
216
|
+
(local $alignedSize i32)
|
|
217
|
+
(local $N i32)
|
|
218
|
+
(local $i i32)
|
|
219
|
+
(local $offsetVal i32)
|
|
220
|
+
(local $fieldPtr i32)
|
|
221
|
+
(local $child_final i32)
|
|
222
|
+
|
|
223
|
+
local.get $root
|
|
224
|
+
local.set $curr
|
|
225
|
+
i32.const 0
|
|
226
|
+
local.set $prev_dest
|
|
227
|
+
|
|
228
|
+
(block $break_chain
|
|
229
|
+
(loop $chain_loop
|
|
230
|
+
;; 1. Check null / empty
|
|
231
|
+
local.get $curr
|
|
232
|
+
i32.eqz
|
|
233
|
+
if
|
|
234
|
+
local.get $prev_dest
|
|
235
|
+
if
|
|
236
|
+
local.get $prev_dest
|
|
237
|
+
i32.const 0
|
|
238
|
+
i32.store offset=8
|
|
239
|
+
end
|
|
240
|
+
br $break_chain
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
;; 2. Check if < mark
|
|
244
|
+
local.get $curr
|
|
245
|
+
local.get $mark
|
|
246
|
+
i32.lt_u
|
|
247
|
+
if
|
|
248
|
+
local.get $prev_dest
|
|
249
|
+
if
|
|
250
|
+
local.get $prev_dest
|
|
251
|
+
local.get $curr
|
|
252
|
+
i32.store offset=8
|
|
253
|
+
end
|
|
254
|
+
local.get $first_final
|
|
255
|
+
i32.eqz
|
|
256
|
+
if
|
|
257
|
+
local.get $curr
|
|
258
|
+
local.set $first_final
|
|
259
|
+
end
|
|
260
|
+
br $break_chain
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
;; 3. Check if forwarded
|
|
264
|
+
local.get $curr
|
|
265
|
+
i32.load offset=0
|
|
266
|
+
local.set $size
|
|
267
|
+
|
|
268
|
+
local.get $size
|
|
269
|
+
i32.const -1
|
|
270
|
+
i32.eq
|
|
271
|
+
if
|
|
272
|
+
local.get $curr
|
|
273
|
+
i32.load offset=4
|
|
274
|
+
local.set $final_ptr
|
|
275
|
+
local.get $prev_dest
|
|
276
|
+
if
|
|
277
|
+
local.get $prev_dest
|
|
278
|
+
local.get $final_ptr
|
|
279
|
+
i32.store offset=8
|
|
280
|
+
end
|
|
281
|
+
local.get $first_final
|
|
282
|
+
i32.eqz
|
|
283
|
+
if
|
|
284
|
+
local.get $final_ptr
|
|
285
|
+
local.set $first_final
|
|
286
|
+
end
|
|
287
|
+
br $break_chain
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
;; 4. Compute final_ptr = mark + (compact_buf_free - compact_buf_start)
|
|
291
|
+
local.get $mark
|
|
292
|
+
global.get $compact_buf_free
|
|
293
|
+
global.get $compact_buf_start
|
|
294
|
+
i32.sub
|
|
295
|
+
i32.add
|
|
296
|
+
local.set $final_ptr
|
|
297
|
+
|
|
298
|
+
local.get $first_final
|
|
299
|
+
i32.eqz
|
|
300
|
+
if
|
|
301
|
+
local.get $final_ptr
|
|
302
|
+
local.set $first_final
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
;; If prev_dest != 0, patch its payload to final_ptr
|
|
306
|
+
local.get $prev_dest
|
|
307
|
+
if
|
|
308
|
+
local.get $prev_dest
|
|
309
|
+
local.get $final_ptr
|
|
310
|
+
i32.store offset=8
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
;; 5. Check if Variant (size == 12)
|
|
314
|
+
local.get $size
|
|
315
|
+
i32.const 12
|
|
316
|
+
i32.eq
|
|
317
|
+
if
|
|
318
|
+
i32.const 16
|
|
319
|
+
call $ensure_buf_capacity
|
|
320
|
+
|
|
321
|
+
local.get $curr
|
|
322
|
+
i32.load offset=4
|
|
323
|
+
local.set $tag
|
|
324
|
+
local.get $curr
|
|
325
|
+
i32.load offset=8
|
|
326
|
+
local.set $payload
|
|
327
|
+
|
|
328
|
+
local.get $curr
|
|
329
|
+
i32.const -1
|
|
330
|
+
i32.store offset=0
|
|
331
|
+
local.get $curr
|
|
332
|
+
local.get $final_ptr
|
|
333
|
+
i32.store offset=4
|
|
334
|
+
|
|
335
|
+
global.get $compact_buf_free
|
|
336
|
+
local.set $dest
|
|
337
|
+
global.get $compact_buf_free
|
|
338
|
+
i32.const 16
|
|
339
|
+
i32.add
|
|
340
|
+
global.set $compact_buf_free
|
|
341
|
+
|
|
342
|
+
local.get $dest
|
|
343
|
+
i32.const 12
|
|
344
|
+
i32.store offset=0
|
|
345
|
+
local.get $dest
|
|
346
|
+
local.get $tag
|
|
347
|
+
i32.store offset=4
|
|
348
|
+
|
|
349
|
+
local.get $dest
|
|
350
|
+
local.set $prev_dest
|
|
351
|
+
local.get $payload
|
|
352
|
+
local.set $curr
|
|
353
|
+
br $chain_loop
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
;; 6. Product handling (size != 12)
|
|
357
|
+
local.get $size
|
|
358
|
+
i32.const 7
|
|
359
|
+
i32.add
|
|
360
|
+
i32.const -8
|
|
361
|
+
i32.and
|
|
362
|
+
local.set $alignedSize
|
|
363
|
+
|
|
364
|
+
local.get $alignedSize
|
|
365
|
+
call $ensure_buf_capacity
|
|
366
|
+
|
|
367
|
+
local.get $curr
|
|
368
|
+
i32.load offset=4
|
|
369
|
+
local.set $N
|
|
370
|
+
|
|
371
|
+
local.get $curr
|
|
372
|
+
i32.const -1
|
|
373
|
+
i32.store offset=0
|
|
374
|
+
local.get $curr
|
|
375
|
+
local.get $final_ptr
|
|
376
|
+
i32.store offset=4
|
|
377
|
+
|
|
378
|
+
global.get $compact_buf_free
|
|
379
|
+
local.set $dest
|
|
380
|
+
global.get $compact_buf_free
|
|
381
|
+
local.get $alignedSize
|
|
382
|
+
i32.add
|
|
383
|
+
global.set $compact_buf_free
|
|
384
|
+
|
|
385
|
+
local.get $dest
|
|
386
|
+
local.get $size
|
|
387
|
+
i32.store offset=0
|
|
388
|
+
local.get $dest
|
|
389
|
+
local.get $N
|
|
390
|
+
i32.store offset=4
|
|
391
|
+
|
|
392
|
+
i32.const 0
|
|
393
|
+
local.set $i
|
|
394
|
+
(block $break_prod
|
|
395
|
+
(loop $loop_prod
|
|
396
|
+
local.get $i
|
|
397
|
+
local.get $N
|
|
398
|
+
i32.ge_u
|
|
399
|
+
br_if $break_prod
|
|
400
|
+
|
|
401
|
+
local.get $curr
|
|
402
|
+
i32.const 8
|
|
403
|
+
local.get $i
|
|
404
|
+
i32.const 4
|
|
405
|
+
i32.mul
|
|
406
|
+
i32.add
|
|
407
|
+
i32.add
|
|
408
|
+
i32.load
|
|
409
|
+
local.set $offsetVal
|
|
410
|
+
|
|
411
|
+
local.get $dest
|
|
412
|
+
i32.const 8
|
|
413
|
+
local.get $i
|
|
414
|
+
i32.const 4
|
|
415
|
+
i32.mul
|
|
416
|
+
i32.add
|
|
417
|
+
i32.add
|
|
418
|
+
local.get $offsetVal
|
|
419
|
+
i32.store
|
|
420
|
+
|
|
421
|
+
local.get $curr
|
|
422
|
+
local.get $offsetVal
|
|
423
|
+
i32.add
|
|
424
|
+
i32.load
|
|
425
|
+
local.set $fieldPtr
|
|
426
|
+
|
|
427
|
+
local.get $fieldPtr
|
|
428
|
+
local.get $mark
|
|
429
|
+
call $compact_obj
|
|
430
|
+
local.set $child_final
|
|
431
|
+
|
|
432
|
+
local.get $dest
|
|
433
|
+
local.get $offsetVal
|
|
434
|
+
i32.add
|
|
435
|
+
local.get $child_final
|
|
436
|
+
i32.store
|
|
437
|
+
|
|
438
|
+
local.get $i
|
|
439
|
+
i32.const 1
|
|
440
|
+
i32.add
|
|
441
|
+
local.set $i
|
|
442
|
+
br $loop_prod
|
|
443
|
+
)
|
|
444
|
+
)
|
|
445
|
+
br $break_chain
|
|
446
|
+
)
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
local.get $first_final
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
;; Finalize compaction by copying staging buffer into mark and resetting arena_free
|
|
453
|
+
(func $compact_finish (export "compact_finish") (param $mark i32)
|
|
454
|
+
(local $total_size i32)
|
|
455
|
+
global.get $compact_buf_free
|
|
456
|
+
global.get $compact_buf_start
|
|
457
|
+
i32.sub
|
|
458
|
+
local.set $total_size
|
|
459
|
+
|
|
460
|
+
local.get $total_size
|
|
461
|
+
i32.const 0
|
|
462
|
+
i32.gt_u
|
|
463
|
+
if
|
|
464
|
+
local.get $mark
|
|
465
|
+
global.get $compact_buf_start
|
|
466
|
+
local.get $total_size
|
|
467
|
+
memory.copy
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
local.get $mark
|
|
471
|
+
local.get $total_size
|
|
472
|
+
i32.add
|
|
473
|
+
global.set $arena_free
|
|
474
|
+
)
|
|
475
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
|
+
const node = process.execPath;
|
|
9
|
+
const tests = [
|
|
10
|
+
["tests/test-wasm.mjs", node, ["tests/test-wasm.mjs"]],
|
|
11
|
+
["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function formatDuration(milliseconds) {
|
|
15
|
+
if (milliseconds < 1000) return `${milliseconds.toFixed(0)} ms`;
|
|
16
|
+
return `${(milliseconds / 1000).toFixed(2)} s`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const suiteStarted = performance.now();
|
|
20
|
+
for (const [name, command, args] of tests) {
|
|
21
|
+
console.log(`\n==> ${name}`);
|
|
22
|
+
const started = performance.now();
|
|
23
|
+
const result = spawnSync(command, args, {
|
|
24
|
+
cwd: root,
|
|
25
|
+
stdio: "inherit"
|
|
26
|
+
});
|
|
27
|
+
const duration = formatDuration(performance.now() - started);
|
|
28
|
+
|
|
29
|
+
if (result.error) {
|
|
30
|
+
console.error(`<== ${name} FAILED (${duration})`);
|
|
31
|
+
console.error(result.error.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
if (result.status !== 0) {
|
|
35
|
+
console.error(`<== ${name} FAILED (${duration})`);
|
|
36
|
+
process.exit(result.status ?? 1);
|
|
37
|
+
}
|
|
38
|
+
console.log(`<== ${name} passed (${duration})`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`\nAll tests passed (${formatDuration(performance.now() - suiteStarted)})`);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { decodeObject, loadLibrary } from "@fraczak/k/backend-api.mjs";
|
|
5
|
+
import {
|
|
6
|
+
compileWasmArtifact,
|
|
7
|
+
compileWasmArtifactFromKVM,
|
|
8
|
+
compileWasmArtifactFromObject
|
|
9
|
+
} from "./wasm.mjs";
|
|
10
|
+
|
|
11
|
+
function readAll(stream) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
15
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
16
|
+
stream.on("error", reject);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseCompileOptions(args) {
|
|
21
|
+
const libraries = [];
|
|
22
|
+
const exportSpecs = [];
|
|
23
|
+
let loadedLibrary = false;
|
|
24
|
+
|
|
25
|
+
while (args.length > 0) {
|
|
26
|
+
if (args[0] === "--") {
|
|
27
|
+
args.shift();
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (args[0] === "--lib") {
|
|
31
|
+
if (loadedLibrary) throw new Error("--lib may only be specified once");
|
|
32
|
+
args.shift();
|
|
33
|
+
const libPath = args.shift();
|
|
34
|
+
if (!libPath) throw new Error("--lib requires a file argument");
|
|
35
|
+
libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
|
|
36
|
+
loadedLibrary = true;
|
|
37
|
+
} else if (args[0] === "--export") {
|
|
38
|
+
args.shift();
|
|
39
|
+
const spec = args.shift();
|
|
40
|
+
if (!spec) throw new Error("--export requires a spec argument (name or libname:localname)");
|
|
41
|
+
exportSpecs.push(spec);
|
|
42
|
+
} else if (args[0].startsWith("--")) {
|
|
43
|
+
throw new Error(`Unknown option: ${args[0]}`);
|
|
44
|
+
} else {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { libraries, exportSpecs };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function fileInputType(filePath) {
|
|
53
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
54
|
+
if (ext === ".ko") return "ko";
|
|
55
|
+
if (ext === ".kvm") return "kvm";
|
|
56
|
+
if (ext === ".klib") return "klib";
|
|
57
|
+
return "source-file";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveProgramInput(args, { allowStdinSource = false } = {}) {
|
|
61
|
+
const inputArg = args.shift() ?? null;
|
|
62
|
+
if (inputArg == null) {
|
|
63
|
+
if (!allowStdinSource) throw new Error("Missing script argument");
|
|
64
|
+
return { kind: "stdin-source", sourceName: "<stdin>" };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ext = path.extname(inputArg).toLowerCase();
|
|
68
|
+
if (fs.existsSync(inputArg)) {
|
|
69
|
+
const kind = fileInputType(inputArg);
|
|
70
|
+
if (kind === "klib") {
|
|
71
|
+
throw new Error("Cannot compile a .klib library to WebAssembly without a main relation; load it with --lib.");
|
|
72
|
+
}
|
|
73
|
+
return { kind, path: inputArg, sourceName: inputArg };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if ([".k", ".ko", ".kvm", ".klib", ".wasm"].includes(ext)) {
|
|
77
|
+
throw new Error(`Input file not found: ${inputArg}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { kind: "inline-source", source: inputArg, sourceName: "<inline>" };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function compileProgramInput(
|
|
84
|
+
input,
|
|
85
|
+
{ libraries = [], exportSpecs = [], stdin = null, inputEnvelopePattern = null } = {}
|
|
86
|
+
) {
|
|
87
|
+
if (input.kind === "inline-source") {
|
|
88
|
+
return compileWasmArtifact(input.source, {
|
|
89
|
+
libraries,
|
|
90
|
+
exports: exportSpecs,
|
|
91
|
+
source: input.sourceName,
|
|
92
|
+
inputEnvelopePattern
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (input.kind === "stdin-source") {
|
|
97
|
+
if (!stdin) throw new Error("stdin source requested without a stdin stream");
|
|
98
|
+
return compileWasmArtifact((await readAll(stdin)).toString("utf8"), {
|
|
99
|
+
libraries,
|
|
100
|
+
exports: exportSpecs,
|
|
101
|
+
source: input.sourceName,
|
|
102
|
+
inputEnvelopePattern
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (input.kind === "source-file") {
|
|
107
|
+
return compileWasmArtifact(fs.readFileSync(input.path, "utf8"), {
|
|
108
|
+
libraries,
|
|
109
|
+
exports: exportSpecs,
|
|
110
|
+
source: input.sourceName,
|
|
111
|
+
inputEnvelopePattern
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (input.kind === "ko") {
|
|
116
|
+
return compileWasmArtifactFromObject(decodeObject(fs.readFileSync(input.path)), {
|
|
117
|
+
inputEnvelopePattern
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (input.kind === "kvm") {
|
|
122
|
+
return compileWasmArtifactFromKVM(JSON.parse(fs.readFileSync(input.path, "utf8")));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
throw new Error(`Unsupported input kind: ${input.kind}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
compileProgramInput,
|
|
130
|
+
parseCompileOptions,
|
|
131
|
+
readAll,
|
|
132
|
+
resolveProgramInput
|
|
133
|
+
};
|