gofront 1.5.1 → 1.6.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.
- package/README.md +174 -466
- package/package.json +16 -20
- package/src/backend/js/expressions.js +288 -128
- package/src/backend/js/index.js +138 -56
- package/src/backend/js/runtime.js +1055 -53
- package/src/backend/js/source-map.js +32 -0
- package/src/backend/js/statements.js +151 -83
- package/src/backend/js/stdlib/base64.js +12 -0
- package/src/backend/js/stdlib/binary.js +102 -0
- package/src/backend/js/stdlib/bits.js +15 -1
- package/src/backend/js/stdlib/builder.js +28 -9
- package/src/backend/js/stdlib/bytes.js +75 -18
- package/src/backend/js/stdlib/errors.js +22 -3
- package/src/backend/js/stdlib/fmt.js +95 -20
- package/src/backend/js/stdlib/hex.js +17 -0
- package/src/backend/js/stdlib/html.js +1 -1
- package/src/backend/js/stdlib/index.js +19 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/maps.js +1 -1
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +20 -6
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/backend/js/stdlib/slices.js +53 -27
- package/src/backend/js/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +52 -11
- package/src/backend/js/stdlib/strings.js +152 -16
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/testing.js +2 -2
- package/src/backend/js/stdlib/time.js +93 -22
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/js/templ.js +1 -1
- package/src/backend/wasm/boundary.js +1677 -58
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +1230 -0
- package/src/backend/wasm/emit-exprs.js +2096 -0
- package/src/backend/wasm/emit-maps.js +1999 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +13 -0
- package/src/backend/wasm/emit-stmts.js +2466 -0
- package/src/backend/wasm/emit.js +656 -5031
- package/src/backend/wasm/encode.js +259 -85
- package/src/backend/wasm/glue.js +19 -5
- package/src/backend/wasm/index.js +2432 -86
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +236 -0
- package/src/backend/wasm/stdlib/bytes.js +5039 -0
- package/src/backend/wasm/stdlib/core.js +8903 -0
- package/src/backend/wasm/stdlib/index.js +40 -0
- package/src/backend/wasm/stdlib/io.js +2161 -0
- package/src/backend/wasm/stdlib/packages.js +2400 -0
- package/src/backend/wasm/stdlib/pure.js +720 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +312 -36
- package/src/backend/wasm/wat.js +49 -2
- package/src/cli-core.js +276 -73
- package/src/compiler.js +162 -25
- package/src/dts-parser.js +79 -126
- package/src/index.js +88 -121
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +4 -6
- package/src/lower/captures.js +12 -23
- package/src/lower/escape.js +4 -9
- package/src/lower/functions.js +277 -5
- package/src/lower/globals.js +7 -15
- package/src/lower/index.js +5 -2
- package/src/lower/ownership.js +35 -19
- package/src/lower/range.js +2 -5
- package/src/lower/walk.js +25 -0
- package/src/minifier.js +20 -68
- package/src/parser/declarations.js +3 -6
- package/src/parser/expressions.js +3 -8
- package/src/parser/index.js +18 -3
- package/src/parser/statements.js +25 -38
- package/src/parser/types.js +1 -2
- package/src/resolver.js +3 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/test-runner.js +20 -0
- package/src/typechecker/assignability.js +123 -14
- package/src/typechecker/expressions.js +244 -4
- package/src/typechecker/index.js +27 -1
- package/src/typechecker/resolve.js +71 -12
- package/src/typechecker/statements.js +0 -7
- package/src/typechecker/stdlib/core.js +292 -103
- package/src/typechecker/stdlib/extended.js +471 -4
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +545 -8
- package/src/vendor.js +2 -2
|
@@ -52,24 +52,36 @@ export function encodeI64LEB(val) {
|
|
|
52
52
|
return bytes;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const _f32Arr = new Float32Array(1);
|
|
56
|
+
const _f32Bytes = new Uint8Array(_f32Arr.buffer);
|
|
55
57
|
export function encodeF32(val) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return Array.from(new Uint8Array(buf));
|
|
58
|
+
_f32Arr[0] = Number(val);
|
|
59
|
+
return [_f32Bytes[0], _f32Bytes[1], _f32Bytes[2], _f32Bytes[3]];
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
const _f64Arr = new Float64Array(1);
|
|
63
|
+
const _f64Bytes = new Uint8Array(_f64Arr.buffer);
|
|
61
64
|
export function encodeF64(val) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
_f64Arr[0] = Number(val);
|
|
66
|
+
return [
|
|
67
|
+
_f64Bytes[0],
|
|
68
|
+
_f64Bytes[1],
|
|
69
|
+
_f64Bytes[2],
|
|
70
|
+
_f64Bytes[3],
|
|
71
|
+
_f64Bytes[4],
|
|
72
|
+
_f64Bytes[5],
|
|
73
|
+
_f64Bytes[6],
|
|
74
|
+
_f64Bytes[7],
|
|
75
|
+
];
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
const _textEncoder = new TextEncoder();
|
|
79
|
+
function encodeString(str) {
|
|
80
|
+
const utf8 = _textEncoder.encode(str);
|
|
69
81
|
return [...encodeU32LEB(utf8.length), ...utf8];
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
function encodeVector(items, encodeItem) {
|
|
73
85
|
const count = encodeU32LEB(items.length);
|
|
74
86
|
const bytes = [];
|
|
75
87
|
for (const item of items) {
|
|
@@ -83,7 +95,7 @@ export function encodeVector(items, encodeItem) {
|
|
|
83
95
|
|
|
84
96
|
// ── Value Types & Heap Types ─────────────────────────────────
|
|
85
97
|
|
|
86
|
-
|
|
98
|
+
const ValType = {
|
|
87
99
|
i32: 0x7f,
|
|
88
100
|
i64: 0x7e,
|
|
89
101
|
f32: 0x7d,
|
|
@@ -101,9 +113,11 @@ export const ValType = {
|
|
|
101
113
|
nullref: 0x71,
|
|
102
114
|
nullfuncref: 0x73,
|
|
103
115
|
nullexternref: 0x72,
|
|
116
|
+
exnref: 0x69,
|
|
117
|
+
nullexnref: 0x75,
|
|
104
118
|
};
|
|
105
119
|
|
|
106
|
-
|
|
120
|
+
function encodeValType(type) {
|
|
107
121
|
if (typeof type === "number") {
|
|
108
122
|
return [type];
|
|
109
123
|
}
|
|
@@ -129,7 +143,7 @@ export function encodeValType(type) {
|
|
|
129
143
|
throw new Error(`Invalid valtype specification: ${JSON.stringify(type)}`);
|
|
130
144
|
}
|
|
131
145
|
|
|
132
|
-
|
|
146
|
+
function encodeBlockType(blockType) {
|
|
133
147
|
if (!blockType || blockType === "void") {
|
|
134
148
|
return [0x40];
|
|
135
149
|
}
|
|
@@ -153,6 +167,7 @@ const OPCODES = {
|
|
|
153
167
|
if: 0x04,
|
|
154
168
|
else: 0x05,
|
|
155
169
|
throw: 0x08,
|
|
170
|
+
throw_ref: 0x0a,
|
|
156
171
|
end: 0x0b,
|
|
157
172
|
br: 0x0c,
|
|
158
173
|
br_if: 0x0d,
|
|
@@ -164,6 +179,7 @@ const OPCODES = {
|
|
|
164
179
|
return_call_indirect: 0x13,
|
|
165
180
|
call_ref: 0x14,
|
|
166
181
|
return_call_ref: 0x15,
|
|
182
|
+
try_table: 0x1f,
|
|
167
183
|
drop: 0x1a,
|
|
168
184
|
select: 0x1b,
|
|
169
185
|
|
|
@@ -173,6 +189,23 @@ const OPCODES = {
|
|
|
173
189
|
"global.get": 0x23,
|
|
174
190
|
"global.set": 0x24,
|
|
175
191
|
|
|
192
|
+
"i32.load": 0x28,
|
|
193
|
+
"i64.load": 0x29,
|
|
194
|
+
"f32.load": 0x2a,
|
|
195
|
+
"f64.load": 0x2b,
|
|
196
|
+
"i32.load8_s": 0x2c,
|
|
197
|
+
"i32.load8_u": 0x2d,
|
|
198
|
+
"i32.load16_s": 0x2e,
|
|
199
|
+
"i32.load16_u": 0x2f,
|
|
200
|
+
"i32.store": 0x36,
|
|
201
|
+
"i64.store": 0x37,
|
|
202
|
+
"f32.store": 0x38,
|
|
203
|
+
"f64.store": 0x39,
|
|
204
|
+
"i32.store8": 0x3a,
|
|
205
|
+
"i32.store16": 0x3b,
|
|
206
|
+
"memory.size": 0x3f,
|
|
207
|
+
"memory.grow": 0x40,
|
|
208
|
+
|
|
176
209
|
"i32.const": 0x41,
|
|
177
210
|
"i64.const": 0x42,
|
|
178
211
|
"f32.const": 0x43,
|
|
@@ -360,12 +393,41 @@ const GC_OPCODES = {
|
|
|
360
393
|
"extern.convert_any": 0x1b,
|
|
361
394
|
};
|
|
362
395
|
|
|
363
|
-
|
|
396
|
+
// Natural alignment (log2) per load/store opcode; memarg = align, offset.
|
|
397
|
+
const MEM_ALIGN = {
|
|
398
|
+
"i32.load": 2,
|
|
399
|
+
"i64.load": 3,
|
|
400
|
+
"f32.load": 2,
|
|
401
|
+
"f64.load": 3,
|
|
402
|
+
"i32.load8_s": 0,
|
|
403
|
+
"i32.load8_u": 0,
|
|
404
|
+
"i32.load16_s": 1,
|
|
405
|
+
"i32.load16_u": 1,
|
|
406
|
+
"i32.store": 2,
|
|
407
|
+
"i64.store": 3,
|
|
408
|
+
"f32.store": 2,
|
|
409
|
+
"f64.store": 3,
|
|
410
|
+
"i32.store8": 0,
|
|
411
|
+
"i32.store16": 1,
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
function encodeInstruction(inst) {
|
|
364
415
|
if (typeof inst === "string") {
|
|
365
416
|
inst = { op: inst };
|
|
366
417
|
}
|
|
367
418
|
const { op } = inst;
|
|
368
419
|
|
|
420
|
+
if (MEM_ALIGN[op] !== undefined) {
|
|
421
|
+
return [
|
|
422
|
+
OPCODES[op],
|
|
423
|
+
...encodeU32LEB(inst.align ?? MEM_ALIGN[op]),
|
|
424
|
+
...encodeU32LEB(inst.offset ?? 0),
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
if (op === "memory.size" || op === "memory.grow") {
|
|
428
|
+
return [OPCODES[op], 0x00];
|
|
429
|
+
}
|
|
430
|
+
|
|
369
431
|
// 1. Check saturating truncations (0xFC prefix)
|
|
370
432
|
if (SAT_TRUNC_OPCODES[op] !== undefined) {
|
|
371
433
|
return [0xfc, ...encodeU32LEB(SAT_TRUNC_OPCODES[op])];
|
|
@@ -392,6 +454,26 @@ export function encodeInstruction(inst) {
|
|
|
392
454
|
) {
|
|
393
455
|
return bytes;
|
|
394
456
|
}
|
|
457
|
+
if (
|
|
458
|
+
op === "ref.cast" ||
|
|
459
|
+
op === "ref.cast_null" ||
|
|
460
|
+
op === "ref.test" ||
|
|
461
|
+
op === "ref.test_null"
|
|
462
|
+
) {
|
|
463
|
+
const ht =
|
|
464
|
+
inst.heapType !== undefined
|
|
465
|
+
? inst.heapType
|
|
466
|
+
: inst.typeIndex !== undefined
|
|
467
|
+
? inst.typeIndex
|
|
468
|
+
: "any";
|
|
469
|
+
if (typeof ht === "number") {
|
|
470
|
+
bytes.push(...encodeI32LEB(ht));
|
|
471
|
+
} else {
|
|
472
|
+
const code = ValType[ht] ?? ValType[`${ht}ref`] ?? 0x6e;
|
|
473
|
+
bytes.push(code);
|
|
474
|
+
}
|
|
475
|
+
return bytes;
|
|
476
|
+
}
|
|
395
477
|
if (inst.typeIndex !== undefined) {
|
|
396
478
|
bytes.push(...encodeU32LEB(inst.typeIndex));
|
|
397
479
|
}
|
|
@@ -425,6 +507,40 @@ export function encodeInstruction(inst) {
|
|
|
425
507
|
case "throw":
|
|
426
508
|
return [byte, ...encodeU32LEB(inst.tagIndex ?? inst.index ?? 0)];
|
|
427
509
|
|
|
510
|
+
case "throw_ref":
|
|
511
|
+
return [byte];
|
|
512
|
+
|
|
513
|
+
case "try_table": {
|
|
514
|
+
const blockTypeBytes = encodeBlockType(
|
|
515
|
+
inst.blockType ?? inst.resultType,
|
|
516
|
+
);
|
|
517
|
+
const catches = inst.catches ?? [];
|
|
518
|
+
const catchBytes = encodeVector(catches, (c) => {
|
|
519
|
+
const kind = c.kind ?? c.op;
|
|
520
|
+
switch (kind) {
|
|
521
|
+
case "catch":
|
|
522
|
+
return [
|
|
523
|
+
0x00,
|
|
524
|
+
...encodeU32LEB(c.tagIndex ?? c.tag ?? 0),
|
|
525
|
+
...encodeU32LEB(c.label ?? c.depth ?? 0),
|
|
526
|
+
];
|
|
527
|
+
case "catch_ref":
|
|
528
|
+
return [
|
|
529
|
+
0x01,
|
|
530
|
+
...encodeU32LEB(c.tagIndex ?? c.tag ?? 0),
|
|
531
|
+
...encodeU32LEB(c.label ?? c.depth ?? 0),
|
|
532
|
+
];
|
|
533
|
+
case "catch_all":
|
|
534
|
+
return [0x02, ...encodeU32LEB(c.label ?? c.depth ?? 0)];
|
|
535
|
+
case "catch_all_ref":
|
|
536
|
+
return [0x03, ...encodeU32LEB(c.label ?? c.depth ?? 0)];
|
|
537
|
+
default:
|
|
538
|
+
throw new Error(`Unknown catch kind: ${kind}`);
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
return [byte, ...blockTypeBytes, ...catchBytes];
|
|
542
|
+
}
|
|
543
|
+
|
|
428
544
|
case "call":
|
|
429
545
|
case "return_call":
|
|
430
546
|
return [byte, ...encodeU32LEB(inst.funcIndex ?? inst.index ?? 0)];
|
|
@@ -494,7 +610,7 @@ function encodeSection(id, payload) {
|
|
|
494
610
|
return [id, ...encodeU32LEB(payload.length), ...payload];
|
|
495
611
|
}
|
|
496
612
|
|
|
497
|
-
|
|
613
|
+
function encodeTypeEntry(t) {
|
|
498
614
|
if (t.form === "rec") {
|
|
499
615
|
// Recursive type group: 0x4E, count, types
|
|
500
616
|
const count = encodeU32LEB(t.types.length);
|
|
@@ -533,12 +649,12 @@ export function encodeTypeEntry(t) {
|
|
|
533
649
|
];
|
|
534
650
|
}
|
|
535
651
|
|
|
536
|
-
|
|
652
|
+
function encodeTypeSection(types) {
|
|
537
653
|
if (!types || types.length === 0) return [];
|
|
538
654
|
return encodeSection(1, encodeVector(types, encodeTypeEntry));
|
|
539
655
|
}
|
|
540
656
|
|
|
541
|
-
|
|
657
|
+
function encodeImportSection(imports) {
|
|
542
658
|
if (!imports || imports.length === 0) return [];
|
|
543
659
|
return encodeSection(
|
|
544
660
|
2,
|
|
@@ -581,7 +697,7 @@ export function encodeImportSection(imports) {
|
|
|
581
697
|
);
|
|
582
698
|
}
|
|
583
699
|
|
|
584
|
-
|
|
700
|
+
function encodeFunctionSection(funcs) {
|
|
585
701
|
if (!funcs || funcs.length === 0) return [];
|
|
586
702
|
return encodeSection(
|
|
587
703
|
3,
|
|
@@ -589,7 +705,7 @@ export function encodeFunctionSection(funcs) {
|
|
|
589
705
|
);
|
|
590
706
|
}
|
|
591
707
|
|
|
592
|
-
|
|
708
|
+
function encodeTagSection(tags) {
|
|
593
709
|
if (!tags || tags.length === 0) return [];
|
|
594
710
|
return encodeSection(
|
|
595
711
|
13,
|
|
@@ -597,7 +713,22 @@ export function encodeTagSection(tags) {
|
|
|
597
713
|
);
|
|
598
714
|
}
|
|
599
715
|
|
|
600
|
-
|
|
716
|
+
// Single linear memory: `{ min, max }` in 64 KiB pages. `max` is optional;
|
|
717
|
+
// the shared-buffer runtime only grows the memory inside the start function,
|
|
718
|
+
// before any JS TypedArray view exists.
|
|
719
|
+
function encodeMemorySection(memory) {
|
|
720
|
+
if (!memory) return [];
|
|
721
|
+
const limits =
|
|
722
|
+
memory.max != null
|
|
723
|
+
? [0x01, ...encodeU32LEB(memory.min), ...encodeU32LEB(memory.max)]
|
|
724
|
+
: [0x00, ...encodeU32LEB(memory.min)];
|
|
725
|
+
return encodeSection(
|
|
726
|
+
5,
|
|
727
|
+
encodeVector([limits], (b) => b),
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function encodeGlobalSection(globals) {
|
|
601
732
|
if (!globals || globals.length === 0) return [];
|
|
602
733
|
return encodeSection(
|
|
603
734
|
6,
|
|
@@ -621,7 +752,7 @@ export function encodeGlobalSection(globals) {
|
|
|
621
752
|
);
|
|
622
753
|
}
|
|
623
754
|
|
|
624
|
-
|
|
755
|
+
function encodeExportSection(exports) {
|
|
625
756
|
if (!exports || exports.length === 0) return [];
|
|
626
757
|
return encodeSection(
|
|
627
758
|
7,
|
|
@@ -670,7 +801,7 @@ function sameValType(a, b) {
|
|
|
670
801
|
return false;
|
|
671
802
|
}
|
|
672
803
|
|
|
673
|
-
|
|
804
|
+
function encodeElementSection(elements) {
|
|
674
805
|
if (!elements || elements.length === 0) return [];
|
|
675
806
|
const segment = [0x03, 0x00, ...encodeVector(elements, encodeU32LEB)];
|
|
676
807
|
return encodeSection(
|
|
@@ -679,64 +810,76 @@ export function encodeElementSection(elements) {
|
|
|
679
810
|
);
|
|
680
811
|
}
|
|
681
812
|
|
|
682
|
-
|
|
813
|
+
// Encodes the code section. `bodyOffsets` (when given) receives, per
|
|
814
|
+
// function, the offset of the body's first instruction relative to the start
|
|
815
|
+
// of the section bytes returned.
|
|
816
|
+
function encodeCodeSection(funcs, bodyOffsets = null) {
|
|
683
817
|
if (!funcs || funcs.length === 0) return [];
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
typeof loc === "string"
|
|
693
|
-
? loc
|
|
694
|
-
: loc.type !== undefined
|
|
695
|
-
? loc.type
|
|
696
|
-
: loc;
|
|
697
|
-
if (
|
|
698
|
-
compressedLocals.length > 0 &&
|
|
699
|
-
sameValType(
|
|
700
|
-
compressedLocals[compressedLocals.length - 1].type,
|
|
701
|
-
locType,
|
|
702
|
-
)
|
|
703
|
-
) {
|
|
704
|
-
compressedLocals[compressedLocals.length - 1].count++;
|
|
705
|
-
} else {
|
|
706
|
-
compressedLocals.push({ count: 1, type: locType });
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
const localsBytes = encodeVector(compressedLocals, (group) => [
|
|
711
|
-
...encodeU32LEB(group.count),
|
|
712
|
-
...encodeValType(group.type),
|
|
713
|
-
]);
|
|
714
|
-
|
|
715
|
-
const bodyInsts = fn.body ?? [];
|
|
716
|
-
const bodyBytes = [];
|
|
717
|
-
for (const inst of bodyInsts) {
|
|
718
|
-
const chunk = encodeInstruction(inst);
|
|
719
|
-
for (let i = 0; i < chunk.length; i++) bodyBytes.push(chunk[i]);
|
|
720
|
-
}
|
|
721
|
-
// Ensure terminating end opcode (0x0B)
|
|
818
|
+
const relOffsets = [];
|
|
819
|
+
const payload = encodeVector(funcs, (fn) => {
|
|
820
|
+
// Compress locals: [type1, type1, type2] -> [{ count: 2, type: type1 }, { count: 1, type: type2 }]
|
|
821
|
+
const rawLocals = fn.locals ?? [];
|
|
822
|
+
const compressedLocals = [];
|
|
823
|
+
for (const loc of rawLocals) {
|
|
824
|
+
const locType =
|
|
825
|
+
typeof loc === "string" ? loc : loc.type !== undefined ? loc.type : loc;
|
|
722
826
|
if (
|
|
723
|
-
|
|
724
|
-
|
|
827
|
+
compressedLocals.length > 0 &&
|
|
828
|
+
sameValType(compressedLocals[compressedLocals.length - 1].type, locType)
|
|
725
829
|
) {
|
|
726
|
-
|
|
830
|
+
compressedLocals[compressedLocals.length - 1].count++;
|
|
831
|
+
} else {
|
|
832
|
+
compressedLocals.push({ count: 1, type: locType });
|
|
727
833
|
}
|
|
834
|
+
}
|
|
728
835
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
836
|
+
const localsBytes = encodeVector(compressedLocals, (group) => [
|
|
837
|
+
...encodeU32LEB(group.count),
|
|
838
|
+
...encodeValType(group.type),
|
|
839
|
+
]);
|
|
840
|
+
|
|
841
|
+
const bodyInsts = fn.body ?? [];
|
|
842
|
+
const bodyBytes = [];
|
|
843
|
+
for (const inst of bodyInsts) {
|
|
844
|
+
const chunk = encodeInstruction(inst);
|
|
845
|
+
for (let i = 0; i < chunk.length; i++) bodyBytes.push(chunk[i]);
|
|
846
|
+
}
|
|
847
|
+
// Ensure terminating end opcode (0x0B)
|
|
848
|
+
if (
|
|
849
|
+
bodyInsts.length === 0 ||
|
|
850
|
+
bodyInsts[bodyInsts.length - 1].op !== "end"
|
|
851
|
+
) {
|
|
852
|
+
bodyBytes.push(0x0b);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const fullBody = [...localsBytes, ...bodyBytes];
|
|
856
|
+
const sizeBytes = encodeU32LEB(fullBody.length);
|
|
857
|
+
// Offset of the first instruction within this entry + entry length.
|
|
858
|
+
relOffsets.push([
|
|
859
|
+
sizeBytes.length + localsBytes.length,
|
|
860
|
+
sizeBytes.length + fullBody.length,
|
|
861
|
+
]);
|
|
862
|
+
return [...sizeBytes, ...fullBody];
|
|
863
|
+
});
|
|
864
|
+
if (bodyOffsets) {
|
|
865
|
+
// Section-relative: id + size LEB + count LEB + preceding entries.
|
|
866
|
+
let cursor =
|
|
867
|
+
1 +
|
|
868
|
+
encodeU32LEB(payload.length).length +
|
|
869
|
+
encodeU32LEB(funcs.length).length;
|
|
870
|
+
for (const [first, len] of relOffsets) {
|
|
871
|
+
bodyOffsets.push(cursor + first);
|
|
872
|
+
cursor += len;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return encodeSection(10, payload);
|
|
733
876
|
}
|
|
734
877
|
|
|
735
878
|
// ── Top-level Module Encoder ─────────────────────────────────
|
|
736
879
|
|
|
737
880
|
// Custom section placed right after the header; `isGoFrontWasm` keys off it.
|
|
738
|
-
|
|
739
|
-
const GOFRONT_SECTION_BYTES = [
|
|
881
|
+
const GOFRONT_SECTION_NAME = "gofront";
|
|
882
|
+
export const GOFRONT_SECTION_BYTES = [
|
|
740
883
|
0x00,
|
|
741
884
|
...encodeU32LEB(1 + GOFRONT_SECTION_NAME.length),
|
|
742
885
|
...encodeString(GOFRONT_SECTION_NAME),
|
|
@@ -753,6 +896,10 @@ export function isGoFrontWasm(bytes) {
|
|
|
753
896
|
return true;
|
|
754
897
|
}
|
|
755
898
|
|
|
899
|
+
// Encodes the module. When `mod.sourceMappingURL` is set a trailing
|
|
900
|
+
// `sourceMappingURL` custom section is appended, and `mod.codeOffsets` is
|
|
901
|
+
// filled with the absolute byte offset of every function body (aligned with
|
|
902
|
+
// `mod.funcs`) so a function-level source map can be built.
|
|
756
903
|
export function encodeModule(mod) {
|
|
757
904
|
const magic = [0x00, 0x61, 0x73, 0x6d]; // \0asm
|
|
758
905
|
const version = [0x01, 0x00, 0x00, 0x00]; // version 1
|
|
@@ -760,6 +907,7 @@ export function encodeModule(mod) {
|
|
|
760
907
|
const typeSec = encodeTypeSection(mod.types);
|
|
761
908
|
const importSec = encodeImportSection(mod.imports);
|
|
762
909
|
const funcSec = encodeFunctionSection(mod.funcs);
|
|
910
|
+
const memorySec = encodeMemorySection(mod.memory);
|
|
763
911
|
const tagSec = encodeTagSection(mod.tags);
|
|
764
912
|
const globalSec = encodeGlobalSection(mod.globals);
|
|
765
913
|
const exportSec = encodeExportSection(mod.exports);
|
|
@@ -768,22 +916,48 @@ export function encodeModule(mod) {
|
|
|
768
916
|
? encodeSection(8, encodeU32LEB(mod.start))
|
|
769
917
|
: [];
|
|
770
918
|
const elemSec = encodeElementSection(mod.elements);
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
919
|
+
const sectionOffsets = [];
|
|
920
|
+
const codeSec = encodeCodeSection(mod.funcs, sectionOffsets);
|
|
921
|
+
|
|
922
|
+
const sections = [
|
|
923
|
+
magic,
|
|
924
|
+
version,
|
|
925
|
+
GOFRONT_SECTION_BYTES,
|
|
926
|
+
typeSec,
|
|
927
|
+
importSec,
|
|
928
|
+
funcSec,
|
|
929
|
+
memorySec,
|
|
930
|
+
tagSec,
|
|
931
|
+
globalSec,
|
|
932
|
+
exportSec,
|
|
933
|
+
startSec,
|
|
934
|
+
elemSec,
|
|
786
935
|
];
|
|
936
|
+
let totalLen = 0;
|
|
937
|
+
for (const s of sections) totalLen += s.length;
|
|
938
|
+
const codeStart = totalLen;
|
|
939
|
+
mod.codeOffsets = sectionOffsets.map((o) => codeStart + o);
|
|
940
|
+
totalLen += codeSec.length;
|
|
941
|
+
let smSec = null;
|
|
942
|
+
if (mod.sourceMappingURL) {
|
|
943
|
+
smSec = encodeSection(0, [
|
|
944
|
+
...encodeString("sourceMappingURL"),
|
|
945
|
+
...encodeString(mod.sourceMappingURL),
|
|
946
|
+
]);
|
|
947
|
+
totalLen += smSec.length;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
const out = new Uint8Array(totalLen);
|
|
951
|
+
let offset = 0;
|
|
952
|
+
for (const s of sections) {
|
|
953
|
+
out.set(s, offset);
|
|
954
|
+
offset += s.length;
|
|
955
|
+
}
|
|
956
|
+
out.set(codeSec, offset);
|
|
957
|
+
offset += codeSec.length;
|
|
958
|
+
if (smSec) {
|
|
959
|
+
out.set(smSec, offset);
|
|
960
|
+
}
|
|
787
961
|
|
|
788
|
-
return
|
|
962
|
+
return out;
|
|
789
963
|
}
|
package/src/backend/wasm/glue.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
// src/backend/wasm/glue.js
|
|
2
2
|
// Runtime imports and JS glue for executing GoFront WASM modules.
|
|
3
3
|
|
|
4
|
-
import { WASM_IMPORTS_JS } from "./boundary.js";
|
|
4
|
+
import { WASM_IMPORTS_JS, WASM_STDLIB_JS } from "./boundary.js";
|
|
5
5
|
|
|
6
6
|
// The import table is authored once as source text (it is spliced into the
|
|
7
7
|
// production bundle by the facade); evaluate that same text here so tests
|
|
8
8
|
// exercise exactly what ships. The text is a compile-time constant.
|
|
9
|
-
const makeImports = new Function(
|
|
9
|
+
const makeImports = new Function(
|
|
10
|
+
`${WASM_IMPORTS_JS}\n${WASM_STDLIB_JS}\nreturn __gfw_imports;`,
|
|
11
|
+
)();
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
function createWasmImports({
|
|
12
14
|
stringTable = [],
|
|
13
15
|
panicTag = null,
|
|
14
16
|
stdout = null,
|
|
@@ -30,6 +32,14 @@ const NIL_DEREF_PATTERNS = [
|
|
|
30
32
|
"null dereference", // JavaScriptCore
|
|
31
33
|
];
|
|
32
34
|
|
|
35
|
+
function safeString(v) {
|
|
36
|
+
try {
|
|
37
|
+
return String(v);
|
|
38
|
+
} catch {
|
|
39
|
+
return "[panic object]";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
function isNilDerefTrap(e) {
|
|
34
44
|
if (
|
|
35
45
|
typeof WebAssembly !== "undefined" &&
|
|
@@ -53,6 +63,7 @@ export function instantiateWasm(
|
|
|
53
63
|
|
|
54
64
|
const module = new WebAssembly.Module(wasmBytes);
|
|
55
65
|
const instance = new WebAssembly.Instance(module, imports);
|
|
66
|
+
imports.__bind?.(instance.exports);
|
|
56
67
|
|
|
57
68
|
// The module exports its panic tag if defined internally, or uses the imported one
|
|
58
69
|
const tag = instance.exports.panicTag ?? defaultPanicTag;
|
|
@@ -67,9 +78,12 @@ export function instantiateWasm(
|
|
|
67
78
|
try {
|
|
68
79
|
return val(...cur);
|
|
69
80
|
} catch (e) {
|
|
81
|
+
if (instance.exports.__panic) {
|
|
82
|
+
instance.exports.__panic.value = null;
|
|
83
|
+
}
|
|
70
84
|
if (tag && e instanceof WebAssembly.Exception && e.is(tag)) {
|
|
71
85
|
const msg = e.getArg(tag, 0);
|
|
72
|
-
throw new Error(
|
|
86
|
+
throw new Error(safeString(msg));
|
|
73
87
|
}
|
|
74
88
|
if (isNilDerefTrap(e)) {
|
|
75
89
|
throw new Error(
|
|
@@ -91,7 +105,7 @@ export function instantiateWasm(
|
|
|
91
105
|
inner.is(tag)
|
|
92
106
|
) {
|
|
93
107
|
const msg = inner.getArg(tag, 0);
|
|
94
|
-
throw new Error(
|
|
108
|
+
throw new Error(safeString(msg));
|
|
95
109
|
}
|
|
96
110
|
if (isNilDerefTrap(inner)) {
|
|
97
111
|
throw new Error(
|