@fraczak/k 6.3.3 → 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.
- 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 +51 -48
- 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/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 +60 -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 +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -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 +617 -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 +2 -2
- 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,97 @@
|
|
|
1
|
+
# k WebAssembly Backend
|
|
2
|
+
|
|
3
|
+
`@fraczak/k-wasm` is the experimental WebAssembly backend for
|
|
4
|
+
[`@fraczak/k`](https://github.com/fraczak/k). It lowers typed k programs through
|
|
5
|
+
the kVM representation, emits standard `.wasm` modules with WABT, and provides
|
|
6
|
+
a Node.js runner for the binary `pattern + value` streams used by the k codec
|
|
7
|
+
toolchain.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Install dependencies from the monorepo root:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Optionally expose the three backend commands on your path:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm link
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
Compile an expression into a standalone WebAssembly artifact:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node ./bin/k-wasm-compile.mjs '|ok' /tmp/ok.wasm
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Run it over the unit value and print the decoded result:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
node ../../codecs/unit.mjs --parse |
|
|
35
|
+
node ./bin/k-wasm-run.mjs /tmp/ok.wasm |
|
|
36
|
+
node ../../codecs/k-print.mjs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Expected output:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
"ok"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
With the backend and k codec commands on your path, the equivalent shorter
|
|
46
|
+
form is:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
k-wasm-compile '|ok' /tmp/ok.wasm
|
|
50
|
+
k-unit --parse | k-wasm-run /tmp/ok.wasm | k-print
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Commands
|
|
54
|
+
|
|
55
|
+
| Command | Purpose |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `k-wasm` | Compile k source, `.ko`, or `.kvm` input in memory and run it immediately |
|
|
58
|
+
| `k-wasm-compile` | Compile k source, `.ko`, or `.kvm` input into a `.wasm` artifact |
|
|
59
|
+
| `k-wasm-run` | Run an existing `.wasm` artifact over a binary input stream |
|
|
60
|
+
|
|
61
|
+
All commands accept `--help`. The compile commands follow the `k-compile`
|
|
62
|
+
input convention: pass inline source, an existing source path, a `.ko` object,
|
|
63
|
+
or a `.kvm` program. They also accept one `--lib` option for a `.klib`
|
|
64
|
+
dependency and repeated `--export` options to bring library aliases into the
|
|
65
|
+
source scope. Existing paths are treated as files; non-existing names with
|
|
66
|
+
`.k`, `.ko`, `.kvm`, `.klib`, or `.wasm` extensions are treated as missing
|
|
67
|
+
files; other arguments are treated as inline source. The runners read a binary
|
|
68
|
+
input stream from standard input unless an input file is given.
|
|
69
|
+
|
|
70
|
+
## Artifacts
|
|
71
|
+
|
|
72
|
+
The compiler produces a standard WebAssembly binary module containing the
|
|
73
|
+
reachable relations, the arena runtime, and a `k.metadata` custom section. The
|
|
74
|
+
metadata stores the entry point and the pattern information needed to encode
|
|
75
|
+
and decode values. A compiled artifact can be run later without its original k
|
|
76
|
+
source, object, kVM, or `.klib` files.
|
|
77
|
+
|
|
78
|
+
The current host runner targets Node.js. It is still needed to bridge between
|
|
79
|
+
WebAssembly linear memory and k binary streams.
|
|
80
|
+
|
|
81
|
+
## Development
|
|
82
|
+
|
|
83
|
+
Run the test suite:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm test
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Run the comparative IEEE benchmark:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm run perf:ieee
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
See [DOCS/USE-WEB-ASSEMBLY.md](DOCS/USE-WEB-ASSEMBLY.md) for the artifact
|
|
96
|
+
format, source-file and library examples, profiling options, and current
|
|
97
|
+
limitations.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Technical Debt
|
|
2
|
+
|
|
3
|
+
## Polymorphic Input Retyping for Precompiled Wasm
|
|
4
|
+
|
|
5
|
+
`k-wasm` can retype a polymorphic program when it compiles and runs in one step:
|
|
6
|
+
the CLI decodes the input stream first, intersects the program input pattern with
|
|
7
|
+
the input value envelope, and compiles a specialized WebAssembly module for that
|
|
8
|
+
run.
|
|
9
|
+
|
|
10
|
+
`k-wasm-run` cannot currently do the same for an already compiled `.wasm`
|
|
11
|
+
artifact. By the time the runner sees the input envelope, the k program has
|
|
12
|
+
already been lowered to WebAssembly and the artifact only carries metadata such
|
|
13
|
+
as the generic input/output patterns. The original source/object relation graph
|
|
14
|
+
needed to re-run type derivation is not available.
|
|
15
|
+
|
|
16
|
+
This means precompiled artifacts can execute polymorphic programs, but their
|
|
17
|
+
output envelopes are limited to the generic artifact metadata rather than being
|
|
18
|
+
retyped against each input envelope.
|
|
19
|
+
|
|
20
|
+
One possible fix is to delay compilation for programs with polymorphic input
|
|
21
|
+
until the input envelope is available. That could mean storing enough source,
|
|
22
|
+
object, or typed relation data in the artifact to specialize on first run, or
|
|
23
|
+
using a separate artifact form for deferred compilation.
|
|
24
|
+
|
|
25
|
+
## Wasm Arena Memory Management
|
|
26
|
+
|
|
27
|
+
The WebAssembly backend currently uses a bump arena for all product and variant
|
|
28
|
+
values created during execution. This keeps allocation cheap and simple, and
|
|
29
|
+
failed union branches can roll the arena back to a checkpoint, but successful
|
|
30
|
+
paths do not reclaim temporary values until the whole run ends.
|
|
31
|
+
|
|
32
|
+
Tail-call lowering now avoids allocating replacement input products for some
|
|
33
|
+
self-tail-recursive loops by keeping top-level product fields in Wasm locals.
|
|
34
|
+
That improves arithmetic workloads such as `factorial:o`, but it is still only
|
|
35
|
+
a first step. Large runs still allocate far more arena memory than the final
|
|
36
|
+
result requires because intermediate relation results, accumulator fragments,
|
|
37
|
+
and temporary products remain in the bump arena.
|
|
38
|
+
|
|
39
|
+
Future memory-management targets:
|
|
40
|
+
|
|
41
|
+
- Add allocation profiling that attributes arena growth to generated relations
|
|
42
|
+
and static allocation sites. Large regressions should be visible without
|
|
43
|
+
manually instrumenting `factorial:o` or similar workloads.
|
|
44
|
+
- Extend local-loop lowering beyond top-level product fields. Hot tail loops
|
|
45
|
+
should keep common accumulator state in locals where possible and materialize
|
|
46
|
+
arena values only at function boundaries or observable return points.
|
|
47
|
+
- Introduce safe lifetime boundaries for successful non-tail calls. The runtime
|
|
48
|
+
needs a way to reclaim scratch values after a callee result has been consumed
|
|
49
|
+
without copying large live values on every call.
|
|
50
|
+
- Make arena checkpoints part of code generation decisions, not just union
|
|
51
|
+
failure handling. Tail loops should be able to reset dead scratch space while
|
|
52
|
+
preserving the next live input/result.
|
|
53
|
+
- Keep unsigned pointer handling explicit. Wasm arena addresses are `i32`
|
|
54
|
+
offsets, and JavaScript sees exported `i32` values as signed numbers, so all
|
|
55
|
+
JS-side arena offsets must be normalized before `DataView` access.
|
|
56
|
+
|
|
57
|
+
The preferred direction is performance first: reduce allocation volume in hot
|
|
58
|
+
generated loops before adding a general garbage collector or compaction pass.
|
|
59
|
+
Copying live arena values can control memory, but it risks slowing exactly the
|
|
60
|
+
large recursive arithmetic workloads that motivated tail-call lowering.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
compileProgramInput,
|
|
8
|
+
parseCompileOptions,
|
|
9
|
+
resolveProgramInput
|
|
10
|
+
} from "../src/cli.mjs";
|
|
11
|
+
|
|
12
|
+
function usage(stream = console.error) {
|
|
13
|
+
const prog = argv[1] || "k-wasm-compile.mjs";
|
|
14
|
+
stream(`Usage: node ${prog} [options] [source-snippet | input-file [wasm-file]]`);
|
|
15
|
+
stream("Compile k source, .ko, or .kvm input into a standalone WebAssembly artifact.");
|
|
16
|
+
stream("");
|
|
17
|
+
stream("Arguments:");
|
|
18
|
+
stream(" source-snippet Inline k source, in the same style as k.mjs.");
|
|
19
|
+
stream(" input-file Source .k, .ko, or .kvm file. Reads UTF-8 source from stdin when omitted.");
|
|
20
|
+
stream(" wasm-file Output .wasm path. Writes the binary artifact to stdout when omitted.");
|
|
21
|
+
stream("");
|
|
22
|
+
stream("Options:");
|
|
23
|
+
stream(" --lib file Load one .klib dependency before compiling.");
|
|
24
|
+
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
25
|
+
stream(" spec is 'name' or 'libname:localname'.");
|
|
26
|
+
stream(" -h, --help Show this help.");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const args = argv.slice(2);
|
|
31
|
+
if (args.includes("-h") || args.includes("--help")) {
|
|
32
|
+
usage(console.log);
|
|
33
|
+
exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const { libraries, exportSpecs } = parseCompileOptions(args);
|
|
37
|
+
const input = resolveProgramInput(args, { allowStdinSource: true });
|
|
38
|
+
const outputPath = args.shift();
|
|
39
|
+
if (args.length > 0) throw new Error("Too many arguments");
|
|
40
|
+
const artifact = await compileProgramInput(input, { libraries, exportSpecs, stdin });
|
|
41
|
+
if (outputPath == null) {
|
|
42
|
+
stdout.write(artifact);
|
|
43
|
+
} else {
|
|
44
|
+
fs.writeFileSync(outputPath, artifact);
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error(error.stack || error.message || String(error));
|
|
48
|
+
usage();
|
|
49
|
+
exit(1);
|
|
50
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, exit, stdin, stdout, stderr } from "node:process";
|
|
5
|
+
|
|
6
|
+
import { instantiateWasmArtifact } from "../src/wasm.mjs";
|
|
7
|
+
|
|
8
|
+
function usage(stream = console.error) {
|
|
9
|
+
const prog = argv[1] || "k-wasm-run.mjs";
|
|
10
|
+
stream(`Usage: node ${prog} [ --server ] wasm-file [ input-file ]`);
|
|
11
|
+
stream("Run a standalone k WebAssembly artifact over a binary pattern+value stream.");
|
|
12
|
+
stream("");
|
|
13
|
+
stream("Arguments:");
|
|
14
|
+
stream(" wasm-file Input .wasm artifact produced by k-wasm-compile.");
|
|
15
|
+
stream(" input-file Optional binary input stream. Reads stdin when omitted.");
|
|
16
|
+
stream("");
|
|
17
|
+
stream("Options:");
|
|
18
|
+
stream(" --server Run as a persistent server reading framed requests from stdin.");
|
|
19
|
+
stream(" -h, --help Show this help.");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readAll(stream) {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
26
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
27
|
+
stream.on("error", reject);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function runServer(runner) {
|
|
32
|
+
const tracing = process.env.K_TRACE === "1" || process.env.TRACE === "1";
|
|
33
|
+
let inBuffer = Buffer.alloc(0);
|
|
34
|
+
let readStartNs = 0n;
|
|
35
|
+
|
|
36
|
+
stdin.on("data", (chunk) => {
|
|
37
|
+
if (inBuffer.length === 0) {
|
|
38
|
+
readStartNs = process.hrtime.bigint();
|
|
39
|
+
}
|
|
40
|
+
inBuffer = Buffer.concat([inBuffer, chunk]);
|
|
41
|
+
processBuffer();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
stdin.on("end", () => {
|
|
45
|
+
exit(0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function processBuffer() {
|
|
49
|
+
while (inBuffer.length >= 4) {
|
|
50
|
+
const len = inBuffer.readUInt32BE(0);
|
|
51
|
+
if (inBuffer.length < 4 + len) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
const t1 = process.hrtime.bigint();
|
|
55
|
+
const payload = inBuffer.subarray(4, 4 + len);
|
|
56
|
+
inBuffer = inBuffer.subarray(4 + len);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
let outWire;
|
|
60
|
+
let trace = null;
|
|
61
|
+
if (tracing) {
|
|
62
|
+
const res = runner.execute(payload, { trace: true });
|
|
63
|
+
outWire = res.outputWire;
|
|
64
|
+
trace = res.trace;
|
|
65
|
+
} else {
|
|
66
|
+
outWire = runner.execute(payload);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const writeStart = process.hrtime.bigint();
|
|
70
|
+
const outHdr = Buffer.allocUnsafe(4);
|
|
71
|
+
outHdr.writeUInt32BE(outWire.length, 0);
|
|
72
|
+
stdout.write(outHdr);
|
|
73
|
+
stdout.write(outWire);
|
|
74
|
+
const tEnd = process.hrtime.bigint();
|
|
75
|
+
|
|
76
|
+
if (tracing && trace) {
|
|
77
|
+
const ipcReadNs = readStartNs > 0n ? Number(t1 - readStartNs) : 0;
|
|
78
|
+
const decodeNs = trace.decodeNs;
|
|
79
|
+
const flatInNs = trace.flatInNs;
|
|
80
|
+
const evalNs = trace.evalNs;
|
|
81
|
+
const flatOutNs = trace.flatOutNs;
|
|
82
|
+
const encodeNs = trace.encodeNs;
|
|
83
|
+
const ipcWriteNs = Number(tEnd - writeStart);
|
|
84
|
+
const totalNs = Number(tEnd - (readStartNs > 0n ? readStartNs : t1));
|
|
85
|
+
stderr.write(`K_TRACE_PHASES backend=wasm ipc_read_ns=${ipcReadNs} decode_ns=${decodeNs} flat_in_ns=${flatInNs} eval_ns=${evalNs} flat_out_ns=${flatOutNs} encode_ns=${encodeNs} ipc_write_ns=${ipcWriteNs} total_ns=${totalNs}\n`);
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
stderr.write(`Wasm server error: ${err.stack || err.message || String(err)}\n`);
|
|
89
|
+
exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
readStartNs = process.hrtime.bigint();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function main() {
|
|
98
|
+
const rawArgs = argv.slice(2);
|
|
99
|
+
if (rawArgs.includes("-h") || rawArgs.includes("--help")) {
|
|
100
|
+
usage(console.log);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const isServer = rawArgs.includes("--server");
|
|
105
|
+
const args = rawArgs.filter(a => a !== "--server");
|
|
106
|
+
|
|
107
|
+
const wasmPath = args.shift();
|
|
108
|
+
if (!wasmPath) throw new Error("Missing .wasm artifact path");
|
|
109
|
+
|
|
110
|
+
const artifact = fs.readFileSync(wasmPath);
|
|
111
|
+
const runner = await instantiateWasmArtifact(artifact);
|
|
112
|
+
|
|
113
|
+
if (isServer) {
|
|
114
|
+
if (args.length > 0) throw new Error("Too many arguments for --server mode");
|
|
115
|
+
await runServer(runner);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const inputPath = args.shift();
|
|
120
|
+
if (args.length > 0) throw new Error("Too many arguments");
|
|
121
|
+
|
|
122
|
+
const input = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
|
|
123
|
+
const tracing = process.env.K_TRACE === "1" || process.env.TRACE === "1";
|
|
124
|
+
if (tracing) {
|
|
125
|
+
const res = runner.execute(input, { trace: true });
|
|
126
|
+
stdout.write(res.outputWire);
|
|
127
|
+
if (res.trace) {
|
|
128
|
+
const trace = res.trace;
|
|
129
|
+
stderr.write(`K_TRACE_PHASES backend=wasm ipc_read_ns=0 decode_ns=${trace.decodeNs} flat_in_ns=${trace.flatInNs} eval_ns=${trace.evalNs} flat_out_ns=${trace.flatOutNs} encode_ns=${trace.encodeNs} ipc_write_ns=0 total_ns=${trace.evalNs}\n`);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
stdout.write(runner.execute(input));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main().catch((error) => {
|
|
137
|
+
console.error(error.stack || error.message || String(error));
|
|
138
|
+
usage();
|
|
139
|
+
exit(1);
|
|
140
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
+
import { decodeWire } from "@fraczak/k/backend-api.mjs";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
compileProgramInput,
|
|
9
|
+
parseCompileOptions,
|
|
10
|
+
readAll,
|
|
11
|
+
resolveProgramInput
|
|
12
|
+
} from "../src/cli.mjs";
|
|
13
|
+
import { runWasmArtifact } from "../src/wasm.mjs";
|
|
14
|
+
|
|
15
|
+
function usage(stream = console.error) {
|
|
16
|
+
const prog = argv[1] || "k-wasm.mjs";
|
|
17
|
+
stream(`Usage: node ${prog} [options] ( source-snippet | input-file ) [ input-file ]`);
|
|
18
|
+
stream("Compile k source, .ko, or .kvm input to WebAssembly in memory and run it over a binary pattern+value stream.");
|
|
19
|
+
stream("");
|
|
20
|
+
stream("Options:");
|
|
21
|
+
stream(" --lib file Load one .klib dependency before compiling.");
|
|
22
|
+
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
23
|
+
stream(" spec is 'name' or 'libname:localname'.");
|
|
24
|
+
stream(" -h, --help Show this help.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function main() {
|
|
28
|
+
const args = argv.slice(2);
|
|
29
|
+
if (args.includes("-h") || args.includes("--help")) {
|
|
30
|
+
usage(console.log);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { libraries, exportSpecs } = parseCompileOptions(args);
|
|
35
|
+
const programInput = resolveProgramInput(args);
|
|
36
|
+
const inputPath = args.shift();
|
|
37
|
+
if (args.length > 0) throw new Error("Too many arguments");
|
|
38
|
+
|
|
39
|
+
const inputBuffer = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
|
|
40
|
+
const { pattern: inputEnvelopePattern } = decodeWire(inputBuffer);
|
|
41
|
+
const artifact = await compileProgramInput(programInput, { libraries, exportSpecs, inputEnvelopePattern });
|
|
42
|
+
stdout.write(await runWasmArtifact(artifact, inputBuffer));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
main().catch((error) => {
|
|
46
|
+
console.error(error.stack || error.message || String(error));
|
|
47
|
+
usage();
|
|
48
|
+
exit(1);
|
|
49
|
+
});
|