@ai-ecoverse/slicc-kernel 1.48.3 → 1.49.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/README.md +1 -0
- package/dist/kernel-worker.js +20 -0
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +405 -61
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +20 -0
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +405 -61
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
package/dist/process-worker.js
CHANGED
|
@@ -1991,12 +1991,12 @@ var init_kernel_streams = __esm({
|
|
|
1991
1991
|
usePipes(pipefs) {
|
|
1992
1992
|
const createPipe = pipefs.createPipe.bind(pipefs);
|
|
1993
1993
|
pipefs.createPipe = () => {
|
|
1994
|
-
const [
|
|
1994
|
+
const [read2, write2] = this.call(() => this.sys.pipe());
|
|
1995
1995
|
let fds;
|
|
1996
1996
|
try {
|
|
1997
1997
|
fds = createPipe();
|
|
1998
1998
|
} catch (e) {
|
|
1999
|
-
for (const kfd of [
|
|
1999
|
+
for (const kfd of [read2, write2]) {
|
|
2000
2000
|
try {
|
|
2001
2001
|
this.sys.close(kfd);
|
|
2002
2002
|
} catch {
|
|
@@ -2004,8 +2004,8 @@ var init_kernel_streams = __esm({
|
|
|
2004
2004
|
}
|
|
2005
2005
|
throw e;
|
|
2006
2006
|
}
|
|
2007
|
-
this.attach(this.Fs.getStream(fds.readable_fd),
|
|
2008
|
-
this.attach(this.Fs.getStream(fds.writable_fd),
|
|
2007
|
+
this.attach(this.Fs.getStream(fds.readable_fd), read2, false);
|
|
2008
|
+
this.attach(this.Fs.getStream(fds.writable_fd), write2, false);
|
|
2009
2009
|
return fds;
|
|
2010
2010
|
};
|
|
2011
2011
|
}
|
|
@@ -2394,12 +2394,12 @@ function readInto(sys, kfd, target, at) {
|
|
|
2394
2394
|
}
|
|
2395
2395
|
return done;
|
|
2396
2396
|
}
|
|
2397
|
-
function positioned(original,
|
|
2397
|
+
function positioned(original, write2, deps) {
|
|
2398
2398
|
return (fd, iov, iovcnt, ...rest2) => {
|
|
2399
2399
|
const stream = deps.fs()?.getStream(Number(fd));
|
|
2400
2400
|
const memory = deps.memory();
|
|
2401
2401
|
const kfd = stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
|
|
2402
|
-
if (kfd === void 0 || !memory || !(
|
|
2402
|
+
if (kfd === void 0 || !memory || !(write2 ? deps.sys.pwrite : deps.sys.pread)) {
|
|
2403
2403
|
return original(fd, iov, iovcnt, ...rest2);
|
|
2404
2404
|
}
|
|
2405
2405
|
const at = offsetOf(rest2);
|
|
@@ -2411,7 +2411,7 @@ function positioned(original, write, deps) {
|
|
|
2411
2411
|
const ptr = view.getUint32(Number(iov) + i * 8, true);
|
|
2412
2412
|
const len = view.getUint32(Number(iov) + i * 8 + 4, true);
|
|
2413
2413
|
const part = new Uint8Array(memory.buffer, ptr, len);
|
|
2414
|
-
const moved =
|
|
2414
|
+
const moved = write2 ? deps.sys.pwrite?.(kfd, part.slice(), at + done) ?? 0 : readInto(deps.sys, kfd, part, at + done);
|
|
2415
2415
|
done += moved;
|
|
2416
2416
|
if (moved < len) break;
|
|
2417
2417
|
}
|
|
@@ -2424,13 +2424,13 @@ function positioned(original, write, deps) {
|
|
|
2424
2424
|
}
|
|
2425
2425
|
function positionalIo(imports, deps) {
|
|
2426
2426
|
for (const namespace of namespaces(imports)) {
|
|
2427
|
-
for (const [name,
|
|
2427
|
+
for (const [name, write2] of [
|
|
2428
2428
|
["fd_pread", false],
|
|
2429
2429
|
["fd_pwrite", true]
|
|
2430
2430
|
]) {
|
|
2431
2431
|
const key = keyOf(namespace, name, deps.glue);
|
|
2432
2432
|
if (key !== void 0) {
|
|
2433
|
-
namespace[key] = positioned(namespace[key],
|
|
2433
|
+
namespace[key] = positioned(namespace[key], write2, deps);
|
|
2434
2434
|
}
|
|
2435
2435
|
}
|
|
2436
2436
|
}
|
|
@@ -2558,10 +2558,10 @@ function useZeroDevices(Fs) {
|
|
|
2558
2558
|
}
|
|
2559
2559
|
]
|
|
2560
2560
|
];
|
|
2561
|
-
for (const [path, minor,
|
|
2561
|
+
for (const [path, minor, write2] of devices) {
|
|
2562
2562
|
if (analyzePath.call(Fs, path).exists) continue;
|
|
2563
2563
|
const dev = makedev.call(Fs, 1, minor);
|
|
2564
|
-
registerDevice.call(Fs, dev, { read: zeros, write, llseek: () => 0 });
|
|
2564
|
+
registerDevice.call(Fs, dev, { read: zeros, write: write2, llseek: () => 0 });
|
|
2565
2565
|
mkdev.call(Fs, path, CHAR_DEVICE, dev);
|
|
2566
2566
|
}
|
|
2567
2567
|
}
|
|
@@ -2957,38 +2957,38 @@ function drain(Fs, stream) {
|
|
|
2957
2957
|
}
|
|
2958
2958
|
return out;
|
|
2959
2959
|
}
|
|
2960
|
-
function kernelSelect(Fs, transport,
|
|
2960
|
+
function kernelSelect(Fs, transport, read2, write2, timeoutMs) {
|
|
2961
2961
|
const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
|
|
2962
|
-
const kr =
|
|
2963
|
-
const kw =
|
|
2962
|
+
const kr = read2.map(kernel);
|
|
2963
|
+
const kw = write2.map(kernel);
|
|
2964
2964
|
const r = transport.call({ op: "fd-select", read: kr, write: kw, timeoutMs }, Infinity, "select");
|
|
2965
2965
|
if (!r.ok) return -wasiErrno(r.errno);
|
|
2966
2966
|
const got = r.kind === "json" ? r.json : { read: [], write: [] };
|
|
2967
2967
|
return {
|
|
2968
|
-
read:
|
|
2969
|
-
write:
|
|
2968
|
+
read: read2.filter((_, i) => got.read.includes(kr[i])),
|
|
2969
|
+
write: write2.filter((_, i) => got.write.includes(kw[i]))
|
|
2970
2970
|
};
|
|
2971
2971
|
}
|
|
2972
|
-
function ownReady(Fs,
|
|
2972
|
+
function ownReady(Fs, read2, write2) {
|
|
2973
2973
|
const flags = (fd) => {
|
|
2974
2974
|
const stream = Fs.getStream(fd);
|
|
2975
2975
|
if (!stream) return POLLNVAL;
|
|
2976
2976
|
return stream.stream_ops.poll ? stream.stream_ops.poll(stream) : POLLIN2 | POLLOUT2;
|
|
2977
2977
|
};
|
|
2978
2978
|
return {
|
|
2979
|
-
read:
|
|
2980
|
-
write:
|
|
2979
|
+
read: read2.filter((fd) => flags(fd) & (POLLIN2 | POLLHUP2 | POLLERR2 | POLLNVAL)),
|
|
2980
|
+
write: write2.filter((fd) => flags(fd) & (POLLOUT2 | POLLERR2 | POLLNVAL))
|
|
2981
2981
|
};
|
|
2982
2982
|
}
|
|
2983
|
-
function anySelect(Fs, transport,
|
|
2983
|
+
function anySelect(Fs, transport, read2, write2, timeoutMs) {
|
|
2984
2984
|
const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
|
|
2985
2985
|
const own = (fd) => kernel(fd) === void 0;
|
|
2986
|
-
if (![...
|
|
2986
|
+
if (![...read2, ...write2].some(own)) return kernelSelect(Fs, transport, read2, write2, timeoutMs);
|
|
2987
2987
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
2988
|
-
const kernelRead =
|
|
2989
|
-
const kernelWrite =
|
|
2988
|
+
const kernelRead = read2.filter((fd) => !own(fd));
|
|
2989
|
+
const kernelWrite = write2.filter((fd) => !own(fd));
|
|
2990
2990
|
for (; ; ) {
|
|
2991
|
-
const local = ownReady(Fs,
|
|
2991
|
+
const local = ownReady(Fs, read2.filter(own), write2.filter(own));
|
|
2992
2992
|
const pending = local.read.length > 0 || local.write.length > 0;
|
|
2993
2993
|
const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
|
|
2994
2994
|
const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
|
|
@@ -3095,7 +3095,7 @@ function createProcessKernel(deps) {
|
|
|
3095
3095
|
if (!r.ok) return -wasiErrno(r.errno);
|
|
3096
3096
|
return r.kind === "json" ? r.json : -wasiErrno("EIO");
|
|
3097
3097
|
},
|
|
3098
|
-
select: (
|
|
3098
|
+
select: (read2, write2, timeoutMs) => anySelect(Fs, transport, read2, write2, timeoutMs),
|
|
3099
3099
|
execWait,
|
|
3100
3100
|
execve(file, argv, env, cwd) {
|
|
3101
3101
|
const pid = spawnChild(file, argv, env, cwd, [0, 1, 2], void 0, true);
|
|
@@ -5393,17 +5393,17 @@ function writeEvents(mem, ptr, events) {
|
|
|
5393
5393
|
}
|
|
5394
5394
|
function classify(fds, subs) {
|
|
5395
5395
|
const events = [];
|
|
5396
|
-
const
|
|
5397
|
-
const
|
|
5396
|
+
const read2 = [];
|
|
5397
|
+
const write2 = [];
|
|
5398
5398
|
for (const s of subs) {
|
|
5399
5399
|
if (s.type === EVENTTYPE.CLOCK) continue;
|
|
5400
5400
|
const e = fds.find(s.fd);
|
|
5401
5401
|
if (!e) events.push({ userdata: s.userdata, error: E.BADF, type: s.type });
|
|
5402
5402
|
else if (e.type !== "kernel")
|
|
5403
5403
|
events.push({ userdata: s.userdata, error: E.SUCCESS, type: s.type });
|
|
5404
|
-
else (s.type === EVENTTYPE.FD_READ ?
|
|
5404
|
+
else (s.type === EVENTTYPE.FD_READ ? read2 : write2).push(s.fd);
|
|
5405
5405
|
}
|
|
5406
|
-
return { events, read, write };
|
|
5406
|
+
return { events, read: read2, write: write2 };
|
|
5407
5407
|
}
|
|
5408
5408
|
function readyEvents(subs, ready) {
|
|
5409
5409
|
return subs.filter(
|
|
@@ -5419,11 +5419,11 @@ function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
|
|
|
5419
5419
|
if (nsubs === 0) return E.INVAL;
|
|
5420
5420
|
const { mem, kernel } = deps;
|
|
5421
5421
|
const subs = readSubscriptions(mem, inPtr, nsubs, deps.now);
|
|
5422
|
-
const { events, read, write } = classify(deps.fds, subs);
|
|
5422
|
+
const { events, read: read2, write: write2 } = classify(deps.fds, subs);
|
|
5423
5423
|
let interrupted = false;
|
|
5424
5424
|
const earliest = subs.reduce((min, s) => Math.min(min, s.deadline), Infinity);
|
|
5425
5425
|
const expired = () => performance.now() + CLOCK_SLACK_MS >= earliest;
|
|
5426
|
-
if (
|
|
5426
|
+
if (read2.length > 0 || write2.length > 0 || events.length === 0) {
|
|
5427
5427
|
do {
|
|
5428
5428
|
let timeoutMs = -1;
|
|
5429
5429
|
if (events.length > 0) timeoutMs = 0;
|
|
@@ -5431,7 +5431,7 @@ function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
|
|
|
5431
5431
|
timeoutMs = Math.max(0, Math.ceil(earliest - performance.now()));
|
|
5432
5432
|
let ready;
|
|
5433
5433
|
try {
|
|
5434
|
-
ready = kernel.call({ op: "fd-select", read, write, timeoutMs });
|
|
5434
|
+
ready = kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
|
|
5435
5435
|
} catch (e) {
|
|
5436
5436
|
if (!deps.interruptWakes || e.code !== "EINTR") throw e;
|
|
5437
5437
|
interrupted = true;
|
|
@@ -6669,10 +6669,10 @@ function processes(host, call2, inThread) {
|
|
|
6669
6669
|
const slot = (n, how, mine, theirs) => {
|
|
6670
6670
|
if (how === "inherit") return { fd: n };
|
|
6671
6671
|
if (how === "null") return { none: true };
|
|
6672
|
-
const [
|
|
6673
|
-
mine[n] = n === 0 ?
|
|
6674
|
-
theirs.push(n === 0 ?
|
|
6675
|
-
return { fd: n === 0 ?
|
|
6672
|
+
const [read2, write2] = call2({ op: "fd-pipe" });
|
|
6673
|
+
mine[n] = n === 0 ? write2 : read2;
|
|
6674
|
+
theirs.push(n === 0 ? read2 : write2);
|
|
6675
|
+
return { fd: n === 0 ? read2 : write2 };
|
|
6676
6676
|
};
|
|
6677
6677
|
return {
|
|
6678
6678
|
spawn(o) {
|
|
@@ -7056,6 +7056,289 @@ var init_wasix_fork = __esm({
|
|
|
7056
7056
|
}
|
|
7057
7057
|
});
|
|
7058
7058
|
|
|
7059
|
+
// src/process/wasi/wasix-ffi.ts
|
|
7060
|
+
function read(view, at, type) {
|
|
7061
|
+
if (type === "i32") return view.getInt32(at, true);
|
|
7062
|
+
if (type === "i64") return view.getBigInt64(at, true);
|
|
7063
|
+
if (type === "f32") return view.getFloat32(at, true);
|
|
7064
|
+
return view.getFloat64(at, true);
|
|
7065
|
+
}
|
|
7066
|
+
function write(view, at, type, value2) {
|
|
7067
|
+
if (type === "i32") view.setInt32(at, Number(value2), true);
|
|
7068
|
+
else if (type === "i64") view.setBigInt64(at, BigInt(value2), true);
|
|
7069
|
+
else if (type === "f32") view.setFloat32(at, Number(value2), true);
|
|
7070
|
+
else view.setFloat64(at, Number(value2), true);
|
|
7071
|
+
}
|
|
7072
|
+
function scalars(types) {
|
|
7073
|
+
if (types.includes("other")) throw new WasiError("EINVAL");
|
|
7074
|
+
return types;
|
|
7075
|
+
}
|
|
7076
|
+
function callDynamic(ctx, id, values, valuesLen, results, resultsLen, strict) {
|
|
7077
|
+
const table = ctx.table();
|
|
7078
|
+
if (!table) throw new WasiError("ENOTSUP");
|
|
7079
|
+
const fn = id < table.length ? table.get(id) : null;
|
|
7080
|
+
const sig = fn ? ctx.types.of(fn) : void 0;
|
|
7081
|
+
if (!fn || !sig) throw new WasiError("EINVAL");
|
|
7082
|
+
const params = scalars(sig.params);
|
|
7083
|
+
const outs = scalars(sig.results);
|
|
7084
|
+
const view = ctx.mem.view();
|
|
7085
|
+
const end = values + valuesLen;
|
|
7086
|
+
let at = values;
|
|
7087
|
+
const args = params.map((type) => {
|
|
7088
|
+
if (at + SIZE2[type] > end) {
|
|
7089
|
+
if (strict) throw new WasiError("EINVAL");
|
|
7090
|
+
return type === "i64" ? 0n : 0;
|
|
7091
|
+
}
|
|
7092
|
+
const v = read(view, at, type);
|
|
7093
|
+
at += SIZE2[type];
|
|
7094
|
+
return v;
|
|
7095
|
+
});
|
|
7096
|
+
if (strict && at !== end) throw new WasiError("EINVAL");
|
|
7097
|
+
const returned = fn(...args);
|
|
7098
|
+
const got = outs.length === 1 ? [returned] : returned ?? [];
|
|
7099
|
+
const after = ctx.mem.view();
|
|
7100
|
+
const stop = results + resultsLen;
|
|
7101
|
+
let out = results;
|
|
7102
|
+
outs.forEach((type, i) => {
|
|
7103
|
+
if (out + SIZE2[type] > stop) {
|
|
7104
|
+
if (strict) throw new WasiError("EINVAL");
|
|
7105
|
+
return;
|
|
7106
|
+
}
|
|
7107
|
+
write(after, out, type, got[i]);
|
|
7108
|
+
out += SIZE2[type];
|
|
7109
|
+
});
|
|
7110
|
+
if (strict && out !== stop) throw new WasiError("EINVAL");
|
|
7111
|
+
}
|
|
7112
|
+
var SIZE2;
|
|
7113
|
+
var init_wasix_ffi = __esm({
|
|
7114
|
+
"src/process/wasi/wasix-ffi.ts"() {
|
|
7115
|
+
"use strict";
|
|
7116
|
+
init_wasi_files();
|
|
7117
|
+
SIZE2 = { i32: 4, i64: 8, f32: 4, f64: 8 };
|
|
7118
|
+
}
|
|
7119
|
+
});
|
|
7120
|
+
|
|
7121
|
+
// src/process/wasi/wasm-functypes.ts
|
|
7122
|
+
function readTypes(r, s) {
|
|
7123
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
7124
|
+
r.byte();
|
|
7125
|
+
const params = [];
|
|
7126
|
+
for (let n = r.u32(); n > 0; n--) params.push(r.valtype());
|
|
7127
|
+
const results = [];
|
|
7128
|
+
for (let n = r.u32(); n > 0; n--) results.push(r.valtype());
|
|
7129
|
+
s.info.sigs.push({ params, results });
|
|
7130
|
+
}
|
|
7131
|
+
}
|
|
7132
|
+
function readImports(r, s) {
|
|
7133
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
7134
|
+
r.name();
|
|
7135
|
+
const field2 = r.name();
|
|
7136
|
+
const kind = r.byte();
|
|
7137
|
+
if (kind === 0) s.info.funcs.push(r.u32());
|
|
7138
|
+
else if (kind === 1) {
|
|
7139
|
+
r.valtype();
|
|
7140
|
+
r.limits();
|
|
7141
|
+
} else if (kind === 2) r.limits();
|
|
7142
|
+
else if (kind === 3) {
|
|
7143
|
+
r.valtype();
|
|
7144
|
+
r.byte();
|
|
7145
|
+
s.globals.push(field2);
|
|
7146
|
+
} else {
|
|
7147
|
+
r.byte();
|
|
7148
|
+
r.u32();
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
function readFunctions(r, s) {
|
|
7153
|
+
for (let i = r.u32(); i > 0; i--) s.info.funcs.push(r.u32());
|
|
7154
|
+
}
|
|
7155
|
+
function constExpr(r, s) {
|
|
7156
|
+
let value2 = 0;
|
|
7157
|
+
let tableBase = false;
|
|
7158
|
+
let known = true;
|
|
7159
|
+
for (; ; ) {
|
|
7160
|
+
const op = r.byte();
|
|
7161
|
+
if (op === 11) return known ? { value: value2, tableBase } : void 0;
|
|
7162
|
+
if (op === 65) value2 += r.s32();
|
|
7163
|
+
else if (op === 35) {
|
|
7164
|
+
const g = s.globals[r.u32()];
|
|
7165
|
+
if (g === TABLE_BASE) tableBase = true;
|
|
7166
|
+
else if (typeof g === "number") value2 += g;
|
|
7167
|
+
else known = false;
|
|
7168
|
+
} else if (op === 210) {
|
|
7169
|
+
value2 = r.u32();
|
|
7170
|
+
} else if (op in SKIP) {
|
|
7171
|
+
SKIP[op]?.(r);
|
|
7172
|
+
known = false;
|
|
7173
|
+
} else if (op !== 106) {
|
|
7174
|
+
r.at = r.bytes.length;
|
|
7175
|
+
return void 0;
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
}
|
|
7179
|
+
function readGlobals(r, s) {
|
|
7180
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
7181
|
+
r.valtype();
|
|
7182
|
+
r.byte();
|
|
7183
|
+
const init = constExpr(r, s);
|
|
7184
|
+
s.globals.push(init && !init.tableBase ? init.value : void 0);
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
function readExports(r, s) {
|
|
7188
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
7189
|
+
const name = r.name();
|
|
7190
|
+
const kind = r.byte();
|
|
7191
|
+
const index2 = r.u32();
|
|
7192
|
+
if (kind === 0) s.info.exports[name] = index2;
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
function readElems(r, s) {
|
|
7196
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
7197
|
+
const flags = r.u32();
|
|
7198
|
+
const active = (flags & 1) === 0;
|
|
7199
|
+
const table = flags & 2 ? active ? r.u32() : 0 : 0;
|
|
7200
|
+
const offset = active ? constExpr(r, s) : void 0;
|
|
7201
|
+
if (flags & 3) r.valtype();
|
|
7202
|
+
const funcs = [];
|
|
7203
|
+
for (let n = r.u32(); n > 0; n--) {
|
|
7204
|
+
if (flags & 4) {
|
|
7205
|
+
const ref = constExpr(r, s);
|
|
7206
|
+
funcs.push(ref ? ref.value : -1);
|
|
7207
|
+
} else funcs.push(r.u32());
|
|
7208
|
+
}
|
|
7209
|
+
if (offset && table === 0) {
|
|
7210
|
+
s.info.elems.push({ offset: offset.value, tableBase: offset.tableBase, funcs });
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
}
|
|
7214
|
+
function funcTypeInfo(bytes) {
|
|
7215
|
+
const r = new Reader(bytes);
|
|
7216
|
+
const s = { info: { sigs: [], funcs: [], exports: {}, elems: [] }, globals: [] };
|
|
7217
|
+
while (r.at < bytes.length) {
|
|
7218
|
+
const id = r.byte();
|
|
7219
|
+
const end = r.u32() + r.at;
|
|
7220
|
+
SECTIONS[id]?.(r, s);
|
|
7221
|
+
r.at = end;
|
|
7222
|
+
}
|
|
7223
|
+
return s.info;
|
|
7224
|
+
}
|
|
7225
|
+
var VALTYPES, TABLE_BASE, Reader, SKIP, SECTIONS, FuncTypes;
|
|
7226
|
+
var init_wasm_functypes = __esm({
|
|
7227
|
+
"src/process/wasi/wasm-functypes.ts"() {
|
|
7228
|
+
"use strict";
|
|
7229
|
+
VALTYPES = {
|
|
7230
|
+
127: "i32",
|
|
7231
|
+
126: "i64",
|
|
7232
|
+
125: "f32",
|
|
7233
|
+
124: "f64"
|
|
7234
|
+
};
|
|
7235
|
+
TABLE_BASE = "__table_base";
|
|
7236
|
+
Reader = class {
|
|
7237
|
+
at = 8;
|
|
7238
|
+
bytes;
|
|
7239
|
+
constructor(bytes) {
|
|
7240
|
+
this.bytes = bytes;
|
|
7241
|
+
}
|
|
7242
|
+
byte() {
|
|
7243
|
+
return this.bytes[this.at++] ?? 0;
|
|
7244
|
+
}
|
|
7245
|
+
u32() {
|
|
7246
|
+
let result = 0;
|
|
7247
|
+
let shift = 0;
|
|
7248
|
+
for (; ; ) {
|
|
7249
|
+
const b = this.byte();
|
|
7250
|
+
result |= (b & 127) << shift;
|
|
7251
|
+
if (!(b & 128)) return result >>> 0;
|
|
7252
|
+
shift += 7;
|
|
7253
|
+
}
|
|
7254
|
+
}
|
|
7255
|
+
s32() {
|
|
7256
|
+
let result = 0;
|
|
7257
|
+
let shift = 0;
|
|
7258
|
+
let b;
|
|
7259
|
+
do {
|
|
7260
|
+
b = this.byte();
|
|
7261
|
+
result |= (b & 127) << shift;
|
|
7262
|
+
shift += 7;
|
|
7263
|
+
} while (b & 128);
|
|
7264
|
+
return shift < 32 && b & 64 ? result | -1 << shift : result;
|
|
7265
|
+
}
|
|
7266
|
+
name() {
|
|
7267
|
+
const len = this.u32();
|
|
7268
|
+
const s = new TextDecoder().decode(this.bytes.subarray(this.at, this.at + len));
|
|
7269
|
+
this.at += len;
|
|
7270
|
+
return s;
|
|
7271
|
+
}
|
|
7272
|
+
valtype() {
|
|
7273
|
+
const code2 = this.byte();
|
|
7274
|
+
if (code2 === 99 || code2 === 100) this.s32();
|
|
7275
|
+
return VALTYPES[code2] ?? "other";
|
|
7276
|
+
}
|
|
7277
|
+
limits() {
|
|
7278
|
+
const flags = this.byte();
|
|
7279
|
+
this.u32();
|
|
7280
|
+
if (flags & 1) this.u32();
|
|
7281
|
+
}
|
|
7282
|
+
};
|
|
7283
|
+
SKIP = {
|
|
7284
|
+
66: (r) => r.s32(),
|
|
7285
|
+
67: (r) => {
|
|
7286
|
+
r.at += 4;
|
|
7287
|
+
},
|
|
7288
|
+
68: (r) => {
|
|
7289
|
+
r.at += 8;
|
|
7290
|
+
},
|
|
7291
|
+
208: (r) => r.valtype()
|
|
7292
|
+
};
|
|
7293
|
+
SECTIONS = {
|
|
7294
|
+
1: readTypes,
|
|
7295
|
+
2: readImports,
|
|
7296
|
+
3: readFunctions,
|
|
7297
|
+
6: readGlobals,
|
|
7298
|
+
7: readExports,
|
|
7299
|
+
9: readElems
|
|
7300
|
+
};
|
|
7301
|
+
FuncTypes = class {
|
|
7302
|
+
known = /* @__PURE__ */ new WeakMap();
|
|
7303
|
+
pending = [];
|
|
7304
|
+
register(read2, instance, table, tableBase) {
|
|
7305
|
+
this.pending.push(() => {
|
|
7306
|
+
const bytes = read2();
|
|
7307
|
+
if (bytes) this.add(funcTypeInfo(bytes), instance, table, tableBase);
|
|
7308
|
+
});
|
|
7309
|
+
}
|
|
7310
|
+
add(info, instance, table, tableBase) {
|
|
7311
|
+
const sig = (func) => info.sigs[info.funcs[func] ?? -1];
|
|
7312
|
+
for (const [name, func] of Object.entries(info.exports)) {
|
|
7313
|
+
const fn = instance.exports[name];
|
|
7314
|
+
const type = sig(func);
|
|
7315
|
+
if (typeof fn === "function" && type) this.known.set(fn, type);
|
|
7316
|
+
}
|
|
7317
|
+
if (!table) return;
|
|
7318
|
+
for (const seg of info.elems) {
|
|
7319
|
+
const start2 = seg.offset + (seg.tableBase ? tableBase : 0);
|
|
7320
|
+
seg.funcs.forEach((func, i) => {
|
|
7321
|
+
const type = sig(func);
|
|
7322
|
+
const fn = start2 + i < table.length ? table.get(start2 + i) : null;
|
|
7323
|
+
if (fn && type) this.known.set(fn, type);
|
|
7324
|
+
});
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
set(fn, sig) {
|
|
7328
|
+
this.known.set(fn, sig);
|
|
7329
|
+
}
|
|
7330
|
+
of(fn) {
|
|
7331
|
+
const known = this.known.get(fn);
|
|
7332
|
+
if (known || this.pending.length === 0) return known;
|
|
7333
|
+
const pending = this.pending;
|
|
7334
|
+
this.pending = [];
|
|
7335
|
+
for (const run of pending) run();
|
|
7336
|
+
return this.known.get(fn);
|
|
7337
|
+
}
|
|
7338
|
+
};
|
|
7339
|
+
}
|
|
7340
|
+
});
|
|
7341
|
+
|
|
7059
7342
|
// src/process/wasi/wasix-linker.ts
|
|
7060
7343
|
function expandOrigin(entry, dir) {
|
|
7061
7344
|
return entry.replace(/\$(?:ORIGIN\b|\{ORIGIN\})/g, dir);
|
|
@@ -7074,13 +7357,14 @@ function call(instance, name) {
|
|
|
7074
7357
|
const fn = instance.exports[name];
|
|
7075
7358
|
if (typeof fn === "function") fn();
|
|
7076
7359
|
}
|
|
7077
|
-
var
|
|
7360
|
+
var TABLE_BASE2, PAGE2, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
|
|
7078
7361
|
var init_wasix_linker = __esm({
|
|
7079
7362
|
"src/process/wasi/wasix-linker.ts"() {
|
|
7080
7363
|
"use strict";
|
|
7081
7364
|
init_dylink();
|
|
7082
7365
|
init_wasi_files();
|
|
7083
|
-
|
|
7366
|
+
init_wasm_functypes();
|
|
7367
|
+
TABLE_BASE2 = 1;
|
|
7084
7368
|
PAGE2 = 65536;
|
|
7085
7369
|
STACK_SIZE = 8 * 1024 * 1024;
|
|
7086
7370
|
LIBRARY_DIRS = ["/lib", "/usr/lib", "/usr/local/lib"];
|
|
@@ -7101,6 +7385,8 @@ var init_wasix_linker = __esm({
|
|
|
7101
7385
|
slots = /* @__PURE__ */ new Map();
|
|
7102
7386
|
nextHandle = 1;
|
|
7103
7387
|
publisher;
|
|
7388
|
+
closures;
|
|
7389
|
+
types = new FuncTypes();
|
|
7104
7390
|
memory;
|
|
7105
7391
|
host;
|
|
7106
7392
|
constructor(memory, mainInfo, host, thread = false) {
|
|
@@ -7112,7 +7398,7 @@ var init_wasix_linker = __esm({
|
|
|
7112
7398
|
if (!thread) growTo(memory, this.stackHigh);
|
|
7113
7399
|
this.table = new WebAssembly.Table({
|
|
7114
7400
|
element: "anyfunc",
|
|
7115
|
-
initial:
|
|
7401
|
+
initial: TABLE_BASE2 + mainInfo.tableSize
|
|
7116
7402
|
});
|
|
7117
7403
|
this.stackPointer = new WebAssembly.Global(
|
|
7118
7404
|
{ value: "i32", mutable: true },
|
|
@@ -7132,7 +7418,7 @@ var init_wasix_linker = __esm({
|
|
|
7132
7418
|
__indirect_function_table: this.table,
|
|
7133
7419
|
__stack_pointer: this.stackPointer,
|
|
7134
7420
|
__memory_base: i32(this.memoryBase),
|
|
7135
|
-
__table_base: i32(
|
|
7421
|
+
__table_base: i32(TABLE_BASE2),
|
|
7136
7422
|
__c_longjmp: this.cLongjmp,
|
|
7137
7423
|
__cpp_exception: this.cppException
|
|
7138
7424
|
};
|
|
@@ -7184,7 +7470,22 @@ var init_wasix_linker = __esm({
|
|
|
7184
7470
|
for (const [path, linked] of this.byPath) out[path] = linked.module;
|
|
7185
7471
|
return out;
|
|
7186
7472
|
}
|
|
7473
|
+
allocateClosure() {
|
|
7474
|
+
const index2 = this.closures.allocate(
|
|
7475
|
+
this.table.length
|
|
7476
|
+
);
|
|
7477
|
+
growTable(this.table, index2 + 1);
|
|
7478
|
+
return index2;
|
|
7479
|
+
}
|
|
7480
|
+
freeClosure(index2) {
|
|
7481
|
+
this.closures?.free(index2);
|
|
7482
|
+
this.table.set(index2, null);
|
|
7483
|
+
}
|
|
7187
7484
|
replay(record) {
|
|
7485
|
+
if (record.kind === "closure") {
|
|
7486
|
+
growTable(this.table, record.index + 1);
|
|
7487
|
+
return;
|
|
7488
|
+
}
|
|
7188
7489
|
if (record.kind === "load") {
|
|
7189
7490
|
if (this.modules.has(record.handle)) return;
|
|
7190
7491
|
this.instantiate(record.path, this.moduleAt(record.path), record, false);
|
|
@@ -7299,6 +7600,7 @@ var init_wasix_linker = __esm({
|
|
|
7299
7600
|
"GOT.func": gotFunc
|
|
7300
7601
|
};
|
|
7301
7602
|
linked.instance = new WebAssembly.Instance(module, imports);
|
|
7603
|
+
this.types.register(() => this.host.read(path), linked.instance, this.table, at.tableBase);
|
|
7302
7604
|
this.modules.set(at.handle, linked);
|
|
7303
7605
|
this.byPath.set(path, linked);
|
|
7304
7606
|
for (const resolve of pending) resolve();
|
|
@@ -7676,9 +7978,11 @@ var init_wasix_host = __esm({
|
|
|
7676
7978
|
init_wasi_files();
|
|
7677
7979
|
init_wasi_host();
|
|
7678
7980
|
init_wasi_threads();
|
|
7981
|
+
init_wasix_ffi();
|
|
7679
7982
|
init_wasix_linker();
|
|
7680
7983
|
init_wasix_process();
|
|
7681
7984
|
init_wasix_sockets();
|
|
7985
|
+
init_wasm_functypes();
|
|
7682
7986
|
FDFLAGSEXT_CLOEXEC = 1;
|
|
7683
7987
|
SPAWN_OP_SIZE = 56;
|
|
7684
7988
|
SPAWN_OPS = ["close", "dup2", "open", "chdir", "fchdir"];
|
|
@@ -7690,6 +7994,8 @@ var init_wasix_host = __esm({
|
|
|
7690
7994
|
process;
|
|
7691
7995
|
threads;
|
|
7692
7996
|
linker;
|
|
7997
|
+
types = new FuncTypes();
|
|
7998
|
+
table;
|
|
7693
7999
|
signals;
|
|
7694
8000
|
host;
|
|
7695
8001
|
driver;
|
|
@@ -7771,6 +8077,18 @@ var init_wasix_host = __esm({
|
|
|
7771
8077
|
...this.processImports(),
|
|
7772
8078
|
...this.threadImports(),
|
|
7773
8079
|
...this.dlImports(),
|
|
8080
|
+
closure_allocate: (out) => {
|
|
8081
|
+
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
8082
|
+
this.mem.view().setUint32(out, this.linker.allocateClosure(), true);
|
|
8083
|
+
},
|
|
8084
|
+
closure_free: (index2) => {
|
|
8085
|
+
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
8086
|
+
this.linker.freeClosure(index2);
|
|
8087
|
+
},
|
|
8088
|
+
call_dynamic: (...a) => void callDynamic(
|
|
8089
|
+
{ mem: this.mem, table: () => this.table, types: this.types },
|
|
8090
|
+
...a
|
|
8091
|
+
),
|
|
7774
8092
|
...wasixSocketImports(this.host, this.host.imports())
|
|
7775
8093
|
});
|
|
7776
8094
|
}
|
|
@@ -8092,12 +8410,12 @@ function nameFrame(line, module, name) {
|
|
|
8092
8410
|
const found = name(Number(m[4]));
|
|
8093
8411
|
return found === void 0 ? line : `${m[1]}${found} (${m[2]})`;
|
|
8094
8412
|
}
|
|
8095
|
-
function sidecarNames(
|
|
8413
|
+
function sidecarNames(read2, path) {
|
|
8096
8414
|
let names;
|
|
8097
8415
|
return (index2) => {
|
|
8098
8416
|
if (!names) {
|
|
8099
8417
|
try {
|
|
8100
|
-
names = parseFunctionNames(
|
|
8418
|
+
names = parseFunctionNames(read2(path));
|
|
8101
8419
|
} catch {
|
|
8102
8420
|
names = /* @__PURE__ */ new Map();
|
|
8103
8421
|
}
|
|
@@ -8267,7 +8585,8 @@ async function instantiate(host, module, memory, threads, {
|
|
|
8267
8585
|
stats,
|
|
8268
8586
|
signals,
|
|
8269
8587
|
program,
|
|
8270
|
-
foreign
|
|
8588
|
+
foreign,
|
|
8589
|
+
path
|
|
8271
8590
|
} = {}) {
|
|
8272
8591
|
const driver = new AsyncifyDriver(host.mem);
|
|
8273
8592
|
const wasixHost = WebAssembly.Module.imports(module).some((i) => i.module === WASIX) ? new WasixHost(host, driver, module) : void 0;
|
|
@@ -8293,7 +8612,10 @@ async function instantiate(host, module, memory, threads, {
|
|
|
8293
8612
|
) : void 0;
|
|
8294
8613
|
if (sync) {
|
|
8295
8614
|
({ preview1, wasix } = sync.guard(preview1, wasix));
|
|
8296
|
-
if (wasixHost)
|
|
8615
|
+
if (wasixHost) {
|
|
8616
|
+
wasixHost.linker = sync.linker;
|
|
8617
|
+
wasixHost.types = sync.linker.types;
|
|
8618
|
+
}
|
|
8297
8619
|
if (threads) {
|
|
8298
8620
|
sync.linker.cache = threads.received;
|
|
8299
8621
|
threads.modules = () => sync.linker.compiled();
|
|
@@ -8324,6 +8646,14 @@ async function instantiate(host, module, memory, threads, {
|
|
|
8324
8646
|
stats?.phase("instantiate");
|
|
8325
8647
|
const exports = instance.exports;
|
|
8326
8648
|
host.mem.bind(memory ?? exports.memory);
|
|
8649
|
+
if (wasixHost) {
|
|
8650
|
+
const table = sync?.linker.table ?? exportedTable(instance);
|
|
8651
|
+
wasixHost.table = table;
|
|
8652
|
+
if (path !== void 0) {
|
|
8653
|
+
const read2 = linkerHost(host, () => ({})).read;
|
|
8654
|
+
wasixHost.types.register(() => read2(path), instance, table, sync ? TABLE_BASE2 : 0);
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8327
8657
|
if (sync) {
|
|
8328
8658
|
sync.linker.bindMain(instance, !thread);
|
|
8329
8659
|
if (thread) sync.catchUp();
|
|
@@ -8331,6 +8661,10 @@ async function instantiate(host, module, memory, threads, {
|
|
|
8331
8661
|
}
|
|
8332
8662
|
return { instance, driver };
|
|
8333
8663
|
}
|
|
8664
|
+
function exportedTable(instance) {
|
|
8665
|
+
const table = instance.exports.__indirect_function_table;
|
|
8666
|
+
return table instanceof WebAssembly.Table ? table : void 0;
|
|
8667
|
+
}
|
|
8334
8668
|
function linkerHost(host, imports) {
|
|
8335
8669
|
return {
|
|
8336
8670
|
read: (path) => {
|
|
@@ -8410,6 +8744,7 @@ async function runWasiProcess(init, port2) {
|
|
|
8410
8744
|
stats,
|
|
8411
8745
|
signals,
|
|
8412
8746
|
foreign: init.program.foreign,
|
|
8747
|
+
path: init.program.path,
|
|
8413
8748
|
...program ? { program } : {}
|
|
8414
8749
|
});
|
|
8415
8750
|
restoreExportedMemory(instance, memory, init);
|
|
@@ -8494,6 +8829,7 @@ async function runWasiThread(init, port2) {
|
|
|
8494
8829
|
const { instance } = await instantiate(host, init.program.module, thread.memory, threads, {
|
|
8495
8830
|
thread: true,
|
|
8496
8831
|
foreign: init.program.foreign,
|
|
8832
|
+
path: init.program.path,
|
|
8497
8833
|
...program ? { program } : {}
|
|
8498
8834
|
});
|
|
8499
8835
|
signals.bind(instance.exports);
|
|
@@ -8573,6 +8909,14 @@ var init_wasi_runtime = __esm({
|
|
|
8573
8909
|
this.call = call2;
|
|
8574
8910
|
this.ids = ids;
|
|
8575
8911
|
linker.publisher = (record) => this.publish(record);
|
|
8912
|
+
linker.closures = {
|
|
8913
|
+
allocate: (floor) => {
|
|
8914
|
+
const index2 = this.call({ op: "dl-closure", floor });
|
|
8915
|
+
this.catchUp();
|
|
8916
|
+
return index2;
|
|
8917
|
+
},
|
|
8918
|
+
free: (index2) => void this.call({ op: "dl-closure-free", index: index2 })
|
|
8919
|
+
};
|
|
8576
8920
|
}
|
|
8577
8921
|
publish(record) {
|
|
8578
8922
|
const since = this.call({ op: "dl-log", append: record, from: this.count });
|
|
@@ -8931,10 +9275,10 @@ async function slots(kernel, o, mine, theirs) {
|
|
|
8931
9275
|
else if (how === "null") stdio.push({ none: true });
|
|
8932
9276
|
else if (typeof how === "number") stdio.push({ fd: how });
|
|
8933
9277
|
else {
|
|
8934
|
-
const [
|
|
8935
|
-
mine[n] = n === 0 ?
|
|
8936
|
-
theirs.push(n === 0 ?
|
|
8937
|
-
stdio.push({ fd: n === 0 ?
|
|
9278
|
+
const [read2, write2] = await kernel.json({ op: "fd-pipe" });
|
|
9279
|
+
mine[n] = n === 0 ? write2 : read2;
|
|
9280
|
+
theirs.push(n === 0 ? read2 : write2);
|
|
9281
|
+
stdio.push({ fd: n === 0 ? read2 : write2 });
|
|
8938
9282
|
}
|
|
8939
9283
|
}
|
|
8940
9284
|
return stdio;
|
|
@@ -9354,8 +9698,8 @@ function checkOpen(abs, o, existing) {
|
|
|
9354
9698
|
if (existing?.isDirectory) throw new JsCallError("EISDIR", abs);
|
|
9355
9699
|
}
|
|
9356
9700
|
function flagsOf(o) {
|
|
9357
|
-
const
|
|
9358
|
-
const access =
|
|
9701
|
+
const write2 = o.write || o.append || o.truncate;
|
|
9702
|
+
const access = write2 ? o.read ? O_RDWR6 : O_WRONLY6 : 0;
|
|
9359
9703
|
return access | (o.append ? O_APPEND3 : 0);
|
|
9360
9704
|
}
|
|
9361
9705
|
function openRequest(abs, o) {
|
|
@@ -9540,14 +9884,14 @@ function syncOps(kernel, shared) {
|
|
|
9540
9884
|
infos.set(fd, got);
|
|
9541
9885
|
return got;
|
|
9542
9886
|
};
|
|
9543
|
-
const
|
|
9887
|
+
const read2 = (fd, max = CHUNK2) => {
|
|
9544
9888
|
index(max, "read");
|
|
9545
9889
|
const emulated = readDevice(info(fd), max, shared.random);
|
|
9546
9890
|
if (emulated) return emulated;
|
|
9547
9891
|
const r = kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
|
|
9548
9892
|
return r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
|
|
9549
9893
|
};
|
|
9550
|
-
const
|
|
9894
|
+
const write2 = (fd, data) => {
|
|
9551
9895
|
const bytes = typeof data === "string" ? encoder2.encode(data) : data;
|
|
9552
9896
|
const i = info(fd);
|
|
9553
9897
|
if (writeDevice(i)) return;
|
|
@@ -9594,8 +9938,8 @@ function syncOps(kernel, shared) {
|
|
|
9594
9938
|
return handle.file;
|
|
9595
9939
|
};
|
|
9596
9940
|
return {
|
|
9597
|
-
read,
|
|
9598
|
-
write,
|
|
9941
|
+
read: read2,
|
|
9942
|
+
write: write2,
|
|
9599
9943
|
close(fd) {
|
|
9600
9944
|
handles.get(fd)?.();
|
|
9601
9945
|
handles.delete(fd);
|
|
@@ -10029,7 +10373,7 @@ function createContext(o) {
|
|
|
10029
10373
|
infos.set(fd, got);
|
|
10030
10374
|
return got;
|
|
10031
10375
|
};
|
|
10032
|
-
const
|
|
10376
|
+
const read2 = async (fd, max = CHUNK2, signal) => {
|
|
10033
10377
|
index(max, "read");
|
|
10034
10378
|
const emulated = readDevice(await info(fd), max, random);
|
|
10035
10379
|
if (emulated) return emulated;
|
|
@@ -10049,7 +10393,7 @@ function createContext(o) {
|
|
|
10049
10393
|
}
|
|
10050
10394
|
}
|
|
10051
10395
|
};
|
|
10052
|
-
const
|
|
10396
|
+
const write2 = (fd, data) => {
|
|
10053
10397
|
const bytes = typeof data === "string" ? encoder3.encode(data) : data;
|
|
10054
10398
|
let settle;
|
|
10055
10399
|
const settled = new Promise((resolve2) => settle = resolve2);
|
|
@@ -10063,7 +10407,7 @@ function createContext(o) {
|
|
|
10063
10407
|
}
|
|
10064
10408
|
})();
|
|
10065
10409
|
};
|
|
10066
|
-
const writable2 = (fd) => new WritableStream({ write: (chunk) =>
|
|
10410
|
+
const writable2 = (fd) => new WritableStream({ write: (chunk) => write2(fd, chunk) });
|
|
10067
10411
|
const statOf = async (op, path) => {
|
|
10068
10412
|
const abs = resolve(path);
|
|
10069
10413
|
await kernel.call({ op: "fd-path-flush", path: abs });
|
|
@@ -10099,7 +10443,7 @@ function createContext(o) {
|
|
|
10099
10443
|
handles
|
|
10100
10444
|
});
|
|
10101
10445
|
const terminal = ttyOps(kernel);
|
|
10102
|
-
const io = { read, send: writeAll, close: (fd) => ctx.close(fd) };
|
|
10446
|
+
const io = { read: read2, send: writeAll, close: (fd) => ctx.close(fd) };
|
|
10103
10447
|
const children = childOps(kernel, io, { env: o.env, cwd: o.cwd, signal: signalNumber });
|
|
10104
10448
|
const strays = o.strays ?? { exception: /* @__PURE__ */ new Set(), rejection: /* @__PURE__ */ new Set() };
|
|
10105
10449
|
const ctx = {
|
|
@@ -10113,7 +10457,7 @@ function createContext(o) {
|
|
|
10113
10457
|
stdin: new ReadableStream(
|
|
10114
10458
|
{
|
|
10115
10459
|
async pull(controller) {
|
|
10116
|
-
const chunk = await
|
|
10460
|
+
const chunk = await read2(0);
|
|
10117
10461
|
if (chunk.length === 0) controller.close();
|
|
10118
10462
|
else controller.enqueue(chunk);
|
|
10119
10463
|
}
|
|
@@ -10122,8 +10466,8 @@ function createContext(o) {
|
|
|
10122
10466
|
),
|
|
10123
10467
|
stdout: writable2(1),
|
|
10124
10468
|
stderr: writable2(2),
|
|
10125
|
-
read,
|
|
10126
|
-
write,
|
|
10469
|
+
read: read2,
|
|
10470
|
+
write: write2,
|
|
10127
10471
|
async close(fd) {
|
|
10128
10472
|
handles.get(fd)?.();
|
|
10129
10473
|
handles.delete(fd);
|