@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.
@@ -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
- return { ...node.live.stat, size: node.live.len };
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.orphan) return;
207
- const bytes = s.data.slice(0, s.len);
208
- call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
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
- ensureLoaded(open);
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
- if (!ownedBy(plugin, node) || !node.live.dirty || !node.live.data) continue;
808
+ const s = node.live;
809
+ if (!ownedBy(plugin, node) || !s.dirty || !(s.data || s.ranged)) continue;
514
810
  try {
515
- const bytes = node.live.data.slice(0, node.live.len);
516
- node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
517
- node.live.dirty = false;
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.loaded && !s.dirty) {
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, port, 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, port, 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
- port.postMessage(msg);
1188
+ if (offset === 0 && transfer.length > 0) port.postMessage(msg, transfer);
1189
+ else port.postMessage(msg);
881
1190
  } catch {
882
1191
  throw syncError("EIO", label);
883
1192
  }
884
1193
  awaitReady(id, deadline, label);
885
- const total = Atomics.load(header, SAB_I_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 = Atomics.load(header, SAB_I_OFFSET);
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
- path;
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.path = path;
3815
+ this.where = path;
3491
3816
  this.maxFile = maxFile;
3492
- if (empty) {
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 || !this.data) return;
3558
- this.fs.writeFile(this.path, this.data.slice(0, this.length));
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
- const joins = !orphan && handed.has(f.buffer);
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)?.load();
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
- buffer = new FileBuffer(this.fs, path, empty, (existing ?? this.fs.stat(path)).maxFile);
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 / PAGE) - memory.buffer.byteLength / PAGE;
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, PAGE, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
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
- PAGE = 65536;
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 {