@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
|
@@ -1647,17 +1647,17 @@ function writeEvents(mem, ptr, events) {
|
|
|
1647
1647
|
}
|
|
1648
1648
|
function classify(fds, subs) {
|
|
1649
1649
|
const events = [];
|
|
1650
|
-
const
|
|
1651
|
-
const
|
|
1650
|
+
const read2 = [];
|
|
1651
|
+
const write2 = [];
|
|
1652
1652
|
for (const s of subs) {
|
|
1653
1653
|
if (s.type === EVENTTYPE.CLOCK) continue;
|
|
1654
1654
|
const e = fds.find(s.fd);
|
|
1655
1655
|
if (!e) events.push({ userdata: s.userdata, error: E.BADF, type: s.type });
|
|
1656
1656
|
else if (e.type !== "kernel")
|
|
1657
1657
|
events.push({ userdata: s.userdata, error: E.SUCCESS, type: s.type });
|
|
1658
|
-
else (s.type === EVENTTYPE.FD_READ ?
|
|
1658
|
+
else (s.type === EVENTTYPE.FD_READ ? read2 : write2).push(s.fd);
|
|
1659
1659
|
}
|
|
1660
|
-
return { events, read, write };
|
|
1660
|
+
return { events, read: read2, write: write2 };
|
|
1661
1661
|
}
|
|
1662
1662
|
function readyEvents(subs, ready) {
|
|
1663
1663
|
return subs.filter(
|
|
@@ -1673,11 +1673,11 @@ function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
|
|
|
1673
1673
|
if (nsubs === 0) return E.INVAL;
|
|
1674
1674
|
const { mem, kernel } = deps;
|
|
1675
1675
|
const subs = readSubscriptions(mem, inPtr, nsubs, deps.now);
|
|
1676
|
-
const { events, read, write } = classify(deps.fds, subs);
|
|
1676
|
+
const { events, read: read2, write: write2 } = classify(deps.fds, subs);
|
|
1677
1677
|
let interrupted = false;
|
|
1678
1678
|
const earliest = subs.reduce((min, s) => Math.min(min, s.deadline), Infinity);
|
|
1679
1679
|
const expired = () => performance.now() + CLOCK_SLACK_MS >= earliest;
|
|
1680
|
-
if (
|
|
1680
|
+
if (read2.length > 0 || write2.length > 0 || events.length === 0) {
|
|
1681
1681
|
do {
|
|
1682
1682
|
let timeoutMs = -1;
|
|
1683
1683
|
if (events.length > 0) timeoutMs = 0;
|
|
@@ -1685,7 +1685,7 @@ function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
|
|
|
1685
1685
|
timeoutMs = Math.max(0, Math.ceil(earliest - performance.now()));
|
|
1686
1686
|
let ready;
|
|
1687
1687
|
try {
|
|
1688
|
-
ready = kernel.call({ op: "fd-select", read, write, timeoutMs });
|
|
1688
|
+
ready = kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
|
|
1689
1689
|
} catch (e) {
|
|
1690
1690
|
if (!deps.interruptWakes || e.code !== "EINTR") throw e;
|
|
1691
1691
|
interrupted = true;
|
|
@@ -2798,10 +2798,10 @@ function processes(host, call2, inThread) {
|
|
|
2798
2798
|
const slot = (n, how, mine, theirs) => {
|
|
2799
2799
|
if (how === "inherit") return { fd: n };
|
|
2800
2800
|
if (how === "null") return { none: true };
|
|
2801
|
-
const [
|
|
2802
|
-
mine[n] = n === 0 ?
|
|
2803
|
-
theirs.push(n === 0 ?
|
|
2804
|
-
return { fd: n === 0 ?
|
|
2801
|
+
const [read2, write2] = call2({ op: "fd-pipe" });
|
|
2802
|
+
mine[n] = n === 0 ? write2 : read2;
|
|
2803
|
+
theirs.push(n === 0 ? read2 : write2);
|
|
2804
|
+
return { fd: n === 0 ? read2 : write2 };
|
|
2805
2805
|
};
|
|
2806
2806
|
return {
|
|
2807
2807
|
spawn(o) {
|
|
@@ -3396,10 +3396,10 @@ async function slots(kernel, o, mine, theirs) {
|
|
|
3396
3396
|
else if (how === "null") stdio.push({ none: true });
|
|
3397
3397
|
else if (typeof how === "number") stdio.push({ fd: how });
|
|
3398
3398
|
else {
|
|
3399
|
-
const [
|
|
3400
|
-
mine[n] = n === 0 ?
|
|
3401
|
-
theirs.push(n === 0 ?
|
|
3402
|
-
stdio.push({ fd: n === 0 ?
|
|
3399
|
+
const [read2, write2] = await kernel.json({ op: "fd-pipe" });
|
|
3400
|
+
mine[n] = n === 0 ? write2 : read2;
|
|
3401
|
+
theirs.push(n === 0 ? read2 : write2);
|
|
3402
|
+
stdio.push({ fd: n === 0 ? read2 : write2 });
|
|
3403
3403
|
}
|
|
3404
3404
|
}
|
|
3405
3405
|
return stdio;
|
|
@@ -3819,8 +3819,8 @@ function checkOpen(abs, o, existing) {
|
|
|
3819
3819
|
if (existing?.isDirectory) throw new JsCallError("EISDIR", abs);
|
|
3820
3820
|
}
|
|
3821
3821
|
function flagsOf(o) {
|
|
3822
|
-
const
|
|
3823
|
-
const access =
|
|
3822
|
+
const write2 = o.write || o.append || o.truncate;
|
|
3823
|
+
const access = write2 ? o.read ? O_RDWR3 : O_WRONLY3 : 0;
|
|
3824
3824
|
return access | (o.append ? O_APPEND3 : 0);
|
|
3825
3825
|
}
|
|
3826
3826
|
function openRequest(abs, o) {
|
|
@@ -4191,14 +4191,14 @@ function syncOps(kernel, shared) {
|
|
|
4191
4191
|
infos.set(fd, got);
|
|
4192
4192
|
return got;
|
|
4193
4193
|
};
|
|
4194
|
-
const
|
|
4194
|
+
const read2 = (fd, max = CHUNK2) => {
|
|
4195
4195
|
index(max, "read");
|
|
4196
4196
|
const emulated = readDevice(info(fd), max, shared.random);
|
|
4197
4197
|
if (emulated) return emulated;
|
|
4198
4198
|
const r = kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
|
|
4199
4199
|
return r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
|
|
4200
4200
|
};
|
|
4201
|
-
const
|
|
4201
|
+
const write2 = (fd, data) => {
|
|
4202
4202
|
const bytes = typeof data === "string" ? encoder2.encode(data) : data;
|
|
4203
4203
|
const i = info(fd);
|
|
4204
4204
|
if (writeDevice(i)) return;
|
|
@@ -4245,8 +4245,8 @@ function syncOps(kernel, shared) {
|
|
|
4245
4245
|
return handle.file;
|
|
4246
4246
|
};
|
|
4247
4247
|
return {
|
|
4248
|
-
read,
|
|
4249
|
-
write,
|
|
4248
|
+
read: read2,
|
|
4249
|
+
write: write2,
|
|
4250
4250
|
close(fd) {
|
|
4251
4251
|
handles.get(fd)?.();
|
|
4252
4252
|
handles.delete(fd);
|
|
@@ -4680,7 +4680,7 @@ function createContext(o) {
|
|
|
4680
4680
|
infos.set(fd, got);
|
|
4681
4681
|
return got;
|
|
4682
4682
|
};
|
|
4683
|
-
const
|
|
4683
|
+
const read2 = async (fd, max = CHUNK2, signal) => {
|
|
4684
4684
|
index(max, "read");
|
|
4685
4685
|
const emulated = readDevice(await info(fd), max, random);
|
|
4686
4686
|
if (emulated) return emulated;
|
|
@@ -4700,7 +4700,7 @@ function createContext(o) {
|
|
|
4700
4700
|
}
|
|
4701
4701
|
}
|
|
4702
4702
|
};
|
|
4703
|
-
const
|
|
4703
|
+
const write2 = (fd, data) => {
|
|
4704
4704
|
const bytes = typeof data === "string" ? encoder3.encode(data) : data;
|
|
4705
4705
|
let settle;
|
|
4706
4706
|
const settled = new Promise((resolve2) => settle = resolve2);
|
|
@@ -4714,7 +4714,7 @@ function createContext(o) {
|
|
|
4714
4714
|
}
|
|
4715
4715
|
})();
|
|
4716
4716
|
};
|
|
4717
|
-
const writable2 = (fd) => new WritableStream({ write: (chunk) =>
|
|
4717
|
+
const writable2 = (fd) => new WritableStream({ write: (chunk) => write2(fd, chunk) });
|
|
4718
4718
|
const statOf = async (op, path) => {
|
|
4719
4719
|
const abs = resolve(path);
|
|
4720
4720
|
await kernel.call({ op: "fd-path-flush", path: abs });
|
|
@@ -4750,7 +4750,7 @@ function createContext(o) {
|
|
|
4750
4750
|
handles
|
|
4751
4751
|
});
|
|
4752
4752
|
const terminal = ttyOps(kernel);
|
|
4753
|
-
const io = { read, send: writeAll, close: (fd) => ctx.close(fd) };
|
|
4753
|
+
const io = { read: read2, send: writeAll, close: (fd) => ctx.close(fd) };
|
|
4754
4754
|
const children = childOps(kernel, io, { env: o.env, cwd: o.cwd, signal: signalNumber });
|
|
4755
4755
|
const strays = o.strays ?? { exception: /* @__PURE__ */ new Set(), rejection: /* @__PURE__ */ new Set() };
|
|
4756
4756
|
const ctx = {
|
|
@@ -4764,7 +4764,7 @@ function createContext(o) {
|
|
|
4764
4764
|
stdin: new ReadableStream(
|
|
4765
4765
|
{
|
|
4766
4766
|
async pull(controller) {
|
|
4767
|
-
const chunk = await
|
|
4767
|
+
const chunk = await read2(0);
|
|
4768
4768
|
if (chunk.length === 0) controller.close();
|
|
4769
4769
|
else controller.enqueue(chunk);
|
|
4770
4770
|
}
|
|
@@ -4773,8 +4773,8 @@ function createContext(o) {
|
|
|
4773
4773
|
),
|
|
4774
4774
|
stdout: writable2(1),
|
|
4775
4775
|
stderr: writable2(2),
|
|
4776
|
-
read,
|
|
4777
|
-
write,
|
|
4776
|
+
read: read2,
|
|
4777
|
+
write: write2,
|
|
4778
4778
|
async close(fd) {
|
|
4779
4779
|
handles.get(fd)?.();
|
|
4780
4780
|
handles.delete(fd);
|
|
@@ -6221,12 +6221,12 @@ var init_kernel_streams = __esm({
|
|
|
6221
6221
|
usePipes(pipefs) {
|
|
6222
6222
|
const createPipe = pipefs.createPipe.bind(pipefs);
|
|
6223
6223
|
pipefs.createPipe = () => {
|
|
6224
|
-
const [
|
|
6224
|
+
const [read2, write2] = this.call(() => this.sys.pipe());
|
|
6225
6225
|
let fds;
|
|
6226
6226
|
try {
|
|
6227
6227
|
fds = createPipe();
|
|
6228
6228
|
} catch (e) {
|
|
6229
|
-
for (const kfd of [
|
|
6229
|
+
for (const kfd of [read2, write2]) {
|
|
6230
6230
|
try {
|
|
6231
6231
|
this.sys.close(kfd);
|
|
6232
6232
|
} catch {
|
|
@@ -6234,8 +6234,8 @@ var init_kernel_streams = __esm({
|
|
|
6234
6234
|
}
|
|
6235
6235
|
throw e;
|
|
6236
6236
|
}
|
|
6237
|
-
this.attach(this.Fs.getStream(fds.readable_fd),
|
|
6238
|
-
this.attach(this.Fs.getStream(fds.writable_fd),
|
|
6237
|
+
this.attach(this.Fs.getStream(fds.readable_fd), read2, false);
|
|
6238
|
+
this.attach(this.Fs.getStream(fds.writable_fd), write2, false);
|
|
6239
6239
|
return fds;
|
|
6240
6240
|
};
|
|
6241
6241
|
}
|
|
@@ -6624,12 +6624,12 @@ function readInto(sys, kfd, target, at) {
|
|
|
6624
6624
|
}
|
|
6625
6625
|
return done;
|
|
6626
6626
|
}
|
|
6627
|
-
function positioned(original,
|
|
6627
|
+
function positioned(original, write2, deps) {
|
|
6628
6628
|
return (fd, iov, iovcnt, ...rest2) => {
|
|
6629
6629
|
const stream = deps.fs()?.getStream(Number(fd));
|
|
6630
6630
|
const memory = deps.memory();
|
|
6631
6631
|
const kfd = stream?.sliccKernelFile ? stream.sliccKernelFd : void 0;
|
|
6632
|
-
if (kfd === void 0 || !memory || !(
|
|
6632
|
+
if (kfd === void 0 || !memory || !(write2 ? deps.sys.pwrite : deps.sys.pread)) {
|
|
6633
6633
|
return original(fd, iov, iovcnt, ...rest2);
|
|
6634
6634
|
}
|
|
6635
6635
|
const at = offsetOf(rest2);
|
|
@@ -6641,7 +6641,7 @@ function positioned(original, write, deps) {
|
|
|
6641
6641
|
const ptr = view.getUint32(Number(iov) + i * 8, true);
|
|
6642
6642
|
const len = view.getUint32(Number(iov) + i * 8 + 4, true);
|
|
6643
6643
|
const part = new Uint8Array(memory.buffer, ptr, len);
|
|
6644
|
-
const moved =
|
|
6644
|
+
const moved = write2 ? deps.sys.pwrite?.(kfd, part.slice(), at + done) ?? 0 : readInto(deps.sys, kfd, part, at + done);
|
|
6645
6645
|
done += moved;
|
|
6646
6646
|
if (moved < len) break;
|
|
6647
6647
|
}
|
|
@@ -6654,13 +6654,13 @@ function positioned(original, write, deps) {
|
|
|
6654
6654
|
}
|
|
6655
6655
|
function positionalIo(imports, deps) {
|
|
6656
6656
|
for (const namespace of namespaces(imports)) {
|
|
6657
|
-
for (const [name,
|
|
6657
|
+
for (const [name, write2] of [
|
|
6658
6658
|
["fd_pread", false],
|
|
6659
6659
|
["fd_pwrite", true]
|
|
6660
6660
|
]) {
|
|
6661
6661
|
const key = keyOf(namespace, name, deps.glue);
|
|
6662
6662
|
if (key !== void 0) {
|
|
6663
|
-
namespace[key] = positioned(namespace[key],
|
|
6663
|
+
namespace[key] = positioned(namespace[key], write2, deps);
|
|
6664
6664
|
}
|
|
6665
6665
|
}
|
|
6666
6666
|
}
|
|
@@ -6788,10 +6788,10 @@ function useZeroDevices(Fs) {
|
|
|
6788
6788
|
}
|
|
6789
6789
|
]
|
|
6790
6790
|
];
|
|
6791
|
-
for (const [path, minor,
|
|
6791
|
+
for (const [path, minor, write2] of devices) {
|
|
6792
6792
|
if (analyzePath.call(Fs, path).exists) continue;
|
|
6793
6793
|
const dev = makedev.call(Fs, 1, minor);
|
|
6794
|
-
registerDevice.call(Fs, dev, { read: zeros, write, llseek: () => 0 });
|
|
6794
|
+
registerDevice.call(Fs, dev, { read: zeros, write: write2, llseek: () => 0 });
|
|
6795
6795
|
mkdev.call(Fs, path, CHAR_DEVICE, dev);
|
|
6796
6796
|
}
|
|
6797
6797
|
}
|
|
@@ -7187,38 +7187,38 @@ function drain(Fs, stream) {
|
|
|
7187
7187
|
}
|
|
7188
7188
|
return out;
|
|
7189
7189
|
}
|
|
7190
|
-
function kernelSelect(Fs, transport,
|
|
7190
|
+
function kernelSelect(Fs, transport, read2, write2, timeoutMs) {
|
|
7191
7191
|
const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
|
|
7192
|
-
const kr =
|
|
7193
|
-
const kw =
|
|
7192
|
+
const kr = read2.map(kernel);
|
|
7193
|
+
const kw = write2.map(kernel);
|
|
7194
7194
|
const r = transport.call({ op: "fd-select", read: kr, write: kw, timeoutMs }, Infinity, "select");
|
|
7195
7195
|
if (!r.ok) return -wasiErrno(r.errno);
|
|
7196
7196
|
const got = r.kind === "json" ? r.json : { read: [], write: [] };
|
|
7197
7197
|
return {
|
|
7198
|
-
read:
|
|
7199
|
-
write:
|
|
7198
|
+
read: read2.filter((_, i) => got.read.includes(kr[i])),
|
|
7199
|
+
write: write2.filter((_, i) => got.write.includes(kw[i]))
|
|
7200
7200
|
};
|
|
7201
7201
|
}
|
|
7202
|
-
function ownReady(Fs,
|
|
7202
|
+
function ownReady(Fs, read2, write2) {
|
|
7203
7203
|
const flags = (fd) => {
|
|
7204
7204
|
const stream = Fs.getStream(fd);
|
|
7205
7205
|
if (!stream) return POLLNVAL;
|
|
7206
7206
|
return stream.stream_ops.poll ? stream.stream_ops.poll(stream) : POLLIN2 | POLLOUT2;
|
|
7207
7207
|
};
|
|
7208
7208
|
return {
|
|
7209
|
-
read:
|
|
7210
|
-
write:
|
|
7209
|
+
read: read2.filter((fd) => flags(fd) & (POLLIN2 | POLLHUP2 | POLLERR2 | POLLNVAL)),
|
|
7210
|
+
write: write2.filter((fd) => flags(fd) & (POLLOUT2 | POLLERR2 | POLLNVAL))
|
|
7211
7211
|
};
|
|
7212
7212
|
}
|
|
7213
|
-
function anySelect(Fs, transport,
|
|
7213
|
+
function anySelect(Fs, transport, read2, write2, timeoutMs) {
|
|
7214
7214
|
const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
|
|
7215
7215
|
const own = (fd) => kernel(fd) === void 0;
|
|
7216
|
-
if (![...
|
|
7216
|
+
if (![...read2, ...write2].some(own)) return kernelSelect(Fs, transport, read2, write2, timeoutMs);
|
|
7217
7217
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
7218
|
-
const kernelRead =
|
|
7219
|
-
const kernelWrite =
|
|
7218
|
+
const kernelRead = read2.filter((fd) => !own(fd));
|
|
7219
|
+
const kernelWrite = write2.filter((fd) => !own(fd));
|
|
7220
7220
|
for (; ; ) {
|
|
7221
|
-
const local = ownReady(Fs,
|
|
7221
|
+
const local = ownReady(Fs, read2.filter(own), write2.filter(own));
|
|
7222
7222
|
const pending = local.read.length > 0 || local.write.length > 0;
|
|
7223
7223
|
const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
|
|
7224
7224
|
const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
|
|
@@ -7325,7 +7325,7 @@ function createProcessKernel(deps) {
|
|
|
7325
7325
|
if (!r.ok) return -wasiErrno(r.errno);
|
|
7326
7326
|
return r.kind === "json" ? r.json : -wasiErrno("EIO");
|
|
7327
7327
|
},
|
|
7328
|
-
select: (
|
|
7328
|
+
select: (read2, write2, timeoutMs) => anySelect(Fs, transport, read2, write2, timeoutMs),
|
|
7329
7329
|
execWait,
|
|
7330
7330
|
execve(file, argv, env, cwd) {
|
|
7331
7331
|
const pid = spawnChild(file, argv, env, cwd, [0, 1, 2], void 0, true);
|
|
@@ -8933,6 +8933,289 @@ var init_wasix_fork = __esm({
|
|
|
8933
8933
|
}
|
|
8934
8934
|
});
|
|
8935
8935
|
|
|
8936
|
+
// src/process/wasi/wasix-ffi.ts
|
|
8937
|
+
function read(view, at, type) {
|
|
8938
|
+
if (type === "i32") return view.getInt32(at, true);
|
|
8939
|
+
if (type === "i64") return view.getBigInt64(at, true);
|
|
8940
|
+
if (type === "f32") return view.getFloat32(at, true);
|
|
8941
|
+
return view.getFloat64(at, true);
|
|
8942
|
+
}
|
|
8943
|
+
function write(view, at, type, value2) {
|
|
8944
|
+
if (type === "i32") view.setInt32(at, Number(value2), true);
|
|
8945
|
+
else if (type === "i64") view.setBigInt64(at, BigInt(value2), true);
|
|
8946
|
+
else if (type === "f32") view.setFloat32(at, Number(value2), true);
|
|
8947
|
+
else view.setFloat64(at, Number(value2), true);
|
|
8948
|
+
}
|
|
8949
|
+
function scalars(types) {
|
|
8950
|
+
if (types.includes("other")) throw new WasiError("EINVAL");
|
|
8951
|
+
return types;
|
|
8952
|
+
}
|
|
8953
|
+
function callDynamic(ctx, id, values, valuesLen, results, resultsLen, strict) {
|
|
8954
|
+
const table = ctx.table();
|
|
8955
|
+
if (!table) throw new WasiError("ENOTSUP");
|
|
8956
|
+
const fn = id < table.length ? table.get(id) : null;
|
|
8957
|
+
const sig = fn ? ctx.types.of(fn) : void 0;
|
|
8958
|
+
if (!fn || !sig) throw new WasiError("EINVAL");
|
|
8959
|
+
const params = scalars(sig.params);
|
|
8960
|
+
const outs = scalars(sig.results);
|
|
8961
|
+
const view = ctx.mem.view();
|
|
8962
|
+
const end = values + valuesLen;
|
|
8963
|
+
let at = values;
|
|
8964
|
+
const args = params.map((type) => {
|
|
8965
|
+
if (at + SIZE2[type] > end) {
|
|
8966
|
+
if (strict) throw new WasiError("EINVAL");
|
|
8967
|
+
return type === "i64" ? 0n : 0;
|
|
8968
|
+
}
|
|
8969
|
+
const v = read(view, at, type);
|
|
8970
|
+
at += SIZE2[type];
|
|
8971
|
+
return v;
|
|
8972
|
+
});
|
|
8973
|
+
if (strict && at !== end) throw new WasiError("EINVAL");
|
|
8974
|
+
const returned = fn(...args);
|
|
8975
|
+
const got = outs.length === 1 ? [returned] : returned ?? [];
|
|
8976
|
+
const after = ctx.mem.view();
|
|
8977
|
+
const stop = results + resultsLen;
|
|
8978
|
+
let out = results;
|
|
8979
|
+
outs.forEach((type, i) => {
|
|
8980
|
+
if (out + SIZE2[type] > stop) {
|
|
8981
|
+
if (strict) throw new WasiError("EINVAL");
|
|
8982
|
+
return;
|
|
8983
|
+
}
|
|
8984
|
+
write(after, out, type, got[i]);
|
|
8985
|
+
out += SIZE2[type];
|
|
8986
|
+
});
|
|
8987
|
+
if (strict && out !== stop) throw new WasiError("EINVAL");
|
|
8988
|
+
}
|
|
8989
|
+
var SIZE2;
|
|
8990
|
+
var init_wasix_ffi = __esm({
|
|
8991
|
+
"src/process/wasi/wasix-ffi.ts"() {
|
|
8992
|
+
"use strict";
|
|
8993
|
+
init_wasi_files();
|
|
8994
|
+
SIZE2 = { i32: 4, i64: 8, f32: 4, f64: 8 };
|
|
8995
|
+
}
|
|
8996
|
+
});
|
|
8997
|
+
|
|
8998
|
+
// src/process/wasi/wasm-functypes.ts
|
|
8999
|
+
function readTypes(r, s) {
|
|
9000
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
9001
|
+
r.byte();
|
|
9002
|
+
const params = [];
|
|
9003
|
+
for (let n = r.u32(); n > 0; n--) params.push(r.valtype());
|
|
9004
|
+
const results = [];
|
|
9005
|
+
for (let n = r.u32(); n > 0; n--) results.push(r.valtype());
|
|
9006
|
+
s.info.sigs.push({ params, results });
|
|
9007
|
+
}
|
|
9008
|
+
}
|
|
9009
|
+
function readImports(r, s) {
|
|
9010
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
9011
|
+
r.name();
|
|
9012
|
+
const field2 = r.name();
|
|
9013
|
+
const kind = r.byte();
|
|
9014
|
+
if (kind === 0) s.info.funcs.push(r.u32());
|
|
9015
|
+
else if (kind === 1) {
|
|
9016
|
+
r.valtype();
|
|
9017
|
+
r.limits();
|
|
9018
|
+
} else if (kind === 2) r.limits();
|
|
9019
|
+
else if (kind === 3) {
|
|
9020
|
+
r.valtype();
|
|
9021
|
+
r.byte();
|
|
9022
|
+
s.globals.push(field2);
|
|
9023
|
+
} else {
|
|
9024
|
+
r.byte();
|
|
9025
|
+
r.u32();
|
|
9026
|
+
}
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
function readFunctions(r, s) {
|
|
9030
|
+
for (let i = r.u32(); i > 0; i--) s.info.funcs.push(r.u32());
|
|
9031
|
+
}
|
|
9032
|
+
function constExpr(r, s) {
|
|
9033
|
+
let value2 = 0;
|
|
9034
|
+
let tableBase = false;
|
|
9035
|
+
let known = true;
|
|
9036
|
+
for (; ; ) {
|
|
9037
|
+
const op = r.byte();
|
|
9038
|
+
if (op === 11) return known ? { value: value2, tableBase } : void 0;
|
|
9039
|
+
if (op === 65) value2 += r.s32();
|
|
9040
|
+
else if (op === 35) {
|
|
9041
|
+
const g = s.globals[r.u32()];
|
|
9042
|
+
if (g === TABLE_BASE) tableBase = true;
|
|
9043
|
+
else if (typeof g === "number") value2 += g;
|
|
9044
|
+
else known = false;
|
|
9045
|
+
} else if (op === 210) {
|
|
9046
|
+
value2 = r.u32();
|
|
9047
|
+
} else if (op in SKIP) {
|
|
9048
|
+
SKIP[op]?.(r);
|
|
9049
|
+
known = false;
|
|
9050
|
+
} else if (op !== 106) {
|
|
9051
|
+
r.at = r.bytes.length;
|
|
9052
|
+
return void 0;
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
9055
|
+
}
|
|
9056
|
+
function readGlobals(r, s) {
|
|
9057
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
9058
|
+
r.valtype();
|
|
9059
|
+
r.byte();
|
|
9060
|
+
const init = constExpr(r, s);
|
|
9061
|
+
s.globals.push(init && !init.tableBase ? init.value : void 0);
|
|
9062
|
+
}
|
|
9063
|
+
}
|
|
9064
|
+
function readExports(r, s) {
|
|
9065
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
9066
|
+
const name = r.name();
|
|
9067
|
+
const kind = r.byte();
|
|
9068
|
+
const index2 = r.u32();
|
|
9069
|
+
if (kind === 0) s.info.exports[name] = index2;
|
|
9070
|
+
}
|
|
9071
|
+
}
|
|
9072
|
+
function readElems(r, s) {
|
|
9073
|
+
for (let i = r.u32(); i > 0; i--) {
|
|
9074
|
+
const flags = r.u32();
|
|
9075
|
+
const active = (flags & 1) === 0;
|
|
9076
|
+
const table = flags & 2 ? active ? r.u32() : 0 : 0;
|
|
9077
|
+
const offset = active ? constExpr(r, s) : void 0;
|
|
9078
|
+
if (flags & 3) r.valtype();
|
|
9079
|
+
const funcs = [];
|
|
9080
|
+
for (let n = r.u32(); n > 0; n--) {
|
|
9081
|
+
if (flags & 4) {
|
|
9082
|
+
const ref = constExpr(r, s);
|
|
9083
|
+
funcs.push(ref ? ref.value : -1);
|
|
9084
|
+
} else funcs.push(r.u32());
|
|
9085
|
+
}
|
|
9086
|
+
if (offset && table === 0) {
|
|
9087
|
+
s.info.elems.push({ offset: offset.value, tableBase: offset.tableBase, funcs });
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9091
|
+
function funcTypeInfo(bytes) {
|
|
9092
|
+
const r = new Reader(bytes);
|
|
9093
|
+
const s = { info: { sigs: [], funcs: [], exports: {}, elems: [] }, globals: [] };
|
|
9094
|
+
while (r.at < bytes.length) {
|
|
9095
|
+
const id = r.byte();
|
|
9096
|
+
const end = r.u32() + r.at;
|
|
9097
|
+
SECTIONS[id]?.(r, s);
|
|
9098
|
+
r.at = end;
|
|
9099
|
+
}
|
|
9100
|
+
return s.info;
|
|
9101
|
+
}
|
|
9102
|
+
var VALTYPES, TABLE_BASE, Reader, SKIP, SECTIONS, FuncTypes;
|
|
9103
|
+
var init_wasm_functypes = __esm({
|
|
9104
|
+
"src/process/wasi/wasm-functypes.ts"() {
|
|
9105
|
+
"use strict";
|
|
9106
|
+
VALTYPES = {
|
|
9107
|
+
127: "i32",
|
|
9108
|
+
126: "i64",
|
|
9109
|
+
125: "f32",
|
|
9110
|
+
124: "f64"
|
|
9111
|
+
};
|
|
9112
|
+
TABLE_BASE = "__table_base";
|
|
9113
|
+
Reader = class {
|
|
9114
|
+
at = 8;
|
|
9115
|
+
bytes;
|
|
9116
|
+
constructor(bytes) {
|
|
9117
|
+
this.bytes = bytes;
|
|
9118
|
+
}
|
|
9119
|
+
byte() {
|
|
9120
|
+
return this.bytes[this.at++] ?? 0;
|
|
9121
|
+
}
|
|
9122
|
+
u32() {
|
|
9123
|
+
let result = 0;
|
|
9124
|
+
let shift = 0;
|
|
9125
|
+
for (; ; ) {
|
|
9126
|
+
const b = this.byte();
|
|
9127
|
+
result |= (b & 127) << shift;
|
|
9128
|
+
if (!(b & 128)) return result >>> 0;
|
|
9129
|
+
shift += 7;
|
|
9130
|
+
}
|
|
9131
|
+
}
|
|
9132
|
+
s32() {
|
|
9133
|
+
let result = 0;
|
|
9134
|
+
let shift = 0;
|
|
9135
|
+
let b;
|
|
9136
|
+
do {
|
|
9137
|
+
b = this.byte();
|
|
9138
|
+
result |= (b & 127) << shift;
|
|
9139
|
+
shift += 7;
|
|
9140
|
+
} while (b & 128);
|
|
9141
|
+
return shift < 32 && b & 64 ? result | -1 << shift : result;
|
|
9142
|
+
}
|
|
9143
|
+
name() {
|
|
9144
|
+
const len = this.u32();
|
|
9145
|
+
const s = new TextDecoder().decode(this.bytes.subarray(this.at, this.at + len));
|
|
9146
|
+
this.at += len;
|
|
9147
|
+
return s;
|
|
9148
|
+
}
|
|
9149
|
+
valtype() {
|
|
9150
|
+
const code2 = this.byte();
|
|
9151
|
+
if (code2 === 99 || code2 === 100) this.s32();
|
|
9152
|
+
return VALTYPES[code2] ?? "other";
|
|
9153
|
+
}
|
|
9154
|
+
limits() {
|
|
9155
|
+
const flags = this.byte();
|
|
9156
|
+
this.u32();
|
|
9157
|
+
if (flags & 1) this.u32();
|
|
9158
|
+
}
|
|
9159
|
+
};
|
|
9160
|
+
SKIP = {
|
|
9161
|
+
66: (r) => r.s32(),
|
|
9162
|
+
67: (r) => {
|
|
9163
|
+
r.at += 4;
|
|
9164
|
+
},
|
|
9165
|
+
68: (r) => {
|
|
9166
|
+
r.at += 8;
|
|
9167
|
+
},
|
|
9168
|
+
208: (r) => r.valtype()
|
|
9169
|
+
};
|
|
9170
|
+
SECTIONS = {
|
|
9171
|
+
1: readTypes,
|
|
9172
|
+
2: readImports,
|
|
9173
|
+
3: readFunctions,
|
|
9174
|
+
6: readGlobals,
|
|
9175
|
+
7: readExports,
|
|
9176
|
+
9: readElems
|
|
9177
|
+
};
|
|
9178
|
+
FuncTypes = class {
|
|
9179
|
+
known = /* @__PURE__ */ new WeakMap();
|
|
9180
|
+
pending = [];
|
|
9181
|
+
register(read2, instance, table, tableBase) {
|
|
9182
|
+
this.pending.push(() => {
|
|
9183
|
+
const bytes = read2();
|
|
9184
|
+
if (bytes) this.add(funcTypeInfo(bytes), instance, table, tableBase);
|
|
9185
|
+
});
|
|
9186
|
+
}
|
|
9187
|
+
add(info, instance, table, tableBase) {
|
|
9188
|
+
const sig = (func) => info.sigs[info.funcs[func] ?? -1];
|
|
9189
|
+
for (const [name, func] of Object.entries(info.exports)) {
|
|
9190
|
+
const fn = instance.exports[name];
|
|
9191
|
+
const type = sig(func);
|
|
9192
|
+
if (typeof fn === "function" && type) this.known.set(fn, type);
|
|
9193
|
+
}
|
|
9194
|
+
if (!table) return;
|
|
9195
|
+
for (const seg of info.elems) {
|
|
9196
|
+
const start2 = seg.offset + (seg.tableBase ? tableBase : 0);
|
|
9197
|
+
seg.funcs.forEach((func, i) => {
|
|
9198
|
+
const type = sig(func);
|
|
9199
|
+
const fn = start2 + i < table.length ? table.get(start2 + i) : null;
|
|
9200
|
+
if (fn && type) this.known.set(fn, type);
|
|
9201
|
+
});
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
set(fn, sig) {
|
|
9205
|
+
this.known.set(fn, sig);
|
|
9206
|
+
}
|
|
9207
|
+
of(fn) {
|
|
9208
|
+
const known = this.known.get(fn);
|
|
9209
|
+
if (known || this.pending.length === 0) return known;
|
|
9210
|
+
const pending = this.pending;
|
|
9211
|
+
this.pending = [];
|
|
9212
|
+
for (const run of pending) run();
|
|
9213
|
+
return this.known.get(fn);
|
|
9214
|
+
}
|
|
9215
|
+
};
|
|
9216
|
+
}
|
|
9217
|
+
});
|
|
9218
|
+
|
|
8936
9219
|
// src/process/wasi/wasix-linker.ts
|
|
8937
9220
|
function expandOrigin(entry, dir) {
|
|
8938
9221
|
return entry.replace(/\$(?:ORIGIN\b|\{ORIGIN\})/g, dir);
|
|
@@ -8951,13 +9234,14 @@ function call(instance, name) {
|
|
|
8951
9234
|
const fn = instance.exports[name];
|
|
8952
9235
|
if (typeof fn === "function") fn();
|
|
8953
9236
|
}
|
|
8954
|
-
var
|
|
9237
|
+
var TABLE_BASE2, PAGE2, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
|
|
8955
9238
|
var init_wasix_linker = __esm({
|
|
8956
9239
|
"src/process/wasi/wasix-linker.ts"() {
|
|
8957
9240
|
"use strict";
|
|
8958
9241
|
init_dylink();
|
|
8959
9242
|
init_wasi_files();
|
|
8960
|
-
|
|
9243
|
+
init_wasm_functypes();
|
|
9244
|
+
TABLE_BASE2 = 1;
|
|
8961
9245
|
PAGE2 = 65536;
|
|
8962
9246
|
STACK_SIZE = 8 * 1024 * 1024;
|
|
8963
9247
|
LIBRARY_DIRS = ["/lib", "/usr/lib", "/usr/local/lib"];
|
|
@@ -8978,6 +9262,8 @@ var init_wasix_linker = __esm({
|
|
|
8978
9262
|
slots = /* @__PURE__ */ new Map();
|
|
8979
9263
|
nextHandle = 1;
|
|
8980
9264
|
publisher;
|
|
9265
|
+
closures;
|
|
9266
|
+
types = new FuncTypes();
|
|
8981
9267
|
memory;
|
|
8982
9268
|
host;
|
|
8983
9269
|
constructor(memory, mainInfo, host, thread = false) {
|
|
@@ -8989,7 +9275,7 @@ var init_wasix_linker = __esm({
|
|
|
8989
9275
|
if (!thread) growTo(memory, this.stackHigh);
|
|
8990
9276
|
this.table = new WebAssembly.Table({
|
|
8991
9277
|
element: "anyfunc",
|
|
8992
|
-
initial:
|
|
9278
|
+
initial: TABLE_BASE2 + mainInfo.tableSize
|
|
8993
9279
|
});
|
|
8994
9280
|
this.stackPointer = new WebAssembly.Global(
|
|
8995
9281
|
{ value: "i32", mutable: true },
|
|
@@ -9009,7 +9295,7 @@ var init_wasix_linker = __esm({
|
|
|
9009
9295
|
__indirect_function_table: this.table,
|
|
9010
9296
|
__stack_pointer: this.stackPointer,
|
|
9011
9297
|
__memory_base: i32(this.memoryBase),
|
|
9012
|
-
__table_base: i32(
|
|
9298
|
+
__table_base: i32(TABLE_BASE2),
|
|
9013
9299
|
__c_longjmp: this.cLongjmp,
|
|
9014
9300
|
__cpp_exception: this.cppException
|
|
9015
9301
|
};
|
|
@@ -9061,7 +9347,22 @@ var init_wasix_linker = __esm({
|
|
|
9061
9347
|
for (const [path, linked] of this.byPath) out[path] = linked.module;
|
|
9062
9348
|
return out;
|
|
9063
9349
|
}
|
|
9350
|
+
allocateClosure() {
|
|
9351
|
+
const index2 = this.closures.allocate(
|
|
9352
|
+
this.table.length
|
|
9353
|
+
);
|
|
9354
|
+
growTable(this.table, index2 + 1);
|
|
9355
|
+
return index2;
|
|
9356
|
+
}
|
|
9357
|
+
freeClosure(index2) {
|
|
9358
|
+
this.closures?.free(index2);
|
|
9359
|
+
this.table.set(index2, null);
|
|
9360
|
+
}
|
|
9064
9361
|
replay(record) {
|
|
9362
|
+
if (record.kind === "closure") {
|
|
9363
|
+
growTable(this.table, record.index + 1);
|
|
9364
|
+
return;
|
|
9365
|
+
}
|
|
9065
9366
|
if (record.kind === "load") {
|
|
9066
9367
|
if (this.modules.has(record.handle)) return;
|
|
9067
9368
|
this.instantiate(record.path, this.moduleAt(record.path), record, false);
|
|
@@ -9176,6 +9477,7 @@ var init_wasix_linker = __esm({
|
|
|
9176
9477
|
"GOT.func": gotFunc
|
|
9177
9478
|
};
|
|
9178
9479
|
linked.instance = new WebAssembly.Instance(module, imports);
|
|
9480
|
+
this.types.register(() => this.host.read(path), linked.instance, this.table, at.tableBase);
|
|
9179
9481
|
this.modules.set(at.handle, linked);
|
|
9180
9482
|
this.byPath.set(path, linked);
|
|
9181
9483
|
for (const resolve of pending) resolve();
|
|
@@ -9553,9 +9855,11 @@ var init_wasix_host = __esm({
|
|
|
9553
9855
|
init_wasi_files();
|
|
9554
9856
|
init_wasi_host();
|
|
9555
9857
|
init_wasi_threads();
|
|
9858
|
+
init_wasix_ffi();
|
|
9556
9859
|
init_wasix_linker();
|
|
9557
9860
|
init_wasix_process();
|
|
9558
9861
|
init_wasix_sockets();
|
|
9862
|
+
init_wasm_functypes();
|
|
9559
9863
|
FDFLAGSEXT_CLOEXEC = 1;
|
|
9560
9864
|
SPAWN_OP_SIZE = 56;
|
|
9561
9865
|
SPAWN_OPS = ["close", "dup2", "open", "chdir", "fchdir"];
|
|
@@ -9567,6 +9871,8 @@ var init_wasix_host = __esm({
|
|
|
9567
9871
|
process;
|
|
9568
9872
|
threads;
|
|
9569
9873
|
linker;
|
|
9874
|
+
types = new FuncTypes();
|
|
9875
|
+
table;
|
|
9570
9876
|
signals;
|
|
9571
9877
|
host;
|
|
9572
9878
|
driver;
|
|
@@ -9648,6 +9954,18 @@ var init_wasix_host = __esm({
|
|
|
9648
9954
|
...this.processImports(),
|
|
9649
9955
|
...this.threadImports(),
|
|
9650
9956
|
...this.dlImports(),
|
|
9957
|
+
closure_allocate: (out) => {
|
|
9958
|
+
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
9959
|
+
this.mem.view().setUint32(out, this.linker.allocateClosure(), true);
|
|
9960
|
+
},
|
|
9961
|
+
closure_free: (index2) => {
|
|
9962
|
+
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
9963
|
+
this.linker.freeClosure(index2);
|
|
9964
|
+
},
|
|
9965
|
+
call_dynamic: (...a) => void callDynamic(
|
|
9966
|
+
{ mem: this.mem, table: () => this.table, types: this.types },
|
|
9967
|
+
...a
|
|
9968
|
+
),
|
|
9651
9969
|
...wasixSocketImports(this.host, this.host.imports())
|
|
9652
9970
|
});
|
|
9653
9971
|
}
|
|
@@ -9969,12 +10287,12 @@ function nameFrame(line, module, name) {
|
|
|
9969
10287
|
const found = name(Number(m[4]));
|
|
9970
10288
|
return found === void 0 ? line : `${m[1]}${found} (${m[2]})`;
|
|
9971
10289
|
}
|
|
9972
|
-
function sidecarNames(
|
|
10290
|
+
function sidecarNames(read2, path) {
|
|
9973
10291
|
let names;
|
|
9974
10292
|
return (index2) => {
|
|
9975
10293
|
if (!names) {
|
|
9976
10294
|
try {
|
|
9977
|
-
names = parseFunctionNames(
|
|
10295
|
+
names = parseFunctionNames(read2(path));
|
|
9978
10296
|
} catch {
|
|
9979
10297
|
names = /* @__PURE__ */ new Map();
|
|
9980
10298
|
}
|
|
@@ -10144,7 +10462,8 @@ async function instantiate(host, module, memory, threads, {
|
|
|
10144
10462
|
stats,
|
|
10145
10463
|
signals,
|
|
10146
10464
|
program,
|
|
10147
|
-
foreign
|
|
10465
|
+
foreign,
|
|
10466
|
+
path
|
|
10148
10467
|
} = {}) {
|
|
10149
10468
|
const driver = new AsyncifyDriver(host.mem);
|
|
10150
10469
|
const wasixHost = WebAssembly.Module.imports(module).some((i) => i.module === WASIX) ? new WasixHost(host, driver, module) : void 0;
|
|
@@ -10170,7 +10489,10 @@ async function instantiate(host, module, memory, threads, {
|
|
|
10170
10489
|
) : void 0;
|
|
10171
10490
|
if (sync) {
|
|
10172
10491
|
({ preview1, wasix } = sync.guard(preview1, wasix));
|
|
10173
|
-
if (wasixHost)
|
|
10492
|
+
if (wasixHost) {
|
|
10493
|
+
wasixHost.linker = sync.linker;
|
|
10494
|
+
wasixHost.types = sync.linker.types;
|
|
10495
|
+
}
|
|
10174
10496
|
if (threads) {
|
|
10175
10497
|
sync.linker.cache = threads.received;
|
|
10176
10498
|
threads.modules = () => sync.linker.compiled();
|
|
@@ -10201,6 +10523,14 @@ async function instantiate(host, module, memory, threads, {
|
|
|
10201
10523
|
stats?.phase("instantiate");
|
|
10202
10524
|
const exports = instance.exports;
|
|
10203
10525
|
host.mem.bind(memory ?? exports.memory);
|
|
10526
|
+
if (wasixHost) {
|
|
10527
|
+
const table = sync?.linker.table ?? exportedTable(instance);
|
|
10528
|
+
wasixHost.table = table;
|
|
10529
|
+
if (path !== void 0) {
|
|
10530
|
+
const read2 = linkerHost(host, () => ({})).read;
|
|
10531
|
+
wasixHost.types.register(() => read2(path), instance, table, sync ? TABLE_BASE2 : 0);
|
|
10532
|
+
}
|
|
10533
|
+
}
|
|
10204
10534
|
if (sync) {
|
|
10205
10535
|
sync.linker.bindMain(instance, !thread);
|
|
10206
10536
|
if (thread) sync.catchUp();
|
|
@@ -10208,6 +10538,10 @@ async function instantiate(host, module, memory, threads, {
|
|
|
10208
10538
|
}
|
|
10209
10539
|
return { instance, driver };
|
|
10210
10540
|
}
|
|
10541
|
+
function exportedTable(instance) {
|
|
10542
|
+
const table = instance.exports.__indirect_function_table;
|
|
10543
|
+
return table instanceof WebAssembly.Table ? table : void 0;
|
|
10544
|
+
}
|
|
10211
10545
|
function linkerHost(host, imports) {
|
|
10212
10546
|
return {
|
|
10213
10547
|
read: (path) => {
|
|
@@ -10287,6 +10621,7 @@ async function runWasiProcess(init, port3) {
|
|
|
10287
10621
|
stats,
|
|
10288
10622
|
signals,
|
|
10289
10623
|
foreign: init.program.foreign,
|
|
10624
|
+
path: init.program.path,
|
|
10290
10625
|
...program ? { program } : {}
|
|
10291
10626
|
});
|
|
10292
10627
|
restoreExportedMemory(instance, memory, init);
|
|
@@ -10371,6 +10706,7 @@ async function runWasiThread(init, port3) {
|
|
|
10371
10706
|
const { instance } = await instantiate(host, init.program.module, thread.memory, threads, {
|
|
10372
10707
|
thread: true,
|
|
10373
10708
|
foreign: init.program.foreign,
|
|
10709
|
+
path: init.program.path,
|
|
10374
10710
|
...program ? { program } : {}
|
|
10375
10711
|
});
|
|
10376
10712
|
signals.bind(instance.exports);
|
|
@@ -10450,6 +10786,14 @@ var init_wasi_runtime = __esm({
|
|
|
10450
10786
|
this.call = call2;
|
|
10451
10787
|
this.ids = ids;
|
|
10452
10788
|
linker.publisher = (record) => this.publish(record);
|
|
10789
|
+
linker.closures = {
|
|
10790
|
+
allocate: (floor) => {
|
|
10791
|
+
const index2 = this.call({ op: "dl-closure", floor });
|
|
10792
|
+
this.catchUp();
|
|
10793
|
+
return index2;
|
|
10794
|
+
},
|
|
10795
|
+
free: (index2) => void this.call({ op: "dl-closure-free", index: index2 })
|
|
10796
|
+
};
|
|
10453
10797
|
}
|
|
10454
10798
|
publish(record) {
|
|
10455
10799
|
const since = this.call({ op: "dl-log", append: record, from: this.count });
|