@daugasauron/dolly-build 0.0.0-stage → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +11 -2
- package/host/abi.mjs +5 -0
- package/host/requirements.mjs +62 -0
- package/package.json +16 -4
- package/scripts/dolly-build-init/Dollyfile +54 -0
- package/scripts/dolly-build-init/public/index.html +61 -0
- package/scripts/dolly-build-init/public/theme.json +67 -0
- package/scripts/dolly-build-init/public/workspace/README.md +5 -0
- package/scripts/dolly-build.mjs +278 -0
- package/scripts/dollyfile-graph.mjs +41 -0
- package/scripts/image-directory.mjs +85 -0
- package/scripts/page-image-build.mjs +53 -0
- package/scripts/recipe-files.mjs +31 -0
- package/scripts/release-layout.mjs +29 -0
- package/scripts/serve.mjs +112 -0
- package/scripts/share-pages-snapshots.mjs +219 -0
- package/scripts/snapshot-identity.mjs +36 -0
- package/scripts/system-snapshot-format.mjs +103 -0
- package/scripts/wasm-interface.mjs +7 -0
- package/src/alphabetical.mjs +4 -0
- package/src/dollyfile-graph.mjs +127 -0
- package/src/dollyfile-view.mjs +335 -0
- package/src/image-entry.mjs +29 -0
- package/src/image-inputs.mjs +20 -0
- package/src/image-names.mjs +11 -0
- package/src/process-abi.mjs +69 -0
- package/src/snapshot-records.mjs +221 -0
- package/src/static-asset.mjs +124 -0
- package/src/version.mjs +3 -0
- package/src/wasm-interface.mjs +440 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
2
|
+
const valueTypes = new Map([
|
|
3
|
+
[0x7f, "i32"],
|
|
4
|
+
[0x7e, "i64"],
|
|
5
|
+
[0x7d, "f32"],
|
|
6
|
+
[0x7c, "f64"],
|
|
7
|
+
[0x7b, "v128"],
|
|
8
|
+
[0x70, "funcref"],
|
|
9
|
+
[0x6f, "externref"],
|
|
10
|
+
[0x69, "exnref"],
|
|
11
|
+
[0x74, "nullexnref"],
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export class Reader {
|
|
15
|
+
constructor(bytes, label = "WebAssembly binary") {
|
|
16
|
+
this.bytes = bytes;
|
|
17
|
+
this.offset = 0;
|
|
18
|
+
this.label = label;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get done() {
|
|
22
|
+
return this.offset === this.bytes.length;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fail(message) {
|
|
26
|
+
throw new Error(`${this.label} at byte ${this.offset}: ${message}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
u8() {
|
|
30
|
+
if (this.offset >= this.bytes.length) this.fail("unexpected end of file");
|
|
31
|
+
return this.bytes[this.offset++];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
take(length) {
|
|
35
|
+
if (!Number.isSafeInteger(length) || length < 0 || this.offset + length > this.bytes.length) {
|
|
36
|
+
this.fail(`invalid byte range of length ${length}`);
|
|
37
|
+
}
|
|
38
|
+
const result = this.bytes.subarray(this.offset, this.offset + length);
|
|
39
|
+
this.offset += length;
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
subreader(length, label) {
|
|
44
|
+
return new Reader(this.take(length), label);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
unsigned(bits = 32) {
|
|
48
|
+
let result = 0n;
|
|
49
|
+
let shift = 0n;
|
|
50
|
+
const limit = Math.ceil(bits / 7);
|
|
51
|
+
for (let index = 0; index < limit; index += 1) {
|
|
52
|
+
const byte = this.u8();
|
|
53
|
+
result |= BigInt(byte & 0x7f) << shift;
|
|
54
|
+
if ((byte & 0x80) === 0) {
|
|
55
|
+
if (result >= (1n << BigInt(bits))) this.fail(`unsigned LEB exceeds ${bits} bits`);
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
shift += 7n;
|
|
59
|
+
}
|
|
60
|
+
this.fail(`unterminated unsigned ${bits}-bit LEB`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
signed(bits = 32) {
|
|
64
|
+
let result = 0n;
|
|
65
|
+
let shift = 0n;
|
|
66
|
+
let byte = 0;
|
|
67
|
+
const limit = Math.ceil(bits / 7);
|
|
68
|
+
for (let index = 0; index < limit; index += 1) {
|
|
69
|
+
byte = this.u8();
|
|
70
|
+
result |= BigInt(byte & 0x7f) << shift;
|
|
71
|
+
shift += 7n;
|
|
72
|
+
if ((byte & 0x80) === 0) {
|
|
73
|
+
if ((byte & 0x40) !== 0 && shift < BigInt(bits)) result |= (-1n) << shift;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
this.fail(`unterminated signed ${bits}-bit LEB`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
u32() {
|
|
81
|
+
return Number(this.unsigned(32));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
string() {
|
|
85
|
+
const length = this.u32();
|
|
86
|
+
try {
|
|
87
|
+
return decoder.decode(this.take(length));
|
|
88
|
+
} catch {
|
|
89
|
+
this.fail("invalid UTF-8 string");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readValueType(reader) {
|
|
95
|
+
const byte = reader.u8();
|
|
96
|
+
const type = valueTypes.get(byte);
|
|
97
|
+
if (!type) reader.fail(`unsupported value type 0x${byte.toString(16)}`);
|
|
98
|
+
return type;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function readVector(reader, readElement, result = []) {
|
|
102
|
+
const count = reader.u32();
|
|
103
|
+
if (count > reader.bytes.length - reader.offset) reader.fail("vector count exceeds section size");
|
|
104
|
+
for (let index = 0; index < count; index++) result.push(readElement(reader));
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function readLimits(reader) {
|
|
109
|
+
const flags = reader.u32();
|
|
110
|
+
if ((flags & ~0x7) !== 0) reader.fail(`unsupported limits flags 0x${flags.toString(16)}`);
|
|
111
|
+
const hasMaximum = (flags & 0x1) !== 0;
|
|
112
|
+
const shared = (flags & 0x2) !== 0;
|
|
113
|
+
const address64 = (flags & 0x4) !== 0;
|
|
114
|
+
const readBound = () => reader.unsigned(address64 ? 64 : 32);
|
|
115
|
+
const minimum = readBound();
|
|
116
|
+
const maximum = hasMaximum ? readBound() : null;
|
|
117
|
+
if (shared && maximum === null) reader.fail("shared limits require a maximum");
|
|
118
|
+
return { minimum, maximum, shared, address64 };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function readTableType(reader) {
|
|
122
|
+
return { kind: "table", element: readValueType(reader), ...readLimits(reader) };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function readMemoryType(reader) {
|
|
126
|
+
return { kind: "memory", ...readLimits(reader) };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function readGlobalType(reader) {
|
|
130
|
+
return { kind: "global", value: readValueType(reader), mutable: reader.u8() !== 0 };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function readTagType(reader, types) {
|
|
134
|
+
const attribute = reader.u32();
|
|
135
|
+
return { kind: "tag", attribute, type: functionType(types, reader.u32(), reader) };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function skipConstantExpression(reader) {
|
|
139
|
+
for (;;) {
|
|
140
|
+
const opcode = reader.u8();
|
|
141
|
+
switch (opcode) {
|
|
142
|
+
case 0x0b:
|
|
143
|
+
return;
|
|
144
|
+
case 0x41:
|
|
145
|
+
reader.signed(32);
|
|
146
|
+
break;
|
|
147
|
+
case 0x42:
|
|
148
|
+
reader.signed(64);
|
|
149
|
+
break;
|
|
150
|
+
case 0x43:
|
|
151
|
+
reader.take(4);
|
|
152
|
+
break;
|
|
153
|
+
case 0x44:
|
|
154
|
+
reader.take(8);
|
|
155
|
+
break;
|
|
156
|
+
case 0x23:
|
|
157
|
+
case 0xd2:
|
|
158
|
+
reader.u32();
|
|
159
|
+
break;
|
|
160
|
+
case 0xd0:
|
|
161
|
+
readValueType(reader);
|
|
162
|
+
break;
|
|
163
|
+
case 0x6a: // i32.add
|
|
164
|
+
case 0x6b: // i32.sub
|
|
165
|
+
case 0x6c: // i32.mul
|
|
166
|
+
case 0x7c: // i64.add
|
|
167
|
+
case 0x7d: // i64.sub
|
|
168
|
+
case 0x7e: // i64.mul
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
reader.fail(`unsupported constant-expression opcode 0x${opcode.toString(16)}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// An element of an expression segment: the function a ref.func names, or
|
|
177
|
+
// null for ref.null.
|
|
178
|
+
function readElementExpression(reader) {
|
|
179
|
+
const opcode = reader.u8();
|
|
180
|
+
let index = null;
|
|
181
|
+
if (opcode === 0xd2) index = reader.u32();
|
|
182
|
+
else if (opcode === 0xd0) readValueType(reader);
|
|
183
|
+
else reader.fail(`unsupported element expression opcode 0x${opcode.toString(16)}`);
|
|
184
|
+
if (reader.u8() !== 0x0b) reader.fail("element expression has more than one instruction");
|
|
185
|
+
return index;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// The functions an element segment puts into a table: an active segment's,
|
|
189
|
+
// none for a passive or declarative one (flag bit 0).
|
|
190
|
+
function readElementSegment(reader) {
|
|
191
|
+
const flags = reader.u32();
|
|
192
|
+
if (flags > 7) reader.fail(`unsupported element segment flags ${flags}`);
|
|
193
|
+
const active = (flags & 0x1) === 0;
|
|
194
|
+
if (flags === 2 || flags === 6) reader.u32();
|
|
195
|
+
if (active) skipConstantExpression(reader);
|
|
196
|
+
if (flags & 0x4) {
|
|
197
|
+
if (flags !== 4) readValueType(reader);
|
|
198
|
+
const indices = readVector(reader, readElementExpression);
|
|
199
|
+
return active ? indices.filter(index => index !== null) : [];
|
|
200
|
+
}
|
|
201
|
+
if (flags !== 0 && reader.u8() !== 0x00) reader.fail("unsupported element kind");
|
|
202
|
+
const indices = readVector(reader, item => item.u32());
|
|
203
|
+
return active ? indices : [];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Binaryen's --fpcast-emu leaves one signature in the table, which every
|
|
207
|
+
// indirect call uses: thunks of i64 parameters, sixteen or more
|
|
208
|
+
// (max-func-params), and an i64 result. Their parameter count, or 0.
|
|
209
|
+
function castEmulationParameters(tableFunctions) {
|
|
210
|
+
const [type] = tableFunctions;
|
|
211
|
+
const thunk = type && type.params.length >= 16 && type.params.every(param => param === "i64") &&
|
|
212
|
+
type.results.length === 1 && type.results[0] === "i64";
|
|
213
|
+
return thunk && tableFunctions.every(other => other === type) ? type.params.length : 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function functionType(types, index, reader) {
|
|
217
|
+
const type = types[index];
|
|
218
|
+
if (!type) reader.fail(`function references missing type ${index}`);
|
|
219
|
+
return type;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function parseWasmInterface(input, label = "WebAssembly binary") {
|
|
223
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
224
|
+
const reader = new Reader(bytes, label);
|
|
225
|
+
const expectedHeader = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];
|
|
226
|
+
for (const byte of expectedHeader) {
|
|
227
|
+
if (reader.u8() !== byte) reader.fail("invalid WebAssembly header");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const types = [];
|
|
231
|
+
const imports = [];
|
|
232
|
+
const definedFunctionTypes = [];
|
|
233
|
+
const importedTables = [];
|
|
234
|
+
const definedTables = [];
|
|
235
|
+
const importedMemories = [];
|
|
236
|
+
const definedMemories = [];
|
|
237
|
+
const importedGlobals = [];
|
|
238
|
+
const definedGlobals = [];
|
|
239
|
+
const importedTags = [];
|
|
240
|
+
const definedTags = [];
|
|
241
|
+
const rawExports = [];
|
|
242
|
+
const tableFunctionIndices = [];
|
|
243
|
+
const customSections = [];
|
|
244
|
+
const customSectionData = [];
|
|
245
|
+
|
|
246
|
+
while (!reader.done) {
|
|
247
|
+
const id = reader.u8();
|
|
248
|
+
const size = reader.u32();
|
|
249
|
+
const section = reader.subreader(size, `${label} section ${id}`);
|
|
250
|
+
|
|
251
|
+
if (id === 0) {
|
|
252
|
+
const name = section.string();
|
|
253
|
+
customSections.push(name);
|
|
254
|
+
customSectionData.push({ name, data: section.take(section.bytes.length - section.offset) });
|
|
255
|
+
} else if (id === 1) {
|
|
256
|
+
readVector(section, (item) => {
|
|
257
|
+
if (item.u8() !== 0x60) item.fail("only function types are supported");
|
|
258
|
+
return {
|
|
259
|
+
kind: "func",
|
|
260
|
+
params: readVector(item, readValueType),
|
|
261
|
+
results: readVector(item, readValueType),
|
|
262
|
+
};
|
|
263
|
+
}, types);
|
|
264
|
+
} else if (id === 2) {
|
|
265
|
+
readVector(section, (item) => {
|
|
266
|
+
const module = item.string();
|
|
267
|
+
const name = item.string();
|
|
268
|
+
const externalKind = item.u8();
|
|
269
|
+
let type;
|
|
270
|
+
if (externalKind === 0) {
|
|
271
|
+
const typeIndex = item.u32();
|
|
272
|
+
type = functionType(types, typeIndex, item);
|
|
273
|
+
} else if (externalKind === 1) {
|
|
274
|
+
type = readTableType(item);
|
|
275
|
+
importedTables.push(type);
|
|
276
|
+
} else if (externalKind === 2) {
|
|
277
|
+
type = readMemoryType(item);
|
|
278
|
+
importedMemories.push(type);
|
|
279
|
+
} else if (externalKind === 3) {
|
|
280
|
+
type = readGlobalType(item);
|
|
281
|
+
importedGlobals.push(type);
|
|
282
|
+
} else if (externalKind === 4) {
|
|
283
|
+
type = readTagType(item, types);
|
|
284
|
+
importedTags.push(type);
|
|
285
|
+
} else {
|
|
286
|
+
item.fail(`unknown import kind ${externalKind}`);
|
|
287
|
+
}
|
|
288
|
+
return { module, name, type };
|
|
289
|
+
}, imports);
|
|
290
|
+
} else if (id === 3) {
|
|
291
|
+
readVector(section, (item) => item.u32(), definedFunctionTypes);
|
|
292
|
+
} else if (id === 4) {
|
|
293
|
+
readVector(section, readTableType, definedTables);
|
|
294
|
+
} else if (id === 5) {
|
|
295
|
+
readVector(section, readMemoryType, definedMemories);
|
|
296
|
+
} else if (id === 6) {
|
|
297
|
+
readVector(section, (item) => {
|
|
298
|
+
const type = readGlobalType(item);
|
|
299
|
+
skipConstantExpression(item);
|
|
300
|
+
return type;
|
|
301
|
+
}, definedGlobals);
|
|
302
|
+
} else if (id === 7) {
|
|
303
|
+
readVector(section, (item) => ({
|
|
304
|
+
name: item.string(),
|
|
305
|
+
externalKind: item.u8(),
|
|
306
|
+
index: item.u32(),
|
|
307
|
+
}), rawExports);
|
|
308
|
+
} else if (id === 9) {
|
|
309
|
+
// One by one: a large program's table (Mojo's, Codex's) exceeds the
|
|
310
|
+
// arguments a spread may pass.
|
|
311
|
+
for (const indices of readVector(section, readElementSegment)) for (const index of indices) tableFunctionIndices.push(index);
|
|
312
|
+
} else if (id === 13) {
|
|
313
|
+
readVector(section, item => readTagType(item, types), definedTags);
|
|
314
|
+
} else {
|
|
315
|
+
section.take(section.bytes.length - section.offset);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!section.done) section.fail("section has trailing bytes");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const importedFunctions = imports.filter((entry) => entry.type.kind === "func").map((entry) => entry.type);
|
|
322
|
+
const functions = [
|
|
323
|
+
...importedFunctions,
|
|
324
|
+
...definedFunctionTypes.map((index) => functionType(types, index, reader)),
|
|
325
|
+
];
|
|
326
|
+
const tables = [...importedTables, ...definedTables];
|
|
327
|
+
const memories = [...importedMemories, ...definedMemories];
|
|
328
|
+
const globals = [...importedGlobals, ...definedGlobals];
|
|
329
|
+
const collections = [functions, tables, memories, globals, [...importedTags, ...definedTags]];
|
|
330
|
+
const kindNames = ["func", "table", "memory", "global", "tag"];
|
|
331
|
+
const exports = rawExports.map(({ name, externalKind, index }) => {
|
|
332
|
+
const collection = collections[externalKind];
|
|
333
|
+
const type = collection?.[index];
|
|
334
|
+
if (!type) reader.fail(`export ${name} references unknown ${kindNames[externalKind] ?? externalKind} ${index}`);
|
|
335
|
+
return { name, type };
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const tableFunctions = tableFunctionIndices.map(index =>
|
|
339
|
+
functions[index] ?? reader.fail(`element segment references unknown function ${index}`));
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
label,
|
|
343
|
+
imports,
|
|
344
|
+
exports,
|
|
345
|
+
castEmulationParameters: castEmulationParameters(tableFunctions),
|
|
346
|
+
customSections,
|
|
347
|
+
customSectionData,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function encodeUnsigned(value) {
|
|
352
|
+
let remaining = BigInt(value);
|
|
353
|
+
const bytes = [];
|
|
354
|
+
do {
|
|
355
|
+
let byte = Number(remaining & 0x7fn);
|
|
356
|
+
remaining >>= 7n;
|
|
357
|
+
if (remaining !== 0n) byte |= 0x80;
|
|
358
|
+
bytes.push(byte);
|
|
359
|
+
} while (remaining !== 0n);
|
|
360
|
+
return Uint8Array.from(bytes);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function joinBytes(parts) {
|
|
364
|
+
const length = parts.reduce((total, part) => total + part.length, 0);
|
|
365
|
+
const result = new Uint8Array(length);
|
|
366
|
+
let offset = 0;
|
|
367
|
+
for (const part of parts) {
|
|
368
|
+
result.set(part, offset);
|
|
369
|
+
offset += part.length;
|
|
370
|
+
}
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function appendCustomSection(input, name, data) {
|
|
375
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
376
|
+
const encodedName = new TextEncoder().encode(name);
|
|
377
|
+
const payload = joinBytes([encodeUnsigned(encodedName.length), encodedName, data]);
|
|
378
|
+
const section = joinBytes([Uint8Array.of(0), encodeUnsigned(payload.length), payload]);
|
|
379
|
+
return joinBytes([bytes, section]);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function formatLimits(type) {
|
|
383
|
+
const width = type.address64 ? "64" : "32";
|
|
384
|
+
const maximum = type.maximum === null ? "*" : type.maximum;
|
|
385
|
+
return `${width}(min=${type.minimum},max=${maximum}${type.shared ? ",shared" : ""})`;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function formatWasmType(type) {
|
|
389
|
+
if (type.kind === "func") {
|
|
390
|
+
return `func(${type.params.join(",")})->(${type.results.join(",")})`;
|
|
391
|
+
}
|
|
392
|
+
if (type.kind === "global") {
|
|
393
|
+
return `global(${type.mutable ? "mut " : ""}${type.value})`;
|
|
394
|
+
}
|
|
395
|
+
if (type.kind === "memory") return `memory${formatLimits(type)}`;
|
|
396
|
+
if (type.kind === "table") return `table${formatLimits(type)}:${type.element}`;
|
|
397
|
+
if (type.kind === "tag") return `tag(${formatWasmType(type.type)})`;
|
|
398
|
+
throw new Error(`unknown WebAssembly type kind ${type.kind}`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function arraysEqual(left, right) {
|
|
402
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export function sameWasmType(left, right) {
|
|
406
|
+
if (left.kind !== right.kind) return false;
|
|
407
|
+
if (left.kind === "func") {
|
|
408
|
+
return arraysEqual(left.params, right.params) && arraysEqual(left.results, right.results);
|
|
409
|
+
}
|
|
410
|
+
if (left.kind === "global") return left.value === right.value && left.mutable === right.mutable;
|
|
411
|
+
if (left.kind === "tag") return left.attribute === right.attribute && sameWasmType(left.type, right.type);
|
|
412
|
+
if (left.kind === "memory") {
|
|
413
|
+
return left.address64 === right.address64
|
|
414
|
+
&& left.shared === right.shared
|
|
415
|
+
&& left.minimum === right.minimum
|
|
416
|
+
&& left.maximum === right.maximum;
|
|
417
|
+
}
|
|
418
|
+
if (left.kind === "table") {
|
|
419
|
+
return left.element === right.element
|
|
420
|
+
&& left.address64 === right.address64
|
|
421
|
+
&& left.minimum === right.minimum
|
|
422
|
+
&& left.maximum === right.maximum;
|
|
423
|
+
}
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export function providerSatisfiesImport(provider, required, { dynamicTable = false } = {}) {
|
|
428
|
+
if (provider.kind !== required.kind) return false;
|
|
429
|
+
if (["func", "global", "tag"].includes(provider.kind)) return sameWasmType(provider, required);
|
|
430
|
+
if (provider.kind === "memory" || provider.kind === "table") {
|
|
431
|
+
if (provider.address64 !== required.address64 || provider.shared !== required.shared) return false;
|
|
432
|
+
if (provider.kind === "table" && provider.element !== required.element) return false;
|
|
433
|
+
if (!dynamicTable && provider.minimum < required.minimum) return false;
|
|
434
|
+
if (required.maximum !== null) {
|
|
435
|
+
if (provider.maximum === null || provider.maximum > required.maximum) return false;
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
return false;
|
|
440
|
+
}
|