@amritk/nish-x86_64-linux 0.18.0 → 0.20.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 +43 -25
- package/bin/nish +0 -0
- package/package.json +2 -2
- package/runtime/nish.d.ts +55 -5
- package/runtime/nish.h +215 -18
- package/runtime/nish.mjs +16 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +7 -6
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +213 -15
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +4 -4
- package/runtime/runtime-wasm.c +5 -3
- package/runtime/runtime.c +69 -13
- package/runtime/shim.mjs +71 -1
- package/scripts/build.sh +223 -22
- package/std/README.md +81 -51
- package/std/bytes.ts +163 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +245 -53
- package/std/crypto/p256.ts +932 -61
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +9 -9
- package/std/json-tokenizer.ts +1296 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1163 -0
- package/std/json.ts +1120 -34
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +417 -55
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +211 -31
- package/std/net/http3.ts +187 -28
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +88 -7
- package/std/net/quic-packet.ts +243 -82
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +424 -24
- package/std/net/quic.ts +519 -167
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +196 -53
- package/std/net/tls.ts +1018 -260
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/threads.ts +438 -14
package/INSTALL.md
CHANGED
|
@@ -109,7 +109,7 @@ Through npm, which is also how an Nish *program* resolves its dependencies
|
|
|
109
109
|
the compiler pinned per project in a `package.json`:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
|
-
npm install -g
|
|
112
|
+
npm install -g nish
|
|
113
113
|
nish --version
|
|
114
114
|
```
|
|
115
115
|
|
|
@@ -171,13 +171,12 @@ never fails over it.
|
|
|
171
171
|
> underlying defect is [wp19 §5a](wp19-stage0-retirement.md#5a-what-r6-is-waiting-on)
|
|
172
172
|
> item 4.
|
|
173
173
|
|
|
174
|
-
**
|
|
175
|
-
`
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
strings, and that is the one thing the scope costs.
|
|
174
|
+
**The package is `nish` from 0.20.0.** Releases up to 0.18.0 were published
|
|
175
|
+
as `@amritk/nish` (0.19.0's publish to npm failed), which is deprecated and
|
|
176
|
+
points here; `npm install -g nish`
|
|
177
|
+
replaces it ([docs/wp12-release.md](wp12-release.md#the-npm-name)). Versions
|
|
178
|
+
0.0.0 and 0.0.1 of `nish` are an unrelated 2014 project that held the name
|
|
179
|
+
before it, so pin `nish@^0.20.0` or later rather than an older range.
|
|
181
180
|
|
|
182
181
|
**On a platform this project attaches no binary for, `npm install` gets you a
|
|
183
182
|
command that refuses.** The table below is the whole list, so musl, FreeBSD and
|
|
@@ -224,7 +223,8 @@ routes are
|
|
|
224
223
|
build/nish app.ts -o app.ll
|
|
225
224
|
# on the musl host, with its own clang and the runtime from this repository
|
|
226
225
|
clang app.ll runtime/runtime.c runtime/runtime-os.c runtime/runtime-parallel.c \
|
|
227
|
-
runtime/runtime-host.c runtime/runtime-net.c
|
|
226
|
+
runtime/runtime-cross.c runtime/runtime-host.c runtime/runtime-net.c \
|
|
227
|
+
runtime/runtime-simd.c runtime/runtime-aes.c -lm -o app
|
|
228
228
|
```
|
|
229
229
|
|
|
230
230
|
`--link`ing inside the container is the mistake to avoid: it shells out to the
|
|
@@ -240,18 +240,20 @@ routes are
|
|
|
240
240
|
If you need one of these to be a first-class install, that is the conversation
|
|
241
241
|
to have on the issue tracker rather than a workaround to discover here.
|
|
242
242
|
|
|
243
|
-
**On the registry from 0.10.0
|
|
244
|
-
|
|
243
|
+
**On the registry from 0.10.0** — as `@amritk/nish` through 0.18.0, and as
|
|
244
|
+
`nish` from 0.20.0; 0.19.0 is on GitHub only, because its npm publish
|
|
245
|
+
failed. Every release publishes the main package and its platform packages to
|
|
246
|
+
npm from `release.yml`, by trusted publishing
|
|
245
247
|
([docs/wp12-release.md](wp12-release.md#release-procedure) step 4), so
|
|
246
|
-
`npm install -g
|
|
248
|
+
`npm install -g nish` is the whole install. The rest of this section is
|
|
247
249
|
for a machine that cannot reach the registry, or a release before 0.10.0.
|
|
248
250
|
|
|
249
251
|
From a release tarball on GitHub — the same package `npm publish` uploads,
|
|
250
252
|
carried by the release instead of the registry. The `Release` workflow attaches
|
|
251
253
|
the npm tarball to the release it builds for a `v*` tag. `npm pack` names it
|
|
252
|
-
after `package.json#name`, so it is `
|
|
253
|
-
and `nish-<version>.tgz`
|
|
254
|
-
example below is one of
|
|
254
|
+
after `package.json#name`, so it is `nish-<version>.tgz` before 0.4.0 and
|
|
255
|
+
from 0.20.0 on, and `amritk-nish-<version>.tgz` from 0.4.0 to 0.19.0, while the
|
|
256
|
+
package was scoped — the example below is one of the early ones:
|
|
255
257
|
|
|
256
258
|
```bash
|
|
257
259
|
curl -LO https://github.com/amritk/nish/releases/download/v0.2.0/nish-0.2.0.tgz
|
|
@@ -358,7 +360,7 @@ it into `build/seed/`; `NISH_BOOTSTRAP=<path>` names one you already have and
|
|
|
358
360
|
skips the download. §2a has what the build does with it.
|
|
359
361
|
|
|
360
362
|
The published package ships `bin/` (the `nish` command, which is a launcher),
|
|
361
|
-
`runtime/` (the C runtime —
|
|
363
|
+
`runtime/` (the C runtime — eight translation units, the wasm subset and their header),
|
|
362
364
|
`scripts/build.sh` (the link pipeline) and `std/` (the standard library). The
|
|
363
365
|
compiler itself is not in it: it arrives as one prebuilt
|
|
364
366
|
`@amritk/nish-<asset>` package per platform, and `bin/nish` hands over to
|
|
@@ -368,11 +370,12 @@ working directory — and the binary runs from inside its own platform package
|
|
|
368
370
|
for exactly that reason.
|
|
369
371
|
|
|
370
372
|
Building the IR yourself rather than through `--link` means naming the runtime
|
|
371
|
-
on the `clang` line, and it is
|
|
373
|
+
on the `clang` line, and it is eight files:
|
|
372
374
|
|
|
373
375
|
```bash
|
|
374
376
|
clang app.ll runtime/runtime.c runtime/runtime-os.c runtime/runtime-parallel.c \
|
|
375
|
-
runtime/runtime-host.c runtime/runtime-net.c
|
|
377
|
+
runtime/runtime-cross.c runtime/runtime-host.c runtime/runtime-net.c \
|
|
378
|
+
runtime/runtime-simd.c runtime/runtime-aes.c -lm -o app
|
|
376
379
|
```
|
|
377
380
|
|
|
378
381
|
`runtime.c` is the part every program touches — the arena, strings, arrays,
|
|
@@ -380,13 +383,16 @@ number formatting, the panics — and `runtime-os.c` wraps the system calls:
|
|
|
380
383
|
files, directories, subprocesses, `getenv`, the monotonic clock.
|
|
381
384
|
`runtime-parallel.c` divides work across threads for `nish/threads` (a
|
|
382
385
|
program built with `--threads`, as every importer of `nish/threads` is, also
|
|
383
|
-
needs `-DNISH_THREADS=1 -pthread` on the line), `runtime-
|
|
384
|
-
|
|
385
|
-
of
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
386
|
+
needs `-DNISH_THREADS=1 -pthread` on the line), `runtime-cross.c` copies
|
|
387
|
+
the strings and arrays a task answers, a channel sends or a `Mutex` keeps out
|
|
388
|
+
of the arena they were made in, `runtime-host.c` holds the wall clock,
|
|
389
|
+
entropy, file times and signals, `runtime-net.c` the sockets of `nish:net`,
|
|
390
|
+
and `runtime-simd.c` and `runtime-aes.c` the vector text search and AES-GCM.
|
|
391
|
+
They are separate so that each carries its own measured size ceiling
|
|
392
|
+
([docs/wp7-runtime.md](wp7-runtime.md)); nothing in the core calls into the
|
|
393
|
+
others, so a line that names only `runtime.c` and `runtime-os.c` still links a
|
|
394
|
+
program that uses none of the other six. `scripts/build.sh` compiles the other
|
|
395
|
+
seven beside any
|
|
390
396
|
`runtime.c` it is handed, so a build that goes through it — every `--link`,
|
|
391
397
|
and every `--profile` recipe in these documents — needs to name only the one.
|
|
392
398
|
|
|
@@ -479,6 +485,18 @@ refuses the run without one rather than keep a binary in a shared directory.
|
|
|
479
485
|
The first run that builds into the cache makes its root `0700`, so no other
|
|
480
486
|
user can plant a binary in it ([docs/security/cli.md](security/cli.md)).
|
|
481
487
|
|
|
488
|
+
Every link with the debug, speed or size profile, `nish run`'s and `--link`'s
|
|
489
|
+
alike, keeps the compiled C runtime in `$XDG_CACHE_HOME/nish/runtime` (or
|
|
490
|
+
`~/.cache/nish/runtime`), one entry per profile, `-g`, `--threads`, `CC` and
|
|
491
|
+
the version that compiler reports, made `0700` the same way. The first link
|
|
492
|
+
compiles the runtime's six files at once into it, and every later link
|
|
493
|
+
compiles only the program's modules, also at once, and links against the
|
|
494
|
+
entry: a `hello.ts` debug link goes from about half a second to about a
|
|
495
|
+
tenth. `--link` with no absolute `HOME` or `XDG_CACHE_HOME`, or with a root
|
|
496
|
+
it cannot make private, compiles the runtime itself as it always did; the
|
|
497
|
+
wasi profile and `scripts/build.sh` called directly never use the cache.
|
|
498
|
+
Removing the directory is always safe.
|
|
499
|
+
|
|
482
500
|
## 4. Exit codes
|
|
483
501
|
|
|
484
502
|
| Code | Meaning |
|
package/bin/nish
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/nish-x86_64-linux",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"description": "The nish native compiler for Linux on x86_64",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"os": [
|
|
7
7
|
"linux"
|
package/runtime/nish.d.ts
CHANGED
|
@@ -112,10 +112,10 @@ declare function Err<T, E>(error: E): Result<T, E>;
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* The disposable protocol `using` reads (WP29 P2, docs/wp29-thread-surface.md
|
|
115
|
-
* §5): declared here so that a program using `nish/threads`'s scope
|
|
116
|
-
* `arena()` needs no `"ESNext.Disposable"` in its `lib`.
|
|
117
|
-
* `using` only for a `scope()
|
|
118
|
-
* `nish/threads`.
|
|
115
|
+
* §5): declared here so that a program using `nish/threads`'s scope, a
|
|
116
|
+
* `Mutex`'s lock or `arena()` needs no `"ESNext.Disposable"` in its `lib`.
|
|
117
|
+
* `nish` itself takes `using` only for a `scope()`, a `lock()` or an
|
|
118
|
+
* `arena()`, and `[Symbol.dispose]` only in `nish/threads`.
|
|
119
119
|
*/
|
|
120
120
|
interface SymbolConstructor {
|
|
121
121
|
readonly dispose: unique symbol;
|
|
@@ -124,6 +124,16 @@ interface Disposable {
|
|
|
124
124
|
[Symbol.dispose](): void;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* `String.fromBytes` is Nish's, not JavaScript's, so it merges into the
|
|
129
|
+
* `StringConstructor` `lib.es2022` declares. Under `runtime/nish.mjs` each byte
|
|
130
|
+
* becomes one UTF-16 unit, as `String.fromCharCode`'s does.
|
|
131
|
+
*/
|
|
132
|
+
interface StringConstructor {
|
|
133
|
+
/** The bytes of `bytes[start..end)` as one string; panics unless `0 <= start <= end <= bytes.length`. */
|
|
134
|
+
fromBytes(bytes: readonly u8[], start: number, end: number): string;
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
interface Console {
|
|
128
138
|
/** `x` and a newline to stdout. Statement position; exactly one argument. */
|
|
129
139
|
log(x: string | number | boolean): void;
|
|
@@ -193,7 +203,7 @@ declare function isExecutableSync(path: string): boolean;
|
|
|
193
203
|
// ---- Unsafe (`nish:unsafe`) --------------------------------------------------
|
|
194
204
|
//
|
|
195
205
|
// Declared as globals so `tsc` reads a program that imports them, as every
|
|
196
|
-
// `nish:` export is, but `nish` refuses a call to any of the
|
|
206
|
+
// `nish:` export is, but `nish` refuses a call to any of the six that is not
|
|
197
207
|
// imported from `nish:unsafe`: the import is the module's visible opt-in.
|
|
198
208
|
|
|
199
209
|
/** `xs[i]` with no bounds check: undefined behaviour when `i` is out of range. */
|
|
@@ -206,6 +216,8 @@ declare function wrappingAdd<T extends i32 | i64>(a: T, b: T): T;
|
|
|
206
216
|
declare function wrappingSub<T extends i32 | i64>(a: T, b: T): T;
|
|
207
217
|
/** `a * b` wrapped to the operands' width. */
|
|
208
218
|
declare function wrappingMul<T extends i32 | i64>(a: T, b: T): T;
|
|
219
|
+
/** The `NUL`-terminated bytes at `p`, copied into a string: undefined behaviour unless `p` is a live C string. */
|
|
220
|
+
declare function readCString(p: CPtr): string;
|
|
209
221
|
|
|
210
222
|
// ---- Streams and files (globals: Nish has no package resolution) ---------
|
|
211
223
|
|
|
@@ -266,6 +278,28 @@ declare function spawnSync(argv: string[]): number;
|
|
|
266
278
|
* either path is refused, as `writeFileSync` refuses one, and the answer is -1.
|
|
267
279
|
*/
|
|
268
280
|
declare function spawnSyncTo(argv: string[], stdoutPath: string, stderrPath: string): number;
|
|
281
|
+
/**
|
|
282
|
+
* Start `argv[0]` through `PATH` without waiting: the child's pid, or a
|
|
283
|
+
* negative errno. The child is the program's until `waitPid` reaps it. No
|
|
284
|
+
* reading under Node, which throws.
|
|
285
|
+
*/
|
|
286
|
+
declare function spawn(argv: string[]): i32;
|
|
287
|
+
/**
|
|
288
|
+
* Send `sig` to `pid`: 0, or a negative errno (-3 when no such process). `sig`
|
|
289
|
+
* is 0, 2, 9 or 15, and anything else, like a `pid` of 0 or below, is -22.
|
|
290
|
+
*/
|
|
291
|
+
declare function kill(pid: i32, sig: i32): i32;
|
|
292
|
+
/**
|
|
293
|
+
* Wait for the child `pid`, or any child for -1: `[pid, status]`, the status
|
|
294
|
+
* as `spawnSync` answers it. Flag 1 is WNOHANG, under which `[0, 0]` means a
|
|
295
|
+
* child remains and none has exited; a failure is `[-errno, 0]`, `[-10, 0]`
|
|
296
|
+
* with no child to wait for. No reading under Node, which throws.
|
|
297
|
+
*/
|
|
298
|
+
declare function waitPid(pid: i32, flags: i32): i32[];
|
|
299
|
+
/** How many CPUs the program may use: at least 1, with or without `--threads`. */
|
|
300
|
+
declare function availableParallelism(): i32;
|
|
301
|
+
/** Bytes of physical memory, or -1 when the host does not say. */
|
|
302
|
+
declare function totalMemory(): i64;
|
|
269
303
|
/** One environment variable, or `null` when it is unset (an empty value is a set variable). */
|
|
270
304
|
declare function getenv(name: string): string | null;
|
|
271
305
|
/**
|
|
@@ -305,6 +339,8 @@ declare function netAddress(out: u8[], host: string, port: i32): i32;
|
|
|
305
339
|
declare function netLocalPort(fd: i32): i32;
|
|
306
340
|
/** A listening TCP socket with `SO_REUSEADDR`; `"::"` hears IPv4 and IPv6. */
|
|
307
341
|
declare function tcpListen(host: string, port: i32, backlog: i32): i32;
|
|
342
|
+
/** `tcpListen`'s socket, with `SO_REUSEPORT` for flag 1 and `TCP_NODELAY` on each accepted socket for flag 2; any other bit is -22. */
|
|
343
|
+
declare function tcpListenFlags(host: string, port: i32, backlog: i32, flags: i32): i32;
|
|
308
344
|
/** The next connection's descriptor, its address in `peer`; -11 when none waits. */
|
|
309
345
|
declare function tcpAccept(fd: i32, peer: u8[]): i32;
|
|
310
346
|
/** Up to `len` bytes into `buf` from `off`: the count, 0 at end of stream, or -11. */
|
|
@@ -400,6 +436,16 @@ declare module "nish:process" {
|
|
|
400
436
|
* at either path is refused, and the answer is -1.
|
|
401
437
|
*/
|
|
402
438
|
export function spawnSyncTo(argv: string[], stdoutPath: string, stderrPath: string): number;
|
|
439
|
+
/** Start a child without waiting: its pid, or a negative errno. */
|
|
440
|
+
export function spawn(argv: string[]): i32;
|
|
441
|
+
/** Send 0, 2, 9 or 15 to `pid`: 0, or a negative errno; any other signal is -22. */
|
|
442
|
+
export function kill(pid: i32, sig: i32): i32;
|
|
443
|
+
/** `[pid, status]` for a child that exited, `[0, 0]` under WNOHANG (flag 1) with none, or `[-errno, 0]`. */
|
|
444
|
+
export function waitPid(pid: i32, flags: i32): i32[];
|
|
445
|
+
/** How many CPUs the program may use, at least 1. */
|
|
446
|
+
export function availableParallelism(): i32;
|
|
447
|
+
/** Bytes of physical memory, or -1. */
|
|
448
|
+
export function totalMemory(): i64;
|
|
403
449
|
/**
|
|
404
450
|
* A monotonic clock in nanoseconds. The origin is arbitrary, so only the
|
|
405
451
|
* difference between two reads is meaningful.
|
|
@@ -424,6 +470,8 @@ declare module "nish:net" {
|
|
|
424
470
|
export function netLocalPort(fd: i32): i32;
|
|
425
471
|
/** A listening TCP socket with `SO_REUSEADDR`; `"::"` hears IPv4 and IPv6. */
|
|
426
472
|
export function tcpListen(host: string, port: i32, backlog: i32): i32;
|
|
473
|
+
/** `tcpListen`'s socket, with `SO_REUSEPORT` for flag 1 and `TCP_NODELAY` on each accepted socket for flag 2; any other bit is -22. */
|
|
474
|
+
export function tcpListenFlags(host: string, port: i32, backlog: i32, flags: i32): i32;
|
|
427
475
|
/** The next connection's descriptor, its address in `peer`; -11 when none waits. */
|
|
428
476
|
export function tcpAccept(fd: i32, peer: u8[]): i32;
|
|
429
477
|
/** Up to `len` bytes into `buf` from `off`: the count, 0 at end of stream, or -11. */
|
|
@@ -474,6 +522,8 @@ declare module "nish:unsafe" {
|
|
|
474
522
|
export function wrappingSub<T extends i32 | i64>(a: T, b: T): T;
|
|
475
523
|
/** `a * b` wrapped to the operands' width. */
|
|
476
524
|
export function wrappingMul<T extends i32 | i64>(a: T, b: T): T;
|
|
525
|
+
/** The `NUL`-terminated bytes at `p`, copied into a string: undefined behaviour unless `p` is a live C string. */
|
|
526
|
+
export function readCString(p: CPtr): string;
|
|
477
527
|
}
|
|
478
528
|
|
|
479
529
|
declare module "nish:io" {
|
package/runtime/nish.h
CHANGED
|
@@ -8,11 +8,14 @@
|
|
|
8
8
|
* `runtime/runtime-os.c` holds everything that wraps a system call: the file
|
|
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
|
-
* runtime-net.c
|
|
12
|
-
* time)
|
|
13
|
-
*
|
|
14
|
-
* and budget"); a
|
|
15
|
-
*
|
|
11
|
+
* runtime-net.c, runtime-simd.c (the byte searches that read a vector at a
|
|
12
|
+
* time) and runtime-aes.c (AES-GCM on the CPU's AES instructions) split off
|
|
13
|
+
* the same way since. They are separate so that each carries its own measured
|
|
14
|
+
* code-size ceiling (docs/wp7-runtime.md, "Runtime additions and budget"); a
|
|
15
|
+
* host links all of them, which `scripts/build.sh` does for you when handed
|
|
16
|
+
* runtime.c, runtime-aes.c included: the compiler calls its kernels from
|
|
17
|
+
* std/crypto/aes.ts, so `scripts/build.sh` pairs it and `src/run-cache.ts`
|
|
18
|
+
* caches it like the others. `tests/run.js` checks that every runtime function
|
|
16
19
|
* declared in runtime.ts has a prototype in this file.
|
|
17
20
|
*
|
|
18
21
|
* Headers generated by `nish --emit-header` include this one, so keep
|
|
@@ -155,6 +158,18 @@ int64_t nish_str_index_of_any(const nish_str *s, const nish_str *set, int64_t fr
|
|
|
155
158
|
void nish_print(const nish_str *s);
|
|
156
159
|
/* `console.error` and the newline-free `write` / `writeError`: fd 1 or 2. */
|
|
157
160
|
void nish_write(const nish_str *s, int32_t fd, bool newline);
|
|
161
|
+
/* `panic(message)`, `expect` and a failed range entry: the message and a
|
|
162
|
+
newline on stderr, then `exit(1)`. Only the first panic of a process prints;
|
|
163
|
+
a thread that panics after it parks until that exit (`nish_panic_claim`). */
|
|
164
|
+
__attribute__((noreturn)) void nish_panic(const nish_str *s);
|
|
165
|
+
/* Called by every panic path before it prints: answers for the first caller
|
|
166
|
+
and parks every later one forever. Without threads no second caller can
|
|
167
|
+
exist, so it is empty there. */
|
|
168
|
+
#ifdef NISH_THREADS
|
|
169
|
+
void nish_panic_claim(void);
|
|
170
|
+
#else
|
|
171
|
+
#define nish_panic_claim() ((void)0)
|
|
172
|
+
#endif
|
|
158
173
|
/* Number to string, as `${n}` does: decimal for integers, shortest round-trip (JS Number#toString) for f64. */
|
|
159
174
|
nish_str *nish_str_from_i32(int32_t v);
|
|
160
175
|
nish_str *nish_str_from_f64(double v);
|
|
@@ -164,7 +179,8 @@ nish_str *nish_str_from_i64(int64_t v);
|
|
|
164
179
|
nish_str *nish_str_from_u64(uint64_t v);
|
|
165
180
|
|
|
166
181
|
/* Process and file I/O (WP7). `nish_exit` never returns; the file functions
|
|
167
|
-
* print a message to stderr and
|
|
182
|
+
* print a message to stderr and `_exit(1)` on a fatal error, the first panic
|
|
183
|
+
* of a process only (`nish_panic_claim`).
|
|
168
184
|
*
|
|
169
185
|
* Every function here that takes a path, a name or an argument vector refuses
|
|
170
186
|
* one holding a NUL, answering as it answers a path that does not exist: the
|
|
@@ -239,6 +255,45 @@ nish_array *nish_alloc_array(uint64_t elem_size, uint64_t len);
|
|
|
239
255
|
* elements themselves — which is why the checker refuses to let a program hold
|
|
240
256
|
* a pointer to one across a `push` (WP15 section 2a). */
|
|
241
257
|
void nish_array_grow(nish_array *a, uint64_t elem_size);
|
|
258
|
+
/* ---- AES-GCM on the CPU's AES instructions (WP38 S5) ----------------------
|
|
259
|
+
* runtime/runtime-aes.c: AES-NI and PCLMULQDQ on x86-64, the ARMv8 AES and
|
|
260
|
+
* PMULL instructions on AArch64. The compiler calls each kernel in place of one
|
|
261
|
+
* private function of std/crypto/aes.ts, behind `nish_aes_hw`, and calls the
|
|
262
|
+
* bitsliced Nish function itself when that answers 0. The caller has checked
|
|
263
|
+
* every precondition: a kernel checks no bound, and reads and writes only
|
|
264
|
+
* what is listed. Every kernel is constant time in its key, its data and H.
|
|
265
|
+
*
|
|
266
|
+
* `rk` is a `u64[]` of `8 * (rounds + 1)` words, the length the bitsliced
|
|
267
|
+
* schedule has. On this path it holds, in bytes: the FIPS 197 schedule in
|
|
268
|
+
* [0, 16 * (rounds + 1)), round key r at 16 * r; H = E(K, 0^128), H^2, H^3 and
|
|
269
|
+
* H^4 at [240, 304), each as two u64s, low then high, of the block read
|
|
270
|
+
* big-endian; at [304, 368) each power's halves XORed together, twice over;
|
|
271
|
+
* and zero everywhere else. A process makes and uses every key under one
|
|
272
|
+
* answer of `nish_aes_hw`, so one array never meets both layouts. */
|
|
273
|
+
/* 1 when this process runs the kernels, 0 when it runs the bitsliced Nish
|
|
274
|
+
code. Resolved on the first call and fixed from then on: `NISH_AES=soft`
|
|
275
|
+
pins 0; unset, `hw` or any other value is the best this machine has, read
|
|
276
|
+
on that call from CPUID leaf 1 (AES, PCLMULQDQ, SSSE3) or AArch64's
|
|
277
|
+
AT_HWCAP (AES, PMULL). Always 0 on other targets, wasm32 among them. */
|
|
278
|
+
int32_t nish_aes_hw(void);
|
|
279
|
+
/* `key` (u8[]) is 16 or 32 bytes and `rounds` 10 or 14 to match. Writes the
|
|
280
|
+
kernel layout above into all of `rk`. */
|
|
281
|
+
void nish_aes_schedule(const nish_array *key, int32_t rounds, nish_array *rk);
|
|
282
|
+
/* `src` and `dst` (u8[]) each hold at least 16 bytes: dst[0..16) = E(K, src[0..16)). */
|
|
283
|
+
void nish_aes_block(const nish_array *rk, int32_t rounds, const nish_array *src, nish_array *dst);
|
|
284
|
+
/* GCTR (SP 800-38D §6.5) from inc32(J0): dst[i] = src[i] ^ keystream[i] for
|
|
285
|
+
i < length, the counter J0's last four bytes read big-endian and wrapping
|
|
286
|
+
mod 2^32. `j0` (u8[]) is 16 bytes, 0 <= length <= min(src.len, dst.len),
|
|
287
|
+
and `dst` may be `src`. */
|
|
288
|
+
void nish_aes_ctr(const nish_array *rk, int32_t rounds, const nish_array *j0, const nish_array *src,
|
|
289
|
+
nish_array *dst, int32_t length);
|
|
290
|
+
/* Absorbs data[0..length) (u8[]) into the GHASH state `y` (u64[2], the high
|
|
291
|
+
word first, each read big-endian), zero-padding the last block. `hHi:hLo` is
|
|
292
|
+
H, which the bitsliced walker reads; the kernel reads H and its powers from
|
|
293
|
+
`rk` instead, and they are the same H. 0 <= length <= data.len. */
|
|
294
|
+
void nish_aes_ghash(nish_array *y, uint64_t hHi, uint64_t hLo, const nish_array *rk, const nish_array *data,
|
|
295
|
+
int32_t length);
|
|
296
|
+
|
|
242
297
|
/* `secureZero(bytes)` (#385): sets every byte of `bytes` to zero through
|
|
243
298
|
* `volatile` stores, out of line, so that neither `-O2` nor `-flto` can drop
|
|
244
299
|
* them as dead when the buffer's life ends straight after the call. For
|
|
@@ -313,6 +368,28 @@ int32_t nish_spawn(const nish_array *argv);
|
|
|
313
368
|
* implementation in runtime-os.c backs both spawn builtins, which is what keeps
|
|
314
369
|
* the argument vector, the wait and the signal convention written once. */
|
|
315
370
|
int32_t nish_spawn_to(const nish_array *argv, const nish_str *out, const nish_str *err);
|
|
371
|
+
/* `spawn(argv)` (WP34 N12): start element 0 of `argv` as `nish_spawn` does and
|
|
372
|
+
* answer the child's pid at once, without waiting, or a negative errno:
|
|
373
|
+
* -EINVAL for an empty `argv` or an argument holding a NUL, `posix_spawnp`'s
|
|
374
|
+
* own error otherwise, and -ENOSYS under WASI. The child is reaped by
|
|
375
|
+
* `nish_wait_pid`. */
|
|
376
|
+
int32_t nish_spawn_child(const nish_array *argv);
|
|
377
|
+
/* `kill(pid, sig)`: send `sig` to `pid` and answer 0, or a negative errno. Only
|
|
378
|
+
* 0, 2 (SIGINT), 9 (SIGKILL) and 15 (SIGTERM) are sent; any other signal, and
|
|
379
|
+
* a pid of 0 or below, is -EINVAL. -ESRCH when no process has the pid, -EPERM
|
|
380
|
+
* when it is another user's. Any process of this uid may be signalled, not
|
|
381
|
+
* only a child. */
|
|
382
|
+
int32_t nish_kill(int32_t pid, int32_t sig);
|
|
383
|
+
/* `waitPid(pid, flags)`: a fresh `i32[]` of two, `[pid, status]`. `pid` is a
|
|
384
|
+
* child's or -1 for any; flag 1 is WNOHANG and any other bit is -EINVAL, as is
|
|
385
|
+
* a pid that is neither -1 nor positive. The status is `nish_spawn`'s: the exit
|
|
386
|
+
* code, or `128 + n` for signal `n`. `[0, 0]` is a WNOHANG wait with a child
|
|
387
|
+
* left and none exited; a failure is `[-errno, 0]` (-ECHILD: no child; -EINTR:
|
|
388
|
+
* a signal interrupted the wait). In the arena. */
|
|
389
|
+
nish_array *nish_wait_pid(int32_t pid, int32_t flags);
|
|
390
|
+
/* `totalMemory()`: bytes of physical memory (Linux: `_SC_PHYS_PAGES` times the
|
|
391
|
+
* page size; Darwin: `hw.memsize`), or -1 where the host does not say. */
|
|
392
|
+
int64_t nish_total_memory(void);
|
|
316
393
|
|
|
317
394
|
/* ---- The environment (WP19 R1) ------------------------------------------
|
|
318
395
|
* `getenv(name)`: the value of environment variable `name`, copied into the
|
|
@@ -410,6 +487,8 @@ bool nish_is_executable(const nish_str *path);
|
|
|
410
487
|
* `nish_net_local_port(fd)`: the port a socket is bound to.
|
|
411
488
|
* `nish_tcp_listen(host, port, backlog)`: `SO_REUSEADDR`, and `::` hears
|
|
412
489
|
* both families, or IPv4 alone on a kernel without IPv6.
|
|
490
|
+
* `nish_tcp_listen_flags(host, port, backlog, flags)`: the same listener,
|
|
491
|
+
* with `SO_REUSEPORT` for flag 1 (any other bit is -22).
|
|
413
492
|
* `nish_tcp_accept(fd, peer)`: a new descriptor and the peer's address.
|
|
414
493
|
* `nish_net_read` / `nish_net_write(fd, buf, off, len)`: bytes `[off, off +
|
|
415
494
|
* len)` of `buf`, which the compiled call has range-checked; a write to a
|
|
@@ -443,6 +522,7 @@ bool nish_is_executable(const nish_str *path);
|
|
|
443
522
|
int32_t nish_net_address(nish_array *out, const nish_str *host, int32_t port);
|
|
444
523
|
int32_t nish_net_local_port(int32_t fd);
|
|
445
524
|
int32_t nish_tcp_listen(const nish_str *host, int32_t port, int32_t backlog);
|
|
525
|
+
int32_t nish_tcp_listen_flags(const nish_str *host, int32_t port, int32_t backlog, int32_t flags);
|
|
446
526
|
int32_t nish_tcp_accept(int32_t fd, nish_array *peer);
|
|
447
527
|
int32_t nish_net_read(int32_t fd, nish_array *buf, int64_t off, int64_t len);
|
|
448
528
|
int32_t nish_net_write(int32_t fd, const nish_array *buf, int64_t off, int64_t len);
|
|
@@ -480,12 +560,18 @@ void nish_panic_overflow(uint32_t op);
|
|
|
480
560
|
*
|
|
481
561
|
* One region of work, divided. `nish_parallel_range` calls `body(lo, hi, ctx)`
|
|
482
562
|
* once per chunk of a partition of `[0, len)`: contiguous chunks, at most one
|
|
483
|
-
* element apart in size, at most `
|
|
484
|
-
* `
|
|
485
|
-
*
|
|
563
|
+
* element apart in size, at most `NISH_PAR_PIECES` per thread over at most
|
|
564
|
+
* `nish_cpu_count()` threads and never more than `len / grain` rounded up, with
|
|
565
|
+
* chunk 0 running on the calling thread. Each thread takes the next chunk not
|
|
566
|
+
* yet started when it finishes one, so a thread that runs slower takes fewer.
|
|
567
|
+
* It returns when every chunk has run.
|
|
486
568
|
*
|
|
487
|
-
* Under `-DNISH_THREADS` the other chunks run on
|
|
488
|
-
*
|
|
569
|
+
* Under `-DNISH_THREADS` the other chunks run on the worker pool: threads
|
|
570
|
+
* started on the first region or join that divides, one per CPU but the
|
|
571
|
+
* caller's, which park between calls. Each has its own arena, rewound after
|
|
572
|
+
* every chunk or task it runs. The caller takes chunks off the pool's queue too
|
|
573
|
+
* while it waits, so a chunk the caller took runs in the caller's arena, as
|
|
574
|
+
* chunk 0 does. Without the macro -- and on
|
|
489
575
|
* WASI, which has no threads -- the whole range runs on the calling thread, so
|
|
490
576
|
* the entry point exists either way and the flag decides only whether the work
|
|
491
577
|
* is divided. A body that itself calls this runs its range on one thread: the
|
|
@@ -495,11 +581,31 @@ void nish_panic_overflow(uint32_t op);
|
|
|
495
581
|
* the language surface above it will:
|
|
496
582
|
* - chunks run concurrently, so a body may read what the caller owns and may
|
|
497
583
|
* write only through storage the caller lent it and no two chunks share;
|
|
498
|
-
* - a body
|
|
499
|
-
*
|
|
584
|
+
* - nothing a body leaves in the arena outlives its chunk, because a worker's
|
|
585
|
+
* arena is rewound after each chunk while chunk 0's is the caller's own: a
|
|
586
|
+
* string or an array of scalars a chunk answers is moved to a transfer block
|
|
587
|
+
* first (`nish_cross_keep`, below), and the compiler rewinds the caller's
|
|
588
|
+
* arena after its chunks as the pool rewinds a worker's. */
|
|
500
589
|
typedef void (*nish_par_body)(int64_t lo, int64_t hi, void *ctx);
|
|
590
|
+
/* The CPUs a region may divide over: `nish_cpu_online()` under `--threads`,
|
|
591
|
+
* read once, and 1 in a sequential build. */
|
|
501
592
|
int64_t nish_cpu_count(void);
|
|
593
|
+
/* `availableParallelism()` (WP34 N12), in every build: the fewest of the CPUs
|
|
594
|
+
* online, those the affinity mask allows, the cgroup v2 `cpu.max` quota
|
|
595
|
+
* rounded up, and `NISH_NUM_THREADS` when it is set to a positive number. At
|
|
596
|
+
* least 1; 1 under WASI. Read each call (runtime-os.c). */
|
|
597
|
+
int64_t nish_cpu_online(void);
|
|
502
598
|
void nish_parallel_range(nish_par_body body, void *ctx, int64_t len, int64_t grain);
|
|
599
|
+
/* Keeps every later region and join on threads created and joined per call,
|
|
600
|
+
* as before the pool existed, so no parked worker outlives the code it would
|
|
601
|
+
* run: for a host that can unload the runtime. Call it before the first region
|
|
602
|
+
* or join; a pool already started stays. A Node addon calls it from the
|
|
603
|
+
* constructor below, because its shim includes <node_api.h> before this
|
|
604
|
+
* header, and Node can unload an addon while a pool's workers are parked. */
|
|
605
|
+
void nish_pool_disable(void);
|
|
606
|
+
#if defined(NAPI_VERSION) && defined(NISH_THREADS)
|
|
607
|
+
__attribute__((constructor)) static void nish_napi_unpooled(void) { nish_pool_disable(); }
|
|
608
|
+
#endif
|
|
503
609
|
|
|
504
610
|
/* ---- A scope's tasks (wp29 stage P2), runtime/runtime-parallel.c ----
|
|
505
611
|
*
|
|
@@ -507,11 +613,12 @@ void nish_parallel_range(nish_par_body body, void *ctx, int64_t len, int64_t gra
|
|
|
507
613
|
* alive until it joins: it copies `size` bytes of `payload` and keeps them with
|
|
508
614
|
* `run` and `finish`, and runs nothing yet. `nish_scope_join` takes every task
|
|
509
615
|
* filed under `scope`, runs `run(payload)` for each -- the first on the calling
|
|
510
|
-
* thread and
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* running short of threads costs speed and never an
|
|
616
|
+
* thread and the others on the worker pool, oldest first, with the calling
|
|
617
|
+
* thread taking any no worker is free for, in that order -- waits for all of
|
|
618
|
+
* them, and then calls `finish(payload)` for each on the calling thread, in
|
|
619
|
+
* the order they were filed. Without `-DNISH_THREADS` every task runs on the
|
|
620
|
+
* calling thread, so running short of threads costs speed and never an
|
|
621
|
+
* answer.
|
|
515
622
|
*
|
|
516
623
|
* The preconditions are the language's (docs/LANGUAGE.md, "Scoped tasks"):
|
|
517
624
|
* `run` writes nothing another task or the caller can see, its result is a
|
|
@@ -521,6 +628,96 @@ typedef void (*nish_task_fn)(void *payload);
|
|
|
521
628
|
void nish_scope_spawn(void *scope, nish_task_fn run, nish_task_fn finish, const void *payload, int64_t size);
|
|
522
629
|
void nish_scope_join(void *scope);
|
|
523
630
|
|
|
631
|
+
/* ---- A lock that owns its data (wp29 stage P3), runtime/runtime-parallel.c ----
|
|
632
|
+
*
|
|
633
|
+
* A `Mutex`'s lock is one `int32_t` word inside its guard: 0 free, 1 held. The
|
|
634
|
+
* compiler takes it inline, with an acquire compare-and-swap of 0 to 1, and
|
|
635
|
+
* gives it back inline, with a release store of 0 (src/emit-parallel.ts). Only
|
|
636
|
+
* a swap that finds the word held calls `nish_mutex_wait`, which returns once
|
|
637
|
+
* it has taken the lock itself: it spins briefly, then yields the processor
|
|
638
|
+
* between tries. The word lives in the arena with the rest of the `Mutex`, so
|
|
639
|
+
* there is nothing to create and nothing to destroy.
|
|
640
|
+
*
|
|
641
|
+
* The language holds one lock at a time and waits for nothing while it is
|
|
642
|
+
* held (docs/LANGUAGE.md, "A lock that owns its data"), so a holder always
|
|
643
|
+
* gives the word back and a waiter here always returns. Without real threads
|
|
644
|
+
* -- no `-DNISH_THREADS`, or WASI -- nothing else can hold the word, and the
|
|
645
|
+
* first try takes it. */
|
|
646
|
+
void nish_mutex_wait(int32_t *word);
|
|
647
|
+
|
|
648
|
+
/* ---- A channel of scalars or strings (wp29 stage P3), runtime/runtime-parallel.c ----
|
|
649
|
+
*
|
|
650
|
+
* A `Channel` object holds one `int64_t` word, `state`, and each function here
|
|
651
|
+
* takes its address: 0 before first use, then the address of a buffer, a lock
|
|
652
|
+
* and a count this file keeps outside every arena, then 1 once the receiver
|
|
653
|
+
* has drained it closed and it has been given back. A value is one 8-byte
|
|
654
|
+
* slot; the compiler widens a scalar into it and narrows it back, and a
|
|
655
|
+
* string travels as the block `nish_cross_send` copied it into, which the
|
|
656
|
+
* receiver's `nish_cross_in` frees. A string still in the buffer when the
|
|
657
|
+
* receiver stops early (a `break`) is given back with the buffer unread, so
|
|
658
|
+
* its block leaks.
|
|
659
|
+
*
|
|
660
|
+
* `nish_channel_send` appends and never waits: the channel is unbounded.
|
|
661
|
+
* `nish_channel_count` moves the count that keeps it open, which starts at 1:
|
|
662
|
+
* +1 at the spawn of each task that may send on it, -1 when that task returns,
|
|
663
|
+
* and -1 just before its scope joins. At zero the channel is closed.
|
|
664
|
+
* `nish_channel_receive` takes the next value into `*out` and answers 1,
|
|
665
|
+
* waiting while the channel is empty and open, or answers 0 once it is closed
|
|
666
|
+
* and empty, giving the buffer back the first time.
|
|
667
|
+
*
|
|
668
|
+
* The preconditions are the language's (docs/LANGUAGE.md, "Channels"): one
|
|
669
|
+
* receiver, every sender spawned before it, and no send once the scope's
|
|
670
|
+
* block has begun except by its tasks, so nothing touches a channel after its
|
|
671
|
+
* receiver has drained it. */
|
|
672
|
+
void nish_channel_send(int64_t *state, int64_t value);
|
|
673
|
+
void nish_channel_count(int64_t *state, int64_t delta);
|
|
674
|
+
int32_t nish_channel_receive(int64_t *state, int64_t *out);
|
|
675
|
+
|
|
676
|
+
/* ---- Copy at join: a string or a scalar array crosses threads ----
|
|
677
|
+
* runtime/runtime-cross.c
|
|
678
|
+
*
|
|
679
|
+
* A task's or a chunk's arena is rewound once its job is done, so a string or
|
|
680
|
+
* an array of scalars it answers or sends is copied out of it.
|
|
681
|
+
* `nish_cross_out(v, esize, mark)` runs on the thread that made `v`: when `v`
|
|
682
|
+
* was bumped in that thread's arena since `mark` (0: at any time) it answers a
|
|
683
|
+
* copy in a block of its own, outside every arena, with its low bit set; any
|
|
684
|
+
* other value, a literal or one an outer frame made, is answered as it is.
|
|
685
|
+
* `nish_cross_send(s)` is a channel send's: it copies every string `s`, so a
|
|
686
|
+
* send costs the string's length and not a walk of the sender's arena.
|
|
687
|
+
* `nish_cross_keep(v, esize, mark)` is a map element's: it moves `v` to the
|
|
688
|
+
* end of the chunk's transfer block and rewinds the arena to `mark`, the
|
|
689
|
+
* position before the body was called, so a chunk keeps one element's
|
|
690
|
+
* temporaries at a time. `nish_cross_begin(state, list)` pushes the chunk's
|
|
691
|
+
* transfer state, a `{ void *, void *, uint64_t, void * }` the caller holds,
|
|
692
|
+
* whose filled blocks go on `*list`, and `nish_cross_end(state)` pops it; with
|
|
693
|
+
* no list (a map's sequential path), or none pushed, keep copies `v` out and
|
|
694
|
+
* back in below `mark`. `nish_cross_adopt(list, dst, esize)` runs once every
|
|
695
|
+
* chunk is done, with `dst` the array the region wrote: 64 KB or more of
|
|
696
|
+
* blocks on a list become the newest chunks of the calling thread's arena,
|
|
697
|
+
* and less is copied into it, each element of `dst` in a block moved, and the
|
|
698
|
+
* blocks freed.
|
|
699
|
+
* `nish_cross_in(p, esize)` runs on the thread that takes the value: a tagged
|
|
700
|
+
* `p` of 64 KB or more that does not fit the arena's current chunk becomes a
|
|
701
|
+
* chunk of that arena; a smaller one is copied in and its block freed. Either
|
|
702
|
+
* way the block lives exactly as long as a copy would have. `esize` is 0 for a
|
|
703
|
+
* string and the element size of an array whose elements hold no pointer.
|
|
704
|
+
*
|
|
705
|
+
* `nish_guard_keep(old, s)` is a guard's string store (`g.value = s`): it
|
|
706
|
+
* answers a copy of `s` that the `Mutex` owns, outside every arena, and frees
|
|
707
|
+
* `old`, the string the slot held, when it is such a copy. `old` is null for a
|
|
708
|
+
* `string | null` slot that held none, and `s` is null for a `null` stored into
|
|
709
|
+
* one: the slot's copy is freed, nothing is kept, and the store answers null.
|
|
710
|
+
* A copy still held when its `Mutex` is dropped stays until the process ends:
|
|
711
|
+
* one block per string slot, not one per store. */
|
|
712
|
+
void *nish_cross_out(void *v, uint64_t esize, uint64_t mark);
|
|
713
|
+
void *nish_cross_send(void *s);
|
|
714
|
+
void *nish_cross_keep(void *v, uint64_t esize, uint64_t mark);
|
|
715
|
+
void *nish_cross_in(void *p, uint64_t esize);
|
|
716
|
+
void nish_cross_begin(void *state, void **list);
|
|
717
|
+
void nish_cross_end(void *state);
|
|
718
|
+
void nish_cross_adopt(void *list, void *dst, uint64_t esize);
|
|
719
|
+
void *nish_guard_keep(void *old, const void *s);
|
|
720
|
+
|
|
524
721
|
#ifdef __cplusplus
|
|
525
722
|
}
|
|
526
723
|
#endif
|
package/runtime/nish.mjs
CHANGED
|
@@ -93,6 +93,13 @@ provide("readdirSync", shim.readdirSync);
|
|
|
93
93
|
provide("realpathSync", shim.realpathSync);
|
|
94
94
|
provide("spawnSync", shim.spawnSync);
|
|
95
95
|
provide("spawnSyncTo", shim.spawnSyncTo);
|
|
96
|
+
// WP34 N12. `spawn` and `waitPid` throw, naming themselves: a child is reaped
|
|
97
|
+
// by Node's event loop. `kill`, `availableParallelism` and `totalMemory` answer.
|
|
98
|
+
provide("spawn", shim.spawn);
|
|
99
|
+
provide("kill", shim.kill);
|
|
100
|
+
provide("waitPid", shim.waitPid);
|
|
101
|
+
provide("availableParallelism", shim.availableParallelism);
|
|
102
|
+
provide("totalMemory", shim.totalMemory);
|
|
96
103
|
provide("getenv", shim.getenv);
|
|
97
104
|
provide("statMtimeSync", shim.statMtimeSync);
|
|
98
105
|
provide("signalFd", shim.signalFd);
|
|
@@ -104,6 +111,7 @@ for (const name of [
|
|
|
104
111
|
"netAddress",
|
|
105
112
|
"netLocalPort",
|
|
106
113
|
"tcpListen",
|
|
114
|
+
"tcpListenFlags",
|
|
107
115
|
"tcpAccept",
|
|
108
116
|
"netRead",
|
|
109
117
|
"netWrite",
|
|
@@ -225,6 +233,14 @@ provide("wrappingMul", (a, b) =>
|
|
|
225
233
|
provide("Ok", shim.Ok);
|
|
226
234
|
provide("Err", shim.Err);
|
|
227
235
|
|
|
236
|
+
// `String.fromBytes` is Nish's own static on `String`, so it is added to
|
|
237
|
+
// Node's `String` rather than installed as a global. Each byte is one UTF-16
|
|
238
|
+
// unit, as `String.fromCharCode` makes it: ASCII agrees with a native run,
|
|
239
|
+
// and a byte above 127 is the same divergence `fromCharCode`'s is.
|
|
240
|
+
if (!("fromBytes" in String)) {
|
|
241
|
+
String.fromBytes = shim.fromBytes;
|
|
242
|
+
}
|
|
243
|
+
|
|
228
244
|
// The string parsers, whose deviations from JavaScript are documented rules
|
|
229
245
|
// (base-10 `parseInt` that saturates, `parseFloat` that reads a `0x` prefix).
|
|
230
246
|
globalThis.parseInt = shim.parseInt;
|