@ai-ecoverse/slicc-kernel 1.21.0 → 1.22.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 +7 -4
- package/dist/driver-worker.js +6 -4
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js +6 -4
- package/dist/driver.js.map +2 -2
- package/dist/kernel-worker.js +482 -41
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +6 -4
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +396 -36
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +482 -41
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +396 -36
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
|
@@ -87,6 +87,249 @@ var init_signals = __esm({
|
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
// src/fs/pages.ts
|
|
91
|
+
var PAGE, READAHEAD, CLEAN_LIMIT, WRITEBACK, RUN, Pages;
|
|
92
|
+
var init_pages = __esm({
|
|
93
|
+
"src/fs/pages.ts"() {
|
|
94
|
+
"use strict";
|
|
95
|
+
PAGE = 64 * 1024;
|
|
96
|
+
READAHEAD = 1024 * 1024;
|
|
97
|
+
CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
98
|
+
WRITEBACK = 8 * 1024 * 1024;
|
|
99
|
+
RUN = 1024 * 1024;
|
|
100
|
+
Pages = class {
|
|
101
|
+
length;
|
|
102
|
+
stored;
|
|
103
|
+
shrink;
|
|
104
|
+
pages = /* @__PURE__ */ new Map();
|
|
105
|
+
dirty = /* @__PURE__ */ new Set();
|
|
106
|
+
free = [];
|
|
107
|
+
pinned = false;
|
|
108
|
+
constructor(size) {
|
|
109
|
+
this.length = size;
|
|
110
|
+
this.stored = size;
|
|
111
|
+
}
|
|
112
|
+
get dirtyBytes() {
|
|
113
|
+
return this.dirty.size * PAGE;
|
|
114
|
+
}
|
|
115
|
+
get changed() {
|
|
116
|
+
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
117
|
+
}
|
|
118
|
+
missing(at, length) {
|
|
119
|
+
this.evict();
|
|
120
|
+
const end = Math.min(this.stored, at + length, this.length);
|
|
121
|
+
const runs = [];
|
|
122
|
+
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
123
|
+
if (this.pages.has(page)) continue;
|
|
124
|
+
const last2 = runs[runs.length - 1];
|
|
125
|
+
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
126
|
+
else runs.push([page * PAGE, PAGE]);
|
|
127
|
+
}
|
|
128
|
+
const last = runs[runs.length - 1];
|
|
129
|
+
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
130
|
+
return runs.map(([start, n]) => [start, Math.min(n, this.stored - start)]);
|
|
131
|
+
}
|
|
132
|
+
partial(at, length) {
|
|
133
|
+
if (length === 0) return [];
|
|
134
|
+
this.evict();
|
|
135
|
+
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length - 1) / PAGE)]);
|
|
136
|
+
const runs = [];
|
|
137
|
+
for (const page of edges) {
|
|
138
|
+
const start = page * PAGE;
|
|
139
|
+
const covered = at <= start && at + length >= start + PAGE;
|
|
140
|
+
if (covered || this.pages.has(page) || start >= this.stored) continue;
|
|
141
|
+
runs.push([start, Math.min(PAGE, this.stored - start)]);
|
|
142
|
+
}
|
|
143
|
+
return runs;
|
|
144
|
+
}
|
|
145
|
+
fill(start, bytes) {
|
|
146
|
+
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
147
|
+
const page = (start + at) / PAGE;
|
|
148
|
+
if (this.pages.has(page)) continue;
|
|
149
|
+
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
150
|
+
const fresh = this.take(part.length);
|
|
151
|
+
fresh.set(part);
|
|
152
|
+
this.pages.set(page, fresh);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
read(at, length) {
|
|
156
|
+
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length) - at));
|
|
157
|
+
this.readInto(at, out);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
readInto(at, out) {
|
|
161
|
+
const end = Math.min(this.length, at + out.length);
|
|
162
|
+
for (let pos = at; pos < end; ) {
|
|
163
|
+
const page = Math.floor(pos / PAGE);
|
|
164
|
+
const from = pos - page * PAGE;
|
|
165
|
+
const n = Math.min(PAGE - from, end - pos);
|
|
166
|
+
const bytes = this.pages.get(page);
|
|
167
|
+
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
168
|
+
else out.fill(0, pos - at, pos - at + n);
|
|
169
|
+
pos += n;
|
|
170
|
+
}
|
|
171
|
+
return Math.max(0, end - at);
|
|
172
|
+
}
|
|
173
|
+
write(at, bytes) {
|
|
174
|
+
for (let done = 0; done < bytes.length; ) {
|
|
175
|
+
const pos = at + done;
|
|
176
|
+
const page = Math.floor(pos / PAGE);
|
|
177
|
+
const from = pos - page * PAGE;
|
|
178
|
+
const n = Math.min(PAGE - from, bytes.length - done);
|
|
179
|
+
let target = this.pages.get(page);
|
|
180
|
+
if (!target) {
|
|
181
|
+
target = this.take(0);
|
|
182
|
+
this.pages.set(page, target);
|
|
183
|
+
}
|
|
184
|
+
target.set(bytes.subarray(done, done + n), from);
|
|
185
|
+
this.dirty.add(page);
|
|
186
|
+
done += n;
|
|
187
|
+
}
|
|
188
|
+
this.length = Math.max(this.length, at + bytes.length);
|
|
189
|
+
}
|
|
190
|
+
truncate(size) {
|
|
191
|
+
if (size < this.stored) {
|
|
192
|
+
this.stored = size;
|
|
193
|
+
this.shrink = Math.min(this.shrink ?? size, size);
|
|
194
|
+
}
|
|
195
|
+
if (size < this.length) {
|
|
196
|
+
const edge = Math.floor(size / PAGE);
|
|
197
|
+
for (const page of [...this.pages.keys()]) {
|
|
198
|
+
if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
|
|
199
|
+
}
|
|
200
|
+
this.pages.get(edge)?.fill(0, size - edge * PAGE);
|
|
201
|
+
}
|
|
202
|
+
this.length = size;
|
|
203
|
+
}
|
|
204
|
+
plan() {
|
|
205
|
+
const runs = [];
|
|
206
|
+
const sorted = [...this.dirty].sort((a, b) => a - b);
|
|
207
|
+
for (let i = 0; i < sorted.length; ) {
|
|
208
|
+
let j = i + 1;
|
|
209
|
+
const first = sorted[i];
|
|
210
|
+
while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
|
|
211
|
+
j++;
|
|
212
|
+
}
|
|
213
|
+
const start = first * PAGE;
|
|
214
|
+
const end = Math.min(this.length, (first + (j - i)) * PAGE);
|
|
215
|
+
const bytes = new Uint8Array(end - start);
|
|
216
|
+
for (let k = i; k < j; k++) {
|
|
217
|
+
const page = this.pages.get(sorted[k]);
|
|
218
|
+
bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start)), (k - i) * PAGE);
|
|
219
|
+
}
|
|
220
|
+
runs.push({ offset: start, bytes });
|
|
221
|
+
i = j;
|
|
222
|
+
}
|
|
223
|
+
const written = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
|
|
224
|
+
return {
|
|
225
|
+
...this.shrink !== void 0 ? { shrink: this.shrink } : {},
|
|
226
|
+
runs,
|
|
227
|
+
...this.length > written ? { extend: this.length } : {}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
flushed() {
|
|
231
|
+
this.dirty.clear();
|
|
232
|
+
this.shrink = void 0;
|
|
233
|
+
this.stored = this.length;
|
|
234
|
+
this.evict();
|
|
235
|
+
}
|
|
236
|
+
pin() {
|
|
237
|
+
this.pinned = true;
|
|
238
|
+
}
|
|
239
|
+
reset(size) {
|
|
240
|
+
if (this.pinned) return;
|
|
241
|
+
for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
|
|
242
|
+
if (this.changed) return;
|
|
243
|
+
this.length = size;
|
|
244
|
+
this.stored = size;
|
|
245
|
+
}
|
|
246
|
+
evict() {
|
|
247
|
+
if (this.pinned) return;
|
|
248
|
+
let clean = (this.pages.size - this.dirty.size) * PAGE;
|
|
249
|
+
for (const page of this.pages.keys()) {
|
|
250
|
+
if (clean <= CLEAN_LIMIT) return;
|
|
251
|
+
if (this.dirty.has(page)) continue;
|
|
252
|
+
this.drop(page);
|
|
253
|
+
clean -= PAGE;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
take(used) {
|
|
257
|
+
const page = this.free.pop();
|
|
258
|
+
if (!page) return new Uint8Array(PAGE);
|
|
259
|
+
page.fill(0, used);
|
|
260
|
+
return page;
|
|
261
|
+
}
|
|
262
|
+
drop(page) {
|
|
263
|
+
const bytes = this.pages.get(page);
|
|
264
|
+
this.pages.delete(page);
|
|
265
|
+
this.dirty.delete(page);
|
|
266
|
+
if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// src/fs/ranged.ts
|
|
273
|
+
var RangedFile;
|
|
274
|
+
var init_ranged = __esm({
|
|
275
|
+
"src/fs/ranged.ts"() {
|
|
276
|
+
"use strict";
|
|
277
|
+
init_pages();
|
|
278
|
+
RangedFile = class {
|
|
279
|
+
pages;
|
|
280
|
+
io;
|
|
281
|
+
pinned = false;
|
|
282
|
+
path;
|
|
283
|
+
constructor(io, path, size) {
|
|
284
|
+
this.io = io;
|
|
285
|
+
this.path = path;
|
|
286
|
+
this.pages = new Pages(size);
|
|
287
|
+
}
|
|
288
|
+
get changed() {
|
|
289
|
+
return this.pages.changed;
|
|
290
|
+
}
|
|
291
|
+
size() {
|
|
292
|
+
return this.pages.length;
|
|
293
|
+
}
|
|
294
|
+
fetch(runs) {
|
|
295
|
+
for (const [start, n] of runs) this.pages.fill(start, this.io.pread(this.path, start, n));
|
|
296
|
+
}
|
|
297
|
+
read(at, length) {
|
|
298
|
+
this.fetch(this.pages.missing(at, length));
|
|
299
|
+
return this.pages.read(at, length);
|
|
300
|
+
}
|
|
301
|
+
readInto(at, out) {
|
|
302
|
+
this.fetch(this.pages.missing(at, out.length));
|
|
303
|
+
return this.pages.readInto(at, out);
|
|
304
|
+
}
|
|
305
|
+
write(at, bytes) {
|
|
306
|
+
this.fetch(this.pages.partial(at, bytes.length));
|
|
307
|
+
this.pages.write(at, bytes);
|
|
308
|
+
if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) this.flush();
|
|
309
|
+
}
|
|
310
|
+
truncate(size) {
|
|
311
|
+
this.pages.truncate(size);
|
|
312
|
+
}
|
|
313
|
+
flush() {
|
|
314
|
+
if (this.pinned || !this.pages.changed) return;
|
|
315
|
+
const plan = this.pages.plan();
|
|
316
|
+
if (plan.shrink !== void 0) this.io.truncate(this.path, plan.shrink);
|
|
317
|
+
for (const run of plan.runs) this.io.pwrite(this.path, run.offset, run.bytes, true);
|
|
318
|
+
if (plan.extend !== void 0) this.io.truncate(this.path, plan.extend);
|
|
319
|
+
this.pages.flushed();
|
|
320
|
+
}
|
|
321
|
+
pin() {
|
|
322
|
+
this.pinned = true;
|
|
323
|
+
this.pages.pin();
|
|
324
|
+
this.fetch(this.pages.missing(0, this.pages.length));
|
|
325
|
+
}
|
|
326
|
+
reset(size) {
|
|
327
|
+
this.pages.reset(size);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
90
333
|
// src/fs/types.ts
|
|
91
334
|
function normalizePath(path) {
|
|
92
335
|
const parts = [];
|
|
@@ -171,7 +414,8 @@ function createHelpers(Fs, ops) {
|
|
|
171
414
|
}
|
|
172
415
|
function statOf(node) {
|
|
173
416
|
if (node.live.orphan) {
|
|
174
|
-
|
|
417
|
+
const size = node.live.ranged?.size() ?? node.live.len;
|
|
418
|
+
return { ...node.live.stat, size };
|
|
175
419
|
}
|
|
176
420
|
if (!node.live.stat) {
|
|
177
421
|
const st = call2(() => bridgeOf(node).lstat(liveNodePath(node)));
|
|
@@ -192,6 +436,20 @@ function createHelpers(Fs, ops) {
|
|
|
192
436
|
s.len = bytes.length;
|
|
193
437
|
s.loaded = true;
|
|
194
438
|
}
|
|
439
|
+
function rangedOf(node) {
|
|
440
|
+
const s = node.live;
|
|
441
|
+
if (s.ranged || !s.ranges) return s.ranged;
|
|
442
|
+
const bridge = bridgeOf(node);
|
|
443
|
+
const path = () => liveNodePath(node);
|
|
444
|
+
const io = {
|
|
445
|
+
pread: (_, at, n) => bridge.pread(path(), at, n),
|
|
446
|
+
pwrite: (_, at, bytes, transfer) => bridge.pwrite(path(), at, bytes, transfer),
|
|
447
|
+
truncate: (_, size) => bridge.truncate(path(), size)
|
|
448
|
+
};
|
|
449
|
+
const st = call2(() => bridge.stat(path()));
|
|
450
|
+
s.ranged = new RangedFile(io, path(), st.size);
|
|
451
|
+
return s.ranged;
|
|
452
|
+
}
|
|
195
453
|
function ensureCapacity(node, need) {
|
|
196
454
|
const s = node.live;
|
|
197
455
|
const cur = s.data ?? new Uint8Array(0);
|
|
@@ -203,9 +461,12 @@ function createHelpers(Fs, ops) {
|
|
|
203
461
|
}
|
|
204
462
|
function flushNode(node) {
|
|
205
463
|
const s = node.live;
|
|
206
|
-
if (!s.dirty || !s.data || s.
|
|
207
|
-
|
|
208
|
-
|
|
464
|
+
if (!s.dirty || s.orphan || !(s.data || s.ranged)) return;
|
|
465
|
+
if (s.ranged) call2(() => s.ranged?.flush());
|
|
466
|
+
else {
|
|
467
|
+
const bytes = s.data.slice(0, s.len);
|
|
468
|
+
call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
|
|
469
|
+
}
|
|
209
470
|
s.dirty = false;
|
|
210
471
|
s.stat = void 0;
|
|
211
472
|
}
|
|
@@ -218,6 +479,12 @@ function createHelpers(Fs, ops) {
|
|
|
218
479
|
throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
|
|
219
480
|
}
|
|
220
481
|
}
|
|
482
|
+
const ranged = s.openCount > 0 ? rangedOf(node) : void 0;
|
|
483
|
+
if (ranged) {
|
|
484
|
+
ranged.truncate(size);
|
|
485
|
+
s.dirty = true;
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
221
488
|
if (s.openCount > 0) {
|
|
222
489
|
if (size > 0) ensureLoaded(node);
|
|
223
490
|
else s.loaded = true;
|
|
@@ -228,6 +495,12 @@ function createHelpers(Fs, ops) {
|
|
|
228
495
|
return;
|
|
229
496
|
}
|
|
230
497
|
const path = liveNodePath(node);
|
|
498
|
+
const bridge = bridgeOf(node);
|
|
499
|
+
if (statOf(node).ranged && bridge.truncate) {
|
|
500
|
+
call2(() => bridge.truncate?.(path, size));
|
|
501
|
+
s.stat = void 0;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
231
504
|
const bytes = new Uint8Array(size);
|
|
232
505
|
if (size > 0) {
|
|
233
506
|
const cur = call2(() => bridgeOf(node).readFile(path));
|
|
@@ -246,6 +519,7 @@ function createHelpers(Fs, ops) {
|
|
|
246
519
|
childPath,
|
|
247
520
|
ensureLoaded,
|
|
248
521
|
ensureCapacity,
|
|
522
|
+
rangedOf,
|
|
249
523
|
flushNode,
|
|
250
524
|
truncate
|
|
251
525
|
};
|
|
@@ -257,7 +531,7 @@ function createNodeOps(h) {
|
|
|
257
531
|
getattr(node) {
|
|
258
532
|
const st = statOf(node);
|
|
259
533
|
const s = node.live;
|
|
260
|
-
const size = Fs.isDir(node.mode) ? 4096 : s.loaded ? s.len : st.size;
|
|
534
|
+
const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
|
|
261
535
|
const mtime = new Date(st.mtimeMs ?? 0);
|
|
262
536
|
return {
|
|
263
537
|
dev: st.dev ?? 1,
|
|
@@ -357,7 +631,9 @@ function createNodeOps(h) {
|
|
|
357
631
|
}
|
|
358
632
|
if (open) {
|
|
359
633
|
statOf(open);
|
|
360
|
-
|
|
634
|
+
const ranged = h.rangedOf(open);
|
|
635
|
+
if (ranged) ranged.pin();
|
|
636
|
+
else ensureLoaded(open);
|
|
361
637
|
}
|
|
362
638
|
call2(() => bridgeOf(parent).unlink(childPath(parent, name)));
|
|
363
639
|
if (open) open.live.orphan = true;
|
|
@@ -390,7 +666,7 @@ function createNodeOps(h) {
|
|
|
390
666
|
};
|
|
391
667
|
}
|
|
392
668
|
function createStreamOps(h) {
|
|
393
|
-
const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf } = h;
|
|
669
|
+
const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf, rangedOf } = h;
|
|
394
670
|
const held = (stream, change) => {
|
|
395
671
|
const s = stream.node.live;
|
|
396
672
|
if ((stream.flags & 3) === 0 || s.orphan) return;
|
|
@@ -406,6 +682,11 @@ function createStreamOps(h) {
|
|
|
406
682
|
return {
|
|
407
683
|
open(stream) {
|
|
408
684
|
if (!Fs.isFile(stream.node.mode)) return;
|
|
685
|
+
const s = stream.node.live;
|
|
686
|
+
if (s.openCount === 0 && !s.orphan) {
|
|
687
|
+
const bridge = bridgeOf(stream.node);
|
|
688
|
+
s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
|
|
689
|
+
}
|
|
409
690
|
if ((stream.flags & 3) !== 0) {
|
|
410
691
|
try {
|
|
411
692
|
const st = statOf(stream.node);
|
|
@@ -437,6 +718,8 @@ function createStreamOps(h) {
|
|
|
437
718
|
flushNode(node);
|
|
438
719
|
} finally {
|
|
439
720
|
s.data = void 0;
|
|
721
|
+
s.ranged = void 0;
|
|
722
|
+
s.ranges = false;
|
|
440
723
|
s.len = 0;
|
|
441
724
|
s.loaded = false;
|
|
442
725
|
held(stream, -1);
|
|
@@ -445,6 +728,11 @@ function createStreamOps(h) {
|
|
|
445
728
|
read(stream, buffer, offset, length, position) {
|
|
446
729
|
const node = stream.node;
|
|
447
730
|
if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(ERRNO_BY_CODE.EISDIR);
|
|
731
|
+
const ranged = rangedOf(node);
|
|
732
|
+
if (ranged) {
|
|
733
|
+
const out2 = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, Math.max(0, length));
|
|
734
|
+
return h.call(() => ranged.readInto(position, out2));
|
|
735
|
+
}
|
|
448
736
|
ensureLoaded(node);
|
|
449
737
|
const s = node.live;
|
|
450
738
|
if (position >= s.len || length <= 0) return 0;
|
|
@@ -460,6 +748,13 @@ function createStreamOps(h) {
|
|
|
460
748
|
const s = node.live;
|
|
461
749
|
const end = position + length;
|
|
462
750
|
if (s.maxFile !== void 0 && end > s.maxFile) throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
|
|
751
|
+
const ranged = rangedOf(node);
|
|
752
|
+
if (ranged) {
|
|
753
|
+
const bytes = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, length);
|
|
754
|
+
h.call(() => ranged.write(position, bytes));
|
|
755
|
+
s.dirty = true;
|
|
756
|
+
return length;
|
|
757
|
+
}
|
|
463
758
|
ensureLoaded(node);
|
|
464
759
|
const buf = ensureCapacity(node, end);
|
|
465
760
|
if (position > s.len) buf.fill(0, s.len, position);
|
|
@@ -473,7 +768,7 @@ function createStreamOps(h) {
|
|
|
473
768
|
if (whence === SEEK_CUR) pos += stream.position;
|
|
474
769
|
else if (whence === SEEK_END && Fs.isFile(stream.node.mode)) {
|
|
475
770
|
const s = stream.node.live;
|
|
476
|
-
pos += s.loaded ? s.len : statOf(stream.node).size;
|
|
771
|
+
pos += rangedOf(stream.node)?.size() ?? (s.loaded ? s.len : statOf(stream.node).size);
|
|
477
772
|
}
|
|
478
773
|
if (pos < 0) throw new Fs.ErrnoError(ERRNO_BY_CODE.EINVAL);
|
|
479
774
|
return pos;
|
|
@@ -510,11 +805,15 @@ function ownedBy(plugin, node) {
|
|
|
510
805
|
function flushLiveVfs(Fs, plugin) {
|
|
511
806
|
for (const head of Fs.nameTable ?? []) {
|
|
512
807
|
for (let node = head; node; node = node.name_next ?? null) {
|
|
513
|
-
|
|
808
|
+
const s = node.live;
|
|
809
|
+
if (!ownedBy(plugin, node) || !s.dirty || !(s.data || s.ranged)) continue;
|
|
514
810
|
try {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
811
|
+
if (s.ranged) s.ranged.flush();
|
|
812
|
+
else {
|
|
813
|
+
const bytes = s.data.slice(0, s.len);
|
|
814
|
+
node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
|
|
815
|
+
}
|
|
816
|
+
s.dirty = false;
|
|
518
817
|
} catch (err) {
|
|
519
818
|
throw toErrno(Fs, err);
|
|
520
819
|
}
|
|
@@ -532,8 +831,9 @@ function invalidateLiveVfs(Fs, plugin) {
|
|
|
532
831
|
s.listed = void 0;
|
|
533
832
|
if (s.openCount === 0) {
|
|
534
833
|
if (node !== node.mount.root && !node.mounted) drop.push(node);
|
|
535
|
-
} else if (s.
|
|
834
|
+
} else if (!s.dirty && !s.orphan) {
|
|
536
835
|
s.data = void 0;
|
|
836
|
+
s.ranged = void 0;
|
|
537
837
|
s.len = 0;
|
|
538
838
|
s.loaded = false;
|
|
539
839
|
}
|
|
@@ -652,6 +952,7 @@ var ERRNO_BY_CODE, EIO, S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM,
|
|
|
652
952
|
var init_live_vfs_fs = __esm({
|
|
653
953
|
"src/realm/live-vfs-fs.ts"() {
|
|
654
954
|
"use strict";
|
|
955
|
+
init_ranged();
|
|
655
956
|
init_types();
|
|
656
957
|
ERRNO_BY_CODE = {
|
|
657
958
|
EACCES: 2,
|
|
@@ -761,7 +1062,8 @@ function parseSyncFsStat(json) {
|
|
|
761
1062
|
...typeof s.ino === "number" ? { ino: s.ino } : {},
|
|
762
1063
|
...typeof s.dev === "number" ? { dev: s.dev } : {},
|
|
763
1064
|
...s.readonly === true ? { readonly: true } : {},
|
|
764
|
-
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {}
|
|
1065
|
+
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
|
|
1066
|
+
...s.ranged === true ? { ranged: true } : {}
|
|
765
1067
|
};
|
|
766
1068
|
}
|
|
767
1069
|
var SYNC_FS_REQUEST_TIMEOUT_MS;
|
|
@@ -773,6 +1075,9 @@ var init_sync_fs_wire = __esm({
|
|
|
773
1075
|
});
|
|
774
1076
|
|
|
775
1077
|
// src/realm/sync-sab-wire.ts
|
|
1078
|
+
function loadU53(header, lo, hi) {
|
|
1079
|
+
return (Atomics.load(header, lo) >>> 0) + Atomics.load(header, hi) * U32;
|
|
1080
|
+
}
|
|
776
1081
|
function publishMemory(sab, bytes) {
|
|
777
1082
|
if (bytes > 0)
|
|
778
1083
|
Atomics.store(new Int32Array(sab, 0, SAB_HEADER_I32), SAB_I_MEMORY, Math.ceil(bytes / 65536));
|
|
@@ -812,7 +1117,7 @@ function sabViews(sab) {
|
|
|
812
1117
|
window: new Uint8Array(sab, SAB_HEADER_BYTES)
|
|
813
1118
|
};
|
|
814
1119
|
}
|
|
815
|
-
var SAB_HEADER_I32, SAB_HEADER_BYTES, SAB_I_STATE, SAB_I_SEQ, SAB_I_STATUS, SAB_I_TOTAL, SAB_I_CHUNK, SAB_I_OFFSET, SAB_I_REQ, SAB_I_PUB, SAB_I_SIGNALS, SAB_I_TIMERS, SAB_I_MEMORY, SAB_STATE_IDLE, SAB_STATE_PENDING, SAB_STATE_READY, SAB_STATUS_BYTES, SAB_STATUS_JSON, SAB_STATUS_VOID, SAB_STATUS_ERRNO, SAB_DEFAULT_WINDOW_BYTES, SAB_MIN_BYTES, SYNC_SAB_REQ_MSG, SYNC_SAB_NEXT_MSG, encoder, decoder;
|
|
1120
|
+
var SAB_HEADER_I32, SAB_HEADER_BYTES, SAB_I_STATE, SAB_I_SEQ, SAB_I_STATUS, SAB_I_TOTAL, SAB_I_CHUNK, SAB_I_OFFSET, SAB_I_REQ, SAB_I_PUB, SAB_I_SIGNALS, SAB_I_TIMERS, SAB_I_MEMORY, SAB_I_TOTAL_HI, SAB_I_OFFSET_HI, U32, SAB_STATE_IDLE, SAB_STATE_PENDING, SAB_STATE_READY, SAB_STATUS_BYTES, SAB_STATUS_JSON, SAB_STATUS_VOID, SAB_STATUS_ERRNO, SAB_DEFAULT_WINDOW_BYTES, SAB_MIN_BYTES, SYNC_SAB_REQ_MSG, SYNC_SAB_NEXT_MSG, encoder, decoder;
|
|
816
1121
|
var init_sync_sab_wire = __esm({
|
|
817
1122
|
"src/realm/sync-sab-wire.ts"() {
|
|
818
1123
|
"use strict";
|
|
@@ -829,6 +1134,9 @@ var init_sync_sab_wire = __esm({
|
|
|
829
1134
|
SAB_I_SIGNALS = 8;
|
|
830
1135
|
SAB_I_TIMERS = 9;
|
|
831
1136
|
SAB_I_MEMORY = 10;
|
|
1137
|
+
SAB_I_TOTAL_HI = 11;
|
|
1138
|
+
SAB_I_OFFSET_HI = 12;
|
|
1139
|
+
U32 = 2 ** 32;
|
|
832
1140
|
SAB_STATE_IDLE = 0;
|
|
833
1141
|
SAB_STATE_PENDING = 1;
|
|
834
1142
|
SAB_STATE_READY = 2;
|
|
@@ -864,7 +1172,7 @@ function createSyncSabTransport(sab, port2, deps = {}) {
|
|
|
864
1172
|
}
|
|
865
1173
|
}
|
|
866
1174
|
return {
|
|
867
|
-
call(req, timeoutMs, label) {
|
|
1175
|
+
call(req, timeoutMs, label, transfer = []) {
|
|
868
1176
|
if (deps.memory) publishMemory(sab, deps.memory());
|
|
869
1177
|
const id = ++seq;
|
|
870
1178
|
const deadline = now() + timeoutMs;
|
|
@@ -877,14 +1185,15 @@ function createSyncSabTransport(sab, port2, deps = {}) {
|
|
|
877
1185
|
Atomics.store(header, SAB_I_STATE, SAB_STATE_PENDING);
|
|
878
1186
|
const msg = offset === 0 ? { type: SYNC_SAB_REQ_MSG, id, req } : { type: SYNC_SAB_NEXT_MSG, id, offset };
|
|
879
1187
|
try {
|
|
880
|
-
port2.postMessage(msg);
|
|
1188
|
+
if (offset === 0 && transfer.length > 0) port2.postMessage(msg, transfer);
|
|
1189
|
+
else port2.postMessage(msg);
|
|
881
1190
|
} catch {
|
|
882
1191
|
throw syncError("EIO", label);
|
|
883
1192
|
}
|
|
884
1193
|
awaitReady(id, deadline, label);
|
|
885
|
-
const total =
|
|
1194
|
+
const total = loadU53(header, SAB_I_TOTAL, SAB_I_TOTAL_HI);
|
|
886
1195
|
const chunk = Atomics.load(header, SAB_I_CHUNK);
|
|
887
|
-
const at =
|
|
1196
|
+
const at = loadU53(header, SAB_I_OFFSET, SAB_I_OFFSET_HI);
|
|
888
1197
|
if (at !== offset || chunk < 0 || total < 0 || offset + chunk > total) {
|
|
889
1198
|
throw syncError("EIO", label);
|
|
890
1199
|
}
|
|
@@ -910,8 +1219,8 @@ function errnoError(code2, path) {
|
|
|
910
1219
|
}
|
|
911
1220
|
function createSyncFsSabBridge(transport, opts = {}) {
|
|
912
1221
|
const timeoutMs = opts.timeoutMs ?? SYNC_FS_REQUEST_TIMEOUT_MS;
|
|
913
|
-
function run(req, path) {
|
|
914
|
-
const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'
|
|
1222
|
+
function run(req, path, transfer) {
|
|
1223
|
+
const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'`, transfer);
|
|
915
1224
|
if (!result.ok) throw errnoError(result.errno, path);
|
|
916
1225
|
return result;
|
|
917
1226
|
}
|
|
@@ -995,7 +1304,16 @@ function createSyncFsSabBridge(transport, opts = {}) {
|
|
|
995
1304
|
hold: (path, held) => {
|
|
996
1305
|
run({ op: "hold", path, mode: held ? 1 : 0 }, path);
|
|
997
1306
|
},
|
|
998
|
-
statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path))
|
|
1307
|
+
statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path)),
|
|
1308
|
+
pread: (path, offset, length) => bytes({ op: "pread", path, offset, length }, path),
|
|
1309
|
+
pwrite: (path, offset, body, transfer) => {
|
|
1310
|
+
const whole = body.byteOffset === 0 && body.byteLength === body.buffer.byteLength;
|
|
1311
|
+
const owned = transfer && whole && body.buffer instanceof ArrayBuffer;
|
|
1312
|
+
run({ op: "pwrite", path, offset, body }, path, owned ? [body.buffer] : []);
|
|
1313
|
+
},
|
|
1314
|
+
truncate: (path, length) => {
|
|
1315
|
+
run({ op: "truncate", path, length }, path);
|
|
1316
|
+
}
|
|
999
1317
|
};
|
|
1000
1318
|
}
|
|
1001
1319
|
var init_sync_sab_bridge = __esm({
|
|
@@ -3462,6 +3780,11 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
3462
3780
|
symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
|
|
3463
3781
|
chmod: (p, mode) => mutating(() => bridge.chmod(p, mode)),
|
|
3464
3782
|
utimes: (p, a, m) => mutating(() => bridge.utimes(p, a, m)),
|
|
3783
|
+
...bridge.pread && bridge.pwrite && bridge.truncate ? {
|
|
3784
|
+
pread: bridge.pread.bind(bridge),
|
|
3785
|
+
pwrite: (p, at, bytes, transfer) => mutating(() => bridge.pwrite?.(p, at, bytes, transfer)),
|
|
3786
|
+
truncate: (p, size) => mutating(() => bridge.truncate?.(p, size))
|
|
3787
|
+
} : {},
|
|
3465
3788
|
invalidate
|
|
3466
3789
|
};
|
|
3467
3790
|
}
|
|
@@ -3469,6 +3792,7 @@ var WasiError, FileBuffer, LocalFile, MISS_TTL_MS;
|
|
|
3469
3792
|
var init_wasi_files = __esm({
|
|
3470
3793
|
"src/process/wasi/wasi-files.ts"() {
|
|
3471
3794
|
"use strict";
|
|
3795
|
+
init_ranged();
|
|
3472
3796
|
WasiError = class extends Error {
|
|
3473
3797
|
code;
|
|
3474
3798
|
constructor(code2) {
|
|
@@ -3483,17 +3807,37 @@ var init_wasi_files = __esm({
|
|
|
3483
3807
|
orphaned = false;
|
|
3484
3808
|
opens = 0;
|
|
3485
3809
|
fs;
|
|
3486
|
-
|
|
3810
|
+
where;
|
|
3811
|
+
ranged;
|
|
3487
3812
|
maxFile;
|
|
3488
|
-
constructor(fs, path, empty, maxFile) {
|
|
3813
|
+
constructor(fs, path, empty, maxFile, size) {
|
|
3489
3814
|
this.fs = fs;
|
|
3490
|
-
this.
|
|
3815
|
+
this.where = path;
|
|
3491
3816
|
this.maxFile = maxFile;
|
|
3492
|
-
|
|
3817
|
+
const { pread, pwrite, truncate } = fs;
|
|
3818
|
+
if (size !== void 0 && pread && pwrite && truncate) {
|
|
3819
|
+
const io = { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };
|
|
3820
|
+
this.ranged = new RangedFile(io, path, size);
|
|
3821
|
+
if (empty) this.truncate(0);
|
|
3822
|
+
} else if (empty) {
|
|
3493
3823
|
this.data = new Uint8Array(0);
|
|
3494
3824
|
this.dirty = true;
|
|
3495
3825
|
}
|
|
3496
3826
|
}
|
|
3827
|
+
get path() {
|
|
3828
|
+
return this.where;
|
|
3829
|
+
}
|
|
3830
|
+
set path(path) {
|
|
3831
|
+
this.where = path;
|
|
3832
|
+
if (this.ranged) this.ranged.path = path;
|
|
3833
|
+
}
|
|
3834
|
+
get isRanged() {
|
|
3835
|
+
return this.ranged !== void 0;
|
|
3836
|
+
}
|
|
3837
|
+
keep() {
|
|
3838
|
+
if (this.ranged) this.ranged.pin();
|
|
3839
|
+
else this.load();
|
|
3840
|
+
}
|
|
3497
3841
|
load() {
|
|
3498
3842
|
if (!this.data) {
|
|
3499
3843
|
this.data = this.fs.readFile(this.path);
|
|
@@ -3502,10 +3846,12 @@ var init_wasi_files = __esm({
|
|
|
3502
3846
|
return this.data;
|
|
3503
3847
|
}
|
|
3504
3848
|
size() {
|
|
3849
|
+
if (this.ranged) return this.ranged.size();
|
|
3505
3850
|
this.load();
|
|
3506
3851
|
return this.length;
|
|
3507
3852
|
}
|
|
3508
3853
|
pread(max, at) {
|
|
3854
|
+
if (this.ranged) return this.ranged.read(at, max);
|
|
3509
3855
|
const bytes = this.load();
|
|
3510
3856
|
const n = Math.max(0, Math.min(max, this.length - at));
|
|
3511
3857
|
return bytes.subarray(at, at + n);
|
|
@@ -3517,22 +3863,30 @@ var init_wasi_files = __esm({
|
|
|
3517
3863
|
if (bytes.length === 0) return 0;
|
|
3518
3864
|
const end = at + bytes.length;
|
|
3519
3865
|
this.fits(end);
|
|
3866
|
+
this.dirty = true;
|
|
3867
|
+
if (this.ranged) {
|
|
3868
|
+
this.ranged.write(at, bytes);
|
|
3869
|
+
return bytes.length;
|
|
3870
|
+
}
|
|
3520
3871
|
this.load();
|
|
3521
3872
|
this.ensure(end);
|
|
3522
3873
|
const buf = this.data;
|
|
3523
3874
|
if (at > this.length) buf.fill(0, this.length, at);
|
|
3524
3875
|
buf.set(bytes, at);
|
|
3525
3876
|
this.length = Math.max(this.length, end);
|
|
3526
|
-
this.dirty = true;
|
|
3527
3877
|
return bytes.length;
|
|
3528
3878
|
}
|
|
3529
3879
|
truncate(size) {
|
|
3530
3880
|
this.fits(size);
|
|
3881
|
+
this.dirty = true;
|
|
3882
|
+
if (this.ranged) {
|
|
3883
|
+
this.ranged.truncate(size);
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3531
3886
|
this.load();
|
|
3532
3887
|
this.ensure(size);
|
|
3533
3888
|
if (size > this.length) this.data.fill(0, this.length, size);
|
|
3534
3889
|
this.length = size;
|
|
3535
|
-
this.dirty = true;
|
|
3536
3890
|
}
|
|
3537
3891
|
ensure(need) {
|
|
3538
3892
|
const cur = this.data;
|
|
@@ -3543,6 +3897,7 @@ var init_wasi_files = __esm({
|
|
|
3543
3897
|
}
|
|
3544
3898
|
orphan() {
|
|
3545
3899
|
this.orphaned = true;
|
|
3900
|
+
this.ranged?.pin();
|
|
3546
3901
|
}
|
|
3547
3902
|
isOrphan() {
|
|
3548
3903
|
return this.orphaned;
|
|
@@ -3551,11 +3906,14 @@ var init_wasi_files = __esm({
|
|
|
3551
3906
|
return this.dirty;
|
|
3552
3907
|
}
|
|
3553
3908
|
contents() {
|
|
3909
|
+
if (this.ranged) return this.ranged.read(0, this.ranged.size());
|
|
3554
3910
|
return this.load().slice(0, this.length);
|
|
3555
3911
|
}
|
|
3556
3912
|
flush() {
|
|
3557
|
-
if (this.orphaned || !this.dirty
|
|
3558
|
-
|
|
3913
|
+
if (this.orphaned || !this.dirty) return;
|
|
3914
|
+
if (this.ranged) this.ranged.flush();
|
|
3915
|
+
else if (this.data) this.fs.writeFile(this.path, this.data.slice(0, this.length));
|
|
3916
|
+
else return;
|
|
3559
3917
|
this.dirty = false;
|
|
3560
3918
|
}
|
|
3561
3919
|
};
|
|
@@ -3765,7 +4123,8 @@ function openAccess(existing, oflags, rights) {
|
|
|
3765
4123
|
}
|
|
3766
4124
|
function promoteRequest(fd, f, handed) {
|
|
3767
4125
|
const orphan = f.buffer.isOrphan();
|
|
3768
|
-
|
|
4126
|
+
if (!orphan && f.buffer.isRanged) f.buffer.flush();
|
|
4127
|
+
const joins = !orphan && (handed.has(f.buffer) || f.buffer.isRanged);
|
|
3769
4128
|
return {
|
|
3770
4129
|
op: "fd-promote",
|
|
3771
4130
|
fd,
|
|
@@ -4107,7 +4466,7 @@ var init_wasi_fds = __esm({
|
|
|
4107
4466
|
if (this.shared) this.kernel.call({ op: "fd-path-flush", path });
|
|
4108
4467
|
}
|
|
4109
4468
|
unlinking(path) {
|
|
4110
|
-
this.buffers.get(path)?.
|
|
4469
|
+
this.buffers.get(path)?.keep();
|
|
4111
4470
|
if (this.shared) this.kernel.call({ op: "fd-path-unlinking", path });
|
|
4112
4471
|
}
|
|
4113
4472
|
unlinked(path) {
|
|
@@ -4168,7 +4527,8 @@ var init_wasi_fds = __esm({
|
|
|
4168
4527
|
} else {
|
|
4169
4528
|
if (!existing) this.fs.writeFile(path, new Uint8Array(0));
|
|
4170
4529
|
const empty = !existing || (oflags & OFLAGS.TRUNC) !== 0;
|
|
4171
|
-
|
|
4530
|
+
const st = existing ?? this.fs.stat(path);
|
|
4531
|
+
buffer = new FileBuffer(this.fs, path, empty, st.maxFile, st.ranged ? st.size : void 0);
|
|
4172
4532
|
this.buffers.set(path, buffer);
|
|
4173
4533
|
}
|
|
4174
4534
|
buffer.opens++;
|
|
@@ -5480,7 +5840,7 @@ function align(n, to) {
|
|
|
5480
5840
|
return Math.ceil(n / to) * to;
|
|
5481
5841
|
}
|
|
5482
5842
|
function growTo(memory, bytes) {
|
|
5483
|
-
const pages2 = Math.ceil(bytes /
|
|
5843
|
+
const pages2 = Math.ceil(bytes / PAGE2) - memory.buffer.byteLength / PAGE2;
|
|
5484
5844
|
if (pages2 > 0) memory.grow(pages2);
|
|
5485
5845
|
}
|
|
5486
5846
|
function growTable(table, length) {
|
|
@@ -5490,14 +5850,14 @@ function call(instance, name) {
|
|
|
5490
5850
|
const fn = instance.exports[name];
|
|
5491
5851
|
if (typeof fn === "function") fn();
|
|
5492
5852
|
}
|
|
5493
|
-
var TABLE_BASE,
|
|
5853
|
+
var TABLE_BASE, PAGE2, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
|
|
5494
5854
|
var init_wasix_linker = __esm({
|
|
5495
5855
|
"src/process/wasi/wasix-linker.ts"() {
|
|
5496
5856
|
"use strict";
|
|
5497
5857
|
init_dylink();
|
|
5498
5858
|
init_wasi_files();
|
|
5499
5859
|
TABLE_BASE = 1;
|
|
5500
|
-
|
|
5860
|
+
PAGE2 = 65536;
|
|
5501
5861
|
STACK_SIZE = 8 * 1024 * 1024;
|
|
5502
5862
|
LIBRARY_DIRS = ["/lib", "/usr/lib", "/usr/local/lib"];
|
|
5503
5863
|
DlError = class extends Error {
|