gofront 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -403
- package/package.json +16 -19
- package/src/{codegen → backend/js}/expressions.js +265 -77
- package/src/{codegen → backend/js}/index.js +120 -89
- package/src/{codegen → backend/js}/runtime.js +102 -0
- package/src/{codegen → backend/js}/source-map.js +32 -0
- package/src/{codegen → backend/js}/statements.js +139 -64
- package/src/backend/js/stdlib/bits.js +32 -0
- package/src/{codegen → backend/js}/stdlib/errors.js +2 -2
- package/src/{codegen → backend/js}/stdlib/fmt.js +26 -8
- package/src/{codegen → backend/js}/stdlib/index.js +6 -0
- package/src/{codegen → backend/js}/stdlib/maps.js +1 -1
- package/src/{codegen → backend/js}/stdlib/path.js +2 -2
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/{codegen → backend/js}/stdlib/slices.js +1 -1
- package/src/{codegen → backend/js}/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +58 -0
- package/src/{codegen → backend/js}/stdlib/strings.js +4 -1
- package/src/{codegen → backend/js}/stdlib/testing.js +2 -2
- package/src/{codegen → backend/js}/stdlib/time.js +3 -3
- package/src/{codegen → backend/js}/templ.js +3 -3
- package/src/backend/wasm/boundary.js +1798 -0
- package/src/backend/wasm/emit-builtins.js +1103 -0
- package/src/backend/wasm/emit-exprs.js +1908 -0
- package/src/backend/wasm/emit-maps.js +1863 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +3006 -0
- package/src/backend/wasm/emit-stmts.js +2472 -0
- package/src/backend/wasm/emit.js +1376 -0
- package/src/backend/wasm/encode.js +937 -0
- package/src/backend/wasm/glue.js +144 -0
- package/src/backend/wasm/index.js +2790 -0
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +227 -0
- package/src/backend/wasm/types.js +544 -0
- package/src/backend/wasm/wat.js +302 -0
- package/src/cli-core.js +323 -75
- package/src/compiler.js +447 -14
- package/src/dev-server.js +56 -15
- package/src/index.js +99 -120
- package/src/lexer.js +18 -0
- package/src/lower/boxing.js +35 -0
- package/src/lower/captures.js +172 -0
- package/src/lower/embedding.js +30 -0
- package/src/lower/escape.js +164 -0
- package/src/lower/functions.js +302 -0
- package/src/lower/globals.js +316 -0
- package/src/lower/index.js +118 -0
- package/src/lower/ownership.js +137 -0
- package/src/lower/range.js +67 -0
- package/src/lower/walk.js +25 -0
- package/src/minifier.js +2 -0
- package/src/parser/index.js +8 -3
- package/src/resolver.js +3 -1
- package/src/test-runner.js +94 -20
- package/src/typechecker/assignability.js +42 -1
- package/src/typechecker/expressions.js +182 -3
- package/src/typechecker/index.js +261 -5
- package/src/typechecker/resolve.js +35 -6
- package/src/typechecker/stdlib/core.js +34 -19
- package/src/typechecker/stdlib/extended.js +18 -3
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +259 -6
- package/src/vendor.js +2 -2
- package/src/codegen/stdlib/strconv.js +0 -33
- /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
// src/backend/wasm/encode.js
|
|
2
|
+
// Dependency-free WebAssembly binary encoder (Wasm 2.0, WasmGC, Exception Handling).
|
|
3
|
+
|
|
4
|
+
// ── LEB128 & Primitive Encoders ──────────────────────────────
|
|
5
|
+
|
|
6
|
+
export function encodeU32LEB(val) {
|
|
7
|
+
let v = val >>> 0;
|
|
8
|
+
const bytes = [];
|
|
9
|
+
do {
|
|
10
|
+
let byte = v & 0x7f;
|
|
11
|
+
v >>>= 7;
|
|
12
|
+
if (v !== 0) byte |= 0x80;
|
|
13
|
+
bytes.push(byte);
|
|
14
|
+
} while (v !== 0);
|
|
15
|
+
return bytes;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function encodeI32LEB(val) {
|
|
19
|
+
let v = val | 0;
|
|
20
|
+
const bytes = [];
|
|
21
|
+
let more = true;
|
|
22
|
+
while (more) {
|
|
23
|
+
let byte = v & 0x7f;
|
|
24
|
+
v >>= 7;
|
|
25
|
+
if ((v === 0 && (byte & 0x40) === 0) || (v === -1 && (byte & 0x40) !== 0)) {
|
|
26
|
+
more = false;
|
|
27
|
+
} else {
|
|
28
|
+
byte |= 0x80;
|
|
29
|
+
}
|
|
30
|
+
bytes.push(byte);
|
|
31
|
+
}
|
|
32
|
+
return bytes;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function encodeI64LEB(val) {
|
|
36
|
+
let v = BigInt.asIntN(64, typeof val === "bigint" ? val : BigInt(val));
|
|
37
|
+
const bytes = [];
|
|
38
|
+
let more = true;
|
|
39
|
+
while (more) {
|
|
40
|
+
let byte = Number(v & 0x7fn);
|
|
41
|
+
v >>= 7n;
|
|
42
|
+
if (
|
|
43
|
+
(v === 0n && (byte & 0x40) === 0) ||
|
|
44
|
+
(v === -1n && (byte & 0x40) !== 0)
|
|
45
|
+
) {
|
|
46
|
+
more = false;
|
|
47
|
+
} else {
|
|
48
|
+
byte |= 0x80;
|
|
49
|
+
}
|
|
50
|
+
bytes.push(byte);
|
|
51
|
+
}
|
|
52
|
+
return bytes;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function encodeF32(val) {
|
|
56
|
+
const buf = new ArrayBuffer(4);
|
|
57
|
+
new DataView(buf).setFloat32(0, Number(val), true); // little-endian
|
|
58
|
+
return Array.from(new Uint8Array(buf));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function encodeF64(val) {
|
|
62
|
+
const buf = new ArrayBuffer(8);
|
|
63
|
+
new DataView(buf).setFloat64(0, Number(val), true); // little-endian
|
|
64
|
+
return Array.from(new Uint8Array(buf));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function encodeString(str) {
|
|
68
|
+
const utf8 = new TextEncoder().encode(str);
|
|
69
|
+
return [...encodeU32LEB(utf8.length), ...utf8];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function encodeVector(items, encodeItem) {
|
|
73
|
+
const count = encodeU32LEB(items.length);
|
|
74
|
+
const bytes = [];
|
|
75
|
+
for (const item of items) {
|
|
76
|
+
const chunk = encodeItem(item);
|
|
77
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
78
|
+
bytes.push(chunk[i]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return [...count, ...bytes];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ── Value Types & Heap Types ─────────────────────────────────
|
|
85
|
+
|
|
86
|
+
const ValType = {
|
|
87
|
+
i32: 0x7f,
|
|
88
|
+
i64: 0x7e,
|
|
89
|
+
f32: 0x7d,
|
|
90
|
+
f64: 0x7c,
|
|
91
|
+
v128: 0x7b,
|
|
92
|
+
i8: 0x7a,
|
|
93
|
+
i16: 0x79,
|
|
94
|
+
funcref: 0x70,
|
|
95
|
+
externref: 0x6f,
|
|
96
|
+
anyref: 0x6e,
|
|
97
|
+
eqref: 0x6d,
|
|
98
|
+
i31ref: 0x6c,
|
|
99
|
+
structref: 0x6b,
|
|
100
|
+
arrayref: 0x6a,
|
|
101
|
+
nullref: 0x71,
|
|
102
|
+
nullfuncref: 0x73,
|
|
103
|
+
nullexternref: 0x72,
|
|
104
|
+
exnref: 0x69,
|
|
105
|
+
nullexnref: 0x75,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
function encodeValType(type) {
|
|
109
|
+
if (typeof type === "number") {
|
|
110
|
+
return [type];
|
|
111
|
+
}
|
|
112
|
+
if (typeof type === "string") {
|
|
113
|
+
if (ValType[type] !== undefined) return [ValType[type]];
|
|
114
|
+
throw new Error(`Unknown value type: ${type}`);
|
|
115
|
+
}
|
|
116
|
+
if (typeof type === "object" && type !== null) {
|
|
117
|
+
if (type.kind === "ref") {
|
|
118
|
+
const opcode = type.nullable ? 0x63 : 0x64;
|
|
119
|
+
if (typeof type.typeIndex === "number") {
|
|
120
|
+
return [opcode, ...encodeI32LEB(type.typeIndex)];
|
|
121
|
+
}
|
|
122
|
+
if (typeof type.heapType === "string") {
|
|
123
|
+
const ht = ValType[type.heapType] ?? ValType[`${type.heapType}ref`];
|
|
124
|
+
if (ht !== undefined) return [opcode, ht];
|
|
125
|
+
}
|
|
126
|
+
if (typeof type.heapType === "number") {
|
|
127
|
+
return [opcode, ...encodeI32LEB(type.heapType)];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
throw new Error(`Invalid valtype specification: ${JSON.stringify(type)}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function encodeBlockType(blockType) {
|
|
135
|
+
if (!blockType || blockType === "void") {
|
|
136
|
+
return [0x40];
|
|
137
|
+
}
|
|
138
|
+
if (typeof blockType === "string") {
|
|
139
|
+
return encodeValType(blockType);
|
|
140
|
+
}
|
|
141
|
+
if (typeof blockType === "number") {
|
|
142
|
+
// Type index for multi-value block: signed LEB128
|
|
143
|
+
return encodeI32LEB(blockType);
|
|
144
|
+
}
|
|
145
|
+
return encodeValType(blockType);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── Instruction Encoders ─────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
const OPCODES = {
|
|
151
|
+
unreachable: 0x00,
|
|
152
|
+
nop: 0x01,
|
|
153
|
+
block: 0x02,
|
|
154
|
+
loop: 0x03,
|
|
155
|
+
if: 0x04,
|
|
156
|
+
else: 0x05,
|
|
157
|
+
throw: 0x08,
|
|
158
|
+
throw_ref: 0x0a,
|
|
159
|
+
end: 0x0b,
|
|
160
|
+
br: 0x0c,
|
|
161
|
+
br_if: 0x0d,
|
|
162
|
+
br_table: 0x0e,
|
|
163
|
+
return: 0x0f,
|
|
164
|
+
call: 0x10,
|
|
165
|
+
call_indirect: 0x11,
|
|
166
|
+
return_call: 0x12,
|
|
167
|
+
return_call_indirect: 0x13,
|
|
168
|
+
call_ref: 0x14,
|
|
169
|
+
return_call_ref: 0x15,
|
|
170
|
+
try_table: 0x1f,
|
|
171
|
+
drop: 0x1a,
|
|
172
|
+
select: 0x1b,
|
|
173
|
+
|
|
174
|
+
"local.get": 0x20,
|
|
175
|
+
"local.set": 0x21,
|
|
176
|
+
"local.tee": 0x22,
|
|
177
|
+
"global.get": 0x23,
|
|
178
|
+
"global.set": 0x24,
|
|
179
|
+
|
|
180
|
+
"i32.load": 0x28,
|
|
181
|
+
"i64.load": 0x29,
|
|
182
|
+
"f32.load": 0x2a,
|
|
183
|
+
"f64.load": 0x2b,
|
|
184
|
+
"i32.load8_s": 0x2c,
|
|
185
|
+
"i32.load8_u": 0x2d,
|
|
186
|
+
"i32.load16_s": 0x2e,
|
|
187
|
+
"i32.load16_u": 0x2f,
|
|
188
|
+
"i32.store": 0x36,
|
|
189
|
+
"i64.store": 0x37,
|
|
190
|
+
"f32.store": 0x38,
|
|
191
|
+
"f64.store": 0x39,
|
|
192
|
+
"i32.store8": 0x3a,
|
|
193
|
+
"i32.store16": 0x3b,
|
|
194
|
+
"memory.size": 0x3f,
|
|
195
|
+
"memory.grow": 0x40,
|
|
196
|
+
|
|
197
|
+
"i32.const": 0x41,
|
|
198
|
+
"i64.const": 0x42,
|
|
199
|
+
"f32.const": 0x43,
|
|
200
|
+
"f64.const": 0x44,
|
|
201
|
+
|
|
202
|
+
"i32.eqz": 0x45,
|
|
203
|
+
"i32.eq": 0x46,
|
|
204
|
+
"i32.ne": 0x47,
|
|
205
|
+
"i32.lt_s": 0x48,
|
|
206
|
+
"i32.lt_u": 0x49,
|
|
207
|
+
"i32.gt_s": 0x4a,
|
|
208
|
+
"i32.gt_u": 0x4b,
|
|
209
|
+
"i32.le_s": 0x4c,
|
|
210
|
+
"i32.le_u": 0x4d,
|
|
211
|
+
"i32.ge_s": 0x4e,
|
|
212
|
+
"i32.ge_u": 0x4f,
|
|
213
|
+
|
|
214
|
+
"i64.eqz": 0x50,
|
|
215
|
+
"i64.eq": 0x51,
|
|
216
|
+
"i64.ne": 0x52,
|
|
217
|
+
"i64.lt_s": 0x53,
|
|
218
|
+
"i64.lt_u": 0x54,
|
|
219
|
+
"i64.gt_s": 0x55,
|
|
220
|
+
"i64.gt_u": 0x56,
|
|
221
|
+
"i64.le_s": 0x57,
|
|
222
|
+
"i64.le_u": 0x58,
|
|
223
|
+
"i64.ge_s": 0x59,
|
|
224
|
+
"i64.ge_u": 0x5a,
|
|
225
|
+
|
|
226
|
+
"f32.eq": 0x5b,
|
|
227
|
+
"f32.ne": 0x5c,
|
|
228
|
+
"f32.lt": 0x5d,
|
|
229
|
+
"f32.gt": 0x5e,
|
|
230
|
+
"f32.le": 0x5f,
|
|
231
|
+
"f32.ge": 0x60,
|
|
232
|
+
|
|
233
|
+
"f64.eq": 0x61,
|
|
234
|
+
"f64.ne": 0x62,
|
|
235
|
+
"f64.lt": 0x63,
|
|
236
|
+
"f64.gt": 0x64,
|
|
237
|
+
"f64.le": 0x65,
|
|
238
|
+
"f64.ge": 0x66,
|
|
239
|
+
|
|
240
|
+
"i32.clz": 0x67,
|
|
241
|
+
"i32.ctz": 0x68,
|
|
242
|
+
"i32.popcnt": 0x69,
|
|
243
|
+
"i32.add": 0x6a,
|
|
244
|
+
"i32.sub": 0x6b,
|
|
245
|
+
"i32.mul": 0x6c,
|
|
246
|
+
"i32.div_s": 0x6d,
|
|
247
|
+
"i32.div_u": 0x6e,
|
|
248
|
+
"i32.rem_s": 0x6f,
|
|
249
|
+
"i32.rem_u": 0x70,
|
|
250
|
+
"i32.and": 0x71,
|
|
251
|
+
"i32.or": 0x72,
|
|
252
|
+
"i32.xor": 0x73,
|
|
253
|
+
"i32.shl": 0x74,
|
|
254
|
+
"i32.shr_s": 0x75,
|
|
255
|
+
"i32.shr_u": 0x76,
|
|
256
|
+
"i32.rotl": 0x77,
|
|
257
|
+
"i32.rotr": 0x78,
|
|
258
|
+
|
|
259
|
+
"i64.clz": 0x79,
|
|
260
|
+
"i64.ctz": 0x7a,
|
|
261
|
+
"i64.popcnt": 0x7b,
|
|
262
|
+
"i64.add": 0x7c,
|
|
263
|
+
"i64.sub": 0x7d,
|
|
264
|
+
"i64.mul": 0x7e,
|
|
265
|
+
"i64.div_s": 0x7f,
|
|
266
|
+
"i64.div_u": 0x80,
|
|
267
|
+
"i64.rem_s": 0x81,
|
|
268
|
+
"i64.rem_u": 0x82,
|
|
269
|
+
"i64.and": 0x83,
|
|
270
|
+
"i64.or": 0x84,
|
|
271
|
+
"i64.xor": 0x85,
|
|
272
|
+
"i64.shl": 0x86,
|
|
273
|
+
"i64.shr_s": 0x87,
|
|
274
|
+
"i64.shr_u": 0x88,
|
|
275
|
+
"i64.rotl": 0x89,
|
|
276
|
+
"i64.rotr": 0x8a,
|
|
277
|
+
|
|
278
|
+
"f32.abs": 0x8b,
|
|
279
|
+
"f32.neg": 0x8c,
|
|
280
|
+
"f32.ceil": 0x8d,
|
|
281
|
+
"f32.floor": 0x8e,
|
|
282
|
+
"f32.trunc": 0x8f,
|
|
283
|
+
"f32.nearest": 0x90,
|
|
284
|
+
"f32.sqrt": 0x91,
|
|
285
|
+
"f32.add": 0x92,
|
|
286
|
+
"f32.sub": 0x93,
|
|
287
|
+
"f32.mul": 0x94,
|
|
288
|
+
"f32.div": 0x95,
|
|
289
|
+
"f32.min": 0x96,
|
|
290
|
+
"f32.max": 0x97,
|
|
291
|
+
"f32.copysign": 0x98,
|
|
292
|
+
|
|
293
|
+
"f64.abs": 0x99,
|
|
294
|
+
"f64.neg": 0x9a,
|
|
295
|
+
"f64.ceil": 0x9b,
|
|
296
|
+
"f64.floor": 0x9c,
|
|
297
|
+
"f64.trunc": 0x9d,
|
|
298
|
+
"f64.nearest": 0x9e,
|
|
299
|
+
"f64.sqrt": 0x9f,
|
|
300
|
+
"f64.add": 0xa0,
|
|
301
|
+
"f64.sub": 0xa1,
|
|
302
|
+
"f64.mul": 0xa2,
|
|
303
|
+
"f64.div": 0xa3,
|
|
304
|
+
"f64.min": 0xa4,
|
|
305
|
+
"f64.max": 0xa5,
|
|
306
|
+
"f64.copysign": 0xa6,
|
|
307
|
+
|
|
308
|
+
"i32.wrap_i64": 0xa7,
|
|
309
|
+
"i32.trunc_f32_s": 0xa8,
|
|
310
|
+
"i32.trunc_f32_u": 0xa9,
|
|
311
|
+
"i32.trunc_f64_s": 0xaa,
|
|
312
|
+
"i32.trunc_f64_u": 0xab,
|
|
313
|
+
"i64.extend_i32_s": 0xac,
|
|
314
|
+
"i64.extend_i32_u": 0xad,
|
|
315
|
+
"i64.trunc_f32_s": 0xae,
|
|
316
|
+
"i64.trunc_f32_u": 0xaf,
|
|
317
|
+
"i64.trunc_f64_s": 0xb0,
|
|
318
|
+
"i64.trunc_f64_u": 0xb1,
|
|
319
|
+
"f32.convert_i32_s": 0xb2,
|
|
320
|
+
"f32.convert_i32_u": 0xb3,
|
|
321
|
+
"f32.convert_i64_s": 0xb4,
|
|
322
|
+
"f32.convert_i64_u": 0xb5,
|
|
323
|
+
"f32.demote_f64": 0xb6,
|
|
324
|
+
"f64.convert_i32_s": 0xb7,
|
|
325
|
+
"f64.convert_i32_u": 0xb8,
|
|
326
|
+
"f64.convert_i64_s": 0xb9,
|
|
327
|
+
"f64.convert_i64_u": 0xba,
|
|
328
|
+
"f64.promote_f32": 0xbb,
|
|
329
|
+
"i32.reinterpret_f32": 0xbc,
|
|
330
|
+
"i64.reinterpret_f64": 0xbd,
|
|
331
|
+
"f32.reinterpret_i32": 0xbe,
|
|
332
|
+
"f64.reinterpret_i64": 0xbf,
|
|
333
|
+
|
|
334
|
+
"i32.extend8_s": 0xc0,
|
|
335
|
+
"i32.extend16_s": 0xc1,
|
|
336
|
+
"i64.extend8_s": 0xc2,
|
|
337
|
+
"i64.extend16_s": 0xc3,
|
|
338
|
+
"i64.extend32_s": 0xc4,
|
|
339
|
+
|
|
340
|
+
"ref.null": 0xd0,
|
|
341
|
+
"ref.is_null": 0xd1,
|
|
342
|
+
"ref.func": 0xd2,
|
|
343
|
+
"ref.eq": 0xd3,
|
|
344
|
+
"ref.as_non_null": 0xd4,
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// 0xFC prefixed saturating truncations
|
|
348
|
+
const SAT_TRUNC_OPCODES = {
|
|
349
|
+
"i32.trunc_sat_f32_s": 0x00,
|
|
350
|
+
"i32.trunc_sat_f32_u": 0x01,
|
|
351
|
+
"i32.trunc_sat_f64_s": 0x02,
|
|
352
|
+
"i32.trunc_sat_f64_u": 0x03,
|
|
353
|
+
"i64.trunc_sat_f32_s": 0x04,
|
|
354
|
+
"i64.trunc_sat_f32_u": 0x05,
|
|
355
|
+
"i64.trunc_sat_f64_s": 0x06,
|
|
356
|
+
"i64.trunc_sat_f64_u": 0x07,
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// 0xFB prefixed WasmGC instructions
|
|
360
|
+
const GC_OPCODES = {
|
|
361
|
+
"struct.new": 0x00,
|
|
362
|
+
"struct.new_default": 0x01,
|
|
363
|
+
"struct.get": 0x02,
|
|
364
|
+
"struct.get_s": 0x03,
|
|
365
|
+
"struct.get_u": 0x04,
|
|
366
|
+
"struct.set": 0x05,
|
|
367
|
+
"array.new": 0x06,
|
|
368
|
+
"array.new_default": 0x07,
|
|
369
|
+
"array.new_fixed": 0x08,
|
|
370
|
+
"array.get": 0x0b,
|
|
371
|
+
"array.get_s": 0x0c,
|
|
372
|
+
"array.get_u": 0x0d,
|
|
373
|
+
"array.set": 0x0e,
|
|
374
|
+
"array.len": 0x0f,
|
|
375
|
+
"array.copy": 0x11,
|
|
376
|
+
"ref.test": 0x14,
|
|
377
|
+
"ref.test_null": 0x15,
|
|
378
|
+
"ref.cast": 0x16,
|
|
379
|
+
"ref.cast_null": 0x17,
|
|
380
|
+
"any.convert_extern": 0x1a,
|
|
381
|
+
"extern.convert_any": 0x1b,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Natural alignment (log2) per load/store opcode; memarg = align, offset.
|
|
385
|
+
const MEM_ALIGN = {
|
|
386
|
+
"i32.load": 2,
|
|
387
|
+
"i64.load": 3,
|
|
388
|
+
"f32.load": 2,
|
|
389
|
+
"f64.load": 3,
|
|
390
|
+
"i32.load8_s": 0,
|
|
391
|
+
"i32.load8_u": 0,
|
|
392
|
+
"i32.load16_s": 1,
|
|
393
|
+
"i32.load16_u": 1,
|
|
394
|
+
"i32.store": 2,
|
|
395
|
+
"i64.store": 3,
|
|
396
|
+
"f32.store": 2,
|
|
397
|
+
"f64.store": 3,
|
|
398
|
+
"i32.store8": 0,
|
|
399
|
+
"i32.store16": 1,
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
function encodeInstruction(inst) {
|
|
403
|
+
if (typeof inst === "string") {
|
|
404
|
+
inst = { op: inst };
|
|
405
|
+
}
|
|
406
|
+
const { op } = inst;
|
|
407
|
+
|
|
408
|
+
if (MEM_ALIGN[op] !== undefined) {
|
|
409
|
+
return [
|
|
410
|
+
OPCODES[op],
|
|
411
|
+
...encodeU32LEB(inst.align ?? MEM_ALIGN[op]),
|
|
412
|
+
...encodeU32LEB(inst.offset ?? 0),
|
|
413
|
+
];
|
|
414
|
+
}
|
|
415
|
+
if (op === "memory.size" || op === "memory.grow") {
|
|
416
|
+
return [OPCODES[op], 0x00];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 1. Check saturating truncations (0xFC prefix)
|
|
420
|
+
if (SAT_TRUNC_OPCODES[op] !== undefined) {
|
|
421
|
+
return [0xfc, ...encodeU32LEB(SAT_TRUNC_OPCODES[op])];
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// 2. Check WasmGC opcodes (0xFB prefix)
|
|
425
|
+
if (GC_OPCODES[op] !== undefined) {
|
|
426
|
+
const subOp = GC_OPCODES[op];
|
|
427
|
+
const bytes = [0xfb, ...encodeU32LEB(subOp)];
|
|
428
|
+
if (op === "array.copy") {
|
|
429
|
+
bytes.push(...encodeU32LEB(inst.typeIndexDst ?? inst.typeIndex ?? 0));
|
|
430
|
+
bytes.push(...encodeU32LEB(inst.typeIndexSrc ?? inst.typeIndex ?? 0));
|
|
431
|
+
return bytes;
|
|
432
|
+
}
|
|
433
|
+
if (op === "array.new_fixed") {
|
|
434
|
+
bytes.push(...encodeU32LEB(inst.typeIndex ?? 0));
|
|
435
|
+
bytes.push(...encodeU32LEB(inst.size ?? inst.count ?? 0));
|
|
436
|
+
return bytes;
|
|
437
|
+
}
|
|
438
|
+
if (
|
|
439
|
+
op === "array.len" ||
|
|
440
|
+
op === "any.convert_extern" ||
|
|
441
|
+
op === "extern.convert_any"
|
|
442
|
+
) {
|
|
443
|
+
return bytes;
|
|
444
|
+
}
|
|
445
|
+
if (
|
|
446
|
+
op === "ref.cast" ||
|
|
447
|
+
op === "ref.cast_null" ||
|
|
448
|
+
op === "ref.test" ||
|
|
449
|
+
op === "ref.test_null"
|
|
450
|
+
) {
|
|
451
|
+
const ht =
|
|
452
|
+
inst.heapType !== undefined
|
|
453
|
+
? inst.heapType
|
|
454
|
+
: inst.typeIndex !== undefined
|
|
455
|
+
? inst.typeIndex
|
|
456
|
+
: "any";
|
|
457
|
+
if (typeof ht === "number") {
|
|
458
|
+
bytes.push(...encodeI32LEB(ht));
|
|
459
|
+
} else {
|
|
460
|
+
const code = ValType[ht] ?? ValType[`${ht}ref`] ?? 0x6e;
|
|
461
|
+
bytes.push(code);
|
|
462
|
+
}
|
|
463
|
+
return bytes;
|
|
464
|
+
}
|
|
465
|
+
if (inst.typeIndex !== undefined) {
|
|
466
|
+
bytes.push(...encodeU32LEB(inst.typeIndex));
|
|
467
|
+
}
|
|
468
|
+
if (inst.fieldIndex !== undefined) {
|
|
469
|
+
bytes.push(...encodeU32LEB(inst.fieldIndex));
|
|
470
|
+
}
|
|
471
|
+
return bytes;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// 3. Standard opcodes
|
|
475
|
+
if (OPCODES[op] !== undefined) {
|
|
476
|
+
const byte = OPCODES[op];
|
|
477
|
+
switch (op) {
|
|
478
|
+
case "block":
|
|
479
|
+
case "loop":
|
|
480
|
+
case "if":
|
|
481
|
+
return [byte, ...encodeBlockType(inst.blockType ?? inst.resultType)];
|
|
482
|
+
|
|
483
|
+
case "br":
|
|
484
|
+
case "br_if":
|
|
485
|
+
return [byte, ...encodeU32LEB(inst.depth ?? inst.index ?? 0)];
|
|
486
|
+
|
|
487
|
+
case "br_table": {
|
|
488
|
+
const targets = inst.targets ?? [];
|
|
489
|
+
const defaultTarget = inst.defaultTarget ?? 0;
|
|
490
|
+
const count = encodeU32LEB(targets.length);
|
|
491
|
+
const targetBytes = targets.flatMap((t) => encodeU32LEB(t));
|
|
492
|
+
return [byte, ...count, ...targetBytes, ...encodeU32LEB(defaultTarget)];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
case "throw":
|
|
496
|
+
return [byte, ...encodeU32LEB(inst.tagIndex ?? inst.index ?? 0)];
|
|
497
|
+
|
|
498
|
+
case "throw_ref":
|
|
499
|
+
return [byte];
|
|
500
|
+
|
|
501
|
+
case "try_table": {
|
|
502
|
+
const blockTypeBytes = encodeBlockType(
|
|
503
|
+
inst.blockType ?? inst.resultType,
|
|
504
|
+
);
|
|
505
|
+
const catches = inst.catches ?? [];
|
|
506
|
+
const catchBytes = encodeVector(catches, (c) => {
|
|
507
|
+
const kind = c.kind ?? c.op;
|
|
508
|
+
switch (kind) {
|
|
509
|
+
case "catch":
|
|
510
|
+
return [
|
|
511
|
+
0x00,
|
|
512
|
+
...encodeU32LEB(c.tagIndex ?? c.tag ?? 0),
|
|
513
|
+
...encodeU32LEB(c.label ?? c.depth ?? 0),
|
|
514
|
+
];
|
|
515
|
+
case "catch_ref":
|
|
516
|
+
return [
|
|
517
|
+
0x01,
|
|
518
|
+
...encodeU32LEB(c.tagIndex ?? c.tag ?? 0),
|
|
519
|
+
...encodeU32LEB(c.label ?? c.depth ?? 0),
|
|
520
|
+
];
|
|
521
|
+
case "catch_all":
|
|
522
|
+
return [0x02, ...encodeU32LEB(c.label ?? c.depth ?? 0)];
|
|
523
|
+
case "catch_all_ref":
|
|
524
|
+
return [0x03, ...encodeU32LEB(c.label ?? c.depth ?? 0)];
|
|
525
|
+
default:
|
|
526
|
+
throw new Error(`Unknown catch kind: ${kind}`);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
return [byte, ...blockTypeBytes, ...catchBytes];
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
case "call":
|
|
533
|
+
case "return_call":
|
|
534
|
+
return [byte, ...encodeU32LEB(inst.funcIndex ?? inst.index ?? 0)];
|
|
535
|
+
|
|
536
|
+
case "call_indirect":
|
|
537
|
+
case "return_call_indirect":
|
|
538
|
+
return [
|
|
539
|
+
byte,
|
|
540
|
+
...encodeU32LEB(inst.typeIndex ?? 0),
|
|
541
|
+
...encodeU32LEB(inst.tableIndex ?? 0),
|
|
542
|
+
];
|
|
543
|
+
|
|
544
|
+
case "call_ref":
|
|
545
|
+
case "return_call_ref":
|
|
546
|
+
return [byte, ...encodeU32LEB(inst.typeIndex ?? 0)];
|
|
547
|
+
|
|
548
|
+
case "ref.func":
|
|
549
|
+
return [byte, ...encodeU32LEB(inst.funcIndex ?? inst.index ?? 0)];
|
|
550
|
+
|
|
551
|
+
case "local.get":
|
|
552
|
+
case "local.set":
|
|
553
|
+
case "local.tee":
|
|
554
|
+
return [byte, ...encodeU32LEB(inst.localIndex ?? inst.index ?? 0)];
|
|
555
|
+
|
|
556
|
+
case "global.get":
|
|
557
|
+
case "global.set":
|
|
558
|
+
return [byte, ...encodeU32LEB(inst.globalIndex ?? inst.index ?? 0)];
|
|
559
|
+
|
|
560
|
+
case "i32.const":
|
|
561
|
+
return [byte, ...encodeI32LEB(inst.value ?? 0)];
|
|
562
|
+
|
|
563
|
+
case "i64.const":
|
|
564
|
+
return [byte, ...encodeI64LEB(inst.value ?? 0n)];
|
|
565
|
+
|
|
566
|
+
case "f32.const":
|
|
567
|
+
return [byte, ...encodeF32(inst.value ?? 0)];
|
|
568
|
+
|
|
569
|
+
case "f64.const":
|
|
570
|
+
return [byte, ...encodeF64(inst.value ?? 0)];
|
|
571
|
+
|
|
572
|
+
case "ref.null": {
|
|
573
|
+
const ht =
|
|
574
|
+
inst.heapType !== undefined
|
|
575
|
+
? inst.heapType
|
|
576
|
+
: inst.typeIndex !== undefined
|
|
577
|
+
? inst.typeIndex
|
|
578
|
+
: "any";
|
|
579
|
+
if (typeof ht === "number") {
|
|
580
|
+
return [byte, ...encodeI32LEB(ht)];
|
|
581
|
+
}
|
|
582
|
+
const code = ValType[ht] ?? ValType[`${ht}ref`] ?? 0x6e;
|
|
583
|
+
return [byte, code];
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
default:
|
|
587
|
+
return [byte];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
throw new Error(`Unsupported WASM instruction opcode: '${op}'`);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// ── Section Encoders ─────────────────────────────────────────
|
|
595
|
+
|
|
596
|
+
function encodeSection(id, payload) {
|
|
597
|
+
if (payload.length === 0) return [];
|
|
598
|
+
return [id, ...encodeU32LEB(payload.length), ...payload];
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function encodeTypeEntry(t) {
|
|
602
|
+
if (t.form === "rec") {
|
|
603
|
+
// Recursive type group: 0x4E, count, types
|
|
604
|
+
const count = encodeU32LEB(t.types.length);
|
|
605
|
+
const innerBytes = t.types.flatMap((sub) => encodeTypeEntry(sub));
|
|
606
|
+
return [0x4e, ...count, ...innerBytes];
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (t.form === "struct") {
|
|
610
|
+
// Struct type: 0x5F, vector of fields [valtype, mutability]
|
|
611
|
+
const fields = t.fields ?? [];
|
|
612
|
+
return [
|
|
613
|
+
0x5f,
|
|
614
|
+
...encodeVector(fields, (f) => [
|
|
615
|
+
...encodeValType(f.type),
|
|
616
|
+
f.mutable ? 0x01 : 0x00,
|
|
617
|
+
]),
|
|
618
|
+
];
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (t.form === "array") {
|
|
622
|
+
// Array type: 0x5E, field [valtype, mutability]
|
|
623
|
+
return [
|
|
624
|
+
0x5e,
|
|
625
|
+
...encodeValType(t.elemType ?? t.type),
|
|
626
|
+
t.mutable ? 0x01 : 0x00,
|
|
627
|
+
];
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Function type: 0x60, params vector, results vector
|
|
631
|
+
const params = t.params ?? [];
|
|
632
|
+
const results = t.results ?? [];
|
|
633
|
+
return [
|
|
634
|
+
0x60,
|
|
635
|
+
...encodeVector(params, encodeValType),
|
|
636
|
+
...encodeVector(results, encodeValType),
|
|
637
|
+
];
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function encodeTypeSection(types) {
|
|
641
|
+
if (!types || types.length === 0) return [];
|
|
642
|
+
return encodeSection(1, encodeVector(types, encodeTypeEntry));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function encodeImportSection(imports) {
|
|
646
|
+
if (!imports || imports.length === 0) return [];
|
|
647
|
+
return encodeSection(
|
|
648
|
+
2,
|
|
649
|
+
encodeVector(imports, (imp) => {
|
|
650
|
+
const mod = encodeString(imp.module);
|
|
651
|
+
const name = encodeString(imp.name);
|
|
652
|
+
let desc = [];
|
|
653
|
+
switch (imp.kind) {
|
|
654
|
+
case "func":
|
|
655
|
+
desc = [0x00, ...encodeU32LEB(imp.typeIndex ?? 0)];
|
|
656
|
+
break;
|
|
657
|
+
case "table":
|
|
658
|
+
desc = [
|
|
659
|
+
0x01,
|
|
660
|
+
...encodeValType(imp.elemType ?? "funcref"),
|
|
661
|
+
imp.max !== undefined ? 0x01 : 0x00,
|
|
662
|
+
...encodeU32LEB(imp.min ?? 0),
|
|
663
|
+
...(imp.max !== undefined ? encodeU32LEB(imp.max) : []),
|
|
664
|
+
];
|
|
665
|
+
break;
|
|
666
|
+
case "memory":
|
|
667
|
+
desc = [
|
|
668
|
+
0x02,
|
|
669
|
+
imp.max !== undefined ? 0x01 : 0x00,
|
|
670
|
+
...encodeU32LEB(imp.min ?? 1),
|
|
671
|
+
...(imp.max !== undefined ? encodeU32LEB(imp.max) : []),
|
|
672
|
+
];
|
|
673
|
+
break;
|
|
674
|
+
case "global":
|
|
675
|
+
desc = [0x03, ...encodeValType(imp.type), imp.mutable ? 0x01 : 0x00];
|
|
676
|
+
break;
|
|
677
|
+
case "tag":
|
|
678
|
+
desc = [0x04, 0x00, ...encodeU32LEB(imp.typeIndex ?? 0)];
|
|
679
|
+
break;
|
|
680
|
+
default:
|
|
681
|
+
throw new Error(`Unknown import kind: ${imp.kind}`);
|
|
682
|
+
}
|
|
683
|
+
return [...mod, ...name, ...desc];
|
|
684
|
+
}),
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function encodeFunctionSection(funcs) {
|
|
689
|
+
if (!funcs || funcs.length === 0) return [];
|
|
690
|
+
return encodeSection(
|
|
691
|
+
3,
|
|
692
|
+
encodeVector(funcs, (fn) => encodeU32LEB(fn.typeIndex ?? 0)),
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function encodeTagSection(tags) {
|
|
697
|
+
if (!tags || tags.length === 0) return [];
|
|
698
|
+
return encodeSection(
|
|
699
|
+
13,
|
|
700
|
+
encodeVector(tags, (tag) => [0x00, ...encodeU32LEB(tag.typeIndex ?? 0)]),
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Single linear memory: `{ min, max }` in 64 KiB pages. `max` is optional;
|
|
705
|
+
// the shared-buffer runtime only grows the memory inside the start function,
|
|
706
|
+
// before any JS TypedArray view exists.
|
|
707
|
+
function encodeMemorySection(memory) {
|
|
708
|
+
if (!memory) return [];
|
|
709
|
+
const limits =
|
|
710
|
+
memory.max != null
|
|
711
|
+
? [0x01, ...encodeU32LEB(memory.min), ...encodeU32LEB(memory.max)]
|
|
712
|
+
: [0x00, ...encodeU32LEB(memory.min)];
|
|
713
|
+
return encodeSection(
|
|
714
|
+
5,
|
|
715
|
+
encodeVector([limits], (b) => b),
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
function encodeGlobalSection(globals) {
|
|
720
|
+
if (!globals || globals.length === 0) return [];
|
|
721
|
+
return encodeSection(
|
|
722
|
+
6,
|
|
723
|
+
encodeVector(globals, (g) => {
|
|
724
|
+
const typeBytes = encodeValType(g.type);
|
|
725
|
+
const mutByte = g.mutable ? 0x01 : 0x00;
|
|
726
|
+
const initInsts = g.init ?? [{ op: "i32.const", value: 0 }];
|
|
727
|
+
const exprBytes = [];
|
|
728
|
+
for (const inst of initInsts) {
|
|
729
|
+
const chunk = encodeInstruction(inst);
|
|
730
|
+
for (let i = 0; i < chunk.length; i++) exprBytes.push(chunk[i]);
|
|
731
|
+
}
|
|
732
|
+
if (
|
|
733
|
+
initInsts.length === 0 ||
|
|
734
|
+
initInsts[initInsts.length - 1].op !== "end"
|
|
735
|
+
) {
|
|
736
|
+
exprBytes.push(0x0b);
|
|
737
|
+
}
|
|
738
|
+
return [...typeBytes, mutByte, ...exprBytes];
|
|
739
|
+
}),
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function encodeExportSection(exports) {
|
|
744
|
+
if (!exports || exports.length === 0) return [];
|
|
745
|
+
return encodeSection(
|
|
746
|
+
7,
|
|
747
|
+
encodeVector(exports, (exp) => {
|
|
748
|
+
const name = encodeString(exp.name);
|
|
749
|
+
let kindByte = 0x00;
|
|
750
|
+
switch (exp.kind) {
|
|
751
|
+
case "func":
|
|
752
|
+
kindByte = 0x00;
|
|
753
|
+
break;
|
|
754
|
+
case "table":
|
|
755
|
+
kindByte = 0x01;
|
|
756
|
+
break;
|
|
757
|
+
case "memory":
|
|
758
|
+
kindByte = 0x02;
|
|
759
|
+
break;
|
|
760
|
+
case "global":
|
|
761
|
+
kindByte = 0x03;
|
|
762
|
+
break;
|
|
763
|
+
case "tag":
|
|
764
|
+
kindByte = 0x04;
|
|
765
|
+
break;
|
|
766
|
+
default:
|
|
767
|
+
throw new Error(`Unknown export kind: ${exp.kind}`);
|
|
768
|
+
}
|
|
769
|
+
return [...name, kindByte, ...encodeU32LEB(exp.index ?? 0)];
|
|
770
|
+
}),
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function sameValType(a, b) {
|
|
775
|
+
if (a === b) return true;
|
|
776
|
+
if (
|
|
777
|
+
typeof a === "object" &&
|
|
778
|
+
typeof b === "object" &&
|
|
779
|
+
a !== null &&
|
|
780
|
+
b !== null
|
|
781
|
+
) {
|
|
782
|
+
return (
|
|
783
|
+
a.kind === b.kind &&
|
|
784
|
+
a.nullable === b.nullable &&
|
|
785
|
+
a.typeIndex === b.typeIndex &&
|
|
786
|
+
a.heapType === b.heapType
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function encodeElementSection(elements) {
|
|
793
|
+
if (!elements || elements.length === 0) return [];
|
|
794
|
+
const segment = [0x03, 0x00, ...encodeVector(elements, encodeU32LEB)];
|
|
795
|
+
return encodeSection(
|
|
796
|
+
9,
|
|
797
|
+
encodeVector([segment], (bytes) => bytes),
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Encodes the code section. `bodyOffsets` (when given) receives, per
|
|
802
|
+
// function, the offset of the body's first instruction relative to the start
|
|
803
|
+
// of the section bytes returned.
|
|
804
|
+
function encodeCodeSection(funcs, bodyOffsets = null) {
|
|
805
|
+
if (!funcs || funcs.length === 0) return [];
|
|
806
|
+
const relOffsets = [];
|
|
807
|
+
const payload = encodeVector(funcs, (fn) => {
|
|
808
|
+
// Compress locals: [type1, type1, type2] -> [{ count: 2, type: type1 }, { count: 1, type: type2 }]
|
|
809
|
+
const rawLocals = fn.locals ?? [];
|
|
810
|
+
const compressedLocals = [];
|
|
811
|
+
for (const loc of rawLocals) {
|
|
812
|
+
const locType =
|
|
813
|
+
typeof loc === "string" ? loc : loc.type !== undefined ? loc.type : loc;
|
|
814
|
+
if (
|
|
815
|
+
compressedLocals.length > 0 &&
|
|
816
|
+
sameValType(compressedLocals[compressedLocals.length - 1].type, locType)
|
|
817
|
+
) {
|
|
818
|
+
compressedLocals[compressedLocals.length - 1].count++;
|
|
819
|
+
} else {
|
|
820
|
+
compressedLocals.push({ count: 1, type: locType });
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const localsBytes = encodeVector(compressedLocals, (group) => [
|
|
825
|
+
...encodeU32LEB(group.count),
|
|
826
|
+
...encodeValType(group.type),
|
|
827
|
+
]);
|
|
828
|
+
|
|
829
|
+
const bodyInsts = fn.body ?? [];
|
|
830
|
+
const bodyBytes = [];
|
|
831
|
+
for (const inst of bodyInsts) {
|
|
832
|
+
const chunk = encodeInstruction(inst);
|
|
833
|
+
for (let i = 0; i < chunk.length; i++) bodyBytes.push(chunk[i]);
|
|
834
|
+
}
|
|
835
|
+
// Ensure terminating end opcode (0x0B)
|
|
836
|
+
if (
|
|
837
|
+
bodyInsts.length === 0 ||
|
|
838
|
+
bodyInsts[bodyInsts.length - 1].op !== "end"
|
|
839
|
+
) {
|
|
840
|
+
bodyBytes.push(0x0b);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const fullBody = [...localsBytes, ...bodyBytes];
|
|
844
|
+
const sizeBytes = encodeU32LEB(fullBody.length);
|
|
845
|
+
// Offset of the first instruction within this entry + entry length.
|
|
846
|
+
relOffsets.push([
|
|
847
|
+
sizeBytes.length + localsBytes.length,
|
|
848
|
+
sizeBytes.length + fullBody.length,
|
|
849
|
+
]);
|
|
850
|
+
return [...sizeBytes, ...fullBody];
|
|
851
|
+
});
|
|
852
|
+
if (bodyOffsets) {
|
|
853
|
+
// Section-relative: id + size LEB + count LEB + preceding entries.
|
|
854
|
+
let cursor =
|
|
855
|
+
1 +
|
|
856
|
+
encodeU32LEB(payload.length).length +
|
|
857
|
+
encodeU32LEB(funcs.length).length;
|
|
858
|
+
for (const [first, len] of relOffsets) {
|
|
859
|
+
bodyOffsets.push(cursor + first);
|
|
860
|
+
cursor += len;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return encodeSection(10, payload);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// ── Top-level Module Encoder ─────────────────────────────────
|
|
867
|
+
|
|
868
|
+
// Custom section placed right after the header; `isGoFrontWasm` keys off it.
|
|
869
|
+
const GOFRONT_SECTION_NAME = "gofront";
|
|
870
|
+
export const GOFRONT_SECTION_BYTES = [
|
|
871
|
+
0x00,
|
|
872
|
+
...encodeU32LEB(1 + GOFRONT_SECTION_NAME.length),
|
|
873
|
+
...encodeString(GOFRONT_SECTION_NAME),
|
|
874
|
+
];
|
|
875
|
+
|
|
876
|
+
// True when `bytes` start with the wasm header followed by our custom section.
|
|
877
|
+
export function isGoFrontWasm(bytes) {
|
|
878
|
+
const expected = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];
|
|
879
|
+
expected.push(...GOFRONT_SECTION_BYTES);
|
|
880
|
+
if (!bytes || bytes.length < expected.length) return false;
|
|
881
|
+
for (let i = 0; i < expected.length; i++) {
|
|
882
|
+
if (bytes[i] !== expected[i]) return false;
|
|
883
|
+
}
|
|
884
|
+
return true;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Encodes the module. When `mod.sourceMappingURL` is set a trailing
|
|
888
|
+
// `sourceMappingURL` custom section is appended, and `mod.codeOffsets` is
|
|
889
|
+
// filled with the absolute byte offset of every function body (aligned with
|
|
890
|
+
// `mod.funcs`) so a function-level source map can be built.
|
|
891
|
+
export function encodeModule(mod) {
|
|
892
|
+
const magic = [0x00, 0x61, 0x73, 0x6d]; // \0asm
|
|
893
|
+
const version = [0x01, 0x00, 0x00, 0x00]; // version 1
|
|
894
|
+
|
|
895
|
+
const typeSec = encodeTypeSection(mod.types);
|
|
896
|
+
const importSec = encodeImportSection(mod.imports);
|
|
897
|
+
const funcSec = encodeFunctionSection(mod.funcs);
|
|
898
|
+
const memorySec = encodeMemorySection(mod.memory);
|
|
899
|
+
const tagSec = encodeTagSection(mod.tags);
|
|
900
|
+
const globalSec = encodeGlobalSection(mod.globals);
|
|
901
|
+
const exportSec = encodeExportSection(mod.exports);
|
|
902
|
+
const startSec =
|
|
903
|
+
typeof mod.start === "number"
|
|
904
|
+
? encodeSection(8, encodeU32LEB(mod.start))
|
|
905
|
+
: [];
|
|
906
|
+
const elemSec = encodeElementSection(mod.elements);
|
|
907
|
+
const sectionOffsets = [];
|
|
908
|
+
const codeSec = encodeCodeSection(mod.funcs, sectionOffsets);
|
|
909
|
+
|
|
910
|
+
const allBytes = [
|
|
911
|
+
...magic,
|
|
912
|
+
...version,
|
|
913
|
+
...GOFRONT_SECTION_BYTES,
|
|
914
|
+
...typeSec,
|
|
915
|
+
...importSec,
|
|
916
|
+
...funcSec,
|
|
917
|
+
...memorySec,
|
|
918
|
+
...tagSec,
|
|
919
|
+
...globalSec,
|
|
920
|
+
...exportSec,
|
|
921
|
+
...startSec,
|
|
922
|
+
...elemSec,
|
|
923
|
+
];
|
|
924
|
+
const codeStart = allBytes.length;
|
|
925
|
+
mod.codeOffsets = sectionOffsets.map((o) => codeStart + o);
|
|
926
|
+
allBytes.push(...codeSec);
|
|
927
|
+
if (mod.sourceMappingURL) {
|
|
928
|
+
allBytes.push(
|
|
929
|
+
...encodeSection(0, [
|
|
930
|
+
...encodeString("sourceMappingURL"),
|
|
931
|
+
...encodeString(mod.sourceMappingURL),
|
|
932
|
+
]),
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return new Uint8Array(allBytes);
|
|
937
|
+
}
|