@amritk/nish-x86_64-linux 0.27.2 → 0.28.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/INSTALL.md CHANGED
@@ -254,7 +254,8 @@ routes are
254
254
  # on the musl host, with its own clang and the runtime from this repository
255
255
  clang app.ll runtime/runtime.c runtime/runtime-os.c runtime/runtime-parallel.c \
256
256
  runtime/runtime-cross.c runtime/runtime-host.c runtime/runtime-net.c \
257
- runtime/runtime-simd.c runtime/runtime-aes.c runtime/runtime-term.c runtime/runtime-bytes.c -lm -o app
257
+ runtime/runtime-simd.c runtime/runtime-aes.c runtime/runtime-sha256.c runtime/runtime-term.c \
258
+ runtime/runtime-bytes.c runtime/runtime-checksum.c runtime/runtime-sandbox.c -lm -o app
258
259
  ```
259
260
 
260
261
  `--link`ing inside the container is the mistake to avoid: it shells out to the
@@ -390,7 +391,7 @@ it into `build/seed/`; `NISH_BOOTSTRAP=<path>` names one you already have and
390
391
  skips the download. §2a has what the build does with it.
391
392
 
392
393
  The published package ships `bin/` (the `nish` command, which is a launcher),
393
- `runtime/` (the C runtime — ten translation units, the wasm subset and their
394
+ `runtime/` (the C runtime — thirteen translation units, the wasm subset and their
394
395
  header — and `runtime/sqlite/`, SQLite's vendored source),
395
396
  `scripts/build.sh` (the link pipeline), `std/` (the standard library) and
396
397
  `docs/AI.md` (the rules card). The
@@ -403,12 +404,13 @@ working directory — and the binary runs from inside its own platform package
403
404
  for exactly that reason.
404
405
 
405
406
  Building the IR yourself rather than through `--link` means naming the runtime
406
- on the `clang` line, and it is ten files:
407
+ on the `clang` line, and it is thirteen files:
407
408
 
408
409
  ```bash
409
410
  clang app.ll runtime/runtime.c runtime/runtime-os.c runtime/runtime-parallel.c \
410
411
  runtime/runtime-cross.c runtime/runtime-host.c runtime/runtime-net.c \
411
- runtime/runtime-simd.c runtime/runtime-aes.c runtime/runtime-term.c runtime/runtime-bytes.c -lm -o app
412
+ runtime/runtime-simd.c runtime/runtime-aes.c runtime/runtime-sha256.c runtime/runtime-term.c \
413
+ runtime/runtime-bytes.c runtime/runtime-checksum.c runtime/runtime-sandbox.c -lm -o app
412
414
  ```
413
415
 
414
416
  `runtime.c` is the part every program touches — the arena, strings, arrays,
@@ -421,14 +423,17 @@ the strings and arrays a task answers, a channel sends or a `Mutex` keeps out
421
423
  of the arena they were made in, `runtime-host.c` holds the wall clock,
422
424
  entropy, file times and signals, `runtime-net.c` the sockets of `nish:net`,
423
425
  `runtime-simd.c` and `runtime-aes.c` the vector text search and AES-GCM,
424
- `runtime-term.c` the stdin reads and terminal calls of `nish:term`, and
426
+ `runtime-sha256.c` the SHA-256 block kernel `nish/crypto/sha256` hands its
427
+ blocks to on a CPU with the SHA instructions (`NISH_SHA256=soft` keeps the
428
+ portable path), `runtime-term.c` the stdin reads and terminal calls of `nish:term`,
425
429
  `runtime-bytes.c` the byte-class runs of `nish/bytes`, which `nish/json` steps
426
- over.
430
+ over, `runtime-checksum.c` the CRC-32 kernels of `nish/compress/checksum`,
431
+ and `runtime-sandbox.c` the confinement a `--sandbox` build applies.
427
432
  They are separate so that each carries its own measured size ceiling
428
433
  ([docs/wp7-runtime.md](wp7-runtime.md)); nothing in the core calls into the
429
434
  others, so a line that names only `runtime.c` and `runtime-os.c` still links a
430
- program that uses none of the other eight. `scripts/build.sh` compiles the other
431
- eight beside any
435
+ program that uses none of the other nine. `scripts/build.sh` compiles the other
436
+ nine beside any
432
437
  `runtime.c` it is handed, so a build that goes through it — every `--link`,
433
438
  and every `--profile` recipe in these documents — needs to name only the one.
434
439
 
package/bin/nish CHANGED
Binary file
package/docs/AI.md CHANGED
@@ -2619,7 +2619,8 @@ negative `DEFLATE_ERR_*` / `GZIP_ERR_*` code for any malformed stream, so test
2619
2619
  it before reading `out`. `GzipWriter` and `GzipReader` stream. On HTTP/1.1,
2620
2620
  `conn.respondEncoded(status, names, values, body, off, len, enc,
2621
2621
  conn.acceptEncoding())` with an `HttpCompressor` from `nish/net/http-compress`
2622
- negotiates, compresses and sets the fields. Do not compress a secret beside
2622
+ negotiates, compresses when it pays (`minLength`, `minSavingPercent`,
2623
+ `segmentMode`; `enc.decision` says why not) and sets the fields. Do not compress a secret beside
2623
2624
  text the client chose (BREACH). (No block, as for `nish/text`;
2624
2625
  `tests/link/std_compress` is its program, and the user guide's
2625
2626
  [compression page](guide/using-nish/compression.md) its walk-through.)
@@ -2665,7 +2666,7 @@ or `PG_LOST` to `fail(run)` (on a spent handle these do nothing and count in
2665
2666
  `stray`), and after each call `next(run)` until
2666
2667
  `PG_BATCH_NONE`: `PG_BATCH_ROW` (the connection's row answers request `tag`),
2667
2668
  then one of `PG_BATCH_DONE`, `PG_BATCH_MISSING` or `PG_BATCH_FAILED` per
2668
- request. It reads no clock: when to take is the loop's choice. (No block;
2669
+ request. It reads no clock: when to take is the loop's choice, or a `PgBatchClock`'s (`PgBatchClockConfig`: `minCount`, `factor` × the moving average of batch sizes, `maxWaitUs`, the idle bypass `lightCount`; defaults are a fixed window), which `takeDue(conn, clock, nowUs, pool.inFlight())` consults after `clock.arrived(nowUs)` per add; `PgBatchTurns` wakes one collecting connection only when its batch is due. (No block;
2669
2670
  `tests/postgres/live`'s `batch` scenario runs it against a server, and the user
2670
2671
  guide's [PostgreSQL page](guide/using-nish/postgres.md#batching-keyed-reads)
2671
2672
  its walk-through.)
@@ -2822,6 +2823,22 @@ const settings = (): string => readFileSync("settings.txt");
2822
2823
  export const main = (): i32 => settings().length;
2823
2824
  ```
2824
2825
 
2826
+ The policy judges the source; `--sandbox` (Linux, `--link` and `nish run`)
2827
+ makes the kernel hold the running binary to the same set. Before any C
2828
+ constructor runs, it withholds every file, process and socket operation `main`
2829
+ does not reach, C code it links included. A file operation it refuses fails
2830
+ like a missing permission; a refused process or socket call ends the program
2831
+ with `SIGSYS` (status 159); a kernel that cannot apply it exits 126 before
2832
+ `main` unless built with `--sandbox=best-effort`. A darwin target, a library
2833
+ with no `main` and `--emit-napi` refuse the flag
2834
+ ([LANGUAGE.md](LANGUAGE.md#the-sandbox)). Only under `--sandbox` may an
2835
+ `--allow` list scope `fs.read` or `fs.write` to a directory
2836
+ (`--allow fs.read=/srv/data`): the directory must exist at build time, and
2837
+ the kernel grants the capability beneath it alone — except that a `main`
2838
+ reaching `process.spawn` can still read every file beneath `/`, so that
2839
+ `exec` can load a program. Any other scope, a scope
2840
+ in `--deny` and a scope without `--sandbox` are usage errors, exit 2.
2841
+
2825
2842
  ## Before you say it compiles
2826
2843
 
2827
2844
  Run it. `nish file.ts --json` is one command and it is the only proof.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/nish-x86_64-linux",
3
- "version": "0.27.2",
3
+ "version": "0.28.0",
4
4
  "description": "The nish native compiler for Linux on x86_64",
5
5
  "license": "MIT",
6
6
  "os": [
package/runtime/core.d.ts CHANGED
@@ -7,3 +7,50 @@ export * from "./core/host.js";
7
7
  export * from "./core/numbers.js";
8
8
  export * from "./core/result.js";
9
9
  export * from "./core/strings.js";
10
+
11
+ // `nish:simd`: what `--emit-ts` writes for a program's `import ... from "nish:simd"`.
12
+ import type { f32, f64, i32, u16, u32, u8 } from "./core/numbers.js";
13
+
14
+ /**
15
+ * A sixteen-byte vector of lanes. Opaque: TypeScript refuses `+` on one, as
16
+ * `nish` does, but lets `===` and `<` through, which `nish` refuses. Under
17
+ * Node it is a typed array made once and never written after.
18
+ */
19
+ export interface u8x16 { readonly __nishSimd: "u8x16"; readonly __lane: u8 }
20
+ export interface u16x8 { readonly __nishSimd: "u16x8"; readonly __lane: u16 }
21
+ export interface i32x4 { readonly __nishSimd: "i32x4"; readonly __lane: i32 }
22
+ export interface u32x4 { readonly __nishSimd: "u32x4"; readonly __lane: u32 }
23
+ export interface f32x4 { readonly __nishSimd: "f32x4"; readonly __lane: f32 }
24
+ export interface f64x2 { readonly __nishSimd: "f64x2"; readonly __lane: f64 }
25
+ /** Any of the six. */
26
+ export type SimdVector = u8x16 | u16x8 | i32x4 | u32x4 | f32x4 | f64x2;
27
+ /** One value per lane, lane 0 first. */
28
+ export declare function u8x16(
29
+ a0: u8, a1: u8, a2: u8, a3: u8, a4: u8, a5: u8, a6: u8, a7: u8,
30
+ a8: u8, a9: u8, a10: u8, a11: u8, a12: u8, a13: u8, a14: u8, a15: u8
31
+ ): u8x16;
32
+ export declare function u16x8(a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16): u16x8;
33
+ export declare function i32x4(a0: i32, a1: i32, a2: i32, a3: i32): i32x4;
34
+ export declare function u32x4(a0: u32, a1: u32, a2: u32, a3: u32): u32x4;
35
+ export declare function f32x4(a0: f32, a1: f32, a2: f32, a3: f32): f32x4;
36
+ export declare function f64x2(a0: f64, a1: f64): f64x2;
37
+ /** `x` in every lane. */
38
+ export declare function splatU8x16(x: u8): u8x16;
39
+ export declare function splatU16x8(x: u16): u16x8;
40
+ export declare function splatI32x4(x: i32): i32x4;
41
+ export declare function splatU32x4(x: u32): u32x4;
42
+ export declare function splatF32x4(x: f32): f32x4;
43
+ export declare function splatF64x2(x: f64): f64x2;
44
+ /** `xs[i]` to `xs[i + N - 1]`, bounds-checked once for the whole vector. */
45
+ export declare function loadU8x16(xs: readonly u8[], i: i32): u8x16;
46
+ export declare function loadU16x8(xs: readonly u16[], i: i32): u16x8;
47
+ export declare function loadI32x4(xs: readonly i32[], i: i32): i32x4;
48
+ export declare function loadU32x4(xs: readonly u32[], i: i32): u32x4;
49
+ export declare function loadF32x4(xs: readonly f32[], i: i32): f32x4;
50
+ export declare function loadF64x2(xs: readonly f64[], i: i32): f64x2;
51
+ /** The lanes of `v` into `xs[i]` to `xs[i + N - 1]`, checked once. */
52
+ export declare function store<V extends SimdVector>(v: V, xs: V["__lane"][], i: i32): void;
53
+ /** Lane `k`, an integer literal in range. */
54
+ export declare function extract<V extends SimdVector>(v: V, k: i32): V["__lane"];
55
+ /** A new vector: `v` with lane `k` set to `x`. */
56
+ export declare function replace<V extends SimdVector>(v: V, k: i32, x: V["__lane"]): V;
package/runtime/core.mjs CHANGED
@@ -48,8 +48,75 @@
48
48
  *
49
49
  * The rewrite rules that call these helpers are listed in docs/wp13-differential.md.
50
50
  */
51
+ import { panicIndex, toIndex } from "./core/checks.mjs";
52
+
51
53
  export * from "./core/arrays.mjs";
52
54
  export * from "./core/host.mjs";
53
55
  export * from "./core/numbers.mjs";
54
56
  export * from "./core/result.mjs";
55
57
  export * from "./core/strings.mjs";
58
+
59
+ // ---- `nish:simd` ------------------------------------------------------------
60
+ // A vector is a fresh typed array of its lanes, made once and never written
61
+ // after: `replace` copies, so a vector held in two places stays one value, as
62
+ // the native `<N x T>` register is. The array type does the lane arithmetic a
63
+ // native lane does: a `u8` lane wraps through `Uint8Array`, an `f32` lane rounds
64
+ // through `Float32Array`. `load…` and `store` check the whole vector once, and
65
+ // panic with the native words: the first index, and the array's length.
66
+
67
+ const simdMake = (Lanes) => (...lanes) => new Lanes(lanes);
68
+ const simdSplat = (Lanes) => (x) => new Lanes(16 / Lanes.BYTES_PER_ELEMENT).fill(x);
69
+ // The first index of `count` lanes at `i` in `xs`, or the native panic naming
70
+ // a lane that is out of range: the first when it is, else the last. A negative
71
+ // index prints as the unsigned 64-bit number the native compare saw.
72
+ const simdAt = (xs, i, count) => {
73
+ const k = toIndex(i);
74
+ if (k < 0) panicIndex(BigInt.asUintN(64, BigInt(k)), xs.length);
75
+ if (k >= xs.length) panicIndex(k, xs.length);
76
+ if (k + count > xs.length) panicIndex(k + count - 1, xs.length);
77
+ return k;
78
+ };
79
+ const simdLoad = (Lanes) => (xs, i) => {
80
+ const count = 16 / Lanes.BYTES_PER_ELEMENT;
81
+ const k = simdAt(xs, i, count);
82
+ const out = new Lanes(count);
83
+ for (let j = 0; j < count; j++) out[j] = xs[k + j];
84
+ return out;
85
+ };
86
+
87
+ export const u8x16 = simdMake(Uint8Array);
88
+ export const u16x8 = simdMake(Uint16Array);
89
+ export const i32x4 = simdMake(Int32Array);
90
+ export const u32x4 = simdMake(Uint32Array);
91
+ export const f32x4 = simdMake(Float32Array);
92
+ export const f64x2 = simdMake(Float64Array);
93
+ export const splatU8x16 = simdSplat(Uint8Array);
94
+ export const splatU16x8 = simdSplat(Uint16Array);
95
+ export const splatI32x4 = simdSplat(Int32Array);
96
+ export const splatU32x4 = simdSplat(Uint32Array);
97
+ export const splatF32x4 = simdSplat(Float32Array);
98
+ export const splatF64x2 = simdSplat(Float64Array);
99
+ export const loadU8x16 = simdLoad(Uint8Array);
100
+ export const loadU16x8 = simdLoad(Uint16Array);
101
+ export const loadI32x4 = simdLoad(Int32Array);
102
+ export const loadU32x4 = simdLoad(Uint32Array);
103
+ export const loadF32x4 = simdLoad(Float32Array);
104
+ export const loadF64x2 = simdLoad(Float64Array);
105
+
106
+ /** `store(v, xs, i)`: the lanes into `xs[i]` to `xs[i + N - 1]`, checked once. */
107
+ export function store(v, xs, i) {
108
+ const k = simdAt(xs, i, v.length);
109
+ for (let j = 0; j < v.length; j++) xs[k + j] = v[j];
110
+ }
111
+
112
+ /** `extract(v, k)`: lane `k`, a constant the checker held in range. */
113
+ export function extract(v, k) {
114
+ return v[k];
115
+ }
116
+
117
+ /** `replace(v, k, x)`: a new vector, `v` with lane `k` set to `x`. */
118
+ export function replace(v, k, x) {
119
+ const out = v.slice();
120
+ out[k] = x;
121
+ return out;
122
+ }
package/runtime/nish.d.ts CHANGED
@@ -698,6 +698,55 @@ declare module "nish:unsafe" {
698
698
  export function readCString(p: CPtr): string;
699
699
  }
700
700
 
701
+ // `nish:simd` (docs/LANGUAGE.md -> Vectors): the six sixteen-byte vector
702
+ // types and the calls that make, load, store and take one apart. Under Node,
703
+ // `runtime/nish.mjs` answers the import with `runtime/core.mjs`'s names.
704
+ declare module "nish:simd" {
705
+ /**
706
+ * A sixteen-byte vector of lanes. Opaque: TypeScript refuses `+` on one, as
707
+ * `nish` does, but lets `===` and `<` through, which `nish` refuses. Under
708
+ * Node it is a typed array made once and never written after.
709
+ */
710
+ export interface u8x16 { readonly __nishSimd: "u8x16"; readonly __lane: u8 }
711
+ export interface u16x8 { readonly __nishSimd: "u16x8"; readonly __lane: u16 }
712
+ export interface i32x4 { readonly __nishSimd: "i32x4"; readonly __lane: i32 }
713
+ export interface u32x4 { readonly __nishSimd: "u32x4"; readonly __lane: u32 }
714
+ export interface f32x4 { readonly __nishSimd: "f32x4"; readonly __lane: f32 }
715
+ export interface f64x2 { readonly __nishSimd: "f64x2"; readonly __lane: f64 }
716
+ /** Any of the six. */
717
+ export type SimdVector = u8x16 | u16x8 | i32x4 | u32x4 | f32x4 | f64x2;
718
+ /** One value per lane, lane 0 first. */
719
+ export function u8x16(
720
+ a0: u8, a1: u8, a2: u8, a3: u8, a4: u8, a5: u8, a6: u8, a7: u8,
721
+ a8: u8, a9: u8, a10: u8, a11: u8, a12: u8, a13: u8, a14: u8, a15: u8
722
+ ): u8x16;
723
+ export function u16x8(a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16): u16x8;
724
+ export function i32x4(a0: i32, a1: i32, a2: i32, a3: i32): i32x4;
725
+ export function u32x4(a0: u32, a1: u32, a2: u32, a3: u32): u32x4;
726
+ export function f32x4(a0: f32, a1: f32, a2: f32, a3: f32): f32x4;
727
+ export function f64x2(a0: f64, a1: f64): f64x2;
728
+ /** `x` in every lane. */
729
+ export function splatU8x16(x: u8): u8x16;
730
+ export function splatU16x8(x: u16): u16x8;
731
+ export function splatI32x4(x: i32): i32x4;
732
+ export function splatU32x4(x: u32): u32x4;
733
+ export function splatF32x4(x: f32): f32x4;
734
+ export function splatF64x2(x: f64): f64x2;
735
+ /** `xs[i]` to `xs[i + N - 1]`, bounds-checked once for the whole vector. */
736
+ export function loadU8x16(xs: readonly u8[], i: i32): u8x16;
737
+ export function loadU16x8(xs: readonly u16[], i: i32): u16x8;
738
+ export function loadI32x4(xs: readonly i32[], i: i32): i32x4;
739
+ export function loadU32x4(xs: readonly u32[], i: i32): u32x4;
740
+ export function loadF32x4(xs: readonly f32[], i: i32): f32x4;
741
+ export function loadF64x2(xs: readonly f64[], i: i32): f64x2;
742
+ /** The lanes of `v` into `xs[i]` to `xs[i + N - 1]`, checked once. */
743
+ export function store<V extends SimdVector>(v: V, xs: V["__lane"][], i: i32): void;
744
+ /** Lane `k`, an integer literal in range. */
745
+ export function extract<V extends SimdVector>(v: V, k: i32): V["__lane"];
746
+ /** A new vector: `v` with lane `k` set to `x`. */
747
+ export function replace<V extends SimdVector>(v: V, k: i32, x: V["__lane"]): V;
748
+ }
749
+
701
750
  declare module "nish:io" {
702
751
  /** `s` to stdout with no trailing newline and no conversion. */
703
752
  export function write(s: string): void;
package/runtime/nish.h CHANGED
@@ -9,14 +9,17 @@
9
9
  * functions, the directory and subprocess calls, `nish_getenv`, the monotonic
10
10
  * clock, `nish_platform` / `nish_arch` — and runtime-parallel.c, runtime-host.c,
11
11
  * runtime-net.c, runtime-simd.c (the byte searches that read a vector at a
12
- * time), runtime-aes.c (AES-GCM on the CPU's AES instructions) and
13
- * runtime-term.c (stdin and the terminal, `nish:term`) split off
12
+ * time), runtime-aes.c (AES-GCM on the CPU's AES instructions),
13
+ * runtime-sha256.c (SHA-256 on the CPU's SHA instructions), runtime-checksum.c
14
+ * (CRC-32 on its carry-less multiply or CRC instructions) and runtime-term.c
15
+ * (stdin and the terminal, `nish:term`) split off
14
16
  * the same way since. They are separate so that each carries its own measured
15
17
  * code-size ceiling (docs/wp7-runtime.md, "Runtime additions and budget"); a
16
18
  * host links all of them, which `scripts/build.sh` does for you when handed
17
- * runtime.c, runtime-aes.c included: the compiler calls its kernels from
18
- * std/crypto/aes.ts, so `scripts/build.sh` pairs it and `src/run-cache.ts`
19
- * caches it like the others. `tests/run.js` checks that every runtime function
19
+ * runtime.c, runtime-aes.c, runtime-sha256.c and runtime-checksum.c included: the
20
+ * compiler calls their kernels from std/crypto/aes.ts, std/crypto/sha256.ts and
21
+ * std/compress/checksum.ts, so `scripts/build.sh` pairs each of them with
22
+ * runtime.c and `src/run-cache.ts` caches them like the others. `tests/run.js` checks that every runtime function
20
23
  * declared in runtime.ts has a prototype in this file.
21
24
  *
22
25
  * Headers generated by `nish --emit-header` include this one, so keep
@@ -348,6 +351,40 @@ void nish_aes_ctr(const nish_array *rk, int32_t rounds, const nish_array *j0, co
348
351
  `rk` instead, and they are the same H. 0 <= length <= data.len. */
349
352
  void nish_aes_ghash(nish_array *y, uint64_t hHi, uint64_t hLo, const nish_array *rk, const nish_array *data,
350
353
  int32_t length);
354
+ /* ---- SHA-256 on the CPU's SHA instructions --------------------------------
355
+ * runtime/runtime-sha256.c: SHA-NI on x86-64, the ARMv8 SHA-256 instructions
356
+ * on AArch64. The compiler calls the kernel in place of std/crypto/sha256.ts's
357
+ * private `sha256Compress`, behind `nish_sha256_hw`, and calls the Nish
358
+ * function itself when either answers 0. Constant time in the state and the
359
+ * block. */
360
+ /* 1 when this process runs the kernel, 0 when it runs the Nish code. Resolved
361
+ on the first call and fixed from then on: `NISH_SHA256=soft` pins 0; unset,
362
+ `hw` or any other value is the best this machine has, read on that call from
363
+ CPUID (leaf 7's SHA, leaf 1's SSE4.1 and SSSE3), AArch64 Linux's AT_HWCAP
364
+ (SHA2) or macOS's `hw.optional.arm.FEAT_SHA256`. Always 0 on other targets,
365
+ wasm32 among them. */
366
+ int32_t nish_sha256_hw(void);
367
+ /* FIPS 180-4 §6.2.2 on the 64 bytes at src[at..at + 64) (u8[]), into the hash
368
+ value h[0..8) (u32[]); 1 when it ran. Answers 0 and writes nothing unless
369
+ h.len >= 8, w.len >= 64 and 0 <= at <= src.len - 64, `sha256Compress`'s
370
+ guard, so the caller's fallback panics as the Nish function does. `w` (u32[],
371
+ the message schedule the Nish code fills) is neither read nor written. */
372
+ int32_t nish_sha256_compress(nish_array *h, const nish_array *w, const nish_array *src, int32_t at);
373
+ /* ---- CRC-32 on the CPU's carry-less multiply or CRC instructions ---------
374
+ * runtime/runtime-checksum.c: PCLMULQDQ folding on x86-64, the ARMv8 CRC32
375
+ * instructions on AArch64. The compiler calls the kernel in
376
+ * place of std/compress/checksum.ts's private `crc32Walk`, behind
377
+ * `nish_crc32_hw`, and calls the Nish walker itself when that answers 0. */
378
+ /* 1 when this process runs the kernel, 0 when it runs the Nish tables.
379
+ Resolved on the first call and fixed from then on: `NISH_CRC32=soft` pins 0;
380
+ unset or any other value is the best this machine has, read on that call
381
+ from CPUID leaf 1 (PCLMULQDQ, SSE4.1), AArch64's AT_HWCAP (CRC32) or
382
+ Darwin's hw.optional sysctls. Always 0 on other targets, wasm32 among them. */
383
+ int32_t nish_crc32_hw(void);
384
+ /* The CRC-32 (ISO 3309, RFC 1952) `crc` extended over buf[off..off+len)
385
+ (u8[]), conditioned as zlib's crc32(): 0 starts a message, and the answer
386
+ continues one. The caller has checked 0 <= off <= off + len <= buf.len. */
387
+ uint32_t nish_crc32_update(uint32_t crc, const nish_array *buf, int32_t off, int32_t len);
351
388
 
352
389
  /* `secureZero(bytes)` (#385): sets every byte of `bytes` to zero through
353
390
  * `volatile` stores, out of line, so that neither `-O2` nor `-flto` can drop
@@ -741,6 +778,14 @@ int64_t nish_cpu_count(void);
741
778
  * rounded up, and `NISH_NUM_THREADS` when it is set to a positive number. At
742
779
  * least 1; 1 under WASI. Read each call (runtime-os.c). */
743
780
  int64_t nish_cpu_online(void);
781
+ /* WP37 `--sandbox` (runtime-sandbox.c): `nish_sandbox` confines the process to
782
+ the capability mask `caps` from `.preinit_array`, `mode` 1 strict and 2
783
+ best-effort, and `nish_sandbox_check` refuses to run at the top of `main`
784
+ when it never ran. The directory lists are a later stage's and are null.
785
+ `nish_cpu_prime` caches the pool's CPU count while /sys is still readable. */
786
+ void nish_sandbox(int32_t caps, int32_t mode, const char *read_dirs, const char *write_dirs);
787
+ void nish_sandbox_check(void);
788
+ void nish_cpu_prime(void);
744
789
  void nish_parallel_range(nish_par_body body, void *ctx, int64_t len, int64_t grain);
745
790
  /* Keeps every later region and join on threads created and joined per call,
746
791
  * as before the pool existed, so no parked worker outlives the code it would
package/runtime/nish.mjs CHANGED
@@ -314,6 +314,9 @@ provide("arena", shim.arena);
314
314
  // zero-fills it. `nish:unsafe` and `nish:term` are each answered by a module
315
315
  // that hands back the globals installed above: its functions are globals of this module either
316
316
  // way, and the import is what the compiler requires a program to write.
317
+ // `nish:simd` is `runtime/core.mjs`, whose vectors are typed arrays made once
318
+ // and never written after, so `--emit-ts` output and a program run as it was
319
+ // written share one implementation.
317
320
  const UNSAFE_EXPORTS = ["uncheckedGet", "uncheckedSet", "wrappingAdd", "wrappingSub", "wrappingMul"];
318
321
  const unsafeSource = UNSAFE_EXPORTS.map((name) => `export const ${name} = globalThis.${name};`).join("\n");
319
322
  const TERM_EXPORTS = ["readStdin", "waitStdin", "isTerminal", "terminalSize", "setRawMode", "setTerminalRestore"];
@@ -326,6 +329,9 @@ registerHooks({
326
329
  if (specifier === "nish:unsafe") {
327
330
  return { url: `data:text/javascript,${encodeURIComponent(unsafeSource)}`, shortCircuit: true };
328
331
  }
332
+ if (specifier === "nish:simd") {
333
+ return next(new URL("./core.mjs", import.meta.url).href, context);
334
+ }
329
335
  if (specifier === "nish:term") {
330
336
  return { url: `data:text/javascript,${encodeURIComponent(termSource)}`, shortCircuit: true };
331
337
  }