@daugasauron/dolly 0.0.0-stage → 0.1.4-rc.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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -2
  3. package/dist/dolly-build-id.mjs +1 -0
  4. package/dist/dolly-dso-0.wasm +0 -0
  5. package/dist/dolly-image-build-id.mjs +1 -0
  6. package/dist/dolly-kernel-plugin-abi.mjs +2 -0
  7. package/dist/dolly-process-0.wasm +0 -0
  8. package/dist/dolly-process-abi.mjs +1 -0
  9. package/dist/dolly-process-dso.mjs +1575 -0
  10. package/dist/dolly-process-gate-0.wasm +0 -0
  11. package/dist/dolly-process-stack.mjs +50 -0
  12. package/dist/dolly-process-worker.mjs +275 -0
  13. package/dist/dolly-threads-0.wasm +0 -0
  14. package/dist/dolly.wasm +0 -0
  15. package/host/abi.mjs +5 -0
  16. package/host/dso/abi.mjs +13 -0
  17. package/host/dso/dso.mjs +26 -0
  18. package/host/dso/module.json +15 -0
  19. package/host/http/abi.mjs +28 -0
  20. package/host/http/broker.mjs +325 -0
  21. package/host/http/http.mjs +74 -0
  22. package/host/http/local-services.mjs +37 -0
  23. package/host/http/module.json +15 -0
  24. package/host/http/policy.mjs +293 -0
  25. package/host/modules.mjs +373 -0
  26. package/host/nena/abi.mjs +19 -0
  27. package/host/nena/module.json +15 -0
  28. package/host/nena/nena.mjs +131 -0
  29. package/host/packages/module.json +13 -0
  30. package/host/packages/packages.mjs +15 -0
  31. package/host/packages/service.mjs +59 -0
  32. package/host/requirements.mjs +62 -0
  33. package/host/runtime/abi.mjs +8 -0
  34. package/host/runtime/boot-files.mjs +45 -0
  35. package/host/runtime/grower.mjs +14 -0
  36. package/host/runtime/lease-bridge.mjs +65 -0
  37. package/host/runtime/module.json +16 -0
  38. package/host/runtime/runtime.mjs +209 -0
  39. package/host/snapshot/abi.mjs +16 -0
  40. package/host/snapshot/module.json +15 -0
  41. package/host/snapshot/snapshot.mjs +138 -0
  42. package/host/snapshot/transport.mjs +132 -0
  43. package/host/snapshot/ui.mjs +207 -0
  44. package/host/stack/abi.mjs +5 -0
  45. package/host/stack/module.json +17 -0
  46. package/host/stack/stack.mjs +19 -0
  47. package/host/threads/abi.mjs +8 -0
  48. package/host/threads/module.json +13 -0
  49. package/host/threads/threads.mjs +36 -0
  50. package/package.json +12 -4
  51. package/src/alphabetical.mjs +4 -0
  52. package/src/browser.mjs +237 -0
  53. package/src/build-log.mjs +30 -0
  54. package/src/image-entry.mjs +29 -0
  55. package/src/image-inputs.mjs +20 -0
  56. package/src/image-names.mjs +11 -0
  57. package/src/images.mjs +10 -0
  58. package/src/kernel-plugin.mjs +77 -0
  59. package/src/packaged-snapshot.mjs +175 -0
  60. package/src/page-chords.mjs +43 -0
  61. package/src/page-indicators.mjs +27 -0
  62. package/src/process-abi.mjs +69 -0
  63. package/src/process-constants.mjs +242 -0
  64. package/src/process-supervisor.mjs +1002 -0
  65. package/src/runtime-worker.mjs +55 -0
  66. package/src/session-store.mjs +198 -0
  67. package/src/snapshot-records.mjs +109 -0
  68. package/src/static-asset.mjs +97 -0
  69. package/src/terminal-text.mjs +72 -0
  70. package/src/version.mjs +3 -0
  71. package/src/wasm-interface.mjs +440 -0
  72. package/src/worker-image.mjs +137 -0
@@ -0,0 +1,1575 @@
1
+ // dist/dolly-process-abi.mjs
2
+ var DOLLY_PROCESS_ABI_DIGEST = "8002d2ac9e15e7d366e3eae77fdb1c61ac7650239792dc0c1ca64b7a1c3f4730";
3
+
4
+ // host/dso/abi.mjs
5
+ var DOLLY_DSO_OPEN = 112;
6
+ var DOLLY_DSO_SYMBOL = 113;
7
+ var DOLLY_DSO_CLOSE = 114;
8
+ var DOLLY_DSO_GLOBAL = 1;
9
+ var DOLLY_DSO_LIMIT = 536870912;
10
+ var DOLLY_DSO_ERROR_CAPACITY = 240;
11
+ var DOLLY_FFI_CALL = 120;
12
+ var DOLLY_FFI_CLOSURE_ALLOC = 121;
13
+ var DOLLY_FFI_CLOSURE_FREE = 122;
14
+ var DOLLY_FFI_CLOSURE_PREP = 123;
15
+ var DOLLY_ERRNO = Object.freeze({ E2BIG: 1, EACCES: 2, EADDRINUSE: 3, EADDRNOTAVAIL: 4, EAFNOSUPPORT: 5, EAGAIN: 6, EALREADY: 7, EBADF: 8, EBADMSG: 9, EBUSY: 10, ECANCELED: 11, ECHILD: 12, ECONNABORTED: 13, ECONNREFUSED: 14, ECONNRESET: 15, EDEADLK: 16, EDESTADDRREQ: 17, EDOM: 18, EDQUOT: 19, EEXIST: 20, EFAULT: 21, EFBIG: 22, EHOSTUNREACH: 23, EIDRM: 24, EILSEQ: 25, EINPROGRESS: 26, EINTR: 27, EINVAL: 28, EIO: 29, EISCONN: 30, EISDIR: 31, ELOOP: 32, EMFILE: 33, EMLINK: 34, EMSGSIZE: 35, EMULTIHOP: 36, ENAMETOOLONG: 37, ENETDOWN: 38, ENETRESET: 39, ENETUNREACH: 40, ENFILE: 41, ENOBUFS: 42, ENODEV: 43, ENOENT: 44, ENOEXEC: 45, ENOLCK: 46, ENOLINK: 47, ENOMEM: 48, ENOMSG: 49, ENOPROTOOPT: 50, ENOSPC: 51, ENOSYS: 52, ENOTCONN: 53, ENOTDIR: 54, ENOTEMPTY: 55, ENOTRECOVERABLE: 56, ENOTSOCK: 57, ENOTTY: 59, ENXIO: 60, EOVERFLOW: 61, EOWNERDEAD: 62, EPERM: 63, EPIPE: 64, EPROTO: 65, EPROTONOSUPPORT: 66, EPROTOTYPE: 67, ERANGE: 68, EROFS: 69, ESPIPE: 70, ESRCH: 71, ESTALE: 72, ETIMEDOUT: 73, ETXTBSY: 74, EXDEV: 75, ENODATA: 116, ENOTSUP: 138 });
16
+
17
+ // src/wasm-interface.mjs
18
+ var decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
19
+ var valueTypes = /* @__PURE__ */ new Map([
20
+ [127, "i32"],
21
+ [126, "i64"],
22
+ [125, "f32"],
23
+ [124, "f64"],
24
+ [123, "v128"],
25
+ [112, "funcref"],
26
+ [111, "externref"],
27
+ [105, "exnref"],
28
+ [116, "nullexnref"]
29
+ ]);
30
+ var Reader = class _Reader {
31
+ constructor(bytes, label = "WebAssembly binary") {
32
+ this.bytes = bytes;
33
+ this.offset = 0;
34
+ this.label = label;
35
+ }
36
+ get done() {
37
+ return this.offset === this.bytes.length;
38
+ }
39
+ fail(message) {
40
+ throw new Error(`${this.label} at byte ${this.offset}: ${message}`);
41
+ }
42
+ u8() {
43
+ if (this.offset >= this.bytes.length) this.fail("unexpected end of file");
44
+ return this.bytes[this.offset++];
45
+ }
46
+ take(length) {
47
+ if (!Number.isSafeInteger(length) || length < 0 || this.offset + length > this.bytes.length) {
48
+ this.fail(`invalid byte range of length ${length}`);
49
+ }
50
+ const result = this.bytes.subarray(this.offset, this.offset + length);
51
+ this.offset += length;
52
+ return result;
53
+ }
54
+ subreader(length, label) {
55
+ return new _Reader(this.take(length), label);
56
+ }
57
+ unsigned(bits = 32) {
58
+ let result = 0n;
59
+ let shift = 0n;
60
+ const limit = Math.ceil(bits / 7);
61
+ for (let index = 0; index < limit; index += 1) {
62
+ const byte = this.u8();
63
+ result |= BigInt(byte & 127) << shift;
64
+ if ((byte & 128) === 0) {
65
+ if (result >= 1n << BigInt(bits)) this.fail(`unsigned LEB exceeds ${bits} bits`);
66
+ return result;
67
+ }
68
+ shift += 7n;
69
+ }
70
+ this.fail(`unterminated unsigned ${bits}-bit LEB`);
71
+ }
72
+ signed(bits = 32) {
73
+ let result = 0n;
74
+ let shift = 0n;
75
+ let byte = 0;
76
+ const limit = Math.ceil(bits / 7);
77
+ for (let index = 0; index < limit; index += 1) {
78
+ byte = this.u8();
79
+ result |= BigInt(byte & 127) << shift;
80
+ shift += 7n;
81
+ if ((byte & 128) === 0) {
82
+ if ((byte & 64) !== 0 && shift < BigInt(bits)) result |= -1n << shift;
83
+ return result;
84
+ }
85
+ }
86
+ this.fail(`unterminated signed ${bits}-bit LEB`);
87
+ }
88
+ u32() {
89
+ return Number(this.unsigned(32));
90
+ }
91
+ string() {
92
+ const length = this.u32();
93
+ try {
94
+ return decoder.decode(this.take(length));
95
+ } catch {
96
+ this.fail("invalid UTF-8 string");
97
+ }
98
+ }
99
+ };
100
+ function readValueType(reader) {
101
+ const byte = reader.u8();
102
+ const type = valueTypes.get(byte);
103
+ if (!type) reader.fail(`unsupported value type 0x${byte.toString(16)}`);
104
+ return type;
105
+ }
106
+ function readVector(reader, readElement, result = []) {
107
+ const count = reader.u32();
108
+ if (count > reader.bytes.length - reader.offset) reader.fail("vector count exceeds section size");
109
+ for (let index = 0; index < count; index++) result.push(readElement(reader));
110
+ return result;
111
+ }
112
+ function readLimits(reader) {
113
+ const flags = reader.u32();
114
+ if ((flags & ~7) !== 0) reader.fail(`unsupported limits flags 0x${flags.toString(16)}`);
115
+ const hasMaximum = (flags & 1) !== 0;
116
+ const shared = (flags & 2) !== 0;
117
+ const address64 = (flags & 4) !== 0;
118
+ const readBound = () => reader.unsigned(address64 ? 64 : 32);
119
+ const minimum = readBound();
120
+ const maximum = hasMaximum ? readBound() : null;
121
+ if (shared && maximum === null) reader.fail("shared limits require a maximum");
122
+ return { minimum, maximum, shared, address64 };
123
+ }
124
+ function readTableType(reader) {
125
+ return { kind: "table", element: readValueType(reader), ...readLimits(reader) };
126
+ }
127
+ function readMemoryType(reader) {
128
+ return { kind: "memory", ...readLimits(reader) };
129
+ }
130
+ function readGlobalType(reader) {
131
+ return { kind: "global", value: readValueType(reader), mutable: reader.u8() !== 0 };
132
+ }
133
+ function readTagType(reader, types) {
134
+ const attribute = reader.u32();
135
+ return { kind: "tag", attribute, type: functionType(types, reader.u32(), reader) };
136
+ }
137
+ function skipConstantExpression(reader) {
138
+ for (; ; ) {
139
+ const opcode = reader.u8();
140
+ switch (opcode) {
141
+ case 11:
142
+ return;
143
+ case 65:
144
+ reader.signed(32);
145
+ break;
146
+ case 66:
147
+ reader.signed(64);
148
+ break;
149
+ case 67:
150
+ reader.take(4);
151
+ break;
152
+ case 68:
153
+ reader.take(8);
154
+ break;
155
+ case 35:
156
+ case 210:
157
+ reader.u32();
158
+ break;
159
+ case 208:
160
+ readValueType(reader);
161
+ break;
162
+ case 106:
163
+ // i32.add
164
+ case 107:
165
+ // i32.sub
166
+ case 108:
167
+ // i32.mul
168
+ case 124:
169
+ // i64.add
170
+ case 125:
171
+ // i64.sub
172
+ case 126:
173
+ break;
174
+ default:
175
+ reader.fail(`unsupported constant-expression opcode 0x${opcode.toString(16)}`);
176
+ }
177
+ }
178
+ }
179
+ function readElementExpression(reader) {
180
+ const opcode = reader.u8();
181
+ let index = null;
182
+ if (opcode === 210) index = reader.u32();
183
+ else if (opcode === 208) readValueType(reader);
184
+ else reader.fail(`unsupported element expression opcode 0x${opcode.toString(16)}`);
185
+ if (reader.u8() !== 11) reader.fail("element expression has more than one instruction");
186
+ return index;
187
+ }
188
+ function readElementSegment(reader) {
189
+ const flags = reader.u32();
190
+ if (flags > 7) reader.fail(`unsupported element segment flags ${flags}`);
191
+ const active = (flags & 1) === 0;
192
+ if (flags === 2 || flags === 6) reader.u32();
193
+ if (active) skipConstantExpression(reader);
194
+ if (flags & 4) {
195
+ if (flags !== 4) readValueType(reader);
196
+ const indices2 = readVector(reader, readElementExpression);
197
+ return active ? indices2.filter((index) => index !== null) : [];
198
+ }
199
+ if (flags !== 0 && reader.u8() !== 0) reader.fail("unsupported element kind");
200
+ const indices = readVector(reader, (item) => item.u32());
201
+ return active ? indices : [];
202
+ }
203
+ function castEmulationParameters(tableFunctions) {
204
+ const [type] = tableFunctions;
205
+ const thunk = type && type.params.length >= 16 && type.params.every((param) => param === "i64") && type.results.length === 1 && type.results[0] === "i64";
206
+ return thunk && tableFunctions.every((other) => other === type) ? type.params.length : 0;
207
+ }
208
+ function functionType(types, index, reader) {
209
+ const type = types[index];
210
+ if (!type) reader.fail(`function references missing type ${index}`);
211
+ return type;
212
+ }
213
+ function parseWasmInterface(input, label = "WebAssembly binary") {
214
+ const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
215
+ const reader = new Reader(bytes, label);
216
+ const expectedHeader = [0, 97, 115, 109, 1, 0, 0, 0];
217
+ for (const byte of expectedHeader) {
218
+ if (reader.u8() !== byte) reader.fail("invalid WebAssembly header");
219
+ }
220
+ const types = [];
221
+ const imports = [];
222
+ const definedFunctionTypes = [];
223
+ const importedTables = [];
224
+ const definedTables = [];
225
+ const importedMemories = [];
226
+ const definedMemories = [];
227
+ const importedGlobals = [];
228
+ const definedGlobals = [];
229
+ const importedTags = [];
230
+ const definedTags = [];
231
+ const rawExports = [];
232
+ const tableFunctionIndices = [];
233
+ const customSections = [];
234
+ const customSectionData = [];
235
+ while (!reader.done) {
236
+ const id = reader.u8();
237
+ const size = reader.u32();
238
+ const section2 = reader.subreader(size, `${label} section ${id}`);
239
+ if (id === 0) {
240
+ const name = section2.string();
241
+ customSections.push(name);
242
+ customSectionData.push({ name, data: section2.take(section2.bytes.length - section2.offset) });
243
+ } else if (id === 1) {
244
+ readVector(section2, (item) => {
245
+ if (item.u8() !== 96) item.fail("only function types are supported");
246
+ return {
247
+ kind: "func",
248
+ params: readVector(item, readValueType),
249
+ results: readVector(item, readValueType)
250
+ };
251
+ }, types);
252
+ } else if (id === 2) {
253
+ readVector(section2, (item) => {
254
+ const module = item.string();
255
+ const name = item.string();
256
+ const externalKind = item.u8();
257
+ let type;
258
+ if (externalKind === 0) {
259
+ const typeIndex = item.u32();
260
+ type = functionType(types, typeIndex, item);
261
+ } else if (externalKind === 1) {
262
+ type = readTableType(item);
263
+ importedTables.push(type);
264
+ } else if (externalKind === 2) {
265
+ type = readMemoryType(item);
266
+ importedMemories.push(type);
267
+ } else if (externalKind === 3) {
268
+ type = readGlobalType(item);
269
+ importedGlobals.push(type);
270
+ } else if (externalKind === 4) {
271
+ type = readTagType(item, types);
272
+ importedTags.push(type);
273
+ } else {
274
+ item.fail(`unknown import kind ${externalKind}`);
275
+ }
276
+ return { module, name, type };
277
+ }, imports);
278
+ } else if (id === 3) {
279
+ readVector(section2, (item) => item.u32(), definedFunctionTypes);
280
+ } else if (id === 4) {
281
+ readVector(section2, readTableType, definedTables);
282
+ } else if (id === 5) {
283
+ readVector(section2, readMemoryType, definedMemories);
284
+ } else if (id === 6) {
285
+ readVector(section2, (item) => {
286
+ const type = readGlobalType(item);
287
+ skipConstantExpression(item);
288
+ return type;
289
+ }, definedGlobals);
290
+ } else if (id === 7) {
291
+ readVector(section2, (item) => ({
292
+ name: item.string(),
293
+ externalKind: item.u8(),
294
+ index: item.u32()
295
+ }), rawExports);
296
+ } else if (id === 9) {
297
+ for (const indices of readVector(section2, readElementSegment)) for (const index of indices) tableFunctionIndices.push(index);
298
+ } else if (id === 13) {
299
+ readVector(section2, (item) => readTagType(item, types), definedTags);
300
+ } else {
301
+ section2.take(section2.bytes.length - section2.offset);
302
+ }
303
+ if (!section2.done) section2.fail("section has trailing bytes");
304
+ }
305
+ const importedFunctions = imports.filter((entry) => entry.type.kind === "func").map((entry) => entry.type);
306
+ const functions = [
307
+ ...importedFunctions,
308
+ ...definedFunctionTypes.map((index) => functionType(types, index, reader))
309
+ ];
310
+ const tables = [...importedTables, ...definedTables];
311
+ const memories = [...importedMemories, ...definedMemories];
312
+ const globals = [...importedGlobals, ...definedGlobals];
313
+ const collections = [functions, tables, memories, globals, [...importedTags, ...definedTags]];
314
+ const kindNames = ["func", "table", "memory", "global", "tag"];
315
+ const exports = rawExports.map(({ name, externalKind, index }) => {
316
+ const collection = collections[externalKind];
317
+ const type = collection?.[index];
318
+ if (!type) reader.fail(`export ${name} references unknown ${kindNames[externalKind] ?? externalKind} ${index}`);
319
+ return { name, type };
320
+ });
321
+ const tableFunctions = tableFunctionIndices.map((index) => functions[index] ?? reader.fail(`element segment references unknown function ${index}`));
322
+ return {
323
+ label,
324
+ imports,
325
+ exports,
326
+ castEmulationParameters: castEmulationParameters(tableFunctions),
327
+ customSections,
328
+ customSectionData
329
+ };
330
+ }
331
+ function formatLimits(type) {
332
+ const width = type.address64 ? "64" : "32";
333
+ const maximum = type.maximum === null ? "*" : type.maximum;
334
+ return `${width}(min=${type.minimum},max=${maximum}${type.shared ? ",shared" : ""})`;
335
+ }
336
+ function formatWasmType(type) {
337
+ if (type.kind === "func") {
338
+ return `func(${type.params.join(",")})->(${type.results.join(",")})`;
339
+ }
340
+ if (type.kind === "global") {
341
+ return `global(${type.mutable ? "mut " : ""}${type.value})`;
342
+ }
343
+ if (type.kind === "memory") return `memory${formatLimits(type)}`;
344
+ if (type.kind === "table") return `table${formatLimits(type)}:${type.element}`;
345
+ if (type.kind === "tag") return `tag(${formatWasmType(type.type)})`;
346
+ throw new Error(`unknown WebAssembly type kind ${type.kind}`);
347
+ }
348
+ function arraysEqual(left, right) {
349
+ return left.length === right.length && left.every((value, index) => value === right[index]);
350
+ }
351
+ function sameWasmType(left, right) {
352
+ if (left.kind !== right.kind) return false;
353
+ if (left.kind === "func") {
354
+ return arraysEqual(left.params, right.params) && arraysEqual(left.results, right.results);
355
+ }
356
+ if (left.kind === "global") return left.value === right.value && left.mutable === right.mutable;
357
+ if (left.kind === "tag") return left.attribute === right.attribute && sameWasmType(left.type, right.type);
358
+ if (left.kind === "memory") {
359
+ return left.address64 === right.address64 && left.shared === right.shared && left.minimum === right.minimum && left.maximum === right.maximum;
360
+ }
361
+ if (left.kind === "table") {
362
+ return left.element === right.element && left.address64 === right.address64 && left.minimum === right.minimum && left.maximum === right.maximum;
363
+ }
364
+ return false;
365
+ }
366
+ function providerSatisfiesImport(provider, required, { dynamicTable = false } = {}) {
367
+ if (provider.kind !== required.kind) return false;
368
+ if (["func", "global", "tag"].includes(provider.kind)) return sameWasmType(provider, required);
369
+ if (provider.kind === "memory" || provider.kind === "table") {
370
+ if (provider.address64 !== required.address64 || provider.shared !== required.shared) return false;
371
+ if (provider.kind === "table" && provider.element !== required.element) return false;
372
+ if (!dynamicTable && provider.minimum < required.minimum) return false;
373
+ if (required.maximum !== null) {
374
+ if (provider.maximum === null || provider.maximum > required.maximum) return false;
375
+ }
376
+ return true;
377
+ }
378
+ return false;
379
+ }
380
+
381
+ // host/abi.mjs
382
+ var DOLLY_HOST_RECORD_BYTES = 72;
383
+ var DOLLY_HOST_NAME_BYTES = 32;
384
+ var DOLLY_HOST_DIGEST_BYTES = 32;
385
+ var DOLLY_HOST_MAX_RECORDS = 64;
386
+
387
+ // src/snapshot-records.mjs
388
+ var decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
389
+ var MAX_SNAPSHOT_BYTES = 2 * 1024 * 1024 * 1024;
390
+
391
+ // src/version.mjs
392
+ var DOLLY_VERSION = "0.1.4";
393
+
394
+ // src/static-asset.mjs
395
+ var STATIC_PART_BYTES = 20 * 1024 * 1024;
396
+ var hex = (bytes) => Array.from(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
397
+ var sitePrefix = `/v${DOLLY_VERSION}`;
398
+
399
+ // host/requirements.mjs
400
+ var pattern = /^([a-z][a-z0-9-]{0,30})@(0|[1-9][0-9]{0,4})$/;
401
+ function hostRequirement(value) {
402
+ const match = typeof value === "string" && pattern.exec(value);
403
+ if (!match || Number(match[2]) > 65535) throw new TypeError(`invalid host requirement: ${value}`);
404
+ return { name: match[1], version: Number(match[2]) };
405
+ }
406
+ function hostRequirements(values = []) {
407
+ if (!Array.isArray(values)) throw new TypeError("invalid host requirements");
408
+ const versions = /* @__PURE__ */ new Map();
409
+ for (const value of values) {
410
+ const { name, version } = hostRequirement(value);
411
+ if (versions.has(name) && versions.get(name) !== version) throw new Error(`conflicting host ABI requirements for ${name}`);
412
+ versions.set(name, version);
413
+ }
414
+ if (versions.size > DOLLY_HOST_MAX_RECORDS) throw new TypeError("too many host requirements");
415
+ return [...versions].sort(([a], [b]) => a.localeCompare(b)).map(([name, version]) => `${name}@${version}`);
416
+ }
417
+ function executableHostRequirements(module) {
418
+ const required = /* @__PURE__ */ new Map(), decoder4 = new TextDecoder("utf-8", { fatal: true });
419
+ let records = 0;
420
+ for (const { name, data } of module.customSectionData) {
421
+ if (name !== "dolly.host") continue;
422
+ records += data.length / DOLLY_HOST_RECORD_BYTES;
423
+ if (data.length === 0 || data.length % DOLLY_HOST_RECORD_BYTES || records > DOLLY_HOST_MAX_RECORDS) {
424
+ throw new Error("invalid dolly.host record count");
425
+ }
426
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
427
+ for (let offset = 0; offset < data.length; offset += DOLLY_HOST_RECORD_BYTES) {
428
+ const bytes = data.subarray(offset, offset + DOLLY_HOST_NAME_BYTES), end = bytes.indexOf(0);
429
+ if (end < 1 || bytes.subarray(end).some((byte) => byte !== 0) || view.getUint32(offset + DOLLY_HOST_NAME_BYTES + 4, true) !== 0) {
430
+ throw new Error("invalid dolly.host record");
431
+ }
432
+ const requirement = `${decoder4.decode(bytes.subarray(0, end))}@${view.getUint32(offset + DOLLY_HOST_NAME_BYTES, true)}`;
433
+ const digest = hex(data.subarray(offset + DOLLY_HOST_RECORD_BYTES - DOLLY_HOST_DIGEST_BYTES, offset + DOLLY_HOST_RECORD_BYTES));
434
+ if (required.has(requirement) && required.get(requirement) !== digest) {
435
+ throw new Error(`conflicting host ABI digests for ${requirement}`);
436
+ }
437
+ required.set(requirement, digest);
438
+ }
439
+ }
440
+ hostRequirements([...required.keys()]);
441
+ return required;
442
+ }
443
+ function checkHostAbi(required, available) {
444
+ for (const [requirement, digest] of required) {
445
+ if (!available.has(requirement)) throw new Error(available.has("nena@0") ? `host module ${requirement} is not enabled: nena enable ${hostRequirement(requirement).name}` : `host module ${requirement} is not declared by this image (REQUIRES HOST)`);
446
+ if (available.get(requirement) !== digest) throw new Error(`host module ${requirement} has a different layout than this program was built for`);
447
+ }
448
+ }
449
+
450
+ // host/dso/ffi.mjs
451
+ var FFI_OK = 0;
452
+ var FFI_WASM64_EMSCRIPTEN = 2;
453
+ var VARARGS_FLAG = 1;
454
+ var MAX_ARGS = 1e3;
455
+ var FFI_TYPE_VOID = 0;
456
+ var FFI_TYPE_INT = 1;
457
+ var FFI_TYPE_FLOAT = 2;
458
+ var FFI_TYPE_DOUBLE = 3;
459
+ var FFI_TYPE_LONGDOUBLE = 4;
460
+ var FFI_TYPE_UINT8 = 5;
461
+ var FFI_TYPE_SINT8 = 6;
462
+ var FFI_TYPE_UINT16 = 7;
463
+ var FFI_TYPE_SINT16 = 8;
464
+ var FFI_TYPE_UINT32 = 9;
465
+ var FFI_TYPE_SINT32 = 10;
466
+ var FFI_TYPE_UINT64 = 11;
467
+ var FFI_TYPE_SINT64 = 12;
468
+ var FFI_TYPE_STRUCT = 13;
469
+ var FFI_TYPE_POINTER = 14;
470
+ var FFI_TYPE_COMPLEX = 15;
471
+ var localOperations = /* @__PURE__ */ new Set([
472
+ DOLLY_FFI_CALL,
473
+ DOLLY_FFI_CLOSURE_ALLOC,
474
+ DOLLY_FFI_CLOSURE_FREE,
475
+ DOLLY_FFI_CLOSURE_PREP
476
+ ]);
477
+ function uleb(value) {
478
+ const bytes = [];
479
+ let remaining = BigInt(value);
480
+ do {
481
+ let byte = Number(remaining & 0x7fn);
482
+ remaining >>= 7n;
483
+ if (remaining !== 0n) byte |= 128;
484
+ bytes.push(byte);
485
+ } while (remaining !== 0n);
486
+ return bytes;
487
+ }
488
+ var castEmulationBits = new DataView(new ArrayBuffer(8));
489
+ function toCastEmulation(values, types, parameters) {
490
+ if (values.length > parameters) {
491
+ throw new TypeError(`a cast-emulated call takes at most ${parameters} arguments`);
492
+ }
493
+ const converted = values.map((value, index) => {
494
+ switch (types[index]) {
495
+ case "i32":
496
+ return BigInt(value >>> 0);
497
+ case "f32":
498
+ castEmulationBits.setFloat32(0, value, true);
499
+ return BigInt(castEmulationBits.getUint32(0, true));
500
+ case "f64":
501
+ castEmulationBits.setFloat64(0, value, true);
502
+ return castEmulationBits.getBigUint64(0, true);
503
+ default:
504
+ return BigInt.asUintN(64, value);
505
+ }
506
+ });
507
+ while (converted.length < parameters) converted.push(0n);
508
+ return converted;
509
+ }
510
+ function fromCastEmulation(result, type) {
511
+ castEmulationBits.setBigUint64(0, BigInt.asUintN(64, result), true);
512
+ switch (type) {
513
+ case "i32":
514
+ return castEmulationBits.getInt32(0, true);
515
+ case "f32":
516
+ return castEmulationBits.getFloat32(0, true);
517
+ case "f64":
518
+ return castEmulationBits.getFloat64(0, true);
519
+ case "i64":
520
+ return result;
521
+ default:
522
+ return void 0;
523
+ }
524
+ }
525
+ function section(id, body) {
526
+ return [id, ...uleb(body.length), ...body];
527
+ }
528
+ function wasmName(value) {
529
+ const bytes = new TextEncoder().encode(value);
530
+ return [...uleb(bytes.length), ...bytes];
531
+ }
532
+ function wasmType(name) {
533
+ switch (name) {
534
+ case "i32":
535
+ return 127;
536
+ case "i64":
537
+ return 126;
538
+ case "f32":
539
+ return 125;
540
+ case "f64":
541
+ return 124;
542
+ default:
543
+ throw new TypeError(`unsupported FFI Wasm type ${name}`);
544
+ }
545
+ }
546
+ function typedWasmFunction(function_, parameters, result) {
547
+ const functionType2 = [
548
+ 96,
549
+ ...uleb(parameters.length),
550
+ ...parameters.map(wasmType),
551
+ ...result === null ? [0] : [1, wasmType(result)]
552
+ ];
553
+ const typeSection = section(1, [1, ...functionType2]);
554
+ const importSection = section(2, [
555
+ 1,
556
+ ...wasmName("dolly"),
557
+ ...wasmName("closure"),
558
+ 0,
559
+ 0
560
+ ]);
561
+ const exportSection = section(7, [
562
+ 1,
563
+ ...wasmName("closure"),
564
+ 0,
565
+ 0
566
+ ]);
567
+ const bytes = new Uint8Array([
568
+ 0,
569
+ 97,
570
+ 115,
571
+ 109,
572
+ 1,
573
+ 0,
574
+ 0,
575
+ 0,
576
+ ...typeSection,
577
+ ...importSection,
578
+ ...exportSection
579
+ ]);
580
+ const module = new WebAssembly.Module(bytes);
581
+ return new WebAssembly.Instance(module, {
582
+ dolly: { closure: function_ }
583
+ }).exports.closure;
584
+ }
585
+ function createProcessFfi({
586
+ memory,
587
+ getInstance,
588
+ getTable,
589
+ growTable: growTable2,
590
+ setTable: setTable2,
591
+ castEmulationParameters: castEmulationParameters2 = 0
592
+ }) {
593
+ if (!(memory instanceof WebAssembly.Memory) || typeof getInstance !== "function" || typeof getTable !== "function" || typeof growTable2 !== "function" || typeof setTable2 !== "function") {
594
+ throw new TypeError("invalid process FFI configuration");
595
+ }
596
+ const closures = /* @__PURE__ */ new Map();
597
+ const freeTableIndices = [];
598
+ function asBigInt(value, description) {
599
+ if (typeof value === "bigint") return BigInt.asUintN(64, value);
600
+ if (Number.isSafeInteger(value) && value >= 0) return BigInt(value);
601
+ throw new RangeError(`invalid ${description}`);
602
+ }
603
+ function address(value, size = 0, description = "FFI address") {
604
+ const integer = asBigInt(value, description);
605
+ if (integer > BigInt(Number.MAX_SAFE_INTEGER)) {
606
+ throw new RangeError(`${description} exceeds JavaScript's exact address range`);
607
+ }
608
+ const result = Number(integer);
609
+ const length = memory.buffer.byteLength;
610
+ if (!Number.isSafeInteger(size) || size < 0 || result > length - size || size !== 0 && result === 0) {
611
+ throw new RangeError(`${description} is outside process memory`);
612
+ }
613
+ return result;
614
+ }
615
+ function view(value, size, description) {
616
+ return new DataView(memory.buffer, address(value, size, description), size);
617
+ }
618
+ function bytes(value, size, description) {
619
+ return new Uint8Array(memory.buffer, address(value, size, description), size);
620
+ }
621
+ function readPointer(value, offset = 0) {
622
+ return view(asBigInt(value, "pointer") + BigInt(offset), 8, "pointer field").getBigUint64(0, true);
623
+ }
624
+ function writePointer(value, offset, pointer) {
625
+ view(asBigInt(value, "pointer") + BigInt(offset), 8, "pointer field").setBigUint64(0, asBigInt(pointer, "pointer value"), true);
626
+ }
627
+ function typeInfo(typePointer) {
628
+ const pointer = asBigInt(typePointer, "ffi_type pointer");
629
+ const data = view(pointer, 24, "ffi_type");
630
+ const size = data.getBigUint64(0, true);
631
+ if (size > BigInt(Number.MAX_SAFE_INTEGER)) {
632
+ throw new RangeError("FFI type is too large");
633
+ }
634
+ return {
635
+ pointer,
636
+ size: Number(size),
637
+ alignment: data.getUint16(8, true),
638
+ id: data.getUint16(10, true),
639
+ elements: data.getBigUint64(16, true)
640
+ };
641
+ }
642
+ function unboxType(typePointer) {
643
+ let type = typeInfo(typePointer);
644
+ for (let depth = 0; type.id === FFI_TYPE_STRUCT; ++depth) {
645
+ if (depth === 64) throw new TypeError("recursive singleton FFI structure");
646
+ if (type.size > 16) break;
647
+ if (type.elements === 0n) return { ...type, id: FFI_TYPE_VOID };
648
+ const first = readPointer(type.elements, 0);
649
+ if (first === 0n) return { ...type, id: FFI_TYPE_VOID };
650
+ if (readPointer(type.elements, 8) !== 0n) break;
651
+ type = typeInfo(first);
652
+ }
653
+ return type;
654
+ }
655
+ function cifInfo(cifPointer) {
656
+ const pointer = asBigInt(cifPointer, "ffi_cif pointer");
657
+ const data = view(pointer, 36, "ffi_cif");
658
+ const abi = data.getUint32(0, true);
659
+ const nargs = data.getUint32(4, true);
660
+ const argTypes = data.getBigUint64(8, true);
661
+ const returnType = data.getBigUint64(16, true);
662
+ const flags = data.getUint32(28, true);
663
+ const fixed = data.getUint32(32, true);
664
+ if (abi !== FFI_WASM64_EMSCRIPTEN || nargs > MAX_ARGS || fixed > nargs || returnType === 0n || nargs !== 0 && argTypes === 0n) {
665
+ throw new TypeError("invalid wasm64 ffi_cif");
666
+ }
667
+ const types = [];
668
+ for (let index = 0; index < nargs; ++index) {
669
+ const typePointer = readPointer(argTypes, index * 8);
670
+ if (typePointer === 0n) throw new TypeError("null FFI argument type");
671
+ types.push(unboxType(typePointer));
672
+ }
673
+ return {
674
+ pointer,
675
+ nargs,
676
+ fixed,
677
+ flags,
678
+ types,
679
+ returnType: unboxType(returnType)
680
+ };
681
+ }
682
+ function stack() {
683
+ const global = getInstance()?.exports?.__stack_pointer;
684
+ if (!(global instanceof WebAssembly.Global) || typeof global.value !== "bigint") {
685
+ throw new TypeError("process has no memory64 stack pointer");
686
+ }
687
+ const original = BigInt.asUintN(64, global.value);
688
+ let current = original;
689
+ return {
690
+ allocate(size, alignment) {
691
+ if (!Number.isSafeInteger(size) || size < 0 || !Number.isSafeInteger(alignment) || alignment <= 0 || (alignment & alignment - 1) !== 0) {
692
+ throw new RangeError("invalid FFI stack allocation");
693
+ }
694
+ const count = BigInt(size);
695
+ const boundary = BigInt(alignment);
696
+ if (count > current) throw new RangeError("FFI stack exhausted");
697
+ current = current - count & -boundary;
698
+ address(current, size, "FFI stack allocation");
699
+ return current;
700
+ },
701
+ publish() {
702
+ current &= -16n;
703
+ address(current, 0, "FFI stack pointer");
704
+ global.value = current;
705
+ },
706
+ restore() {
707
+ global.value = original;
708
+ }
709
+ };
710
+ }
711
+ function copy(target, source, size) {
712
+ const destination = bytes(target, size, "FFI structure destination");
713
+ const input = new Uint8Array(bytes(source, size, "FFI structure source"));
714
+ destination.set(input);
715
+ }
716
+ function readArgument(pointer, type) {
717
+ const location = asBigInt(pointer, "FFI argument pointer");
718
+ switch (type.id) {
719
+ case FFI_TYPE_INT:
720
+ case FFI_TYPE_UINT32:
721
+ case FFI_TYPE_SINT32:
722
+ return [view(location, 4, "FFI i32 argument").getUint32(0, true)];
723
+ case FFI_TYPE_FLOAT:
724
+ return [view(location, 4, "FFI f32 argument").getFloat32(0, true)];
725
+ case FFI_TYPE_DOUBLE:
726
+ return [view(location, 8, "FFI f64 argument").getFloat64(0, true)];
727
+ case FFI_TYPE_UINT8:
728
+ return [view(location, 1, "FFI u8 argument").getUint8(0)];
729
+ case FFI_TYPE_SINT8:
730
+ return [view(location, 1, "FFI i8 argument").getInt8(0)];
731
+ case FFI_TYPE_UINT16:
732
+ return [view(location, 2, "FFI u16 argument").getUint16(0, true)];
733
+ case FFI_TYPE_SINT16:
734
+ return [view(location, 2, "FFI i16 argument").getInt16(0, true)];
735
+ case FFI_TYPE_UINT64:
736
+ case FFI_TYPE_SINT64:
737
+ case FFI_TYPE_POINTER:
738
+ return [view(location, 8, "FFI i64 argument").getBigUint64(0, true)];
739
+ case FFI_TYPE_LONGDOUBLE: {
740
+ const data = view(location, 16, "FFI long-double argument");
741
+ return [data.getBigUint64(0, true), data.getBigUint64(8, true)];
742
+ }
743
+ case FFI_TYPE_COMPLEX:
744
+ throw new TypeError("complex FFI arguments are unsupported");
745
+ default:
746
+ throw new TypeError(`unsupported FFI argument type ${type.id}`);
747
+ }
748
+ }
749
+ function storeResult(pointer, type, result) {
750
+ const location = asBigInt(pointer, "FFI result pointer");
751
+ switch (type.id) {
752
+ case FFI_TYPE_VOID:
753
+ return;
754
+ case FFI_TYPE_INT:
755
+ case FFI_TYPE_UINT32:
756
+ case FFI_TYPE_SINT32:
757
+ view(location, 4, "FFI i32 result").setUint32(0, result, true);
758
+ return;
759
+ case FFI_TYPE_FLOAT:
760
+ view(location, 4, "FFI f32 result").setFloat32(0, result, true);
761
+ return;
762
+ case FFI_TYPE_DOUBLE:
763
+ view(location, 8, "FFI f64 result").setFloat64(0, result, true);
764
+ return;
765
+ case FFI_TYPE_UINT8:
766
+ case FFI_TYPE_SINT8:
767
+ view(location, 1, "FFI i8 result").setUint8(0, result);
768
+ return;
769
+ case FFI_TYPE_UINT16:
770
+ case FFI_TYPE_SINT16:
771
+ view(location, 2, "FFI i16 result").setUint16(0, result, true);
772
+ return;
773
+ case FFI_TYPE_UINT64:
774
+ case FFI_TYPE_SINT64:
775
+ case FFI_TYPE_POINTER:
776
+ view(location, 8, "FFI i64 result").setBigUint64(
777
+ 0,
778
+ BigInt.asUintN(64, result),
779
+ true
780
+ );
781
+ return;
782
+ case FFI_TYPE_COMPLEX:
783
+ throw new TypeError("complex FFI results are unsupported");
784
+ default:
785
+ throw new TypeError(`unsupported FFI result type ${type.id}`);
786
+ }
787
+ }
788
+ function tableFunction(indexValue, description) {
789
+ const index = asBigInt(indexValue, `${description} table index`);
790
+ if (index >= getTable().length) {
791
+ throw new RangeError(`${description} table index is out of range`);
792
+ }
793
+ const function_ = getTable().get(index);
794
+ if (typeof function_ !== "function") {
795
+ throw new TypeError(`${description} table slot is empty`);
796
+ }
797
+ return function_;
798
+ }
799
+ function performCall(packet, entered) {
800
+ const cif = cifInfo(packet.getBigUint64(0, true));
801
+ const functionIndex2 = packet.getBigUint64(8, true);
802
+ const returnValue = packet.getBigUint64(16, true);
803
+ const argumentValues = packet.getBigUint64(24, true);
804
+ const frame = stack();
805
+ const arguments_ = [];
806
+ const types = [];
807
+ const push = (type, ...values) => {
808
+ for (const value of values) {
809
+ arguments_.push(value);
810
+ types.push(type);
811
+ }
812
+ };
813
+ const returnByArgument = cif.returnType.id === FFI_TYPE_STRUCT || cif.returnType.id === FFI_TYPE_LONGDOUBLE;
814
+ if (returnByArgument) push("i64", returnValue);
815
+ for (let index = 0; index < cif.fixed; ++index) {
816
+ const argumentPointer = readPointer(argumentValues, index * 8);
817
+ const type = cif.types[index];
818
+ if (type.id === FFI_TYPE_STRUCT) {
819
+ const temporary = frame.allocate(type.size, type.alignment);
820
+ copy(temporary, argumentPointer, type.size);
821
+ push("i64", temporary);
822
+ } else {
823
+ push(argumentWasmType(type), ...readArgument(argumentPointer, type));
824
+ }
825
+ }
826
+ if ((cif.flags & VARARGS_FLAG) !== 0) {
827
+ const structures = [];
828
+ for (let index = cif.nargs - 1; index >= cif.fixed; --index) {
829
+ const argumentPointer = readPointer(argumentValues, index * 8);
830
+ const type = cif.types[index];
831
+ switch (type.id) {
832
+ case FFI_TYPE_UINT8:
833
+ case FFI_TYPE_SINT8: {
834
+ const slot = frame.allocate(1, 1);
835
+ bytes(slot, 1, "FFI variadic byte")[0] = bytes(argumentPointer, 1, "FFI variadic byte source")[0];
836
+ break;
837
+ }
838
+ case FFI_TYPE_UINT16:
839
+ case FFI_TYPE_SINT16: {
840
+ const slot = frame.allocate(2, 2);
841
+ copy(slot, argumentPointer, 2);
842
+ break;
843
+ }
844
+ case FFI_TYPE_INT:
845
+ case FFI_TYPE_UINT32:
846
+ case FFI_TYPE_SINT32:
847
+ case FFI_TYPE_FLOAT: {
848
+ const slot = frame.allocate(4, 4);
849
+ copy(slot, argumentPointer, 4);
850
+ break;
851
+ }
852
+ case FFI_TYPE_DOUBLE:
853
+ case FFI_TYPE_UINT64:
854
+ case FFI_TYPE_SINT64:
855
+ case FFI_TYPE_POINTER: {
856
+ const slot = frame.allocate(8, 8);
857
+ copy(slot, argumentPointer, 8);
858
+ break;
859
+ }
860
+ case FFI_TYPE_LONGDOUBLE: {
861
+ const slot = frame.allocate(16, 8);
862
+ copy(slot, argumentPointer, 16);
863
+ break;
864
+ }
865
+ case FFI_TYPE_STRUCT: {
866
+ const pointerSlot = frame.allocate(8, 8);
867
+ structures.push({ pointerSlot, argumentPointer, type });
868
+ break;
869
+ }
870
+ default:
871
+ throw new TypeError(`unsupported variadic FFI type ${type.id}`);
872
+ }
873
+ }
874
+ const variadicArguments = frame.allocate(0, 1);
875
+ push("i64", variadicArguments);
876
+ for (const structure of structures) {
877
+ const temporary = frame.allocate(
878
+ structure.type.size,
879
+ structure.type.alignment
880
+ );
881
+ copy(temporary, structure.argumentPointer, structure.type.size);
882
+ writePointer(structure.pointerSlot, 0, temporary);
883
+ }
884
+ } else if (cif.fixed !== cif.nargs) {
885
+ throw new TypeError("inconsistent variadic FFI metadata");
886
+ }
887
+ frame.publish();
888
+ let result;
889
+ try {
890
+ const target = tableFunction(functionIndex2, "FFI target");
891
+ entered();
892
+ result = castEmulationParameters2 ? fromCastEmulation(
893
+ target(...toCastEmulation(arguments_, types, castEmulationParameters2)),
894
+ resultWasmType(cif.returnType)
895
+ ) : target(...arguments_);
896
+ } finally {
897
+ frame.restore();
898
+ }
899
+ if (!returnByArgument) storeResult(returnValue, cif.returnType, result);
900
+ }
901
+ function argumentWasmType(type) {
902
+ switch (type.id) {
903
+ case FFI_TYPE_FLOAT:
904
+ return "f32";
905
+ case FFI_TYPE_DOUBLE:
906
+ return "f64";
907
+ case FFI_TYPE_UINT64:
908
+ case FFI_TYPE_SINT64:
909
+ case FFI_TYPE_POINTER:
910
+ case FFI_TYPE_LONGDOUBLE:
911
+ return "i64";
912
+ default:
913
+ return "i32";
914
+ }
915
+ }
916
+ function resultWasmType(type) {
917
+ switch (type.id) {
918
+ case FFI_TYPE_VOID:
919
+ return null;
920
+ case FFI_TYPE_INT:
921
+ case FFI_TYPE_UINT8:
922
+ case FFI_TYPE_SINT8:
923
+ case FFI_TYPE_UINT16:
924
+ case FFI_TYPE_SINT16:
925
+ case FFI_TYPE_UINT32:
926
+ case FFI_TYPE_SINT32:
927
+ return "i32";
928
+ case FFI_TYPE_FLOAT:
929
+ return "f32";
930
+ case FFI_TYPE_DOUBLE:
931
+ return "f64";
932
+ case FFI_TYPE_UINT64:
933
+ case FFI_TYPE_SINT64:
934
+ case FFI_TYPE_POINTER:
935
+ return "i64";
936
+ case FFI_TYPE_STRUCT:
937
+ case FFI_TYPE_LONGDOUBLE:
938
+ return null;
939
+ default:
940
+ throw new TypeError(`unsupported FFI closure result type ${type.id}`);
941
+ }
942
+ }
943
+ function argumentWasmTypes(type) {
944
+ switch (type.id) {
945
+ case FFI_TYPE_INT:
946
+ case FFI_TYPE_UINT8:
947
+ case FFI_TYPE_SINT8:
948
+ case FFI_TYPE_UINT16:
949
+ case FFI_TYPE_SINT16:
950
+ case FFI_TYPE_UINT32:
951
+ case FFI_TYPE_SINT32:
952
+ return ["i32"];
953
+ case FFI_TYPE_FLOAT:
954
+ return ["f32"];
955
+ case FFI_TYPE_DOUBLE:
956
+ return ["f64"];
957
+ case FFI_TYPE_LONGDOUBLE:
958
+ return ["i64", "i64"];
959
+ case FFI_TYPE_UINT64:
960
+ case FFI_TYPE_SINT64:
961
+ case FFI_TYPE_STRUCT:
962
+ case FFI_TYPE_POINTER:
963
+ return ["i64"];
964
+ default:
965
+ throw new TypeError(`unsupported FFI closure argument type ${type.id}`);
966
+ }
967
+ }
968
+ function writeCallbackArgument(pointer, type, values, index) {
969
+ switch (type.id) {
970
+ case FFI_TYPE_UINT8:
971
+ case FFI_TYPE_SINT8:
972
+ view(pointer, 1, "FFI callback byte").setUint8(0, values[index]);
973
+ return index + 1;
974
+ case FFI_TYPE_UINT16:
975
+ case FFI_TYPE_SINT16:
976
+ view(pointer, 2, "FFI callback i16").setUint16(0, values[index], true);
977
+ return index + 1;
978
+ case FFI_TYPE_INT:
979
+ case FFI_TYPE_UINT32:
980
+ case FFI_TYPE_SINT32:
981
+ view(pointer, 4, "FFI callback i32").setUint32(0, values[index], true);
982
+ return index + 1;
983
+ case FFI_TYPE_FLOAT:
984
+ view(pointer, 4, "FFI callback f32").setFloat32(0, values[index], true);
985
+ return index + 1;
986
+ case FFI_TYPE_DOUBLE:
987
+ view(pointer, 8, "FFI callback f64").setFloat64(0, values[index], true);
988
+ return index + 1;
989
+ case FFI_TYPE_UINT64:
990
+ case FFI_TYPE_SINT64:
991
+ case FFI_TYPE_POINTER:
992
+ view(pointer, 8, "FFI callback i64").setBigUint64(
993
+ 0,
994
+ BigInt.asUintN(64, values[index]),
995
+ true
996
+ );
997
+ return index + 1;
998
+ case FFI_TYPE_LONGDOUBLE: {
999
+ const data = view(pointer, 16, "FFI callback long double");
1000
+ data.setBigUint64(0, BigInt.asUintN(64, values[index]), true);
1001
+ data.setBigUint64(8, BigInt.asUintN(64, values[index + 1]), true);
1002
+ return index + 2;
1003
+ }
1004
+ default:
1005
+ throw new TypeError(`unsupported FFI callback type ${type.id}`);
1006
+ }
1007
+ }
1008
+ function callbackResult(pointer, type) {
1009
+ switch (resultWasmType(type)) {
1010
+ case null:
1011
+ return void 0;
1012
+ case "i32":
1013
+ return view(pointer, 4, "FFI callback result").getUint32(0, true);
1014
+ case "i64":
1015
+ return view(pointer, 8, "FFI callback result").getBigUint64(0, true);
1016
+ case "f32":
1017
+ return view(pointer, 4, "FFI callback result").getFloat32(0, true);
1018
+ case "f64":
1019
+ return view(pointer, 8, "FFI callback result").getFloat64(0, true);
1020
+ default:
1021
+ throw new TypeError("invalid FFI callback result");
1022
+ }
1023
+ }
1024
+ function prepareClosure(closure, cif, callbackIndex, userData) {
1025
+ const returnByArgument = cif.returnType.id === FFI_TYPE_STRUCT || cif.returnType.id === FFI_TYPE_LONGDOUBLE;
1026
+ const parameters = [];
1027
+ if (returnByArgument) parameters.push("i64");
1028
+ for (let index = 0; index < cif.fixed; ++index) {
1029
+ parameters.push(...argumentWasmTypes(cif.types[index]));
1030
+ }
1031
+ if ((cif.flags & VARARGS_FLAG) !== 0) parameters.push("i64");
1032
+ const result = returnByArgument ? null : resultWasmType(cif.returnType);
1033
+ return typedWasmFunction((...arguments_) => {
1034
+ const frame = stack();
1035
+ let valueIndex = 0;
1036
+ const returnPointer = returnByArgument ? asBigInt(arguments_[valueIndex++], "FFI closure return pointer") : frame.allocate(8, 8);
1037
+ const argumentArray = frame.allocate(cif.nargs * 8, 8);
1038
+ for (let index = 0; index < cif.fixed; ++index) {
1039
+ const type = cif.types[index];
1040
+ let argumentPointer;
1041
+ if (type.id === FFI_TYPE_STRUCT) {
1042
+ const source = asBigInt(
1043
+ arguments_[valueIndex++],
1044
+ "FFI closure structure pointer"
1045
+ );
1046
+ argumentPointer = frame.allocate(type.size, type.alignment);
1047
+ copy(argumentPointer, source, type.size);
1048
+ } else {
1049
+ const alignment = type.id === FFI_TYPE_UINT8 || type.id === FFI_TYPE_SINT8 || type.id === FFI_TYPE_UINT16 || type.id === FFI_TYPE_SINT16 ? 4 : Math.max(1, Math.min(type.alignment, 8));
1050
+ argumentPointer = frame.allocate(Math.max(type.size, 1), alignment);
1051
+ valueIndex = writeCallbackArgument(
1052
+ argumentPointer,
1053
+ type,
1054
+ arguments_,
1055
+ valueIndex
1056
+ );
1057
+ }
1058
+ writePointer(argumentArray, index * 8, argumentPointer);
1059
+ }
1060
+ if ((cif.flags & VARARGS_FLAG) !== 0) {
1061
+ let variadic = asBigInt(
1062
+ arguments_[arguments_.length - 1],
1063
+ "FFI closure variadic pointer"
1064
+ );
1065
+ for (let index = cif.fixed; index < cif.nargs; ++index) {
1066
+ const type = cif.types[index];
1067
+ if (type.id === FFI_TYPE_STRUCT) {
1068
+ const source = readPointer(variadic, 0);
1069
+ const copyPointer = frame.allocate(type.size, type.alignment);
1070
+ copy(copyPointer, source, type.size);
1071
+ writePointer(argumentArray, index * 8, copyPointer);
1072
+ } else {
1073
+ writePointer(argumentArray, index * 8, variadic);
1074
+ }
1075
+ variadic += 8n;
1076
+ }
1077
+ }
1078
+ frame.publish();
1079
+ try {
1080
+ tableFunction(callbackIndex, "FFI closure callback")(
1081
+ cif.pointer,
1082
+ returnPointer,
1083
+ argumentArray,
1084
+ userData
1085
+ );
1086
+ } finally {
1087
+ frame.restore();
1088
+ }
1089
+ return returnByArgument ? void 0 : callbackResult(returnPointer, cif.returnType);
1090
+ }, parameters, result);
1091
+ }
1092
+ function allocateClosure(request, response) {
1093
+ if (request.size !== 8 || response.size < 8) return -BigInt(DOLLY_ERRNO.EINVAL);
1094
+ const closure = view(request.address, 8, "FFI closure allocation request").getBigUint64(0, true);
1095
+ address(closure, 32, "FFI closure");
1096
+ if (closures.has(closure)) return -BigInt(DOLLY_ERRNO.EINVAL);
1097
+ const index = freeTableIndices.length === 0 ? growTable2(1n) : freeTableIndices.pop();
1098
+ closures.set(closure, { index, prepared: false });
1099
+ view(response.address, 8, "FFI closure allocation response").setBigUint64(0, index, true);
1100
+ return 8n;
1101
+ }
1102
+ function freeClosure(request) {
1103
+ if (request.size !== 8) return -BigInt(DOLLY_ERRNO.EINVAL);
1104
+ const closure = view(request.address, 8, "FFI closure free request").getBigUint64(0, true);
1105
+ const record = closures.get(closure);
1106
+ if (!record) return -BigInt(DOLLY_ERRNO.EINVAL);
1107
+ setTable2(record.index, null);
1108
+ freeTableIndices.push(record.index);
1109
+ closures.delete(closure);
1110
+ return 0n;
1111
+ }
1112
+ function configureClosure(request) {
1113
+ if (request.size !== 40) return -BigInt(DOLLY_ERRNO.EINVAL);
1114
+ const packet = view(request.address, 40, "FFI closure preparation request");
1115
+ const closure = packet.getBigUint64(0, true);
1116
+ const cifPointer = packet.getBigUint64(8, true);
1117
+ const callbackIndex = packet.getBigUint64(16, true);
1118
+ const userData = packet.getBigUint64(24, true);
1119
+ const code = packet.getBigUint64(32, true);
1120
+ const record = closures.get(closure);
1121
+ if (!record || code !== record.index) return -BigInt(DOLLY_ERRNO.EINVAL);
1122
+ const cif = cifInfo(cifPointer);
1123
+ const wrapper = prepareClosure(closure, cif, callbackIndex, userData);
1124
+ setTable2(record.index, wrapper);
1125
+ writePointer(closure, 0, record.index);
1126
+ writePointer(closure, 8, cifPointer);
1127
+ writePointer(closure, 16, callbackIndex);
1128
+ writePointer(closure, 24, userData);
1129
+ record.prepared = true;
1130
+ return BigInt(FFI_OK);
1131
+ }
1132
+ return Object.freeze({
1133
+ handles(operation) {
1134
+ return localOperations.has(operation);
1135
+ },
1136
+ call(operation, request, response) {
1137
+ if (!(getTable() instanceof WebAssembly.Table) || !(getInstance()?.exports.__stack_pointer instanceof WebAssembly.Global)) {
1138
+ return -BigInt(DOLLY_ERRNO.ENOSYS);
1139
+ }
1140
+ let decoding = true;
1141
+ try {
1142
+ if (operation === DOLLY_FFI_CALL) {
1143
+ if (request.size !== 32 || response.size !== 0) return -BigInt(DOLLY_ERRNO.EINVAL);
1144
+ performCall(view(request.address, 32, "FFI call request"), () => {
1145
+ decoding = false;
1146
+ });
1147
+ return 0n;
1148
+ }
1149
+ if (operation === DOLLY_FFI_CLOSURE_ALLOC) return allocateClosure(request, response);
1150
+ if (operation === DOLLY_FFI_CLOSURE_FREE) return freeClosure(request);
1151
+ return configureClosure(request);
1152
+ } catch (error) {
1153
+ if (!decoding || !(error instanceof TypeError || error instanceof RangeError)) throw error;
1154
+ return -BigInt(error instanceof RangeError ? DOLLY_ERRNO.EFAULT : DOLLY_ERRNO.EINVAL);
1155
+ }
1156
+ }
1157
+ });
1158
+ }
1159
+
1160
+ // src/process-abi.mjs
1161
+ function unique(entries, key) {
1162
+ const result = /* @__PURE__ */ new Map();
1163
+ for (const entry of entries) {
1164
+ const name = key(entry);
1165
+ if (result.has(name)) throw new TypeError(`duplicate process interface entry ${name}`);
1166
+ result.set(name, entry);
1167
+ }
1168
+ return result;
1169
+ }
1170
+
1171
+ // host/dso/interface.mjs
1172
+ function requireDsoType(actual, expected, name) {
1173
+ if (!actual || !providerSatisfiesImport(actual, expected)) {
1174
+ throw new TypeError(`DSO ${name}: expected ${formatWasmType(expected)}, got ${actual ? formatWasmType(actual) : "missing symbol"}`);
1175
+ }
1176
+ }
1177
+ function validateDsoHost(contract, exports) {
1178
+ for (const name of ["__indirect_function_table", "__stack_pointer", "__dolly_dso_allocate"]) {
1179
+ requireDsoType(
1180
+ exports.get(name)?.type,
1181
+ contract.exports.find((entry) => entry.name === name).type,
1182
+ name
1183
+ );
1184
+ }
1185
+ }
1186
+ function validateDsoInterface(contract, dso, digest) {
1187
+ const stamps = dso.customSectionData.filter((section2) => section2.name === "dolly.process.dso");
1188
+ if (stamps.length !== 1 || hex(stamps[0].data) !== digest) {
1189
+ throw new TypeError("shared object has the wrong dolly.process.dso stamp");
1190
+ }
1191
+ if (dso.customSections.includes("dolly.process")) throw new TypeError("shared object must not carry a process entry stamp");
1192
+ if (dso.customSections.filter((name) => name === "dylink.0").length !== 1) {
1193
+ throw new TypeError("shared object needs one dylink.0 section");
1194
+ }
1195
+ const key = (entry) => `${entry.module}\0${entry.name}`;
1196
+ const imports = unique(dso.imports, key);
1197
+ const exports = unique(dso.exports, (entry) => entry.name);
1198
+ const allowed = new Map(contract.imports.map((entry) => [key(entry), entry.type]));
1199
+ if (!imports.has("env\0memory")) throw new TypeError("shared object needs exactly one memory import");
1200
+ for (const entry of imports.values()) {
1201
+ const expected = allowed.get(key(entry)) ?? allowed.get(`${entry.module}\0symbol`);
1202
+ if (expected) {
1203
+ const actual = entry.type;
1204
+ if (expected.kind === "memory" || expected.kind === "table") {
1205
+ if (actual.kind !== expected.kind || actual.address64 !== expected.address64 || actual.shared !== expected.shared || actual.element !== expected.element || expected.maximum !== null && (actual.maximum === null || actual.maximum > expected.maximum)) {
1206
+ throw new TypeError(`DSO ${entry.module}.${entry.name}: incompatible ${formatWasmType(actual)}`);
1207
+ }
1208
+ } else requireDsoType(actual, expected, `${entry.module}.${entry.name}`);
1209
+ } else if (entry.module !== "env" || !["func", "tag"].includes(entry.type.kind)) {
1210
+ throw new TypeError(`shared-object import is outside the process namespace: ${entry.module}.${entry.name}`);
1211
+ }
1212
+ }
1213
+ for (const name of ["__wasm_apply_data_relocs", "__wasm_call_ctors"]) {
1214
+ if (exports.has(name)) requireDsoType(
1215
+ exports.get(name).type,
1216
+ contract.exports.find((entry) => entry.name === name).type,
1217
+ name
1218
+ );
1219
+ }
1220
+ return { imports, exports };
1221
+ }
1222
+
1223
+ // host/dso/process.mjs
1224
+ var DSO_RESPONSE_SIZE = 16 + DOLLY_DSO_ERROR_CAPACITY;
1225
+ var encoder = new TextEncoder();
1226
+ var decoder3 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
1227
+ var configuration;
1228
+ var instance;
1229
+ var processTable;
1230
+ var processSymbols;
1231
+ var dsoHostValidated = false;
1232
+ var nextDsoHandle = 2n;
1233
+ var loadedDsos = /* @__PURE__ */ new Map();
1234
+ var globalDsos = [];
1235
+ var functionIndices = /* @__PURE__ */ new WeakMap();
1236
+ function dylinkRequirements(module) {
1237
+ const sections = WebAssembly.Module.customSections(module, "dylink.0");
1238
+ if (sections.length !== 1) throw new TypeError("shared object needs one dylink.0 section");
1239
+ const reader = new Reader(new Uint8Array(sections[0]), "dylink.0");
1240
+ let requirements;
1241
+ const needed = [];
1242
+ const weakImports = /* @__PURE__ */ new Set();
1243
+ while (!reader.done) {
1244
+ const id = Number(reader.unsigned(8));
1245
+ const section2 = reader.subreader(reader.u32(), "dylink.0 subsection");
1246
+ if (id === 1) {
1247
+ if (requirements) throw new TypeError("duplicate dylink memory metadata");
1248
+ requirements = {
1249
+ memorySize: section2.unsigned(64),
1250
+ memoryAlignment: section2.unsigned(32),
1251
+ tableSize: section2.unsigned(64),
1252
+ tableAlignment: section2.unsigned(32)
1253
+ };
1254
+ } else if (id === 2) {
1255
+ for (let count = section2.u32(); count > 0; --count) {
1256
+ const name = section2.string();
1257
+ if (!name || name.includes("/") || name.includes("..")) {
1258
+ throw new TypeError("unsafe dylink dependency name");
1259
+ }
1260
+ needed.push(name);
1261
+ }
1262
+ } else if (id === 4) {
1263
+ for (let count = section2.u32(); count > 0; --count) {
1264
+ const moduleName = section2.string();
1265
+ const symbolName = section2.string();
1266
+ const flags = section2.unsigned(32);
1267
+ if ((flags & 3n) === 1n) weakImports.add(`${moduleName}\0${symbolName}`);
1268
+ }
1269
+ }
1270
+ }
1271
+ if (!requirements) throw new TypeError("shared object lacks dylink memory metadata");
1272
+ if (requirements.memorySize > BigInt(DOLLY_DSO_LIMIT) || requirements.memoryAlignment > 31n || requirements.tableSize > 0xffffffffn || requirements.tableAlignment > 31n) {
1273
+ throw new RangeError("shared object requirements are out of range");
1274
+ }
1275
+ return { ...requirements, needed, weakImports };
1276
+ }
1277
+ function growTable(delta) {
1278
+ if (delta === 0n) return processTable.length;
1279
+ if (delta > 0xffffffffn) throw new RangeError("shared object table is too large");
1280
+ return processTable.grow(delta);
1281
+ }
1282
+ function setTable(index, value) {
1283
+ processTable.set(index, value);
1284
+ }
1285
+ function functionIndex(value) {
1286
+ const previous = functionIndices.get(value);
1287
+ if (previous !== void 0) return previous;
1288
+ const index = growTable(1n);
1289
+ setTable(index, value);
1290
+ functionIndices.set(value, index);
1291
+ return index;
1292
+ }
1293
+ function typedSymbols(exports, values, memoryBase = 0n) {
1294
+ return new Map([...exports].map((entry) => {
1295
+ let value = values[entry.name];
1296
+ if (memoryBase !== 0n && entry.type.kind === "global" && entry.type.value === "i64" && !entry.type.mutable) {
1297
+ value = new WebAssembly.Global({ value: "i64", mutable: false }, memoryBase + value.value);
1298
+ }
1299
+ return [entry.name, { type: entry.type, value }];
1300
+ }));
1301
+ }
1302
+ function globalSymbol(name) {
1303
+ const main = processSymbols.get(name);
1304
+ if (main !== void 0) return main;
1305
+ for (const dso of globalDsos) {
1306
+ const value = dso.symbols.get(name);
1307
+ if (value !== void 0) return value;
1308
+ }
1309
+ return void 0;
1310
+ }
1311
+ function symbolAddress({ value }) {
1312
+ if (typeof value === "function") return functionIndex(value);
1313
+ if (value instanceof WebAssembly.Global) {
1314
+ const raw = value.value;
1315
+ return typeof raw === "bigint" ? raw : BigInt(raw);
1316
+ }
1317
+ throw new TypeError("symbol is not a callable or data address");
1318
+ }
1319
+ function aligned(value, power) {
1320
+ const alignment = 1n << power;
1321
+ return value + alignment - 1n & -alignment;
1322
+ }
1323
+ function instantiateDso(bytes, flags) {
1324
+ bytes = bytes.slice();
1325
+ const contract = configuration.contract;
1326
+ const source = parseWasmInterface(bytes);
1327
+ const parsed = validateDsoInterface(contract, source, DOLLY_PROCESS_ABI_DIGEST);
1328
+ checkHostAbi(executableHostRequirements(source), configuration.hostAbi);
1329
+ const module = new WebAssembly.Module(bytes);
1330
+ const requirements = dylinkRequirements(module);
1331
+ if (requirements.needed.length !== 0) {
1332
+ throw new TypeError(
1333
+ `shared object has unloaded dependencies: ${requirements.needed.join(", ")}`
1334
+ );
1335
+ }
1336
+ const currentTable = processTable.length;
1337
+ const tableBase = aligned(currentTable, requirements.tableAlignment);
1338
+ const infrastructure = new Map(contract.imports.filter((entry) => entry.module === "env").map((entry) => [entry.name, entry.type]));
1339
+ infrastructure.set("memory", {
1340
+ ...configuration.processInterface.imports.find((entry) => entry.type.kind === "memory").type,
1341
+ minimum: BigInt(configuration.memory.buffer.byteLength / 65536)
1342
+ });
1343
+ infrastructure.set("__indirect_function_table", {
1344
+ ...processSymbols.get("__indirect_function_table").type,
1345
+ minimum: tableBase + requirements.tableSize
1346
+ });
1347
+ const bindings = /* @__PURE__ */ new Map();
1348
+ for (const [key, imported] of parsed.imports) {
1349
+ if (imported.module === "env" && infrastructure.has(imported.name)) {
1350
+ requireDsoType(infrastructure.get(imported.name), imported.type, imported.name);
1351
+ continue;
1352
+ }
1353
+ const symbol = parsed.exports.get(imported.name) ?? globalSymbol(imported.name);
1354
+ const weak = requirements.weakImports.has(key);
1355
+ if (!symbol && !weak) throw new TypeError(`undefined symbol: ${imported.name}`);
1356
+ if (symbol) {
1357
+ if (imported.module === "env") requireDsoType(symbol.type, imported.type, imported.name);
1358
+ else if (imported.module === "GOT.mem") {
1359
+ requireDsoType(symbol.type, infrastructure.get("__memory_base"), `GOT.mem.${imported.name}`);
1360
+ } else if (symbol.type.kind !== "func") {
1361
+ throw new TypeError(`DSO GOT.func.${imported.name}: expected a function symbol`);
1362
+ }
1363
+ }
1364
+ bindings.set(key, symbol);
1365
+ }
1366
+ const memoryAlignment = 1n << requirements.memoryAlignment;
1367
+ const memoryBase = instance.exports.__dolly_dso_allocate(
1368
+ requirements.memorySize,
1369
+ memoryAlignment
1370
+ );
1371
+ if (typeof memoryBase !== "bigint" || memoryBase === 0n) {
1372
+ throw new RangeError("process could not reserve shared-object memory");
1373
+ }
1374
+ growTable(tableBase - currentTable + requirements.tableSize);
1375
+ const imports = {
1376
+ env: Object.assign(/* @__PURE__ */ Object.create(null), {
1377
+ memory: configuration.memory,
1378
+ __memory_base: new WebAssembly.Global({ value: "i64", mutable: false }, memoryBase),
1379
+ __table_base: new WebAssembly.Global({ value: "i64", mutable: false }, tableBase),
1380
+ __stack_pointer: instance.exports.__stack_pointer,
1381
+ __indirect_function_table: processTable
1382
+ }),
1383
+ "GOT.mem": /* @__PURE__ */ Object.create(null),
1384
+ "GOT.func": /* @__PURE__ */ Object.create(null)
1385
+ };
1386
+ const relocations = [];
1387
+ const pendingFunctions = [];
1388
+ let dsoInstance;
1389
+ let dsoSymbols;
1390
+ function resolveFunction(pending) {
1391
+ const symbol = dsoSymbols?.get(pending.name) ?? globalSymbol(pending.name);
1392
+ requireDsoType(symbol?.type, pending.type, pending.name);
1393
+ return symbol.value;
1394
+ }
1395
+ for (const [key, imported] of parsed.imports) {
1396
+ if (imported.module === "env" && !Object.hasOwn(imports.env, imported.name)) {
1397
+ const symbol = bindings.get(key);
1398
+ if (symbol?.value !== void 0) {
1399
+ imports.env[imported.name] = symbol.value;
1400
+ } else if (imported.type.kind === "func") {
1401
+ const pending = {
1402
+ name: imported.name,
1403
+ type: imported.type,
1404
+ weak: requirements.weakImports.has(key),
1405
+ value: void 0
1406
+ };
1407
+ imports.env[imported.name] = (...arguments_) => {
1408
+ pending.value ??= resolveFunction(pending);
1409
+ return pending.value(...arguments_);
1410
+ };
1411
+ pendingFunctions.push(pending);
1412
+ } else {
1413
+ throw new TypeError(`undefined symbol: ${imported.name}`);
1414
+ }
1415
+ } else if (imported.module === "GOT.mem" || imported.module === "GOT.func") {
1416
+ const global = new WebAssembly.Global({ value: "i64", mutable: true }, 0n);
1417
+ imports[imported.module][imported.name] = global;
1418
+ relocations.push({
1419
+ module: imported.module,
1420
+ name: imported.name,
1421
+ global,
1422
+ weak: requirements.weakImports.has(key)
1423
+ });
1424
+ }
1425
+ }
1426
+ for (const relocation of relocations) {
1427
+ if (parsed.exports.has(relocation.name)) continue;
1428
+ const existing = globalSymbol(relocation.name);
1429
+ if (existing !== void 0) relocation.global.value = symbolAddress(existing);
1430
+ }
1431
+ dsoInstance = new WebAssembly.Instance(module, imports);
1432
+ dsoSymbols = typedSymbols(parsed.exports.values(), dsoInstance.exports, memoryBase);
1433
+ for (const pending of pendingFunctions) {
1434
+ if (pending.weak && !globalSymbol(pending.name) && !dsoSymbols.has(pending.name)) continue;
1435
+ pending.value = resolveFunction(pending);
1436
+ }
1437
+ for (const relocation of relocations) {
1438
+ const symbol = dsoSymbols.get(relocation.name) ?? globalSymbol(relocation.name);
1439
+ if (symbol !== void 0) relocation.global.value = symbolAddress(symbol);
1440
+ else if (relocation.weak) {
1441
+ relocation.global.value = 0n;
1442
+ } else {
1443
+ throw new TypeError(`undefined ${relocation.module} symbol: ${relocation.name}`);
1444
+ }
1445
+ }
1446
+ const applyDataRelocations = dsoInstance.exports.__wasm_apply_data_relocs;
1447
+ if (applyDataRelocations !== void 0) applyDataRelocations();
1448
+ const handle = nextDsoHandle++;
1449
+ const record = { handle, module, instance: dsoInstance, symbols: dsoSymbols, flags, references: 1 };
1450
+ loadedDsos.set(handle, record);
1451
+ if ((flags & DOLLY_DSO_GLOBAL) !== 0) globalDsos.push(record);
1452
+ const constructors = dsoInstance.exports.__wasm_call_ctors;
1453
+ if (constructors !== void 0) constructors();
1454
+ return handle;
1455
+ }
1456
+ function writeDsoResponse(response, value = 0n, error = 0, message = "") {
1457
+ if (response.size < DSO_RESPONSE_SIZE) return -BigInt(DOLLY_ERRNO.ENOBUFS);
1458
+ const bytes = encoder.encode(message);
1459
+ const messageSize = Math.min(bytes.length, DOLLY_DSO_ERROR_CAPACITY);
1460
+ const output = new Uint8Array(
1461
+ configuration.memory.buffer,
1462
+ response.address,
1463
+ DSO_RESPONSE_SIZE
1464
+ );
1465
+ output.fill(0);
1466
+ const view = new DataView(
1467
+ configuration.memory.buffer,
1468
+ response.address,
1469
+ DSO_RESPONSE_SIZE
1470
+ );
1471
+ view.setBigUint64(0, BigInt.asUintN(64, value), true);
1472
+ view.setInt32(8, error, true);
1473
+ view.setUint32(12, messageSize, true);
1474
+ output.set(bytes.subarray(0, messageSize), 16);
1475
+ return BigInt(DSO_RESPONSE_SIZE);
1476
+ }
1477
+ function processDsoCall(operation, request, response) {
1478
+ if (!(processTable instanceof WebAssembly.Table) || !(instance?.exports.__stack_pointer instanceof WebAssembly.Global) || typeof instance.exports.__dolly_dso_allocate !== "function") {
1479
+ return writeDsoResponse(
1480
+ response,
1481
+ 0n,
1482
+ DOLLY_ERRNO.ENOSYS,
1483
+ "process does not provide a dynamic-link namespace"
1484
+ );
1485
+ }
1486
+ try {
1487
+ if (!dsoHostValidated) {
1488
+ validateDsoHost(configuration.contract, processSymbols);
1489
+ dsoHostValidated = true;
1490
+ }
1491
+ const view = new DataView(configuration.memory.buffer, request.address, request.size);
1492
+ if (operation === DOLLY_DSO_OPEN) {
1493
+ if (request.size < 16) throw new TypeError("short DSO_OPEN packet");
1494
+ const flags = view.getUint32(0, true);
1495
+ const reserved = view.getUint32(4, true);
1496
+ const size = view.getBigUint64(8, true);
1497
+ if ((flags & ~DOLLY_DSO_GLOBAL) !== 0 || reserved !== 0 || size !== BigInt(request.size - 16) || size > BigInt(DOLLY_DSO_LIMIT)) {
1498
+ throw new TypeError("invalid DSO_OPEN packet");
1499
+ }
1500
+ const handle = size === 0n ? 1n : instantiateDso(
1501
+ new Uint8Array(configuration.memory.buffer, request.address + 16, Number(size)),
1502
+ flags
1503
+ );
1504
+ return writeDsoResponse(response, handle);
1505
+ }
1506
+ if (operation === DOLLY_DSO_SYMBOL) {
1507
+ if (request.size < 16) throw new TypeError("short DSO_SYMBOL packet");
1508
+ const handle = view.getBigUint64(0, true);
1509
+ const nameSize = view.getUint32(8, true);
1510
+ if (view.getUint32(12, true) !== 0 || nameSize !== request.size - 16 || nameSize === 0) throw new TypeError("invalid DSO_SYMBOL packet");
1511
+ const name = decoder3.decode(Uint8Array.from(new Uint8Array(
1512
+ configuration.memory.buffer,
1513
+ request.address + 16,
1514
+ nameSize
1515
+ )));
1516
+ let value;
1517
+ if (handle === 0n) value = globalSymbol(name);
1518
+ else if (handle === 1n) value = processSymbols.get(name);
1519
+ else {
1520
+ const dso = loadedDsos.get(handle);
1521
+ if (!dso) return writeDsoResponse(response, 0n, DOLLY_ERRNO.EBADF, "invalid DSO handle");
1522
+ value = dso.symbols.get(name);
1523
+ }
1524
+ if (value === void 0) {
1525
+ return writeDsoResponse(response, 0n, DOLLY_ERRNO.ENOENT, `undefined symbol: ${name}`);
1526
+ }
1527
+ return writeDsoResponse(response, symbolAddress(value));
1528
+ }
1529
+ if (operation === DOLLY_DSO_CLOSE) {
1530
+ if (request.size !== 8) throw new TypeError("invalid DSO_CLOSE packet");
1531
+ const handle = view.getBigUint64(0, true);
1532
+ if (handle === 1n) return writeDsoResponse(response);
1533
+ const dso = loadedDsos.get(handle);
1534
+ if (!dso) return writeDsoResponse(response, 0n, DOLLY_ERRNO.EBADF, "invalid DSO handle");
1535
+ if (dso.references !== 0) --dso.references;
1536
+ return writeDsoResponse(response);
1537
+ }
1538
+ return writeDsoResponse(response, 0n, DOLLY_ERRNO.ENOSYS, "unknown process-local operation");
1539
+ } catch (error) {
1540
+ return writeDsoResponse(
1541
+ response,
1542
+ 0n,
1543
+ error instanceof RangeError ? DOLLY_ERRNO.ENOMEM : DOLLY_ERRNO.ENOEXEC,
1544
+ error instanceof Error ? error.message : String(error)
1545
+ );
1546
+ }
1547
+ }
1548
+ function serve(context) {
1549
+ configuration = context;
1550
+ instance = context.instance;
1551
+ processTable = instance.exports.__indirect_function_table;
1552
+ processSymbols = typedSymbols(configuration.processInterface.exports, instance.exports);
1553
+ const ffi = createProcessFfi({
1554
+ memory: configuration.memory,
1555
+ getInstance: () => instance,
1556
+ getTable: () => processTable,
1557
+ growTable,
1558
+ setTable,
1559
+ castEmulationParameters: context.processInterface.castEmulationParameters
1560
+ });
1561
+ const callsOnly = context.threaded || context.processInterface.castEmulationParameters > 0;
1562
+ const refusal = (operation, response) => ffi.handles(operation) ? -BigInt(DOLLY_ERRNO.ENOTSUP) : writeDsoResponse(
1563
+ response,
1564
+ 0n,
1565
+ DOLLY_ERRNO.ENOTSUP,
1566
+ context.threaded ? "not in a program using threads@0" : "not in a cast-emulated program"
1567
+ );
1568
+ return {
1569
+ handles: (operation) => operation >= DOLLY_DSO_OPEN && operation <= DOLLY_DSO_CLOSE || ffi.handles(operation),
1570
+ call: (operation, request, response) => callsOnly && operation !== DOLLY_FFI_CALL ? refusal(operation, response) : ffi.handles(operation) ? ffi.call(operation, request, response) : processDsoCall(operation, request, response)
1571
+ };
1572
+ }
1573
+ export {
1574
+ serve
1575
+ };