@ai-ecoverse/slicc-kernel 1.56.2 → 1.57.1
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 +19 -5
- package/dist/driver-worker.js +1 -0
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +5 -2
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +310 -62
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +1 -0
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +311 -95
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +307 -62
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +311 -95
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
|
@@ -533,10 +533,26 @@ function pathInode(path) {
|
|
|
533
533
|
}
|
|
534
534
|
return h;
|
|
535
535
|
}
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
|
|
536
|
+
function inoKey(st) {
|
|
537
|
+
return "ino" in st && typeof st.ino === "number" ? st.ino % 4294967296 | 0 : 0;
|
|
538
|
+
}
|
|
539
|
+
function pathHash(path) {
|
|
540
|
+
let h = 2166136261;
|
|
541
|
+
for (let i = 0; i < path.length; i++) h = Math.imul(h ^ path.charCodeAt(i), 16777619);
|
|
542
|
+
return h === 0 ? 1 : h;
|
|
543
|
+
}
|
|
544
|
+
function index(map, key, path) {
|
|
545
|
+
const paths = map.get(key) ?? /* @__PURE__ */ new Set();
|
|
546
|
+
paths.add(path);
|
|
547
|
+
map.set(key, paths);
|
|
548
|
+
}
|
|
549
|
+
function cachingBridge(bridge, now = () => performance.now(), shared) {
|
|
550
|
+
const blind = shared !== void 0 && shared.length * 4 < SHARED_IDS_BYTES;
|
|
551
|
+
const cache = new StatCache(blind ? void 0 : shared);
|
|
552
|
+
const { stats, lstats } = cache;
|
|
539
553
|
const cached = (map, path, get) => {
|
|
554
|
+
if (blind) return get();
|
|
555
|
+
cache.fresh();
|
|
540
556
|
let hit = map.get(path);
|
|
541
557
|
if (hit === void 0 || "until" in hit && hit.until <= now()) {
|
|
542
558
|
try {
|
|
@@ -544,22 +560,29 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
544
560
|
} catch (e) {
|
|
545
561
|
hit = { error: e, until: now() + MISS_TTL_MS };
|
|
546
562
|
}
|
|
547
|
-
|
|
563
|
+
cache.put(map, path, hit);
|
|
548
564
|
}
|
|
549
565
|
if ("until" in hit) throw hit.error;
|
|
550
566
|
return hit;
|
|
551
567
|
};
|
|
552
|
-
const invalidate = () =>
|
|
553
|
-
|
|
554
|
-
|
|
568
|
+
const invalidate = () => cache.mutated([]);
|
|
569
|
+
const touched = (path, ino) => cache.changed(path, ino);
|
|
570
|
+
const mutating = (op, ...paths) => {
|
|
571
|
+
try {
|
|
572
|
+
return op();
|
|
573
|
+
} finally {
|
|
574
|
+
cache.mutated(paths);
|
|
575
|
+
}
|
|
555
576
|
};
|
|
556
|
-
const
|
|
577
|
+
const rewriting = (p, op, ...also) => {
|
|
578
|
+
const ino = cache.inoOf(p, () => bridge.stat(p));
|
|
557
579
|
try {
|
|
558
580
|
return op();
|
|
559
581
|
} finally {
|
|
560
|
-
|
|
582
|
+
cache.mutated([p, ...also], ino);
|
|
561
583
|
}
|
|
562
584
|
};
|
|
585
|
+
const entry = (p) => [p, p.slice(0, p.lastIndexOf("/")) || "/"];
|
|
563
586
|
return {
|
|
564
587
|
readFile: (p) => bridge.readFile(p),
|
|
565
588
|
readdir: (p) => bridge.readdir(p),
|
|
@@ -567,9 +590,9 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
567
590
|
const list = bridge.readdirStat(p);
|
|
568
591
|
const base = p === "/" ? "" : p;
|
|
569
592
|
for (const [name2, st] of list) {
|
|
570
|
-
if (!st) continue;
|
|
571
|
-
|
|
572
|
-
if (!st.isSymbolicLink)
|
|
593
|
+
if (!st || blind) continue;
|
|
594
|
+
cache.put(lstats, `${base}/${name2}`, st);
|
|
595
|
+
if (!st.isSymbolicLink) cache.put(stats, `${base}/${name2}`, st);
|
|
573
596
|
}
|
|
574
597
|
return list;
|
|
575
598
|
},
|
|
@@ -584,40 +607,41 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
584
607
|
return false;
|
|
585
608
|
}
|
|
586
609
|
},
|
|
587
|
-
writeFile: (p, bytes, open) =>
|
|
588
|
-
mkdir: (p) => mutating(() => bridge.mkdir(p)),
|
|
610
|
+
writeFile: (p, bytes, open) => rewriting(p, () => bridge.writeFile(p, bytes, open), ...entry(p).slice(1)),
|
|
611
|
+
mkdir: (p) => mutating(() => bridge.mkdir(p), ...entry(p)),
|
|
589
612
|
rm: (p) => mutating(() => bridge.rm(p)),
|
|
590
613
|
rename: (from, to) => mutating(() => bridge.rename(from, to)),
|
|
591
614
|
unlink: (p) => mutating(() => bridge.unlink(p)),
|
|
592
615
|
rmdir: (p) => mutating(() => bridge.rmdir(p)),
|
|
593
|
-
symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
|
|
594
|
-
chmod: (p, mode) =>
|
|
595
|
-
utimes: (p, a, m) =>
|
|
596
|
-
lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m)),
|
|
616
|
+
symlink: (target, link) => mutating(() => bridge.symlink(target, link), ...entry(link)),
|
|
617
|
+
chmod: (p, mode) => rewriting(p, () => bridge.chmod(p, mode)),
|
|
618
|
+
utimes: (p, a, m) => rewriting(p, () => bridge.utimes(p, a, m)),
|
|
619
|
+
lutimes: (p, a, m) => mutating(() => bridge.lutimes(p, a, m), p),
|
|
597
620
|
...bridge.hold ? { hold: bridge.hold.bind(bridge) } : {},
|
|
598
621
|
...bridge.kept ? { kept: bridge.kept.bind(bridge) } : {},
|
|
599
|
-
...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle,
|
|
600
|
-
...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p)) } : {},
|
|
622
|
+
...bridge.pinned ? { pinned: (handle) => pinnedIo(bridge, handle, rewriting) } : {},
|
|
623
|
+
...bridge.create ? { create: (p) => mutating(() => bridge.create?.(p), ...entry(p)) } : {},
|
|
601
624
|
...bridge.pread && bridge.pwrite && bridge.truncate ? {
|
|
602
625
|
pread: bridge.pread.bind(bridge),
|
|
603
|
-
pwrite: (p, at, bytes, transfer) =>
|
|
604
|
-
truncate: (p, size) =>
|
|
626
|
+
pwrite: (p, at, bytes, transfer) => rewriting(p, () => bridge.pwrite?.(p, at, bytes, transfer)),
|
|
627
|
+
truncate: (p, size) => rewriting(p, () => bridge.truncate?.(p, size))
|
|
605
628
|
} : {},
|
|
606
|
-
invalidate
|
|
629
|
+
invalidate,
|
|
630
|
+
touched
|
|
607
631
|
};
|
|
608
632
|
}
|
|
609
|
-
function pinnedIo(bridge, handle,
|
|
633
|
+
function pinnedIo(bridge, handle, rewriting) {
|
|
610
634
|
const io = bridge.pinned(handle);
|
|
611
635
|
const { pread, pwrite, truncate } = io;
|
|
612
636
|
return {
|
|
613
637
|
readFile: (p) => io.readFile(p),
|
|
614
|
-
writeFile: (p, bytes, open) =>
|
|
638
|
+
writeFile: (p, bytes, open) => rewriting(p, () => io.writeFile(p, bytes, open)),
|
|
615
639
|
pread: (p, at, n, version) => pread(p, at, n, version),
|
|
616
|
-
pwrite: (p, at, bytes, transfer) =>
|
|
617
|
-
truncate: (p, size) =>
|
|
640
|
+
pwrite: (p, at, bytes, transfer) => rewriting(p, () => pwrite(p, at, bytes, transfer)),
|
|
641
|
+
truncate: (p, size) => rewriting(p, () => truncate(p, size))
|
|
618
642
|
};
|
|
619
643
|
}
|
|
620
|
-
var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS;
|
|
644
|
+
var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, RING, RING_SIZE, SLOT, SHARED_IDS_BYTES, StatCache;
|
|
621
645
|
var init_wasi_files = __esm({
|
|
622
646
|
"src/process/wasi/wasi-files.ts"() {
|
|
623
647
|
"use strict";
|
|
@@ -807,6 +831,110 @@ var init_wasi_files = __esm({
|
|
|
807
831
|
};
|
|
808
832
|
MAX_LINKS = 40;
|
|
809
833
|
MISS_TTL_MS = 20;
|
|
834
|
+
FS_GEN = 4;
|
|
835
|
+
RING = 8;
|
|
836
|
+
RING_SIZE = 64;
|
|
837
|
+
SLOT = 3;
|
|
838
|
+
SHARED_IDS_BYTES = (RING + RING_SIZE * SLOT) * 4;
|
|
839
|
+
StatCache = class {
|
|
840
|
+
stats = /* @__PURE__ */ new Map();
|
|
841
|
+
lstats = /* @__PURE__ */ new Map();
|
|
842
|
+
byHash = /* @__PURE__ */ new Map();
|
|
843
|
+
byIno = /* @__PURE__ */ new Map();
|
|
844
|
+
shared;
|
|
845
|
+
seen;
|
|
846
|
+
constructor(shared) {
|
|
847
|
+
this.shared = shared;
|
|
848
|
+
this.seen = shared ? Atomics.load(shared, FS_GEN) : 0;
|
|
849
|
+
}
|
|
850
|
+
put(map, path, entry) {
|
|
851
|
+
map.set(path, entry);
|
|
852
|
+
if (!this.shared) return;
|
|
853
|
+
index(this.byHash, pathHash(path), path);
|
|
854
|
+
const ino = inoKey(entry);
|
|
855
|
+
if (ino !== 0) index(this.byIno, ino, path);
|
|
856
|
+
}
|
|
857
|
+
fresh() {
|
|
858
|
+
if (!this.shared) return;
|
|
859
|
+
const now = Atomics.load(this.shared, FS_GEN);
|
|
860
|
+
if (now === this.seen) return;
|
|
861
|
+
this.replay(now);
|
|
862
|
+
this.seen = now;
|
|
863
|
+
}
|
|
864
|
+
changed(path, ino = 0) {
|
|
865
|
+
const key = ino % 4294967296 | 0;
|
|
866
|
+
if (this.shared) {
|
|
867
|
+
const g = this.publish(this.shared, path === void 0 ? 0 : pathHash(path), key);
|
|
868
|
+
this.replay(g - 1);
|
|
869
|
+
this.seen = g;
|
|
870
|
+
if (path === void 0) this.clear();
|
|
871
|
+
else this.drop(pathHash(path), key);
|
|
872
|
+
}
|
|
873
|
+
if (path === void 0) return;
|
|
874
|
+
this.stats.delete(path);
|
|
875
|
+
this.lstats.delete(path);
|
|
876
|
+
}
|
|
877
|
+
mutated(paths, ino = 0) {
|
|
878
|
+
this.clear();
|
|
879
|
+
if (!this.shared) return;
|
|
880
|
+
const key = ino % 4294967296 | 0;
|
|
881
|
+
for (const [i, hash] of (paths.length > 0 ? paths.map(pathHash) : [0]).entries()) {
|
|
882
|
+
this.seen = this.publish(this.shared, hash, i === 0 ? key : 0);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
inoOf(path, look) {
|
|
886
|
+
if (!this.shared) return 0;
|
|
887
|
+
this.fresh();
|
|
888
|
+
const hit = this.stats.get(path);
|
|
889
|
+
if (hit && "ino" in hit && typeof hit.ino === "number") return hit.ino;
|
|
890
|
+
try {
|
|
891
|
+
return look().ino ?? 0;
|
|
892
|
+
} catch {
|
|
893
|
+
return 0;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
publish(shared, hash, ino) {
|
|
897
|
+
const g = Atomics.add(shared, FS_GEN, 1) + 1;
|
|
898
|
+
const at = RING + g % RING_SIZE * SLOT;
|
|
899
|
+
Atomics.store(shared, at, 0);
|
|
900
|
+
Atomics.store(shared, at + 1, hash);
|
|
901
|
+
Atomics.store(shared, at + 2, ino);
|
|
902
|
+
Atomics.store(shared, at, g);
|
|
903
|
+
return g;
|
|
904
|
+
}
|
|
905
|
+
replay(upTo) {
|
|
906
|
+
const shared = this.shared;
|
|
907
|
+
const missed = [];
|
|
908
|
+
for (let g = this.seen + 1; g <= upTo && upTo - this.seen <= RING_SIZE; g++) {
|
|
909
|
+
const at = RING + g % RING_SIZE * SLOT;
|
|
910
|
+
const tag = Atomics.load(shared, at);
|
|
911
|
+
const hash = Atomics.load(shared, at + 1);
|
|
912
|
+
const ino = Atomics.load(shared, at + 2);
|
|
913
|
+
if (tag !== g || hash === 0 || Atomics.load(shared, at) !== g) break;
|
|
914
|
+
missed.push([hash, ino]);
|
|
915
|
+
}
|
|
916
|
+
if (missed.length < upTo - this.seen) this.clear();
|
|
917
|
+
else for (const [hash, ino] of missed) this.drop(hash, ino);
|
|
918
|
+
}
|
|
919
|
+
drop(hash, ino) {
|
|
920
|
+
const paths = [
|
|
921
|
+
...this.byHash.get(hash) ?? [],
|
|
922
|
+
...ino === 0 ? [] : this.byIno.get(ino) ?? []
|
|
923
|
+
];
|
|
924
|
+
for (const path of paths) {
|
|
925
|
+
this.stats.delete(path);
|
|
926
|
+
this.lstats.delete(path);
|
|
927
|
+
}
|
|
928
|
+
this.byHash.delete(hash);
|
|
929
|
+
if (ino !== 0) this.byIno.delete(ino);
|
|
930
|
+
}
|
|
931
|
+
clear() {
|
|
932
|
+
this.stats.clear();
|
|
933
|
+
this.lstats.clear();
|
|
934
|
+
this.byHash.clear();
|
|
935
|
+
this.byIno.clear();
|
|
936
|
+
}
|
|
937
|
+
};
|
|
810
938
|
}
|
|
811
939
|
});
|
|
812
940
|
|
|
@@ -836,6 +964,7 @@ var init_wasi_threads = __esm({
|
|
|
836
964
|
"src/process/wasi/wasi-threads.ts"() {
|
|
837
965
|
"use strict";
|
|
838
966
|
init_protocol();
|
|
967
|
+
init_wasi_files();
|
|
839
968
|
LAST_TID = 0;
|
|
840
969
|
RUNNING = 1;
|
|
841
970
|
MAIN_TID = 1;
|
|
@@ -858,7 +987,7 @@ var init_wasi_threads = __esm({
|
|
|
858
987
|
this.memory = memory;
|
|
859
988
|
this.cap = cap;
|
|
860
989
|
this.tid = tid;
|
|
861
|
-
this.ids = new Int32Array(ids ?? new SharedArrayBuffer(
|
|
990
|
+
this.ids = new Int32Array(ids ?? new SharedArrayBuffer(SHARED_IDS_BYTES));
|
|
862
991
|
if (!ids) Atomics.store(this.ids, LAST_TID, MAIN_TID);
|
|
863
992
|
}
|
|
864
993
|
spawn(arg) {
|
|
@@ -1327,7 +1456,14 @@ var init_wasi_fds = __esm({
|
|
|
1327
1456
|
handed.add(e.file.buffer);
|
|
1328
1457
|
promoted.set(e.file, fd);
|
|
1329
1458
|
}
|
|
1330
|
-
this.table.set(fd, {
|
|
1459
|
+
this.table.set(fd, {
|
|
1460
|
+
type: "kernel",
|
|
1461
|
+
kind: "file",
|
|
1462
|
+
nonblock: false,
|
|
1463
|
+
append: e.file.append,
|
|
1464
|
+
path: e.file.path,
|
|
1465
|
+
ino: this.inoOf(e.file.path)
|
|
1466
|
+
});
|
|
1331
1467
|
}
|
|
1332
1468
|
for (const file of promoted.keys()) {
|
|
1333
1469
|
if (--file.buffer.opens <= 0) {
|
|
@@ -1441,9 +1577,21 @@ var init_wasi_fds = __esm({
|
|
|
1441
1577
|
buffer.orphan();
|
|
1442
1578
|
this.buffers.delete(path);
|
|
1443
1579
|
}
|
|
1580
|
+
inoOf(path) {
|
|
1581
|
+
try {
|
|
1582
|
+
return this.fs.stat(path).ino;
|
|
1583
|
+
} catch {
|
|
1584
|
+
return void 0;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1444
1587
|
renamed(from, to) {
|
|
1445
1588
|
if (from === to) return;
|
|
1446
1589
|
if (this.shared) this.kernel.call({ op: "fd-path-renamed", from, to });
|
|
1590
|
+
for (const e of this.table.values()) {
|
|
1591
|
+
if (e.type === "kernel" && e.path !== void 0 && within(e.path, from)) {
|
|
1592
|
+
e.path = to + e.path.slice(from.length);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1447
1595
|
const moved = [];
|
|
1448
1596
|
for (const [p, buffer] of this.buffers) {
|
|
1449
1597
|
if (within(p, from)) moved.push([p, buffer]);
|
|
@@ -1522,7 +1670,10 @@ var init_wasi_fds = __esm({
|
|
|
1522
1670
|
const made = !existing && this.createNew(path, oflags);
|
|
1523
1671
|
const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
|
|
1524
1672
|
const fd = this.kernel.sys.openVfs(path, flags, 0, truncate ? { truncate } : {});
|
|
1525
|
-
|
|
1673
|
+
const was = existing && this.inoOf(path);
|
|
1674
|
+
if (truncate) this.fs.touched?.(path, was);
|
|
1675
|
+
const ino = existing ? was : this.inoOf(path);
|
|
1676
|
+
this.table.set(fd, { type: "kernel", kind: "file", nonblock: false, append, path, ino });
|
|
1526
1677
|
if (append) this.publishFlags(fd, { nonblock: false, append });
|
|
1527
1678
|
this.bump();
|
|
1528
1679
|
return fd;
|
|
@@ -2316,11 +2467,29 @@ var init_wasi_host = __esm({
|
|
|
2316
2467
|
if (!kernel.sys.pread) throw new WasiError("ESPIPE");
|
|
2317
2468
|
return kernel.sys.pread(fd, Math.min(max, MAX_READ), at);
|
|
2318
2469
|
},
|
|
2319
|
-
pwrite: (body, at) => kernel.call({ op: "fd-pwrite", fd, offset: at, body }),
|
|
2470
|
+
pwrite: (body, at) => this.changed(fd, e, kernel.call({ op: "fd-pwrite", fd, offset: at, body })),
|
|
2320
2471
|
size: () => this.kernelStat(fd).size,
|
|
2321
|
-
truncate: (size) => void kernel.call({ op: "fd-resize", fd, size })
|
|
2472
|
+
truncate: (size) => this.changed(fd, e, void kernel.call({ op: "fd-resize", fd, size }))
|
|
2322
2473
|
};
|
|
2323
2474
|
}
|
|
2475
|
+
unnamed = /* @__PURE__ */ new WeakSet();
|
|
2476
|
+
changed(fd, e, result) {
|
|
2477
|
+
if (e.path === void 0 && !this.unnamed.has(e)) this.learnPath(fd, e);
|
|
2478
|
+
this.o.fs.touched?.(e.path, e.ino);
|
|
2479
|
+
return result;
|
|
2480
|
+
}
|
|
2481
|
+
learnPath(fd, e) {
|
|
2482
|
+
this.unnamed.add(e);
|
|
2483
|
+
let path;
|
|
2484
|
+
try {
|
|
2485
|
+
const st = this.kernelStat(fd);
|
|
2486
|
+
path = st.orphan ? void 0 : st.path;
|
|
2487
|
+
if (path !== void 0) e.ino = this.o.fs.stat(path).ino;
|
|
2488
|
+
} catch {
|
|
2489
|
+
return;
|
|
2490
|
+
}
|
|
2491
|
+
e.path = path;
|
|
2492
|
+
}
|
|
2324
2493
|
kernelStat(fd) {
|
|
2325
2494
|
return this.o.kernel.call({ op: "fd-vfs-stat", fd });
|
|
2326
2495
|
}
|
|
@@ -2329,7 +2498,8 @@ var init_wasi_host = __esm({
|
|
|
2329
2498
|
const e = this.fds.get(fd);
|
|
2330
2499
|
if (e.type === "kernel") {
|
|
2331
2500
|
try {
|
|
2332
|
-
|
|
2501
|
+
const n = this.o.kernel.sys.write(fd, data, { nonblock: e.nonblock });
|
|
2502
|
+
return this.fds.kind(fd, e) === "file" ? this.changed(fd, e, n) : n;
|
|
2333
2503
|
} catch (err) {
|
|
2334
2504
|
const broken = err.code === "EPIPE";
|
|
2335
2505
|
if (broken && this.fds.kind(fd, e) !== "socket") throw new WasiExit(SIGPIPE_EXIT);
|
|
@@ -3025,8 +3195,8 @@ var init_sync_sab_wire = __esm({
|
|
|
3025
3195
|
});
|
|
3026
3196
|
|
|
3027
3197
|
// src/process/js/async-sab.ts
|
|
3028
|
-
async function changed(header,
|
|
3029
|
-
const waited = waitAsync(header,
|
|
3198
|
+
async function changed(header, index3, seen, waitAsync = defaultWaitAsync) {
|
|
3199
|
+
const waited = waitAsync(header, index3, seen);
|
|
3030
3200
|
if (waited.async) await waited.value;
|
|
3031
3201
|
}
|
|
3032
3202
|
function createAsyncSabTransport(sab, port3, waitAsync = defaultWaitAsync) {
|
|
@@ -3184,7 +3354,9 @@ function parseSyncFsStat(json) {
|
|
|
3184
3354
|
...s.readonly === true ? { readonly: true } : {},
|
|
3185
3355
|
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
|
|
3186
3356
|
...s.ranged === true ? { ranged: true } : {},
|
|
3187
|
-
...typeof s.version === "string" ? { version: s.version } : {}
|
|
3357
|
+
...typeof s.version === "string" ? { version: s.version } : {},
|
|
3358
|
+
...typeof s.uid === "number" ? { uid: s.uid } : {},
|
|
3359
|
+
...typeof s.gid === "number" ? { gid: s.gid } : {}
|
|
3188
3360
|
};
|
|
3189
3361
|
}
|
|
3190
3362
|
var SYNC_FS_OPS, SYNC_FS_REQUEST_TIMEOUT_MS;
|
|
@@ -3215,7 +3387,9 @@ var init_sync_fs_wire = __esm({
|
|
|
3215
3387
|
"kept",
|
|
3216
3388
|
"pread",
|
|
3217
3389
|
"pwrite",
|
|
3218
|
-
"truncate"
|
|
3390
|
+
"truncate",
|
|
3391
|
+
"chown",
|
|
3392
|
+
"lchown"
|
|
3219
3393
|
];
|
|
3220
3394
|
SYNC_FS_REQUEST_TIMEOUT_MS = 25e3;
|
|
3221
3395
|
}
|
|
@@ -3916,7 +4090,7 @@ function openRequest(abs, o) {
|
|
|
3916
4090
|
...o.truncate ? { truncate: true } : {}
|
|
3917
4091
|
};
|
|
3918
4092
|
}
|
|
3919
|
-
function
|
|
4093
|
+
function index2(n, what) {
|
|
3920
4094
|
if (!Number.isSafeInteger(n) || n < 0) throw new JsCallError("EINVAL", what);
|
|
3921
4095
|
}
|
|
3922
4096
|
var CHUNK2, MAX_IO, O_WRONLY3, O_RDWR3, O_APPEND3;
|
|
@@ -4207,8 +4381,8 @@ function createSyncFsSabBridge(transport, opts = {}) {
|
|
|
4207
4381
|
if (typeof v !== "boolean") throw errnoError("EIO", path);
|
|
4208
4382
|
return v;
|
|
4209
4383
|
},
|
|
4210
|
-
mkdir: (path) => {
|
|
4211
|
-
run({ op: "mkdir", path }, path);
|
|
4384
|
+
mkdir: (path, mode) => {
|
|
4385
|
+
run({ op: "mkdir", path, ...mode !== void 0 ? { mode } : {} }, path);
|
|
4212
4386
|
},
|
|
4213
4387
|
rm: (path) => {
|
|
4214
4388
|
run({ op: "rm", path }, path);
|
|
@@ -4239,9 +4413,14 @@ function createSyncFsSabBridge(transport, opts = {}) {
|
|
|
4239
4413
|
lutimes: (path, atimeMs, mtimeMs) => {
|
|
4240
4414
|
run({ op: "lutimes", path, atimeMs, mtimeMs }, path);
|
|
4241
4415
|
},
|
|
4242
|
-
create: (path) => {
|
|
4243
|
-
run({ op: "create", path }, path);
|
|
4416
|
+
create: (path, mode) => {
|
|
4417
|
+
run({ op: "create", path, ...mode !== void 0 ? { mode } : {} }, path);
|
|
4418
|
+
},
|
|
4419
|
+
chown: (path, uid, gid) => {
|
|
4420
|
+
const ids = { ...uid !== void 0 ? { uid } : {}, ...gid !== void 0 ? { gid } : {} };
|
|
4421
|
+
run({ op: "lchown", path, ...ids }, path);
|
|
4244
4422
|
},
|
|
4423
|
+
...opts.owners ? { owners: true } : {},
|
|
4245
4424
|
hold: (path, held, open, handle) => {
|
|
4246
4425
|
const mode = (held ? 1 : 0) | (open ? 2 : 0);
|
|
4247
4426
|
if (mode === 3) return json({ op: "hold", path, mode }, path);
|
|
@@ -4275,7 +4454,7 @@ function syncOps(kernel, shared) {
|
|
|
4275
4454
|
return got;
|
|
4276
4455
|
};
|
|
4277
4456
|
const read2 = (fd, max = CHUNK2) => {
|
|
4278
|
-
|
|
4457
|
+
index2(max, "read");
|
|
4279
4458
|
const emulated = readDevice(info(fd), max, shared.random);
|
|
4280
4459
|
if (emulated) return emulated;
|
|
4281
4460
|
const r = kernel.blocking({ op: "fd-read", fd, max: Math.min(max, MAX_IO) });
|
|
@@ -4353,8 +4532,8 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4353
4532
|
return kernel.json({ op: "fd-vfs-stat", fd }).size;
|
|
4354
4533
|
},
|
|
4355
4534
|
read(position, length) {
|
|
4356
|
-
|
|
4357
|
-
|
|
4535
|
+
index2(position, "read");
|
|
4536
|
+
index2(length, "read");
|
|
4358
4537
|
const parts = [];
|
|
4359
4538
|
let got = 0;
|
|
4360
4539
|
do {
|
|
@@ -4369,7 +4548,7 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4369
4548
|
return joined(parts, got);
|
|
4370
4549
|
},
|
|
4371
4550
|
write(position, data) {
|
|
4372
|
-
|
|
4551
|
+
index2(position, "write");
|
|
4373
4552
|
let at = 0;
|
|
4374
4553
|
do {
|
|
4375
4554
|
live();
|
|
@@ -4383,7 +4562,7 @@ function syncFile(kernel, fd, path, append, forget) {
|
|
|
4383
4562
|
},
|
|
4384
4563
|
truncate(size) {
|
|
4385
4564
|
live();
|
|
4386
|
-
|
|
4565
|
+
index2(size, "truncate");
|
|
4387
4566
|
kernel.call({ op: "fd-resize", fd, size });
|
|
4388
4567
|
},
|
|
4389
4568
|
sync() {
|
|
@@ -4779,7 +4958,7 @@ function createContext(o) {
|
|
|
4779
4958
|
return got;
|
|
4780
4959
|
};
|
|
4781
4960
|
const read2 = async (fd, max = CHUNK2, signal) => {
|
|
4782
|
-
|
|
4961
|
+
index2(max, "read");
|
|
4783
4962
|
const emulated = readDevice(await info(fd), max, random);
|
|
4784
4963
|
if (emulated) return emulated;
|
|
4785
4964
|
return readPipe(kernel, fd, Math.min(max, MAX_IO), signal);
|
|
@@ -4926,8 +5105,8 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4926
5105
|
return s.size;
|
|
4927
5106
|
},
|
|
4928
5107
|
async read(position, length) {
|
|
4929
|
-
|
|
4930
|
-
|
|
5108
|
+
index2(position, "read");
|
|
5109
|
+
index2(length, "read");
|
|
4931
5110
|
const parts = [];
|
|
4932
5111
|
let got = 0;
|
|
4933
5112
|
do {
|
|
@@ -4942,7 +5121,7 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4942
5121
|
return joined(parts, got);
|
|
4943
5122
|
},
|
|
4944
5123
|
async write(position, data) {
|
|
4945
|
-
|
|
5124
|
+
index2(position, "write");
|
|
4946
5125
|
let at = 0;
|
|
4947
5126
|
do {
|
|
4948
5127
|
live();
|
|
@@ -4956,7 +5135,7 @@ function fileHandle(kernel, fd, path, append, forget) {
|
|
|
4956
5135
|
},
|
|
4957
5136
|
async truncate(size) {
|
|
4958
5137
|
live();
|
|
4959
|
-
|
|
5138
|
+
index2(size, "truncate");
|
|
4960
5139
|
await kernel.call({ op: "fd-resize", fd, size });
|
|
4961
5140
|
},
|
|
4962
5141
|
async sync() {
|
|
@@ -5447,6 +5626,7 @@ function createNodeOps(h) {
|
|
|
5447
5626
|
return {
|
|
5448
5627
|
getattr(node) {
|
|
5449
5628
|
const st = statOf(node);
|
|
5629
|
+
const owned = bridgeOf(node).owners === true;
|
|
5450
5630
|
const s = node.live;
|
|
5451
5631
|
const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
|
|
5452
5632
|
const mtime = new Date(st.mtimeMs ?? 0);
|
|
@@ -5455,8 +5635,8 @@ function createNodeOps(h) {
|
|
|
5455
5635
|
ino: st.ino ?? inodeOf(liveNodePath(node)),
|
|
5456
5636
|
mode: node.mode,
|
|
5457
5637
|
nlink: 1,
|
|
5458
|
-
uid: 0,
|
|
5459
|
-
gid: 0,
|
|
5638
|
+
uid: owned ? st.uid ?? 0 : 0,
|
|
5639
|
+
gid: owned ? st.gid ?? 0 : 0,
|
|
5460
5640
|
rdev: 0,
|
|
5461
5641
|
size,
|
|
5462
5642
|
atime: new Date(st.atimeMs ?? mtime.getTime()),
|
|
@@ -5499,14 +5679,17 @@ function createNodeOps(h) {
|
|
|
5499
5679
|
mknod(parent, name2, mode) {
|
|
5500
5680
|
parent.live.listed = void 0;
|
|
5501
5681
|
const path = childPath(parent, name2);
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5682
|
+
const bridge = bridgeOf(parent);
|
|
5683
|
+
const perm = bridge.owners ? mode & PERM_MASK : void 0;
|
|
5684
|
+
if (Fs.isDir(mode) && perm !== void 0) {
|
|
5685
|
+
call2(() => bridge.mkdir(path, perm));
|
|
5686
|
+
} else if (Fs.isDir(mode)) {
|
|
5687
|
+
call2(() => bridge.mkdir(path));
|
|
5688
|
+
const masked = mode & PERM_MASK & ~UMASK;
|
|
5689
|
+
if (masked !== DEFAULT_DIR_PERM) metadataCall(() => bridge.chmod(path, masked));
|
|
5506
5690
|
} else if (Fs.isFile(mode)) {
|
|
5507
|
-
const bridge = bridgeOf(parent);
|
|
5508
5691
|
call2(
|
|
5509
|
-
() => bridge.create ? bridge.create(path) : bridge.writeFile(path, new Uint8Array(0))
|
|
5692
|
+
() => bridge.create ? bridge.create(path, perm) : bridge.writeFile(path, new Uint8Array(0))
|
|
5510
5693
|
);
|
|
5511
5694
|
} else {
|
|
5512
5695
|
throw new Fs.ErrnoError(wasiErrno("EPERM"));
|
|
@@ -5909,6 +6092,32 @@ function guardRenames(Fs) {
|
|
|
5909
6092
|
rename(from, to);
|
|
5910
6093
|
};
|
|
5911
6094
|
}
|
|
6095
|
+
function idOf(value2) {
|
|
6096
|
+
return value2 === -1 || value2 === 4294967295 ? void 0 : value2 >>> 0;
|
|
6097
|
+
}
|
|
6098
|
+
function useLiveChown(Fs) {
|
|
6099
|
+
const chown = Fs.chown?.bind(Fs);
|
|
6100
|
+
if (!chown) return;
|
|
6101
|
+
Fs.chown = (path, uid, gid, dontFollow) => {
|
|
6102
|
+
const node = typeof path === "string" ? Fs.lookupPath(path, { follow: !dontFollow }).node : path;
|
|
6103
|
+
if (!node.live || node.live.orphan) return chown(path, uid, gid, dontFollow);
|
|
6104
|
+
try {
|
|
6105
|
+
node.mount.opts.bridge.chown?.(liveNodePath(node), idOf(uid), idOf(gid));
|
|
6106
|
+
} catch (err) {
|
|
6107
|
+
throw toErrno(Fs, err);
|
|
6108
|
+
}
|
|
6109
|
+
node.live.stat = void 0;
|
|
6110
|
+
if (node.parent?.live) node.parent.live.listed = void 0;
|
|
6111
|
+
};
|
|
6112
|
+
const { getStreamChecked } = Fs;
|
|
6113
|
+
if (!Fs.fchown || !getStreamChecked) return;
|
|
6114
|
+
Fs.fchown = (fd, uid, gid) => {
|
|
6115
|
+
const stream = getStreamChecked.call(Fs, fd);
|
|
6116
|
+
const live = stream.node.live !== void 0;
|
|
6117
|
+
const target = live || stream.path === void 0 ? stream.node : stream.path;
|
|
6118
|
+
Fs.chown(target, uid, gid);
|
|
6119
|
+
};
|
|
6120
|
+
}
|
|
5912
6121
|
var S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END, EARLY_WHOLE_FILE;
|
|
5913
6122
|
var init_live_vfs_fs = __esm({
|
|
5914
6123
|
"src/realm/live-vfs-fs.ts"() {
|
|
@@ -5953,6 +6162,7 @@ function mountVfsIntoEmscripten(Fs, deps) {
|
|
|
5953
6162
|
const dirs = topLevelDirs(bridge, warn);
|
|
5954
6163
|
const { plugin, mounted } = mountLiveVfsDirs(Fs, bridge, dirs ?? [], warn);
|
|
5955
6164
|
if (dirs) liveRoot(Fs, bridge);
|
|
6165
|
+
if (bridge.owners && Fs.lookupPath) useLiveChown(Fs);
|
|
5956
6166
|
try {
|
|
5957
6167
|
Fs.chdir(deps.cwd);
|
|
5958
6168
|
} catch (err) {
|
|
@@ -8358,6 +8568,9 @@ function reportGrowth(imports, publish) {
|
|
|
8358
8568
|
return grown;
|
|
8359
8569
|
};
|
|
8360
8570
|
}
|
|
8571
|
+
function callerOwner(Fs, init) {
|
|
8572
|
+
return init.owners ? {} : { owner: ownByCaller(Fs, init.cred, credAbi(init.program.glue)) };
|
|
8573
|
+
}
|
|
8361
8574
|
async function runWasmProcess(init, port3, deps = {}) {
|
|
8362
8575
|
const signals = new SignalGate(
|
|
8363
8576
|
createSyncSabTransport(init.sab, port3, {
|
|
@@ -8468,7 +8681,7 @@ async function runWasmProcess(init, port3, deps = {}) {
|
|
|
8468
8681
|
const running = module;
|
|
8469
8682
|
if (!hasStreams(running)) return runStdioOnly(running, init);
|
|
8470
8683
|
const vfs = mountVfsIntoEmscripten(running.FS, {
|
|
8471
|
-
bridge: createSyncFsSabBridge(transport),
|
|
8684
|
+
bridge: createSyncFsSabBridge(transport, init.owners ? { owners: true } : {}),
|
|
8472
8685
|
cwd: init.cwd,
|
|
8473
8686
|
warn: deps.warn ?? say(2)
|
|
8474
8687
|
});
|
|
@@ -8510,7 +8723,7 @@ async function runWasmProcess(init, port3, deps = {}) {
|
|
|
8510
8723
|
describeFork: () => describeForFork(running.FS, sys, streams, livePath),
|
|
8511
8724
|
inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
|
|
8512
8725
|
stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath),
|
|
8513
|
-
|
|
8726
|
+
...callerOwner(running.FS, init)
|
|
8514
8727
|
});
|
|
8515
8728
|
running.sliccKernel.http = createHttpKernel(transport);
|
|
8516
8729
|
running.sliccKernel.hostname = hostnameOf(init.env);
|
|
@@ -9694,8 +9907,8 @@ function readExports(r, s) {
|
|
|
9694
9907
|
for (let i = r.u32(); i > 0; i--) {
|
|
9695
9908
|
const name2 = r.name();
|
|
9696
9909
|
const kind = r.byte();
|
|
9697
|
-
const
|
|
9698
|
-
if (kind === 0) s.info.exports[name2] =
|
|
9910
|
+
const index3 = r.u32();
|
|
9911
|
+
if (kind === 0) s.info.exports[name2] = index3;
|
|
9699
9912
|
}
|
|
9700
9913
|
}
|
|
9701
9914
|
function readElems(r, s) {
|
|
@@ -9998,15 +10211,15 @@ var init_wasix_linker = __esm({
|
|
|
9998
10211
|
return out;
|
|
9999
10212
|
}
|
|
10000
10213
|
allocateClosure() {
|
|
10001
|
-
const
|
|
10002
|
-
growTable(this.table,
|
|
10003
|
-
this.live.add(
|
|
10004
|
-
return
|
|
10214
|
+
const index3 = this.indices.allocate(this.table.length);
|
|
10215
|
+
growTable(this.table, index3 + 1);
|
|
10216
|
+
this.live.add(index3);
|
|
10217
|
+
return index3;
|
|
10005
10218
|
}
|
|
10006
|
-
freeClosure(
|
|
10007
|
-
this.indices?.free(
|
|
10008
|
-
this.live.delete(
|
|
10009
|
-
this.table.set(
|
|
10219
|
+
freeClosure(index3) {
|
|
10220
|
+
this.indices?.free(index3);
|
|
10221
|
+
this.live.delete(index3);
|
|
10222
|
+
this.table.set(index3, null);
|
|
10010
10223
|
}
|
|
10011
10224
|
live = /* @__PURE__ */ new Set();
|
|
10012
10225
|
prepareClosure(record) {
|
|
@@ -10239,12 +10452,12 @@ var init_wasix_linker = __esm({
|
|
|
10239
10452
|
this.indexTable();
|
|
10240
10453
|
const known = this.slots.get(fn);
|
|
10241
10454
|
if (known !== void 0) return known;
|
|
10242
|
-
const
|
|
10243
|
-
growTable(this.table,
|
|
10244
|
-
this.table.set(
|
|
10245
|
-
this.slots.set(fn,
|
|
10246
|
-
this.publisher?.({ kind: "slot", index:
|
|
10247
|
-
return
|
|
10455
|
+
const index3 = this.reserve(1);
|
|
10456
|
+
growTable(this.table, index3 + 1);
|
|
10457
|
+
this.table.set(index3, fn);
|
|
10458
|
+
this.slots.set(fn, index3);
|
|
10459
|
+
this.publisher?.({ kind: "slot", index: index3, handle, name: name2 });
|
|
10460
|
+
return index3;
|
|
10248
10461
|
}
|
|
10249
10462
|
allocate(size, alignment) {
|
|
10250
10463
|
if (size === 0) return 0;
|
|
@@ -10529,11 +10742,11 @@ var init_wasix_sockets = __esm({
|
|
|
10529
10742
|
});
|
|
10530
10743
|
|
|
10531
10744
|
// src/process/wasi/wasix-host.ts
|
|
10532
|
-
function futexWait(view,
|
|
10745
|
+
function futexWait(view, index3, expected, ms, interrupted) {
|
|
10533
10746
|
const deadline = performance.now() + ms;
|
|
10534
10747
|
for (; ; ) {
|
|
10535
10748
|
const slice = interrupted ? Math.min(FUTEX_SLICE_MS, ms) : ms;
|
|
10536
|
-
if (Atomics.wait(view,
|
|
10749
|
+
if (Atomics.wait(view, index3, expected, slice) !== "timed-out") return true;
|
|
10537
10750
|
if (interrupted?.()) return true;
|
|
10538
10751
|
ms = deadline - performance.now();
|
|
10539
10752
|
if (ms <= 0) return false;
|
|
@@ -10662,21 +10875,21 @@ var init_wasix_host = __esm({
|
|
|
10662
10875
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10663
10876
|
this.mem.view().setUint32(out, this.linker.allocateClosure(), true);
|
|
10664
10877
|
},
|
|
10665
|
-
closure_prepare: (backing,
|
|
10878
|
+
closure_prepare: (backing, index3, argTypes, argCount, resultTypes, resultCount, userData) => {
|
|
10666
10879
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10667
10880
|
const params = valueTypes(this.mem.bytes(argTypes, argCount));
|
|
10668
10881
|
const results = valueTypes(this.mem.bytes(resultTypes, resultCount));
|
|
10669
10882
|
if (!params || !results) throw new WasiError("EINVAL");
|
|
10670
10883
|
try {
|
|
10671
|
-
this.linker.prepareClosure({ index:
|
|
10884
|
+
this.linker.prepareClosure({ index: index3, backing, userData, params, results });
|
|
10672
10885
|
} catch (e) {
|
|
10673
10886
|
if (e instanceof DlError) throw new WasiError("EINVAL");
|
|
10674
10887
|
throw e;
|
|
10675
10888
|
}
|
|
10676
10889
|
},
|
|
10677
|
-
closure_free: (
|
|
10890
|
+
closure_free: (index3) => {
|
|
10678
10891
|
if (!this.linker) throw new WasiError("ENOTSUP");
|
|
10679
|
-
this.linker.freeClosure(
|
|
10892
|
+
this.linker.freeClosure(index3);
|
|
10680
10893
|
},
|
|
10681
10894
|
call_dynamic: (...a) => void callDynamic(
|
|
10682
10895
|
{ mem: this.mem, table: () => this.table, types: this.types },
|
|
@@ -10981,10 +11194,10 @@ function parseFunctionNames(payload) {
|
|
|
10981
11194
|
if (end > payload.length) throw new RangeError("truncated name section");
|
|
10982
11195
|
if (id === 1) {
|
|
10983
11196
|
for (let count = leb(); count > 0; count--) {
|
|
10984
|
-
const
|
|
11197
|
+
const index3 = leb();
|
|
10985
11198
|
const length = leb();
|
|
10986
11199
|
if (at + length > end) throw new RangeError("truncated name section");
|
|
10987
|
-
names.set(
|
|
11200
|
+
names.set(index3, decoder3.decode(payload.subarray(at, at + length)));
|
|
10988
11201
|
at += length;
|
|
10989
11202
|
}
|
|
10990
11203
|
}
|
|
@@ -11008,7 +11221,7 @@ function nameFrame(line, module, name2) {
|
|
|
11008
11221
|
}
|
|
11009
11222
|
function sidecarNames(read2, path) {
|
|
11010
11223
|
let names;
|
|
11011
|
-
return (
|
|
11224
|
+
return (index3) => {
|
|
11012
11225
|
if (!names) {
|
|
11013
11226
|
try {
|
|
11014
11227
|
names = parseFunctionNames(read2(path));
|
|
@@ -11016,7 +11229,7 @@ function sidecarNames(read2, path) {
|
|
|
11016
11229
|
names = /* @__PURE__ */ new Map();
|
|
11017
11230
|
}
|
|
11018
11231
|
}
|
|
11019
|
-
return names.get(
|
|
11232
|
+
return names.get(index3);
|
|
11020
11233
|
};
|
|
11021
11234
|
}
|
|
11022
11235
|
var UNNAMED_FRAME, WASM_MODULE;
|
|
@@ -11377,7 +11590,7 @@ async function runWasiProcess(init, port3) {
|
|
|
11377
11590
|
parent: () => identify(transport, init).ppid,
|
|
11378
11591
|
kernel: { sys: traced(stats, "kernel", sys), call: call2 },
|
|
11379
11592
|
fs: procfsBridge(
|
|
11380
|
-
cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
|
|
11593
|
+
cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport)), void 0, threads?.ids),
|
|
11381
11594
|
procTree(call2, id.pid)
|
|
11382
11595
|
),
|
|
11383
11596
|
...descriptors(init, fork, threads)
|
|
@@ -11470,7 +11683,10 @@ async function runWasiThread(init, port3) {
|
|
|
11470
11683
|
ppid: id.ppid,
|
|
11471
11684
|
parent: () => identify(transport, init).ppid,
|
|
11472
11685
|
kernel: { sys, call: call2 },
|
|
11473
|
-
fs: procfsBridge(
|
|
11686
|
+
fs: procfsBridge(
|
|
11687
|
+
cachingBridge(createSyncFsSabBridge(transport), void 0, threads.ids),
|
|
11688
|
+
procTree(call2, id.pid)
|
|
11689
|
+
),
|
|
11474
11690
|
shared: threads.ids
|
|
11475
11691
|
});
|
|
11476
11692
|
const program = await programImports(init.program, host, transport, thread.tid);
|
|
@@ -11582,13 +11798,13 @@ var init_wasi_runtime = __esm({
|
|
|
11582
11798
|
},
|
|
11583
11799
|
unlock: () => this.call({ op: "dl-unlock", owner: this.owner }),
|
|
11584
11800
|
allocate: (floor) => {
|
|
11585
|
-
const
|
|
11801
|
+
const index3 = this.call({ op: "dl-closure", floor });
|
|
11586
11802
|
this.catchUp();
|
|
11587
11803
|
this.bump();
|
|
11588
|
-
return
|
|
11804
|
+
return index3;
|
|
11589
11805
|
},
|
|
11590
|
-
free: (
|
|
11591
|
-
this.call({ op: "dl-closure-free", index:
|
|
11806
|
+
free: (index3) => {
|
|
11807
|
+
this.call({ op: "dl-closure-free", index: index3 });
|
|
11592
11808
|
this.bump();
|
|
11593
11809
|
}
|
|
11594
11810
|
};
|