watr 4.3.3 → 4.4.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/dist/watr.js +1198 -432
- package/dist/watr.min.js +6 -6
- package/package.json +1 -1
- package/src/optimize.js +1427 -532
- package/types/src/optimize.d.ts +94 -5
- package/types/src/optimize.d.ts.map +1 -1
- package/watr.js +2 -2
package/dist/watr.js
CHANGED
|
@@ -1529,7 +1529,7 @@ var build = [
|
|
|
1529
1529
|
// (elem (table idx)? (offset expr)|(expr) elem*) - active
|
|
1530
1530
|
// ref: https://webassembly.github.io/spec/core/binary/modules.html#element-section
|
|
1531
1531
|
(parts, ctx) => {
|
|
1532
|
-
let passive = 0, declare = 0, elexpr = 0, nofunc = 0, tabidx,
|
|
1532
|
+
let passive = 0, declare = 0, elexpr = 0, nofunc = 0, tabidx, offset2, rt;
|
|
1533
1533
|
if (parts[0] === "declare") parts.shift(), declare = 1;
|
|
1534
1534
|
if (parts[0]?.[0] === "table") {
|
|
1535
1535
|
[, tabidx] = parts.shift();
|
|
@@ -1538,9 +1538,9 @@ var build = [
|
|
|
1538
1538
|
tabidx = id(parts.shift(), ctx.table);
|
|
1539
1539
|
}
|
|
1540
1540
|
if (parts[0]?.[0] === "offset" || Array.isArray(parts[0]) && parts[0][0] !== "item" && !parts[0][0].startsWith("ref")) {
|
|
1541
|
-
|
|
1542
|
-
if (
|
|
1543
|
-
|
|
1541
|
+
offset2 = parts.shift();
|
|
1542
|
+
if (offset2[0] === "offset") [, offset2] = offset2;
|
|
1543
|
+
offset2 = expr(offset2, ctx);
|
|
1544
1544
|
} else if (!declare) passive = 1;
|
|
1545
1545
|
if (TYPE[parts[0]] || parts[0]?.[0] === "ref") rt = reftype(parts.shift(), ctx);
|
|
1546
1546
|
else if (parts[0] === "func") rt = [TYPE[parts.shift()]];
|
|
@@ -1556,19 +1556,19 @@ var build = [
|
|
|
1556
1556
|
return [
|
|
1557
1557
|
mode,
|
|
1558
1558
|
...// 0b000 e:expr y*:vec(funcidx) | type=(ref func), init ((ref.func y)end)*, active (table=0,offset=e)
|
|
1559
|
-
mode === 0 ?
|
|
1559
|
+
mode === 0 ? offset2 : (
|
|
1560
1560
|
// 0b001 et:elkind y*:vec(funcidx) | type=0x00, init ((ref.func y)end)*, passive
|
|
1561
1561
|
mode === 1 ? [0] : (
|
|
1562
1562
|
// 0b010 x:tabidx e:expr et:elkind y*:vec(funcidx) | type=0x00, init ((ref.func y)end)*, active (table=x,offset=e)
|
|
1563
|
-
mode === 2 ? [...uleb(tabidx || 0), ...
|
|
1563
|
+
mode === 2 ? [...uleb(tabidx || 0), ...offset2, 0] : (
|
|
1564
1564
|
// 0b011 et:elkind y*:vec(funcidx) | type=0x00, init ((ref.func y)end)*, passive declare
|
|
1565
1565
|
mode === 3 ? [0] : (
|
|
1566
1566
|
// 0b100 e:expr el*:vec(expr) | type=(ref null func), init el*, active (table=0, offset=e)
|
|
1567
|
-
mode === 4 ?
|
|
1567
|
+
mode === 4 ? offset2 : (
|
|
1568
1568
|
// 0b101 et:reftype el*:vec(expr) | type=et, init el*, passive
|
|
1569
1569
|
mode === 5 ? rt : (
|
|
1570
1570
|
// 0b110 x:tabidx e:expr et:reftype el*:vec(expr) | type=et, init el*, active (table=x, offset=e)
|
|
1571
|
-
mode === 6 ? [...uleb(tabidx || 0), ...
|
|
1571
|
+
mode === 6 ? [...uleb(tabidx || 0), ...offset2, ...rt] : (
|
|
1572
1572
|
// 0b111 et:reftype el*:vec(expr) | type=et, init el*, passive declare
|
|
1573
1573
|
rt
|
|
1574
1574
|
)
|
|
@@ -1623,7 +1623,7 @@ var build = [
|
|
|
1623
1623
|
// (data (global.get $x) "\aa" "\bb"?)
|
|
1624
1624
|
// (data (i8 1 2 3) ...) numeric values (WAT numeric values, Phase 2)
|
|
1625
1625
|
(inits, ctx) => {
|
|
1626
|
-
let
|
|
1626
|
+
let offset2, memidx = 0;
|
|
1627
1627
|
if (inits[0]?.[0] === "memory") {
|
|
1628
1628
|
[, memidx] = inits.shift();
|
|
1629
1629
|
memidx = id(memidx, ctx.memory);
|
|
@@ -1631,15 +1631,15 @@ var build = [
|
|
|
1631
1631
|
memidx = id(inits.shift(), ctx.memory);
|
|
1632
1632
|
}
|
|
1633
1633
|
if (Array.isArray(inits[0]) && typeof inits[0]?.[0] === "string") {
|
|
1634
|
-
|
|
1635
|
-
if (
|
|
1636
|
-
|
|
1634
|
+
offset2 = inits.shift();
|
|
1635
|
+
if (offset2[0] === "offset") [, offset2] = offset2;
|
|
1636
|
+
offset2 ?? err("Bad offset", offset2);
|
|
1637
1637
|
}
|
|
1638
1638
|
return [
|
|
1639
1639
|
...// active: 2, x=memidx, e=expr
|
|
1640
|
-
memidx ? [2, ...uleb(memidx), ...expr(
|
|
1640
|
+
memidx ? [2, ...uleb(memidx), ...expr(offset2, ctx)] : (
|
|
1641
1641
|
// active: 0, e=expr
|
|
1642
|
-
|
|
1642
|
+
offset2 ? [0, ...expr(offset2, ctx)] : (
|
|
1643
1643
|
// passive: 1
|
|
1644
1644
|
[1]
|
|
1645
1645
|
)
|
|
@@ -1854,12 +1854,12 @@ var expr = (node, ctx) => instr(normalize([node], ctx), ctx);
|
|
|
1854
1854
|
var id = (nm, list, n) => (n = isId(nm) ? list[nm] : +nm, n in list ? n : err(`Unknown ${list.name} ${nm}`));
|
|
1855
1855
|
var blockid = (nm, block, i) => (i = isId(nm) ? block.length - block[nm] : +nm, isNaN(i) || i > block.length ? err(`Bad label ${nm}`) : i);
|
|
1856
1856
|
var memarg = (args) => {
|
|
1857
|
-
let align2,
|
|
1858
|
-
while (isMemParam(args[0])) [k, v] = args.shift().split("="), k === "offset" ?
|
|
1859
|
-
if (
|
|
1857
|
+
let align2, offset2, k, v;
|
|
1858
|
+
while (isMemParam(args[0])) [k, v] = args.shift().split("="), k === "offset" ? offset2 = +v : k === "align" ? align2 = +v : err(`Unknown param ${k}=${v}`);
|
|
1859
|
+
if (offset2 < 0 || offset2 > 4294967295) err(`Bad offset ${offset2}`);
|
|
1860
1860
|
if (align2 <= 0 || align2 > 4294967295) err(`Bad align ${align2}`);
|
|
1861
1861
|
if (align2) (align2 = Math.log2(align2)) % 1 && err(`Bad align ${align2}`);
|
|
1862
|
-
return [align2,
|
|
1862
|
+
return [align2, offset2];
|
|
1863
1863
|
};
|
|
1864
1864
|
var memargEnc = (nodes, op, memIdx = 0) => {
|
|
1865
1865
|
const [a, o] = memarg(nodes), alignVal = (a ?? align(op)) | (memIdx && 64);
|
|
@@ -2345,7 +2345,7 @@ var i31ref = (ast, ctx) => {
|
|
|
2345
2345
|
};
|
|
2346
2346
|
transforms.i31ref = i31ref;
|
|
2347
2347
|
var extended_const = (ast, ctx) => {
|
|
2348
|
-
const
|
|
2348
|
+
const globals2 = {};
|
|
2349
2349
|
walk(ast, (node) => {
|
|
2350
2350
|
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
2351
2351
|
const id2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
@@ -2354,7 +2354,7 @@ var extended_const = (ast, ctx) => {
|
|
|
2354
2354
|
const init = node[i];
|
|
2355
2355
|
if (!Array.isArray(init)) continue;
|
|
2356
2356
|
if (init[0] === "i32.const" || init[0] === "i64.const" || init[0] === "f32.const" || init[0] === "f64.const") {
|
|
2357
|
-
|
|
2357
|
+
globals2[id2] = { type: init[0].split(".")[0], value: init[1] };
|
|
2358
2358
|
break;
|
|
2359
2359
|
}
|
|
2360
2360
|
}
|
|
@@ -2362,8 +2362,8 @@ var extended_const = (ast, ctx) => {
|
|
|
2362
2362
|
const evalConst = (node) => {
|
|
2363
2363
|
if (!Array.isArray(node)) return node;
|
|
2364
2364
|
const op = node[0];
|
|
2365
|
-
if (op === "global.get" &&
|
|
2366
|
-
const g =
|
|
2365
|
+
if (op === "global.get" && globals2[node[1]]) {
|
|
2366
|
+
const g = globals2[node[1]];
|
|
2367
2367
|
return [`${g.type}.const`, g.value];
|
|
2368
2368
|
}
|
|
2369
2369
|
if (op === "i32.add" || op === "i64.add") {
|
|
@@ -2516,11 +2516,11 @@ var gc = (ast, ctx) => {
|
|
|
2516
2516
|
return size;
|
|
2517
2517
|
};
|
|
2518
2518
|
const fieldOffset = (typeDef, fieldIdx) => {
|
|
2519
|
-
let
|
|
2519
|
+
let offset2 = 4;
|
|
2520
2520
|
for (let i = 0; i < fieldIdx; i++) {
|
|
2521
|
-
|
|
2521
|
+
offset2 += TYPE_SIZES[typeDef.fields[i].type] || 4;
|
|
2522
2522
|
}
|
|
2523
|
-
return
|
|
2523
|
+
return offset2;
|
|
2524
2524
|
};
|
|
2525
2525
|
const findFieldIdx = (typeDef, fieldName) => {
|
|
2526
2526
|
for (let i = 0; i < typeDef.fields.length; i++) {
|
|
@@ -2582,17 +2582,17 @@ var gc = (ast, ctx) => {
|
|
|
2582
2582
|
if (node[0] === "struct.new") {
|
|
2583
2583
|
for (let i = 0; i < typeDef.fields.length; i++) {
|
|
2584
2584
|
const f = typeDef.fields[i];
|
|
2585
|
-
const
|
|
2585
|
+
const offset2 = fieldOffset(typeDef, i);
|
|
2586
2586
|
const storeOp = f.type === "i64" ? "i64.store" : f.type === "f32" ? "f32.store" : f.type === "f64" ? "f64.store" : "i32.store";
|
|
2587
|
-
stores.push([storeOp, ["i32.add", ["local.get", ptrLocal], ["i32.const",
|
|
2587
|
+
stores.push([storeOp, ["i32.add", ["local.get", ptrLocal], ["i32.const", offset2]], args[i] || [`${f.type}.const`, 0]]);
|
|
2588
2588
|
}
|
|
2589
2589
|
} else {
|
|
2590
2590
|
for (let i = 0; i < typeDef.fields.length; i++) {
|
|
2591
2591
|
const f = typeDef.fields[i];
|
|
2592
|
-
const
|
|
2592
|
+
const offset2 = fieldOffset(typeDef, i);
|
|
2593
2593
|
const storeOp = f.type === "i64" ? "i64.store" : f.type === "f32" ? "f32.store" : f.type === "f64" ? "f64.store" : "i32.store";
|
|
2594
2594
|
const zero = f.type === "i64" ? ["i64.const", 0n] : f.type === "f32" ? ["f32.const", 0] : f.type === "f64" ? ["f64.const", 0] : ["i32.const", 0];
|
|
2595
|
-
stores.push([storeOp, ["i32.add", ["local.get", ptrLocal], ["i32.const",
|
|
2595
|
+
stores.push([storeOp, ["i32.add", ["local.get", ptrLocal], ["i32.const", offset2]], zero]);
|
|
2596
2596
|
}
|
|
2597
2597
|
}
|
|
2598
2598
|
stores.push(["local.get", ptrLocal]);
|
|
@@ -2607,9 +2607,9 @@ var gc = (ast, ctx) => {
|
|
|
2607
2607
|
const fieldIdx = typeof fieldId === "string" && fieldId[0] === "$" ? findFieldIdx(typeDef, fieldId) : parseInt(fieldId);
|
|
2608
2608
|
if (fieldIdx < 0) return;
|
|
2609
2609
|
const f = typeDef.fields[fieldIdx];
|
|
2610
|
-
const
|
|
2610
|
+
const offset2 = fieldOffset(typeDef, fieldIdx);
|
|
2611
2611
|
const loadOp = f.type === "i64" ? "i64.load" : f.type === "f32" ? "f32.load" : f.type === "f64" ? "f64.load" : "i32.load";
|
|
2612
|
-
parent[idx] = [loadOp, ["i32.add", ref, ["i32.const",
|
|
2612
|
+
parent[idx] = [loadOp, ["i32.add", ref, ["i32.const", offset2]]];
|
|
2613
2613
|
}
|
|
2614
2614
|
if (node[0] === "struct.set") {
|
|
2615
2615
|
const typeId = node[1];
|
|
@@ -2621,9 +2621,9 @@ var gc = (ast, ctx) => {
|
|
|
2621
2621
|
const fieldIdx = typeof fieldId === "string" && fieldId[0] === "$" ? findFieldIdx(typeDef, fieldId) : parseInt(fieldId);
|
|
2622
2622
|
if (fieldIdx < 0) return;
|
|
2623
2623
|
const f = typeDef.fields[fieldIdx];
|
|
2624
|
-
const
|
|
2624
|
+
const offset2 = fieldOffset(typeDef, fieldIdx);
|
|
2625
2625
|
const storeOp = f.type === "i64" ? "i64.store" : f.type === "f32" ? "f32.store" : f.type === "f64" ? "f64.store" : "i32.store";
|
|
2626
|
-
parent[idx] = [storeOp, ["i32.add", ref, ["i32.const",
|
|
2626
|
+
parent[idx] = [storeOp, ["i32.add", ref, ["i32.const", offset2]], val];
|
|
2627
2627
|
}
|
|
2628
2628
|
if (node[0] === "array.new" || node[0] === "array.new_default") {
|
|
2629
2629
|
const typeId = node[1];
|
|
@@ -2876,10 +2876,47 @@ var OPTS = {
|
|
|
2876
2876
|
// simplify constant branches
|
|
2877
2877
|
propagate: true,
|
|
2878
2878
|
// constant propagation through locals
|
|
2879
|
-
inline: true
|
|
2879
|
+
inline: true,
|
|
2880
2880
|
// inline tiny functions
|
|
2881
|
+
vacuum: true,
|
|
2882
|
+
// remove nops, drop-of-pure, empty branches
|
|
2883
|
+
peephole: true,
|
|
2884
|
+
// x-x→0, x&0→0, etc.
|
|
2885
|
+
globals: true,
|
|
2886
|
+
// propagate immutable global constants
|
|
2887
|
+
offset: true,
|
|
2888
|
+
// fold add+const into load/store offset
|
|
2889
|
+
unbranch: true,
|
|
2890
|
+
// remove redundant br at end of own block
|
|
2891
|
+
stripmut: true,
|
|
2892
|
+
// strip mut from never-written globals
|
|
2893
|
+
brif: true,
|
|
2894
|
+
// if-then-br → br_if
|
|
2895
|
+
foldarms: true,
|
|
2896
|
+
// merge identical trailing if arms
|
|
2897
|
+
// minify: true, // NOTE: disabled — renaming $ids has no binary-size effect
|
|
2898
|
+
// without a names section, and risks local-name collisions.
|
|
2899
|
+
dedupe: true,
|
|
2900
|
+
// eliminate duplicate functions
|
|
2901
|
+
reorder: true,
|
|
2902
|
+
// put hot functions first for smaller LEBs
|
|
2903
|
+
dedupTypes: true,
|
|
2904
|
+
// merge identical type definitions
|
|
2905
|
+
packData: true,
|
|
2906
|
+
// trim trailing zeros, merge adjacent data segments
|
|
2907
|
+
minifyImports: false
|
|
2908
|
+
// shorten import names — enable only when you control the host
|
|
2881
2909
|
};
|
|
2882
2910
|
var ALL2 = Object.keys(OPTS);
|
|
2911
|
+
var equal = (a, b) => {
|
|
2912
|
+
if (a === b) return true;
|
|
2913
|
+
if (typeof a !== typeof b) return false;
|
|
2914
|
+
if (typeof a === "bigint") return a === b;
|
|
2915
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return false;
|
|
2916
|
+
if (a.length !== b.length) return false;
|
|
2917
|
+
for (let i = 0; i < a.length; i++) if (!equal(a[i], b[i])) return false;
|
|
2918
|
+
return true;
|
|
2919
|
+
};
|
|
2883
2920
|
var normalize3 = (opts) => {
|
|
2884
2921
|
if (opts === true) return { ...OPTS };
|
|
2885
2922
|
if (opts === false) return {};
|
|
@@ -2910,157 +2947,134 @@ var walkPost2 = (node, fn, parent, idx) => {
|
|
|
2910
2947
|
const result = fn(node, parent, idx);
|
|
2911
2948
|
return result !== void 0 ? result : node;
|
|
2912
2949
|
};
|
|
2950
|
+
var parseIf = (node) => {
|
|
2951
|
+
let condIdx = 1;
|
|
2952
|
+
while (condIdx < node.length) {
|
|
2953
|
+
const c = node[condIdx];
|
|
2954
|
+
if (Array.isArray(c) && (c[0] === "then" || c[0] === "else" || c[0] === "result" || c[0] === "param")) {
|
|
2955
|
+
condIdx++;
|
|
2956
|
+
continue;
|
|
2957
|
+
}
|
|
2958
|
+
break;
|
|
2959
|
+
}
|
|
2960
|
+
let thenBranch = null, elseBranch = null;
|
|
2961
|
+
for (let i = condIdx + 1; i < node.length; i++) {
|
|
2962
|
+
const c = node[i];
|
|
2963
|
+
if (!Array.isArray(c)) continue;
|
|
2964
|
+
if (c[0] === "then") thenBranch = c;
|
|
2965
|
+
else if (c[0] === "else") elseBranch = c;
|
|
2966
|
+
}
|
|
2967
|
+
return { condIdx, cond: node[condIdx], thenBranch, elseBranch };
|
|
2968
|
+
};
|
|
2913
2969
|
var treeshake = (ast) => {
|
|
2914
2970
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
2915
|
-
const funcs = /* @__PURE__ */ new Map();
|
|
2916
|
-
const
|
|
2917
|
-
const
|
|
2918
|
-
const
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2971
|
+
const funcs = /* @__PURE__ */ new Map(), globals2 = /* @__PURE__ */ new Map(), types = /* @__PURE__ */ new Map();
|
|
2972
|
+
const tables = /* @__PURE__ */ new Map(), memories = /* @__PURE__ */ new Map();
|
|
2973
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
2974
|
+
const register = (map, node, idx, isImport = false) => {
|
|
2975
|
+
const named = typeof node[1] === "string" && node[1][0] === "$";
|
|
2976
|
+
const name2 = named ? node[1] : idx;
|
|
2977
|
+
const inlineExported = !isImport && node.some((s) => Array.isArray(s) && s[0] === "export");
|
|
2978
|
+
const entry = { node, idx, used: inlineExported, isImport };
|
|
2979
|
+
map.set(name2, entry);
|
|
2980
|
+
if (named) map.set(idx, entry);
|
|
2981
|
+
nodeMap.set(node, entry);
|
|
2982
|
+
return entry;
|
|
2983
|
+
};
|
|
2984
|
+
let funcIdx = 0, globalIdx = 0, typeIdx = 0, tableIdx = 0, memIdx = 0;
|
|
2985
|
+
const elems = [], exports = [], starts = [];
|
|
2923
2986
|
for (const node of ast.slice(1)) {
|
|
2924
2987
|
if (!Array.isArray(node)) continue;
|
|
2925
2988
|
const kind = node[0];
|
|
2926
|
-
if (kind === "type")
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : funcIdx;
|
|
2933
|
-
const hasInlineExport = node.some((sub) => Array.isArray(sub) && sub[0] === "export");
|
|
2934
|
-
funcs.set(name2, { node, idx: funcIdx, used: hasInlineExport });
|
|
2935
|
-
if (typeof name2 === "string") funcs.set(funcIdx, funcs.get(name2));
|
|
2936
|
-
funcIdx++;
|
|
2937
|
-
} else if (kind === "global") {
|
|
2938
|
-
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : globalIdx;
|
|
2939
|
-
const hasInlineExport = node.some((sub) => Array.isArray(sub) && sub[0] === "export");
|
|
2940
|
-
globals.set(name2, { node, idx: globalIdx, used: hasInlineExport });
|
|
2941
|
-
if (typeof name2 === "string") globals.set(globalIdx, globals.get(name2));
|
|
2942
|
-
globalIdx++;
|
|
2943
|
-
} else if (kind === "table") {
|
|
2944
|
-
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : tableIdx;
|
|
2945
|
-
const hasInlineExport = node.some((sub) => Array.isArray(sub) && sub[0] === "export");
|
|
2946
|
-
tables.set(name2, { node, idx: tableIdx, used: hasInlineExport });
|
|
2947
|
-
if (typeof name2 === "string") tables.set(tableIdx, tables.get(name2));
|
|
2948
|
-
tableIdx++;
|
|
2949
|
-
} else if (kind === "memory") {
|
|
2950
|
-
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : memIdx;
|
|
2951
|
-
const hasInlineExport = node.some((sub) => Array.isArray(sub) && sub[0] === "export");
|
|
2952
|
-
memories.set(name2, { node, idx: memIdx, used: hasInlineExport });
|
|
2953
|
-
if (typeof name2 === "string") memories.set(memIdx, memories.get(name2));
|
|
2954
|
-
memIdx++;
|
|
2955
|
-
} else if (kind === "import") {
|
|
2989
|
+
if (kind === "type") register(types, node, typeIdx++);
|
|
2990
|
+
else if (kind === "func") register(funcs, node, funcIdx++);
|
|
2991
|
+
else if (kind === "global") register(globals2, node, globalIdx++);
|
|
2992
|
+
else if (kind === "table") register(tables, node, tableIdx++);
|
|
2993
|
+
else if (kind === "memory") register(memories, node, memIdx++);
|
|
2994
|
+
else if (kind === "import") {
|
|
2956
2995
|
for (const sub of node) {
|
|
2957
|
-
if (Array.isArray(sub)
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
funcIdx++;
|
|
2963
|
-
}
|
|
2996
|
+
if (!Array.isArray(sub)) continue;
|
|
2997
|
+
if (sub[0] === "func") register(funcs, sub, funcIdx++, true);
|
|
2998
|
+
else if (sub[0] === "global") register(globals2, sub, globalIdx++, true);
|
|
2999
|
+
else if (sub[0] === "table") register(tables, sub, tableIdx++, true);
|
|
3000
|
+
else if (sub[0] === "memory") register(memories, sub, memIdx++, true);
|
|
2964
3001
|
}
|
|
2965
|
-
} else if (kind === "export")
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
starts.push(node);
|
|
2969
|
-
}
|
|
3002
|
+
} else if (kind === "export") exports.push(node);
|
|
3003
|
+
else if (kind === "start") starts.push(node);
|
|
3004
|
+
else if (kind === "elem") elems.push(node);
|
|
2970
3005
|
}
|
|
3006
|
+
const work = [];
|
|
3007
|
+
const enqueue = (entry) => {
|
|
3008
|
+
if (entry && !entry.scanned) work.push(entry);
|
|
3009
|
+
};
|
|
3010
|
+
const markFunc = (ref) => {
|
|
3011
|
+
const e = funcs.get(ref);
|
|
3012
|
+
if (!e) return;
|
|
3013
|
+
if (!e.used) e.used = true;
|
|
3014
|
+
enqueue(e);
|
|
3015
|
+
};
|
|
3016
|
+
const markGlobal = (ref) => {
|
|
3017
|
+
const e = globals2.get(ref);
|
|
3018
|
+
if (e) e.used = true;
|
|
3019
|
+
};
|
|
3020
|
+
const markTable = (ref) => {
|
|
3021
|
+
const e = tables.get(ref);
|
|
3022
|
+
if (e) e.used = true;
|
|
3023
|
+
};
|
|
3024
|
+
const markMemory = (ref) => {
|
|
3025
|
+
const e = memories.get(ref);
|
|
3026
|
+
if (e) e.used = true;
|
|
3027
|
+
};
|
|
3028
|
+
const markType = (ref) => {
|
|
3029
|
+
const e = types.get(ref);
|
|
3030
|
+
if (e) e.used = true;
|
|
3031
|
+
};
|
|
2971
3032
|
for (const exp of exports) {
|
|
2972
3033
|
for (const sub of exp) {
|
|
2973
3034
|
if (!Array.isArray(sub)) continue;
|
|
2974
3035
|
const [kind, ref] = sub;
|
|
2975
|
-
if (kind === "func"
|
|
2976
|
-
else if (kind === "global"
|
|
2977
|
-
else if (kind === "table"
|
|
2978
|
-
else if (kind === "memory"
|
|
3036
|
+
if (kind === "func") markFunc(ref);
|
|
3037
|
+
else if (kind === "global") markGlobal(ref);
|
|
3038
|
+
else if (kind === "table") markTable(ref);
|
|
3039
|
+
else if (kind === "memory") markMemory(ref);
|
|
2979
3040
|
}
|
|
2980
3041
|
}
|
|
2981
3042
|
for (const start of starts) {
|
|
2982
3043
|
let ref = start[1];
|
|
2983
3044
|
if (typeof ref === "string" && ref[0] !== "$") ref = +ref;
|
|
2984
|
-
|
|
3045
|
+
markFunc(ref);
|
|
2985
3046
|
}
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
}
|
|
2992
|
-
if (!hasExports) {
|
|
2993
|
-
for (const [, entry] of globals) if (entry.used) {
|
|
2994
|
-
hasExports = true;
|
|
2995
|
-
break;
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
if (!hasExports) {
|
|
2999
|
-
for (const [, entry] of tables) if (entry.used) {
|
|
3000
|
-
hasExports = true;
|
|
3001
|
-
break;
|
|
3002
|
-
}
|
|
3003
|
-
}
|
|
3004
|
-
if (!hasExports) {
|
|
3005
|
-
for (const [, entry] of memories) if (entry.used) {
|
|
3006
|
-
hasExports = true;
|
|
3007
|
-
break;
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3047
|
+
for (const elem of elems) {
|
|
3048
|
+
walk2(elem, (n) => {
|
|
3049
|
+
if (Array.isArray(n) && n[0] === "ref.func") markFunc(n[1]);
|
|
3050
|
+
else if (typeof n === "string" && n[0] === "$") markFunc(n);
|
|
3051
|
+
});
|
|
3010
3052
|
}
|
|
3011
|
-
if (
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
for (const [,
|
|
3015
|
-
|
|
3053
|
+
for (const m of [funcs, globals2, tables, memories]) for (const e of m.values()) if (e.used) enqueue(e);
|
|
3054
|
+
const hasAnchor = exports.length > 0 || starts.length > 0 || elems.length > 0 || work.length > 0;
|
|
3055
|
+
if (!hasAnchor) {
|
|
3056
|
+
for (const m of [funcs, globals2, tables, memories]) for (const e of m.values()) e.used = true;
|
|
3057
|
+
return ast;
|
|
3016
3058
|
}
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3059
|
+
while (work.length) {
|
|
3060
|
+
const entry = work.pop();
|
|
3061
|
+
if (entry.scanned) continue;
|
|
3062
|
+
entry.scanned = true;
|
|
3063
|
+
if (entry.isImport) continue;
|
|
3064
|
+
walk2(entry.node, (n) => {
|
|
3065
|
+
if (!Array.isArray(n)) {
|
|
3066
|
+
if (typeof n === "string" && n[0] === "$") markFunc(n);
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
const [op, ref] = n;
|
|
3070
|
+
if (op === "call" || op === "return_call" || op === "ref.func") markFunc(ref);
|
|
3071
|
+
else if (op === "global.get" || op === "global.set") markGlobal(ref);
|
|
3072
|
+
else if (op === "type") markType(ref);
|
|
3073
|
+
else if (op === "call_indirect" || op === "return_call_indirect") {
|
|
3074
|
+
for (const sub of n) if (typeof sub === "string" && sub[0] === "$") markTable(sub);
|
|
3023
3075
|
}
|
|
3024
|
-
if (typeof n === "string" && n[0] === "$" && funcs.has(n)) funcs.get(n).used = true;
|
|
3025
3076
|
});
|
|
3026
3077
|
}
|
|
3027
|
-
let changed = true;
|
|
3028
|
-
while (changed) {
|
|
3029
|
-
changed = false;
|
|
3030
|
-
for (const [, entry] of funcs) {
|
|
3031
|
-
if (!entry.used || entry.isImport) continue;
|
|
3032
|
-
walk2(entry.node, (n) => {
|
|
3033
|
-
if (!Array.isArray(n)) {
|
|
3034
|
-
if (typeof n === "string" && n[0] === "$" && funcs.has(n) && !funcs.get(n).used) {
|
|
3035
|
-
funcs.get(n).used = true;
|
|
3036
|
-
changed = true;
|
|
3037
|
-
}
|
|
3038
|
-
return;
|
|
3039
|
-
}
|
|
3040
|
-
const [op, ref] = n;
|
|
3041
|
-
if ((op === "call" || op === "return_call" || op === "ref.func") && funcs.has(ref) && !funcs.get(ref).used) {
|
|
3042
|
-
funcs.get(ref).used = true;
|
|
3043
|
-
changed = true;
|
|
3044
|
-
}
|
|
3045
|
-
if ((op === "global.get" || op === "global.set") && globals.has(ref) && !globals.get(ref).used) {
|
|
3046
|
-
globals.get(ref).used = true;
|
|
3047
|
-
changed = true;
|
|
3048
|
-
}
|
|
3049
|
-
if (op === "call_indirect" || op === "return_call_indirect") {
|
|
3050
|
-
for (const sub of n) {
|
|
3051
|
-
if (typeof sub === "string" && sub[0] === "$" && tables.has(sub) && !tables.get(sub).used) {
|
|
3052
|
-
tables.get(sub).used = true;
|
|
3053
|
-
changed = true;
|
|
3054
|
-
}
|
|
3055
|
-
}
|
|
3056
|
-
}
|
|
3057
|
-
if (op === "type" && types.has(ref) && !types.get(ref).used) {
|
|
3058
|
-
types.get(ref).used = true;
|
|
3059
|
-
changed = true;
|
|
3060
|
-
}
|
|
3061
|
-
});
|
|
3062
|
-
}
|
|
3063
|
-
}
|
|
3064
3078
|
const result = ["module"];
|
|
3065
3079
|
for (const node of ast.slice(1)) {
|
|
3066
3080
|
if (!Array.isArray(node)) {
|
|
@@ -3068,117 +3082,130 @@ var treeshake = (ast) => {
|
|
|
3068
3082
|
continue;
|
|
3069
3083
|
}
|
|
3070
3084
|
const kind = node[0];
|
|
3071
|
-
if (kind === "func") {
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3085
|
+
if (kind === "func" || kind === "global" || kind === "type") {
|
|
3086
|
+
if (nodeMap.get(node)?.used) result.push(node);
|
|
3087
|
+
} else if (kind === "import") {
|
|
3088
|
+
let used = false;
|
|
3089
|
+
for (const sub of node) {
|
|
3090
|
+
if (!Array.isArray(sub)) continue;
|
|
3091
|
+
const e = nodeMap.get(sub);
|
|
3092
|
+
if (e?.used) {
|
|
3093
|
+
used = true;
|
|
3094
|
+
break;
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
if (used) result.push(node);
|
|
3081
3098
|
} else {
|
|
3082
3099
|
result.push(node);
|
|
3083
3100
|
}
|
|
3084
3101
|
}
|
|
3085
3102
|
return result;
|
|
3086
3103
|
};
|
|
3104
|
+
var roundEven = (x) => x - Math.floor(x) !== 0.5 ? Math.round(x) : 2 * Math.round(x / 2);
|
|
3105
|
+
var i32c = (fn) => (a, b) => fn(a, b) ? 1 : 0;
|
|
3106
|
+
var u32c = (fn) => (a, b) => fn(a >>> 0, b >>> 0) ? 1 : 0;
|
|
3107
|
+
var i64c = (fn) => (a, b) => fn(a, b) ? 1 : 0;
|
|
3108
|
+
var u64c = (fn) => (a, b) => fn(BigInt.asUintN(64, a), BigInt.asUintN(64, b)) ? 1 : 0;
|
|
3087
3109
|
var FOLDABLE = {
|
|
3088
|
-
// i32
|
|
3089
|
-
"i32.add": (a, b) => a + b | 0,
|
|
3090
|
-
"i32.sub": (a, b) => a - b | 0,
|
|
3091
|
-
"i32.mul": (a, b) => Math.imul(a, b),
|
|
3092
|
-
"i32.div_s": (a, b) => b !== 0 ? a / b | 0 : null,
|
|
3093
|
-
"i32.div_u": (a, b) => b !== 0 ? (a >>> 0) / (b >>> 0) | 0 : null,
|
|
3094
|
-
"i32.rem_s": (a, b) => b !== 0 ? a % b | 0 : null,
|
|
3095
|
-
"i32.rem_u": (a, b) => b !== 0 ? (a >>> 0) % (b >>> 0) | 0 : null,
|
|
3096
|
-
"i32.and": (a, b) => a & b,
|
|
3097
|
-
"i32.or": (a, b) => a | b,
|
|
3098
|
-
"i32.xor": (a, b) => a ^ b,
|
|
3099
|
-
"i32.shl": (a, b) => a << (b & 31),
|
|
3100
|
-
"i32.shr_s": (a, b) => a >> (b & 31),
|
|
3101
|
-
"i32.shr_u": (a, b) => a >>> (b & 31),
|
|
3102
|
-
"i32.rotl": (a, b) => {
|
|
3110
|
+
// i32 arithmetic
|
|
3111
|
+
"i32.add": [(a, b) => a + b | 0, "i32"],
|
|
3112
|
+
"i32.sub": [(a, b) => a - b | 0, "i32"],
|
|
3113
|
+
"i32.mul": [(a, b) => Math.imul(a, b), "i32"],
|
|
3114
|
+
"i32.div_s": [(a, b) => b !== 0 ? a / b | 0 : null, "i32"],
|
|
3115
|
+
"i32.div_u": [(a, b) => b !== 0 ? (a >>> 0) / (b >>> 0) | 0 : null, "i32"],
|
|
3116
|
+
"i32.rem_s": [(a, b) => b !== 0 ? a % b | 0 : null, "i32"],
|
|
3117
|
+
"i32.rem_u": [(a, b) => b !== 0 ? (a >>> 0) % (b >>> 0) | 0 : null, "i32"],
|
|
3118
|
+
"i32.and": [(a, b) => a & b, "i32"],
|
|
3119
|
+
"i32.or": [(a, b) => a | b, "i32"],
|
|
3120
|
+
"i32.xor": [(a, b) => a ^ b, "i32"],
|
|
3121
|
+
"i32.shl": [(a, b) => a << (b & 31), "i32"],
|
|
3122
|
+
"i32.shr_s": [(a, b) => a >> (b & 31), "i32"],
|
|
3123
|
+
"i32.shr_u": [(a, b) => a >>> (b & 31), "i32"],
|
|
3124
|
+
"i32.rotl": [(a, b) => {
|
|
3103
3125
|
b &= 31;
|
|
3104
3126
|
return a << b | a >>> 32 - b | 0;
|
|
3105
|
-
},
|
|
3106
|
-
"i32.rotr": (a, b) => {
|
|
3127
|
+
}, "i32"],
|
|
3128
|
+
"i32.rotr": [(a, b) => {
|
|
3107
3129
|
b &= 31;
|
|
3108
3130
|
return a >>> b | a << 32 - b | 0;
|
|
3109
|
-
},
|
|
3110
|
-
"i32.eq": (a, b) => a === b
|
|
3111
|
-
"i32.ne": (a, b) => a !== b
|
|
3112
|
-
"i32.lt_s": (a, b) => a < b
|
|
3113
|
-
"i32.lt_u": (a, b) => a
|
|
3114
|
-
"i32.gt_s": (a, b) => a > b
|
|
3115
|
-
"i32.gt_u": (a, b) => a
|
|
3116
|
-
"i32.le_s": (a, b) => a <= b
|
|
3117
|
-
"i32.le_u": (a, b) => a
|
|
3118
|
-
"i32.ge_s": (a, b) => a >= b
|
|
3119
|
-
"i32.ge_u": (a, b) => a
|
|
3120
|
-
"i32.eqz": (a) => a === 0 ? 1 : 0,
|
|
3121
|
-
"i32.clz": (a) => Math.clz32(a),
|
|
3122
|
-
"i32.ctz": (a) => a === 0 ? 32 : 31 - Math.clz32(a & -a),
|
|
3123
|
-
"i32.popcnt": (a) => {
|
|
3131
|
+
}, "i32"],
|
|
3132
|
+
"i32.eq": [i32c((a, b) => a === b), "i32"],
|
|
3133
|
+
"i32.ne": [i32c((a, b) => a !== b), "i32"],
|
|
3134
|
+
"i32.lt_s": [i32c((a, b) => a < b), "i32"],
|
|
3135
|
+
"i32.lt_u": [u32c((a, b) => a < b), "i32"],
|
|
3136
|
+
"i32.gt_s": [i32c((a, b) => a > b), "i32"],
|
|
3137
|
+
"i32.gt_u": [u32c((a, b) => a > b), "i32"],
|
|
3138
|
+
"i32.le_s": [i32c((a, b) => a <= b), "i32"],
|
|
3139
|
+
"i32.le_u": [u32c((a, b) => a <= b), "i32"],
|
|
3140
|
+
"i32.ge_s": [i32c((a, b) => a >= b), "i32"],
|
|
3141
|
+
"i32.ge_u": [u32c((a, b) => a >= b), "i32"],
|
|
3142
|
+
"i32.eqz": [(a) => a === 0 ? 1 : 0, "i32"],
|
|
3143
|
+
"i32.clz": [(a) => Math.clz32(a), "i32"],
|
|
3144
|
+
"i32.ctz": [(a) => a === 0 ? 32 : 31 - Math.clz32(a & -a), "i32"],
|
|
3145
|
+
"i32.popcnt": [(a) => {
|
|
3124
3146
|
let c = 0;
|
|
3125
3147
|
while (a) {
|
|
3126
3148
|
c += a & 1;
|
|
3127
3149
|
a >>>= 1;
|
|
3128
3150
|
}
|
|
3129
3151
|
return c;
|
|
3130
|
-
},
|
|
3131
|
-
"i32.wrap_i64": (a) => Number(BigInt.asIntN(32, a)),
|
|
3152
|
+
}, "i32"],
|
|
3153
|
+
"i32.wrap_i64": [(a) => Number(BigInt.asIntN(32, a)), "i32"],
|
|
3154
|
+
"i32.extend8_s": [(a) => a << 24 >> 24, "i32"],
|
|
3155
|
+
"i32.extend16_s": [(a) => a << 16 >> 16, "i32"],
|
|
3132
3156
|
// i64 (using BigInt)
|
|
3133
|
-
"i64.add": (a, b) => BigInt.asIntN(64, a + b),
|
|
3134
|
-
"i64.sub": (a, b) => BigInt.asIntN(64, a - b),
|
|
3135
|
-
"i64.mul": (a, b) => BigInt.asIntN(64, a * b),
|
|
3136
|
-
"i64.div_s": (a, b) => b !== 0n ? BigInt.asIntN(64, a / b) : null,
|
|
3137
|
-
"i64.div_u": (a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b)) : null,
|
|
3138
|
-
"i64.rem_s": (a, b) => b !== 0n ? BigInt.asIntN(64, a % b) : null,
|
|
3139
|
-
"i64.rem_u": (a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b)) : null,
|
|
3140
|
-
"i64.and": (a, b) => BigInt.asIntN(64, a & b),
|
|
3141
|
-
"i64.or": (a, b) => BigInt.asIntN(64, a | b),
|
|
3142
|
-
"i64.xor": (a, b) => BigInt.asIntN(64, a ^ b),
|
|
3143
|
-
"i64.shl": (a, b) => BigInt.asIntN(64, a << (b & 63n)),
|
|
3144
|
-
"i64.shr_s": (a, b) => BigInt.asIntN(64, a >> (b & 63n)),
|
|
3145
|
-
"i64.shr_u": (a, b) => BigInt.asUintN(64, BigInt.asUintN(64, a) >> (b & 63n)),
|
|
3146
|
-
"i64.eq": (a, b) => a === b
|
|
3147
|
-
"i64.ne": (a, b) => a !== b
|
|
3148
|
-
"i64.lt_s": (a, b) => a < b
|
|
3149
|
-
"i64.lt_u": (a, b) =>
|
|
3150
|
-
"i64.gt_s": (a, b) => a > b
|
|
3151
|
-
"i64.gt_u": (a, b) =>
|
|
3152
|
-
"i64.le_s": (a, b) => a <= b
|
|
3153
|
-
"i64.le_u": (a, b) =>
|
|
3154
|
-
"i64.ge_s": (a, b) => a >= b
|
|
3155
|
-
"i64.ge_u": (a, b) =>
|
|
3156
|
-
"i64.eqz": (a) => a === 0n ? 1 : 0,
|
|
3157
|
-
"i64.extend_i32_s": (a) => BigInt(a),
|
|
3158
|
-
"i64.extend_i32_u": (a) => BigInt(a >>> 0),
|
|
3159
|
-
|
|
3160
|
-
"
|
|
3161
|
-
"
|
|
3162
|
-
|
|
3163
|
-
"f32.
|
|
3164
|
-
"f32.
|
|
3165
|
-
"f32.
|
|
3166
|
-
"f32.
|
|
3167
|
-
"f32.
|
|
3168
|
-
"f32.
|
|
3169
|
-
"f32.
|
|
3170
|
-
"f32.
|
|
3171
|
-
"
|
|
3172
|
-
"
|
|
3173
|
-
"
|
|
3174
|
-
"f64.
|
|
3175
|
-
"f64.
|
|
3176
|
-
"f64.
|
|
3177
|
-
"f64.
|
|
3178
|
-
"f64.
|
|
3179
|
-
"f64.
|
|
3180
|
-
"f64.
|
|
3181
|
-
"f64.
|
|
3157
|
+
"i64.add": [(a, b) => BigInt.asIntN(64, a + b), "i64"],
|
|
3158
|
+
"i64.sub": [(a, b) => BigInt.asIntN(64, a - b), "i64"],
|
|
3159
|
+
"i64.mul": [(a, b) => BigInt.asIntN(64, a * b), "i64"],
|
|
3160
|
+
"i64.div_s": [(a, b) => b !== 0n ? BigInt.asIntN(64, a / b) : null, "i64"],
|
|
3161
|
+
"i64.div_u": [(a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b)) : null, "i64"],
|
|
3162
|
+
"i64.rem_s": [(a, b) => b !== 0n ? BigInt.asIntN(64, a % b) : null, "i64"],
|
|
3163
|
+
"i64.rem_u": [(a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b)) : null, "i64"],
|
|
3164
|
+
"i64.and": [(a, b) => BigInt.asIntN(64, a & b), "i64"],
|
|
3165
|
+
"i64.or": [(a, b) => BigInt.asIntN(64, a | b), "i64"],
|
|
3166
|
+
"i64.xor": [(a, b) => BigInt.asIntN(64, a ^ b), "i64"],
|
|
3167
|
+
"i64.shl": [(a, b) => BigInt.asIntN(64, a << (b & 63n)), "i64"],
|
|
3168
|
+
"i64.shr_s": [(a, b) => BigInt.asIntN(64, a >> (b & 63n)), "i64"],
|
|
3169
|
+
"i64.shr_u": [(a, b) => BigInt.asUintN(64, BigInt.asUintN(64, a) >> (b & 63n)), "i64"],
|
|
3170
|
+
"i64.eq": [i64c((a, b) => a === b), "i32"],
|
|
3171
|
+
"i64.ne": [i64c((a, b) => a !== b), "i32"],
|
|
3172
|
+
"i64.lt_s": [i64c((a, b) => a < b), "i32"],
|
|
3173
|
+
"i64.lt_u": [u64c((a, b) => a < b), "i32"],
|
|
3174
|
+
"i64.gt_s": [i64c((a, b) => a > b), "i32"],
|
|
3175
|
+
"i64.gt_u": [u64c((a, b) => a > b), "i32"],
|
|
3176
|
+
"i64.le_s": [i64c((a, b) => a <= b), "i32"],
|
|
3177
|
+
"i64.le_u": [u64c((a, b) => a <= b), "i32"],
|
|
3178
|
+
"i64.ge_s": [i64c((a, b) => a >= b), "i32"],
|
|
3179
|
+
"i64.ge_u": [u64c((a, b) => a >= b), "i32"],
|
|
3180
|
+
"i64.eqz": [(a) => a === 0n ? 1 : 0, "i32"],
|
|
3181
|
+
"i64.extend_i32_s": [(a) => BigInt(a), "i64"],
|
|
3182
|
+
"i64.extend_i32_u": [(a) => BigInt(a >>> 0), "i64"],
|
|
3183
|
+
"i64.extend8_s": [(a) => BigInt.asIntN(64, BigInt.asIntN(8, a)), "i64"],
|
|
3184
|
+
"i64.extend16_s": [(a) => BigInt.asIntN(64, BigInt.asIntN(16, a)), "i64"],
|
|
3185
|
+
"i64.extend32_s": [(a) => BigInt.asIntN(64, BigInt.asIntN(32, a)), "i64"],
|
|
3186
|
+
// f32/f64 (NaN/precision-aware via Math.fround)
|
|
3187
|
+
"f32.add": [(a, b) => Math.fround(a + b), "f32"],
|
|
3188
|
+
"f32.sub": [(a, b) => Math.fround(a - b), "f32"],
|
|
3189
|
+
"f32.mul": [(a, b) => Math.fround(a * b), "f32"],
|
|
3190
|
+
"f32.div": [(a, b) => Math.fround(a / b), "f32"],
|
|
3191
|
+
"f32.neg": [(a) => Math.fround(-a), "f32"],
|
|
3192
|
+
"f32.abs": [(a) => Math.fround(Math.abs(a)), "f32"],
|
|
3193
|
+
"f32.sqrt": [(a) => Math.fround(Math.sqrt(a)), "f32"],
|
|
3194
|
+
"f32.ceil": [(a) => Math.fround(Math.ceil(a)), "f32"],
|
|
3195
|
+
"f32.floor": [(a) => Math.fround(Math.floor(a)), "f32"],
|
|
3196
|
+
"f32.trunc": [(a) => Math.fround(Math.trunc(a)), "f32"],
|
|
3197
|
+
"f32.nearest": [(a) => Math.fround(roundEven(a)), "f32"],
|
|
3198
|
+
"f64.add": [(a, b) => a + b, "f64"],
|
|
3199
|
+
"f64.sub": [(a, b) => a - b, "f64"],
|
|
3200
|
+
"f64.mul": [(a, b) => a * b, "f64"],
|
|
3201
|
+
"f64.div": [(a, b) => a / b, "f64"],
|
|
3202
|
+
"f64.neg": [(a) => -a, "f64"],
|
|
3203
|
+
"f64.abs": [Math.abs, "f64"],
|
|
3204
|
+
"f64.sqrt": [Math.sqrt, "f64"],
|
|
3205
|
+
"f64.ceil": [Math.ceil, "f64"],
|
|
3206
|
+
"f64.floor": [Math.floor, "f64"],
|
|
3207
|
+
"f64.trunc": [Math.trunc, "f64"],
|
|
3208
|
+
"f64.nearest": [roundEven, "f64"]
|
|
3182
3209
|
};
|
|
3183
3210
|
var getConst = (node) => {
|
|
3184
3211
|
if (!Array.isArray(node) || node.length !== 2) return null;
|
|
@@ -3199,110 +3226,63 @@ var makeConst = (type, value) => {
|
|
|
3199
3226
|
var fold = (ast) => {
|
|
3200
3227
|
return walkPost2(clone2(ast), (node) => {
|
|
3201
3228
|
if (!Array.isArray(node)) return;
|
|
3202
|
-
const
|
|
3203
|
-
|
|
3204
|
-
|
|
3229
|
+
const entry = FOLDABLE[node[0]];
|
|
3230
|
+
if (!entry) return;
|
|
3231
|
+
const [fn, t] = entry;
|
|
3205
3232
|
if (fn.length === 1 && node.length === 2) {
|
|
3206
3233
|
const a = getConst(node[1]);
|
|
3207
3234
|
if (!a) return;
|
|
3208
|
-
const
|
|
3209
|
-
if (
|
|
3210
|
-
|
|
3211
|
-
return makeConst(resultType, result);
|
|
3235
|
+
const r = fn(a.value);
|
|
3236
|
+
if (r === null) return;
|
|
3237
|
+
return makeConst(t, r);
|
|
3212
3238
|
}
|
|
3213
3239
|
if (fn.length === 2 && node.length === 3) {
|
|
3214
|
-
const a = getConst(node[1]);
|
|
3215
|
-
const b = getConst(node[2]);
|
|
3240
|
+
const a = getConst(node[1]), b = getConst(node[2]);
|
|
3216
3241
|
if (!a || !b) return;
|
|
3217
|
-
const
|
|
3218
|
-
if (
|
|
3219
|
-
|
|
3220
|
-
const resultType = isCompare ? "i32" : op.startsWith("i64.") ? "i64" : op.startsWith("f32.") ? "f32" : op.startsWith("f64.") ? "f64" : "i32";
|
|
3221
|
-
return makeConst(resultType, result);
|
|
3242
|
+
const r = fn(a.value, b.value);
|
|
3243
|
+
if (r === null) return;
|
|
3244
|
+
return makeConst(t, r);
|
|
3222
3245
|
}
|
|
3223
3246
|
});
|
|
3224
3247
|
};
|
|
3248
|
+
var commutativeIdentity = (neutral) => (a, b) => {
|
|
3249
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3250
|
+
if (ca?.value === neutral) return b;
|
|
3251
|
+
if (cb?.value === neutral) return a;
|
|
3252
|
+
return null;
|
|
3253
|
+
};
|
|
3254
|
+
var rightIdentity = (neutral) => (a, b) => getConst(b)?.value === neutral ? a : null;
|
|
3225
3255
|
var IDENTITIES = {
|
|
3226
3256
|
// x + 0 → x, 0 + x → x
|
|
3227
|
-
"i32.add": (
|
|
3228
|
-
|
|
3229
|
-
if (ca?.value === 0) return b;
|
|
3230
|
-
if (cb?.value === 0) return a;
|
|
3231
|
-
return null;
|
|
3232
|
-
},
|
|
3233
|
-
"i64.add": (a, b) => {
|
|
3234
|
-
const ca = getConst(a), cb = getConst(b);
|
|
3235
|
-
if (ca?.value === 0n) return b;
|
|
3236
|
-
if (cb?.value === 0n) return a;
|
|
3237
|
-
return null;
|
|
3238
|
-
},
|
|
3257
|
+
"i32.add": commutativeIdentity(0),
|
|
3258
|
+
"i64.add": commutativeIdentity(0n),
|
|
3239
3259
|
// x - 0 → x
|
|
3240
|
-
"i32.sub": (
|
|
3241
|
-
"i64.sub": (
|
|
3260
|
+
"i32.sub": rightIdentity(0),
|
|
3261
|
+
"i64.sub": rightIdentity(0n),
|
|
3242
3262
|
// x * 1 → x, 1 * x → x
|
|
3243
|
-
"i32.mul": (
|
|
3244
|
-
|
|
3245
|
-
if (ca?.value === 1) return b;
|
|
3246
|
-
if (cb?.value === 1) return a;
|
|
3247
|
-
return null;
|
|
3248
|
-
},
|
|
3249
|
-
"i64.mul": (a, b) => {
|
|
3250
|
-
const ca = getConst(a), cb = getConst(b);
|
|
3251
|
-
if (ca?.value === 1n) return b;
|
|
3252
|
-
if (cb?.value === 1n) return a;
|
|
3253
|
-
return null;
|
|
3254
|
-
},
|
|
3263
|
+
"i32.mul": commutativeIdentity(1),
|
|
3264
|
+
"i64.mul": commutativeIdentity(1n),
|
|
3255
3265
|
// x / 1 → x
|
|
3256
|
-
"i32.div_s": (
|
|
3257
|
-
"i32.div_u": (
|
|
3258
|
-
"i64.div_s": (
|
|
3259
|
-
"i64.div_u": (
|
|
3266
|
+
"i32.div_s": rightIdentity(1),
|
|
3267
|
+
"i32.div_u": rightIdentity(1),
|
|
3268
|
+
"i64.div_s": rightIdentity(1n),
|
|
3269
|
+
"i64.div_u": rightIdentity(1n),
|
|
3260
3270
|
// x & -1 → x, -1 & x → x (all bits set)
|
|
3261
|
-
"i32.and": (
|
|
3262
|
-
|
|
3263
|
-
if (ca?.value === -1) return b;
|
|
3264
|
-
if (cb?.value === -1) return a;
|
|
3265
|
-
return null;
|
|
3266
|
-
},
|
|
3267
|
-
"i64.and": (a, b) => {
|
|
3268
|
-
const ca = getConst(a), cb = getConst(b);
|
|
3269
|
-
if (ca?.value === -1n) return b;
|
|
3270
|
-
if (cb?.value === -1n) return a;
|
|
3271
|
-
return null;
|
|
3272
|
-
},
|
|
3271
|
+
"i32.and": commutativeIdentity(-1),
|
|
3272
|
+
"i64.and": commutativeIdentity(-1n),
|
|
3273
3273
|
// x | 0 → x, 0 | x → x
|
|
3274
|
-
"i32.or": (
|
|
3275
|
-
|
|
3276
|
-
if (ca?.value === 0) return b;
|
|
3277
|
-
if (cb?.value === 0) return a;
|
|
3278
|
-
return null;
|
|
3279
|
-
},
|
|
3280
|
-
"i64.or": (a, b) => {
|
|
3281
|
-
const ca = getConst(a), cb = getConst(b);
|
|
3282
|
-
if (ca?.value === 0n) return b;
|
|
3283
|
-
if (cb?.value === 0n) return a;
|
|
3284
|
-
return null;
|
|
3285
|
-
},
|
|
3274
|
+
"i32.or": commutativeIdentity(0),
|
|
3275
|
+
"i64.or": commutativeIdentity(0n),
|
|
3286
3276
|
// x ^ 0 → x, 0 ^ x → x
|
|
3287
|
-
"i32.xor": (
|
|
3288
|
-
|
|
3289
|
-
if (ca?.value === 0) return b;
|
|
3290
|
-
if (cb?.value === 0) return a;
|
|
3291
|
-
return null;
|
|
3292
|
-
},
|
|
3293
|
-
"i64.xor": (a, b) => {
|
|
3294
|
-
const ca = getConst(a), cb = getConst(b);
|
|
3295
|
-
if (ca?.value === 0n) return b;
|
|
3296
|
-
if (cb?.value === 0n) return a;
|
|
3297
|
-
return null;
|
|
3298
|
-
},
|
|
3277
|
+
"i32.xor": commutativeIdentity(0),
|
|
3278
|
+
"i64.xor": commutativeIdentity(0n),
|
|
3299
3279
|
// x << 0 → x, x >> 0 → x
|
|
3300
|
-
"i32.shl": (
|
|
3301
|
-
"i32.shr_s": (
|
|
3302
|
-
"i32.shr_u": (
|
|
3303
|
-
"i64.shl": (
|
|
3304
|
-
"i64.shr_s": (
|
|
3305
|
-
"i64.shr_u": (
|
|
3280
|
+
"i32.shl": rightIdentity(0),
|
|
3281
|
+
"i32.shr_s": rightIdentity(0),
|
|
3282
|
+
"i32.shr_u": rightIdentity(0),
|
|
3283
|
+
"i64.shl": rightIdentity(0n),
|
|
3284
|
+
"i64.shr_s": rightIdentity(0n),
|
|
3285
|
+
"i64.shr_u": rightIdentity(0n)
|
|
3306
3286
|
// f + 0 → x (careful with -0.0, skip for floats)
|
|
3307
3287
|
// f * 1 → x (careful with NaN, skip for floats)
|
|
3308
3288
|
};
|
|
@@ -3377,41 +3357,15 @@ var branch = (ast) => {
|
|
|
3377
3357
|
if (!Array.isArray(node)) return;
|
|
3378
3358
|
const op = node[0];
|
|
3379
3359
|
if (op === "if") {
|
|
3380
|
-
|
|
3381
|
-
while (condIdx < node.length) {
|
|
3382
|
-
const child = node[condIdx];
|
|
3383
|
-
if (Array.isArray(child) && (child[0] === "then" || child[0] === "else" || child[0] === "result" || child[0] === "param")) {
|
|
3384
|
-
condIdx++;
|
|
3385
|
-
continue;
|
|
3386
|
-
}
|
|
3387
|
-
break;
|
|
3388
|
-
}
|
|
3389
|
-
const cond = node[condIdx];
|
|
3360
|
+
const { cond, thenBranch, elseBranch } = parseIf(node);
|
|
3390
3361
|
const c = getConst(cond);
|
|
3391
3362
|
if (!c) return;
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
const
|
|
3395
|
-
|
|
3396
|
-
if (child[0] === "then") thenBranch = child;
|
|
3397
|
-
else if (child[0] === "else") elseBranch = child;
|
|
3398
|
-
}
|
|
3399
|
-
}
|
|
3400
|
-
if (c.value !== 0 && c.value !== 0n) {
|
|
3401
|
-
if (thenBranch && thenBranch.length > 1) {
|
|
3402
|
-
const contents = thenBranch.slice(1);
|
|
3403
|
-
if (contents.length === 1) return contents[0];
|
|
3404
|
-
return ["block", ...contents];
|
|
3405
|
-
}
|
|
3406
|
-
return ["nop"];
|
|
3407
|
-
} else {
|
|
3408
|
-
if (elseBranch && elseBranch.length > 1) {
|
|
3409
|
-
const contents = elseBranch.slice(1);
|
|
3410
|
-
if (contents.length === 1) return contents[0];
|
|
3411
|
-
return ["block", ...contents];
|
|
3412
|
-
}
|
|
3413
|
-
return ["nop"];
|
|
3363
|
+
const taken = c.value !== 0 && c.value !== 0n ? thenBranch : elseBranch;
|
|
3364
|
+
if (taken && taken.length > 1) {
|
|
3365
|
+
const contents = taken.slice(1);
|
|
3366
|
+
return contents.length === 1 ? contents[0] : ["block", ...contents];
|
|
3414
3367
|
}
|
|
3368
|
+
return ["nop"];
|
|
3415
3369
|
}
|
|
3416
3370
|
if (op === "br_if" && node.length >= 3) {
|
|
3417
3371
|
const cond = node[node.length - 1];
|
|
@@ -3518,55 +3472,184 @@ var localReuse = (ast) => {
|
|
|
3518
3472
|
});
|
|
3519
3473
|
return result;
|
|
3520
3474
|
};
|
|
3475
|
+
var IMPURE_OPS = /* @__PURE__ */ new Set([
|
|
3476
|
+
"call",
|
|
3477
|
+
"call_indirect",
|
|
3478
|
+
"return_call",
|
|
3479
|
+
"return_call_indirect",
|
|
3480
|
+
"table.set",
|
|
3481
|
+
"table.grow",
|
|
3482
|
+
"table.fill",
|
|
3483
|
+
"table.copy",
|
|
3484
|
+
"table.init",
|
|
3485
|
+
"struct.set",
|
|
3486
|
+
"struct.new",
|
|
3487
|
+
"array.set",
|
|
3488
|
+
"array.new",
|
|
3489
|
+
"array.new_fixed",
|
|
3490
|
+
"array.new_data",
|
|
3491
|
+
"array.new_elem",
|
|
3492
|
+
"array.init_data",
|
|
3493
|
+
"array.init_elem",
|
|
3494
|
+
"ref.i31",
|
|
3495
|
+
"global.set",
|
|
3496
|
+
"local.set",
|
|
3497
|
+
"local.tee",
|
|
3498
|
+
"unreachable",
|
|
3499
|
+
"return",
|
|
3500
|
+
"br",
|
|
3501
|
+
"br_if",
|
|
3502
|
+
"br_table",
|
|
3503
|
+
"br_on_null",
|
|
3504
|
+
"br_on_non_null",
|
|
3505
|
+
"br_on_cast",
|
|
3506
|
+
"br_on_cast_fail",
|
|
3507
|
+
"throw",
|
|
3508
|
+
"rethrow",
|
|
3509
|
+
"throw_ref",
|
|
3510
|
+
"try_table",
|
|
3511
|
+
"data.drop",
|
|
3512
|
+
"elem.drop"
|
|
3513
|
+
]);
|
|
3514
|
+
var IMPURE_SUBSTRINGS = [".store", "memory.", ".atomic."];
|
|
3515
|
+
var isPure = (node) => {
|
|
3516
|
+
if (!Array.isArray(node)) return true;
|
|
3517
|
+
const op = node[0];
|
|
3518
|
+
if (typeof op !== "string") return false;
|
|
3519
|
+
if (IMPURE_OPS.has(op)) return false;
|
|
3520
|
+
for (const sub of IMPURE_SUBSTRINGS) if (op.includes(sub)) return false;
|
|
3521
|
+
for (let i = 1; i < node.length; i++) if (Array.isArray(node[i]) && !isPure(node[i])) return false;
|
|
3522
|
+
return true;
|
|
3523
|
+
};
|
|
3524
|
+
var countLocalUses = (node) => {
|
|
3525
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3526
|
+
const ensure = (name2) => {
|
|
3527
|
+
if (!counts.has(name2)) counts.set(name2, { gets: 0, sets: 0, tees: 0 });
|
|
3528
|
+
return counts.get(name2);
|
|
3529
|
+
};
|
|
3530
|
+
walk2(node, (n) => {
|
|
3531
|
+
if (!Array.isArray(n) || n.length < 2 || typeof n[1] !== "string") return;
|
|
3532
|
+
if (n[0] === "local.get") ensure(n[1]).gets++;
|
|
3533
|
+
else if (n[0] === "local.set") ensure(n[1]).sets++;
|
|
3534
|
+
else if (n[0] === "local.tee") ensure(n[1]).tees++;
|
|
3535
|
+
});
|
|
3536
|
+
return counts;
|
|
3537
|
+
};
|
|
3538
|
+
var canSubst = (k) => getConst(k.val) || k.pure && k.singleUse;
|
|
3539
|
+
var substGets = (node, known) => walkPost2(node, (n) => {
|
|
3540
|
+
if (!Array.isArray(n) || n[0] !== "local.get" || n.length !== 2) return;
|
|
3541
|
+
const k = typeof n[1] === "string" && known.get(n[1]);
|
|
3542
|
+
if (k && canSubst(k)) return clone2(k.val);
|
|
3543
|
+
});
|
|
3544
|
+
var forwardPropagate = (funcNode, params, useCounts) => {
|
|
3545
|
+
let changed = false;
|
|
3546
|
+
const getUseCount = (name2) => useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3547
|
+
const known = /* @__PURE__ */ new Map();
|
|
3548
|
+
for (let i = 1; i < funcNode.length; i++) {
|
|
3549
|
+
const instr2 = funcNode[i];
|
|
3550
|
+
if (!Array.isArray(instr2)) continue;
|
|
3551
|
+
const op = instr2[0];
|
|
3552
|
+
if (op === "param" || op === "result" || op === "local" || op === "type" || op === "export") continue;
|
|
3553
|
+
if (op === "local.set" && instr2.length === 3 && typeof instr2[1] === "string") {
|
|
3554
|
+
substGets(instr2[2], known);
|
|
3555
|
+
const uses = getUseCount(instr2[1]);
|
|
3556
|
+
known.set(instr2[1], {
|
|
3557
|
+
val: instr2[2],
|
|
3558
|
+
pure: isPure(instr2[2]),
|
|
3559
|
+
singleUse: uses.gets <= 1 && uses.sets <= 1 && uses.tees === 0
|
|
3560
|
+
});
|
|
3561
|
+
continue;
|
|
3562
|
+
}
|
|
3563
|
+
if (op === "block" || op === "loop" || op === "if") known.clear();
|
|
3564
|
+
if (op === "call" || op === "call_indirect" || op === "return_call" || op === "return_call_indirect") {
|
|
3565
|
+
for (const [key, tracked] of known) if (!getConst(tracked.val)) known.delete(key);
|
|
3566
|
+
}
|
|
3567
|
+
if (op === "local.get" && instr2.length === 2 && typeof instr2[1] === "string") {
|
|
3568
|
+
const tracked = known.get(instr2[1]);
|
|
3569
|
+
if (tracked && canSubst(tracked)) {
|
|
3570
|
+
const replacement = clone2(tracked.val);
|
|
3571
|
+
instr2.length = 0;
|
|
3572
|
+
instr2.push(...Array.isArray(replacement) ? replacement : [replacement]);
|
|
3573
|
+
changed = true;
|
|
3574
|
+
continue;
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
if (op !== "block" && op !== "loop" && op !== "if") {
|
|
3578
|
+
const prev = clone2(instr2);
|
|
3579
|
+
substGets(instr2, known);
|
|
3580
|
+
if (!equal(prev, instr2)) changed = true;
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
return changed;
|
|
3584
|
+
};
|
|
3585
|
+
var eliminateSetGetPairs = (funcNode, params, useCounts) => {
|
|
3586
|
+
let changed = false;
|
|
3587
|
+
for (let i = 1; i < funcNode.length - 1; i++) {
|
|
3588
|
+
const setNode = funcNode[i];
|
|
3589
|
+
const getNode = funcNode[i + 1];
|
|
3590
|
+
if (!Array.isArray(setNode) || setNode[0] !== "local.set" || setNode.length !== 3) continue;
|
|
3591
|
+
if (!Array.isArray(getNode) || getNode[0] !== "local.get" || getNode.length !== 2) continue;
|
|
3592
|
+
const name2 = setNode[1];
|
|
3593
|
+
if (getNode[1] !== name2 || params.has(name2)) continue;
|
|
3594
|
+
const uses = useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3595
|
+
if (uses.sets !== 1 || uses.gets !== 1 || uses.tees !== 0) continue;
|
|
3596
|
+
const expr2 = clone2(setNode[2]);
|
|
3597
|
+
funcNode.splice(i, 2, ...Array.isArray(expr2) ? [expr2] : [expr2]);
|
|
3598
|
+
changed = true;
|
|
3599
|
+
i--;
|
|
3600
|
+
}
|
|
3601
|
+
return changed;
|
|
3602
|
+
};
|
|
3603
|
+
var createLocalTees = (funcNode, params, useCounts) => {
|
|
3604
|
+
let changed = false;
|
|
3605
|
+
for (let i = 1; i < funcNode.length - 1; i++) {
|
|
3606
|
+
const setNode = funcNode[i];
|
|
3607
|
+
const getNode = funcNode[i + 1];
|
|
3608
|
+
if (!Array.isArray(setNode) || setNode[0] !== "local.set" || setNode.length !== 3) continue;
|
|
3609
|
+
if (!Array.isArray(getNode) || getNode[0] !== "local.get" || getNode.length !== 2) continue;
|
|
3610
|
+
const name2 = setNode[1];
|
|
3611
|
+
if (getNode[1] !== name2 || params.has(name2)) continue;
|
|
3612
|
+
const uses = useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3613
|
+
if (uses.sets + uses.gets + uses.tees <= 2) continue;
|
|
3614
|
+
funcNode.splice(i, 2, ["local.tee", name2, clone2(setNode[2])]);
|
|
3615
|
+
changed = true;
|
|
3616
|
+
}
|
|
3617
|
+
return changed;
|
|
3618
|
+
};
|
|
3619
|
+
var eliminateDeadStores = (funcNode, params, useCounts) => {
|
|
3620
|
+
let changed = false;
|
|
3621
|
+
const getPostUseCount = (name2) => useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3622
|
+
for (let i = funcNode.length - 1; i >= 1; i--) {
|
|
3623
|
+
const sub = funcNode[i];
|
|
3624
|
+
if (!Array.isArray(sub)) continue;
|
|
3625
|
+
const name2 = typeof sub[1] === "string" ? sub[1] : null;
|
|
3626
|
+
if (!name2 || params.has(name2)) continue;
|
|
3627
|
+
const uses = getPostUseCount(name2);
|
|
3628
|
+
if (sub[0] === "local.set" && uses.gets === 0 && uses.tees === 0 && isPure(sub[2])) {
|
|
3629
|
+
funcNode.splice(i, 1);
|
|
3630
|
+
changed = true;
|
|
3631
|
+
} else if (sub[0] === "local" && name2[0] === "$" && uses.gets === 0 && uses.sets === 0 && uses.tees === 0) {
|
|
3632
|
+
funcNode.splice(i, 1);
|
|
3633
|
+
changed = true;
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
return changed;
|
|
3637
|
+
};
|
|
3521
3638
|
var propagate = (ast) => {
|
|
3522
3639
|
const result = clone2(ast);
|
|
3523
|
-
walk2(result, (
|
|
3524
|
-
if (!Array.isArray(
|
|
3525
|
-
const
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
constLocals.set(local, val);
|
|
3537
|
-
} else if (typeof local === "string") {
|
|
3538
|
-
constLocals.delete(local);
|
|
3539
|
-
}
|
|
3540
|
-
} else if (op === "local.tee" && instr2.length === 3) {
|
|
3541
|
-
const local = instr2[1];
|
|
3542
|
-
const val = instr2[2];
|
|
3543
|
-
const c = getConst(val);
|
|
3544
|
-
if (c && typeof local === "string") {
|
|
3545
|
-
constLocals.set(local, val);
|
|
3546
|
-
} else if (typeof local === "string") {
|
|
3547
|
-
constLocals.delete(local);
|
|
3548
|
-
}
|
|
3549
|
-
} else if (op === "local.get" && instr2.length === 2) {
|
|
3550
|
-
const local = instr2[1];
|
|
3551
|
-
if (typeof local === "string" && constLocals.has(local)) {
|
|
3552
|
-
const constVal = constLocals.get(local);
|
|
3553
|
-
instr2.length = 0;
|
|
3554
|
-
instr2.push(...clone2(constVal));
|
|
3555
|
-
}
|
|
3556
|
-
} else if (op === "block" || op === "loop" || op === "if" || op === "call" || op === "call_indirect") {
|
|
3557
|
-
constLocals.clear();
|
|
3558
|
-
}
|
|
3559
|
-
walkPost2(instr2, (n) => {
|
|
3560
|
-
if (!Array.isArray(n) || n[0] !== "local.get" || n.length !== 2) return;
|
|
3561
|
-
const local = n[1];
|
|
3562
|
-
if (typeof local === "string" && constLocals.has(local)) {
|
|
3563
|
-
const constVal = constLocals.get(local);
|
|
3564
|
-
return clone2(constVal);
|
|
3565
|
-
}
|
|
3566
|
-
});
|
|
3567
|
-
}
|
|
3568
|
-
};
|
|
3569
|
-
processBlock(node);
|
|
3640
|
+
walk2(result, (funcNode) => {
|
|
3641
|
+
if (!Array.isArray(funcNode) || funcNode[0] !== "func") return;
|
|
3642
|
+
const params = /* @__PURE__ */ new Set();
|
|
3643
|
+
for (const sub of funcNode)
|
|
3644
|
+
if (Array.isArray(sub) && sub[0] === "param" && typeof sub[1] === "string") params.add(sub[1]);
|
|
3645
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
3646
|
+
let changed = false;
|
|
3647
|
+
if (forwardPropagate(funcNode, params, countLocalUses(funcNode))) changed = true;
|
|
3648
|
+
if (eliminateSetGetPairs(funcNode, params, countLocalUses(funcNode))) changed = true;
|
|
3649
|
+
if (createLocalTees(funcNode, params, countLocalUses(funcNode))) changed = true;
|
|
3650
|
+
if (eliminateDeadStores(funcNode, params, countLocalUses(funcNode))) changed = true;
|
|
3651
|
+
if (!changed) break;
|
|
3652
|
+
}
|
|
3570
3653
|
});
|
|
3571
3654
|
return result;
|
|
3572
3655
|
};
|
|
@@ -3600,7 +3683,7 @@ var inline = (ast) => {
|
|
|
3600
3683
|
body.push(sub);
|
|
3601
3684
|
}
|
|
3602
3685
|
}
|
|
3603
|
-
if (params && !hasLocals && !hasExport && params.length <=
|
|
3686
|
+
if (params && !hasLocals && !hasExport && params.length <= 4 && body.length === 1) {
|
|
3604
3687
|
const paramNames = new Set(params.map((p) => p.name));
|
|
3605
3688
|
let mutatesParam = false;
|
|
3606
3689
|
walk2(body[0], (n) => {
|
|
@@ -3637,19 +3720,702 @@ var inline = (ast) => {
|
|
|
3637
3720
|
});
|
|
3638
3721
|
return result;
|
|
3639
3722
|
};
|
|
3723
|
+
var vacuum = (ast) => {
|
|
3724
|
+
return walkPost2(clone2(ast), (node) => {
|
|
3725
|
+
if (!Array.isArray(node)) return;
|
|
3726
|
+
const op = node[0];
|
|
3727
|
+
if (op === "nop") return ["nop"];
|
|
3728
|
+
if (op === "drop" && node.length === 2 && isPure(node[1])) {
|
|
3729
|
+
return ["nop"];
|
|
3730
|
+
}
|
|
3731
|
+
if (op === "select" && node.length >= 4 && equal(node[1], node[2])) return node[1];
|
|
3732
|
+
if (op === "if") {
|
|
3733
|
+
const { cond, thenBranch, elseBranch } = parseIf(node);
|
|
3734
|
+
const thenEmpty = !thenBranch || thenBranch.length <= 1;
|
|
3735
|
+
const elseEmpty = !elseBranch || elseBranch.length <= 1;
|
|
3736
|
+
if (thenEmpty && elseEmpty) return isPure(cond) ? ["nop"] : ["drop", cond];
|
|
3737
|
+
if (elseBranch && elseEmpty && !thenEmpty) {
|
|
3738
|
+
return node.filter((c) => c !== elseBranch);
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
if (op === "func" || op === "block" || op === "loop" || op === "then" || op === "else") {
|
|
3742
|
+
const cleaned = [op];
|
|
3743
|
+
for (let i = 1; i < node.length; i++) {
|
|
3744
|
+
const child = node[i];
|
|
3745
|
+
if (child === "nop" || Array.isArray(child) && child[0] === "nop") continue;
|
|
3746
|
+
const next = node[i + 1];
|
|
3747
|
+
const isDrop = next === "drop" || Array.isArray(next) && next[0] === "drop" && next.length === 1;
|
|
3748
|
+
if (Array.isArray(child) && isPure(child) && isDrop) {
|
|
3749
|
+
i++;
|
|
3750
|
+
continue;
|
|
3751
|
+
}
|
|
3752
|
+
cleaned.push(child);
|
|
3753
|
+
}
|
|
3754
|
+
if (cleaned.length !== node.length) return cleaned;
|
|
3755
|
+
}
|
|
3756
|
+
});
|
|
3757
|
+
};
|
|
3758
|
+
var PEEPHOLE = {
|
|
3759
|
+
// Self-cancelling / tautological binary ops
|
|
3760
|
+
"i32.sub": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3761
|
+
"i64.sub": (a, b) => equal(a, b) ? ["i64.const", 0n] : null,
|
|
3762
|
+
"i32.xor": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3763
|
+
"i64.xor": (a, b) => equal(a, b) ? ["i64.const", 0n] : null,
|
|
3764
|
+
"i32.and": (a, b) => equal(a, b) ? a : null,
|
|
3765
|
+
"i64.and": (a, b) => equal(a, b) ? a : null,
|
|
3766
|
+
"i32.or": (a, b) => equal(a, b) ? a : null,
|
|
3767
|
+
"i64.or": (a, b) => equal(a, b) ? a : null,
|
|
3768
|
+
"i32.eq": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3769
|
+
"i64.eq": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3770
|
+
"i32.ne": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3771
|
+
"i64.ne": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3772
|
+
"i32.lt_s": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3773
|
+
"i32.lt_u": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3774
|
+
"i32.gt_s": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3775
|
+
"i32.gt_u": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3776
|
+
"i32.le_s": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3777
|
+
"i32.le_u": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3778
|
+
"i32.ge_s": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3779
|
+
"i32.ge_u": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3780
|
+
"i64.lt_s": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3781
|
+
"i64.lt_u": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3782
|
+
"i64.gt_s": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3783
|
+
"i64.gt_u": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
3784
|
+
"i64.le_s": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3785
|
+
"i64.le_u": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3786
|
+
"i64.ge_s": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3787
|
+
"i64.ge_u": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
3788
|
+
// Zero/all-bits absorption
|
|
3789
|
+
"i32.mul": (a, b) => {
|
|
3790
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3791
|
+
if (ca?.value === 0 || cb?.value === 0) return ["i32.const", 0];
|
|
3792
|
+
return null;
|
|
3793
|
+
},
|
|
3794
|
+
"i64.mul": (a, b) => {
|
|
3795
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3796
|
+
if (ca?.value === 0n || cb?.value === 0n) return ["i64.const", 0n];
|
|
3797
|
+
return null;
|
|
3798
|
+
},
|
|
3799
|
+
"i32.and": (a, b) => {
|
|
3800
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3801
|
+
if (ca?.value === 0 || cb?.value === 0) return ["i32.const", 0];
|
|
3802
|
+
return null;
|
|
3803
|
+
},
|
|
3804
|
+
"i64.and": (a, b) => {
|
|
3805
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3806
|
+
if (ca?.value === 0n || cb?.value === 0n) return ["i64.const", 0n];
|
|
3807
|
+
return null;
|
|
3808
|
+
},
|
|
3809
|
+
"i32.or": (a, b) => {
|
|
3810
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3811
|
+
if (ca?.value === -1 || cb?.value === -1) return ["i32.const", -1];
|
|
3812
|
+
return null;
|
|
3813
|
+
},
|
|
3814
|
+
"i64.or": (a, b) => {
|
|
3815
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3816
|
+
if (ca?.value === -1n || cb?.value === -1n) return ["i64.const", -1n];
|
|
3817
|
+
return null;
|
|
3818
|
+
},
|
|
3819
|
+
// (local.set $x (local.get $x)) → nop
|
|
3820
|
+
"local.set": (a, b) => Array.isArray(b) && b[0] === "local.get" && b[1] === a ? ["nop"] : null
|
|
3821
|
+
};
|
|
3822
|
+
var peephole = (ast) => {
|
|
3823
|
+
return walkPost2(clone2(ast), (node) => {
|
|
3824
|
+
if (!Array.isArray(node) || node.length !== 3) return;
|
|
3825
|
+
const fn = PEEPHOLE[node[0]];
|
|
3826
|
+
if (!fn) return;
|
|
3827
|
+
const result = fn(node[1], node[2]);
|
|
3828
|
+
if (result !== null) return result;
|
|
3829
|
+
});
|
|
3830
|
+
};
|
|
3831
|
+
var globals = (ast) => {
|
|
3832
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
3833
|
+
const result = clone2(ast);
|
|
3834
|
+
const constGlobals = /* @__PURE__ */ new Map();
|
|
3835
|
+
const mutableGlobals = /* @__PURE__ */ new Set();
|
|
3836
|
+
for (const node of result.slice(1)) {
|
|
3837
|
+
if (!Array.isArray(node) || node[0] !== "global") continue;
|
|
3838
|
+
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
3839
|
+
if (!name2) continue;
|
|
3840
|
+
const hasName = typeof node[1] === "string" && node[1][0] === "$";
|
|
3841
|
+
const initIdx = hasName ? 3 : 2;
|
|
3842
|
+
const typeSlot = hasName ? node[2] : node[1];
|
|
3843
|
+
if (Array.isArray(typeSlot) && typeSlot[0] === "mut") continue;
|
|
3844
|
+
const init = node[initIdx];
|
|
3845
|
+
if (getConst(init)) constGlobals.set(name2, init);
|
|
3846
|
+
}
|
|
3847
|
+
walk2(result, (n) => {
|
|
3848
|
+
if (!Array.isArray(n) || n[0] !== "global.set") return;
|
|
3849
|
+
const ref = n[1];
|
|
3850
|
+
if (typeof ref === "string" && ref[0] === "$") mutableGlobals.add(ref);
|
|
3851
|
+
});
|
|
3852
|
+
for (const name2 of mutableGlobals) constGlobals.delete(name2);
|
|
3853
|
+
if (constGlobals.size === 0) return result;
|
|
3854
|
+
return walkPost2(result, (node) => {
|
|
3855
|
+
if (!Array.isArray(node) || node[0] !== "global.get" || node.length !== 2) return;
|
|
3856
|
+
const ref = node[1];
|
|
3857
|
+
if (constGlobals.has(ref)) return clone2(constGlobals.get(ref));
|
|
3858
|
+
});
|
|
3859
|
+
};
|
|
3860
|
+
var offset = (ast) => {
|
|
3861
|
+
return walkPost2(clone2(ast), (node) => {
|
|
3862
|
+
if (!Array.isArray(node)) return;
|
|
3863
|
+
const op = node[0];
|
|
3864
|
+
if (typeof op !== "string" || !op.endsWith("load") && !op.endsWith("store")) return;
|
|
3865
|
+
const isStore = op.endsWith("store");
|
|
3866
|
+
let currentOffset = 0;
|
|
3867
|
+
let memIdx = null;
|
|
3868
|
+
let argStart = 1;
|
|
3869
|
+
if (typeof node[1] === "string" && (node[1][0] === "$" || !isNaN(node[1]))) {
|
|
3870
|
+
memIdx = node[1];
|
|
3871
|
+
argStart = 2;
|
|
3872
|
+
}
|
|
3873
|
+
while (argStart < node.length && typeof node[argStart] === "string" && (node[argStart].startsWith("offset=") || node[argStart].startsWith("align="))) {
|
|
3874
|
+
if (node[argStart].startsWith("offset=")) {
|
|
3875
|
+
currentOffset = +node[argStart].slice(7);
|
|
3876
|
+
}
|
|
3877
|
+
argStart++;
|
|
3878
|
+
}
|
|
3879
|
+
const ptrIdx = isStore ? node.length - 2 : node.length - 1;
|
|
3880
|
+
const valIdx = isStore ? node.length - 1 : -1;
|
|
3881
|
+
if (ptrIdx < argStart) return;
|
|
3882
|
+
const ptr = node[ptrIdx];
|
|
3883
|
+
if (!Array.isArray(ptr) || ptr[0] !== "i32.add" || ptr.length !== 3) return;
|
|
3884
|
+
const a = ptr[1], b = ptr[2];
|
|
3885
|
+
const ca = getConst(a), cb = getConst(b);
|
|
3886
|
+
let base = null, addend = null;
|
|
3887
|
+
if (ca && ca.type === "i32") {
|
|
3888
|
+
addend = ca.value;
|
|
3889
|
+
base = b;
|
|
3890
|
+
} else if (cb && cb.type === "i32") {
|
|
3891
|
+
addend = cb.value;
|
|
3892
|
+
base = a;
|
|
3893
|
+
}
|
|
3894
|
+
if (base === null || addend === null) return;
|
|
3895
|
+
const newOffset = currentOffset + addend;
|
|
3896
|
+
const newNode = [op];
|
|
3897
|
+
if (memIdx !== null) newNode.push(memIdx);
|
|
3898
|
+
newNode.push(`offset=${newOffset}`);
|
|
3899
|
+
let alignParam = null;
|
|
3900
|
+
for (let i = argStart; i < ptrIdx; i++) {
|
|
3901
|
+
if (typeof node[i] === "string" && node[i].startsWith("align=")) {
|
|
3902
|
+
alignParam = node[i];
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
if (alignParam) newNode.push(alignParam);
|
|
3906
|
+
newNode.push(base);
|
|
3907
|
+
if (isStore) newNode.push(node[valIdx]);
|
|
3908
|
+
return newNode;
|
|
3909
|
+
});
|
|
3910
|
+
};
|
|
3911
|
+
var unbranch = (ast) => {
|
|
3912
|
+
const result = clone2(ast);
|
|
3913
|
+
walk2(result, (node) => {
|
|
3914
|
+
if (!Array.isArray(node)) return;
|
|
3915
|
+
const op = node[0];
|
|
3916
|
+
if (op !== "block" && op !== "loop") return;
|
|
3917
|
+
let labelIdx = 1;
|
|
3918
|
+
let label = null;
|
|
3919
|
+
if (typeof node[1] === "string" && node[1][0] === "$") {
|
|
3920
|
+
label = node[1];
|
|
3921
|
+
labelIdx = 2;
|
|
3922
|
+
}
|
|
3923
|
+
if (!label) return;
|
|
3924
|
+
let lastIdx = -1;
|
|
3925
|
+
for (let i = node.length - 1; i >= labelIdx; i--) {
|
|
3926
|
+
const child = node[i];
|
|
3927
|
+
if (!Array.isArray(child)) {
|
|
3928
|
+
if (child !== "nop" && child !== "end") lastIdx = i;
|
|
3929
|
+
continue;
|
|
3930
|
+
}
|
|
3931
|
+
const cop = child[0];
|
|
3932
|
+
if (cop === "param" || cop === "result" || cop === "local" || cop === "type" || cop === "export") continue;
|
|
3933
|
+
lastIdx = i;
|
|
3934
|
+
break;
|
|
3935
|
+
}
|
|
3936
|
+
if (lastIdx < 0) return;
|
|
3937
|
+
const last = node[lastIdx];
|
|
3938
|
+
if (Array.isArray(last) && last[0] === "br" && last[1] === label) {
|
|
3939
|
+
node.splice(lastIdx, 1);
|
|
3940
|
+
}
|
|
3941
|
+
});
|
|
3942
|
+
return result;
|
|
3943
|
+
};
|
|
3944
|
+
var stripmut = (ast) => {
|
|
3945
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
3946
|
+
const result = clone2(ast);
|
|
3947
|
+
const written = /* @__PURE__ */ new Set();
|
|
3948
|
+
walk2(result, (n) => {
|
|
3949
|
+
if (Array.isArray(n) && n[0] === "global.set" && typeof n[1] === "string") written.add(n[1]);
|
|
3950
|
+
});
|
|
3951
|
+
return walkPost2(result, (node) => {
|
|
3952
|
+
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
3953
|
+
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
3954
|
+
if (!name2 || written.has(name2)) return;
|
|
3955
|
+
const hasName = typeof node[1] === "string" && node[1][0] === "$";
|
|
3956
|
+
const typeSlot = hasName ? node[2] : node[1];
|
|
3957
|
+
if (Array.isArray(typeSlot) && typeSlot[0] === "mut") {
|
|
3958
|
+
const newNode = [...node];
|
|
3959
|
+
newNode[hasName ? 2 : 1] = typeSlot[1];
|
|
3960
|
+
return newNode;
|
|
3961
|
+
}
|
|
3962
|
+
});
|
|
3963
|
+
};
|
|
3964
|
+
var brif = (ast) => {
|
|
3965
|
+
return walkPost2(clone2(ast), (node) => {
|
|
3966
|
+
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
3967
|
+
const { cond, thenBranch, elseBranch } = parseIf(node);
|
|
3968
|
+
const thenEmpty = !thenBranch || thenBranch.length <= 1;
|
|
3969
|
+
const elseEmpty = !elseBranch || elseBranch.length <= 1;
|
|
3970
|
+
if (!thenEmpty && elseEmpty && thenBranch.length === 2) {
|
|
3971
|
+
const t = thenBranch[1];
|
|
3972
|
+
if (Array.isArray(t) && t[0] === "br" && t.length === 2) return ["br_if", t[1], cond];
|
|
3973
|
+
}
|
|
3974
|
+
if (thenEmpty && !elseEmpty && elseBranch.length === 2) {
|
|
3975
|
+
const e = elseBranch[1];
|
|
3976
|
+
if (Array.isArray(e) && e[0] === "br" && e.length === 2) return ["br_if", e[1], ["i32.eqz", cond]];
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
};
|
|
3980
|
+
var foldarms = (ast) => {
|
|
3981
|
+
return walkPost2(clone2(ast), (node) => {
|
|
3982
|
+
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
3983
|
+
const { thenBranch, elseBranch } = parseIf(node);
|
|
3984
|
+
if (!thenBranch || !elseBranch) return;
|
|
3985
|
+
if (thenBranch.length <= 1 || elseBranch.length <= 1) return;
|
|
3986
|
+
let common = 0;
|
|
3987
|
+
const minLen = Math.min(thenBranch.length, elseBranch.length);
|
|
3988
|
+
for (let i = 1; i < minLen; i++) {
|
|
3989
|
+
if (!equal(thenBranch[thenBranch.length - i], elseBranch[elseBranch.length - i])) break;
|
|
3990
|
+
common++;
|
|
3991
|
+
}
|
|
3992
|
+
if (common === 0) return;
|
|
3993
|
+
const hoisted = thenBranch.slice(thenBranch.length - common);
|
|
3994
|
+
const newThen = thenBranch.slice(0, thenBranch.length - common);
|
|
3995
|
+
const newElse = elseBranch.slice(0, elseBranch.length - common);
|
|
3996
|
+
const block = ["block"];
|
|
3997
|
+
for (let i = 1; i < node.length; i++) {
|
|
3998
|
+
const c = node[i];
|
|
3999
|
+
if (Array.isArray(c) && (c[0] === "then" || c[0] === "else")) break;
|
|
4000
|
+
if (Array.isArray(c) && (c[0] === "result" || c[0] === "type")) block.push(c);
|
|
4001
|
+
}
|
|
4002
|
+
const newIf = ["if"];
|
|
4003
|
+
for (let i = 1; i < node.length; i++) {
|
|
4004
|
+
const c = node[i];
|
|
4005
|
+
if (Array.isArray(c) && (c[0] === "then" || c[0] === "else")) break;
|
|
4006
|
+
newIf.push(c);
|
|
4007
|
+
}
|
|
4008
|
+
newIf.push(newThen.length > 1 ? newThen : ["then"]);
|
|
4009
|
+
newIf.push(newElse.length > 1 ? newElse : ["else"]);
|
|
4010
|
+
block.push(newIf, ...hoisted);
|
|
4011
|
+
return block;
|
|
4012
|
+
});
|
|
4013
|
+
};
|
|
4014
|
+
var hashFunc = (node, localNames) => {
|
|
4015
|
+
const parts = [];
|
|
4016
|
+
const stack = [node];
|
|
4017
|
+
while (stack.length) {
|
|
4018
|
+
const v = stack.pop();
|
|
4019
|
+
if (Array.isArray(v)) {
|
|
4020
|
+
stack.push("|");
|
|
4021
|
+
for (let i = v.length - 1; i >= 0; i--) stack.push(v[i]);
|
|
4022
|
+
stack.push("[");
|
|
4023
|
+
} else if (typeof v === "string") {
|
|
4024
|
+
parts.push(localNames.has(v) ? "$__L" : v);
|
|
4025
|
+
} else if (typeof v === "bigint") {
|
|
4026
|
+
parts.push(v.toString() + "n");
|
|
4027
|
+
} else if (typeof v === "number") {
|
|
4028
|
+
parts.push(v.toString());
|
|
4029
|
+
} else if (v === null) {
|
|
4030
|
+
parts.push("null");
|
|
4031
|
+
} else if (v === true) {
|
|
4032
|
+
parts.push("t");
|
|
4033
|
+
} else if (v === false) {
|
|
4034
|
+
parts.push("f");
|
|
4035
|
+
} else {
|
|
4036
|
+
parts.push(String(v));
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
return parts.join(",");
|
|
4040
|
+
};
|
|
4041
|
+
var dedupe = (ast) => {
|
|
4042
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4043
|
+
const result = clone2(ast);
|
|
4044
|
+
const signatures = /* @__PURE__ */ new Map();
|
|
4045
|
+
const redirects = /* @__PURE__ */ new Map();
|
|
4046
|
+
for (const node of result.slice(1)) {
|
|
4047
|
+
if (!Array.isArray(node) || node[0] !== "func") continue;
|
|
4048
|
+
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4049
|
+
if (!name2) continue;
|
|
4050
|
+
const localNames = /* @__PURE__ */ new Set();
|
|
4051
|
+
if (typeof node[1] === "string" && node[1][0] === "$") localNames.add(node[1]);
|
|
4052
|
+
walk2(node, (n) => {
|
|
4053
|
+
if (!Array.isArray(n) || typeof n[1] !== "string" || n[1][0] !== "$") return;
|
|
4054
|
+
const op = n[0];
|
|
4055
|
+
if (op === "param" || op === "local" || op === "block" || op === "loop" || op === "if") {
|
|
4056
|
+
localNames.add(n[1]);
|
|
4057
|
+
}
|
|
4058
|
+
});
|
|
4059
|
+
const hash = hashFunc(node, localNames);
|
|
4060
|
+
if (signatures.has(hash)) {
|
|
4061
|
+
redirects.set(name2, signatures.get(hash));
|
|
4062
|
+
} else {
|
|
4063
|
+
signatures.set(hash, name2);
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
4066
|
+
if (redirects.size === 0) return result;
|
|
4067
|
+
walkPost2(result, (node) => {
|
|
4068
|
+
if (!Array.isArray(node)) return;
|
|
4069
|
+
const op = node[0];
|
|
4070
|
+
if ((op === "call" || op === "return_call") && redirects.has(node[1])) {
|
|
4071
|
+
return [op, redirects.get(node[1]), ...node.slice(2)];
|
|
4072
|
+
}
|
|
4073
|
+
if (op === "ref.func" && redirects.has(node[1])) {
|
|
4074
|
+
return ["ref.func", redirects.get(node[1])];
|
|
4075
|
+
}
|
|
4076
|
+
if (op === "elem") {
|
|
4077
|
+
const funcs = node[node.length - 1];
|
|
4078
|
+
if (Array.isArray(funcs)) {
|
|
4079
|
+
return [...node.slice(0, -1), funcs.map((f) => redirects.get(f) || f)];
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
if (op === "call_indirect" && node.length >= 3) {
|
|
4083
|
+
const typeRef = node[1];
|
|
4084
|
+
if (typeof typeRef === "string" && redirects.has(typeRef)) {
|
|
4085
|
+
return ["call_indirect", redirects.get(typeRef), ...node.slice(2)];
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
});
|
|
4089
|
+
return result;
|
|
4090
|
+
};
|
|
4091
|
+
var dedupTypes = (ast) => {
|
|
4092
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4093
|
+
const result = clone2(ast);
|
|
4094
|
+
const signatures = /* @__PURE__ */ new Map();
|
|
4095
|
+
const redirects = /* @__PURE__ */ new Map();
|
|
4096
|
+
for (const node of result.slice(1)) {
|
|
4097
|
+
if (!Array.isArray(node) || node[0] !== "type") continue;
|
|
4098
|
+
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4099
|
+
if (!name2) continue;
|
|
4100
|
+
const hash = hashFunc(node, /* @__PURE__ */ new Set([name2]));
|
|
4101
|
+
if (signatures.has(hash)) {
|
|
4102
|
+
redirects.set(name2, signatures.get(hash));
|
|
4103
|
+
} else {
|
|
4104
|
+
signatures.set(hash, name2);
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
if (redirects.size === 0) return result;
|
|
4108
|
+
for (let i = result.length - 1; i >= 0; i--) {
|
|
4109
|
+
const node = result[i];
|
|
4110
|
+
if (Array.isArray(node) && node[0] === "type") {
|
|
4111
|
+
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4112
|
+
if (name2 && redirects.has(name2)) result.splice(i, 1);
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
walkPost2(result, (node) => {
|
|
4116
|
+
if (!Array.isArray(node)) return;
|
|
4117
|
+
const op = node[0];
|
|
4118
|
+
if (op === "func") {
|
|
4119
|
+
for (let i = 1; i < node.length; i++) {
|
|
4120
|
+
const sub = node[i];
|
|
4121
|
+
if (Array.isArray(sub) && sub[0] === "type" && typeof sub[1] === "string" && redirects.has(sub[1])) {
|
|
4122
|
+
node[i] = ["type", redirects.get(sub[1])];
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
if (op === "import") {
|
|
4127
|
+
for (let i = 1; i < node.length; i++) {
|
|
4128
|
+
const sub = node[i];
|
|
4129
|
+
if (Array.isArray(sub)) {
|
|
4130
|
+
for (let j = 1; j < sub.length; j++) {
|
|
4131
|
+
const inner = sub[j];
|
|
4132
|
+
if (Array.isArray(inner) && inner[0] === "type" && typeof inner[1] === "string" && redirects.has(inner[1])) {
|
|
4133
|
+
sub[j] = ["type", redirects.get(inner[1])];
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
if (op === "call_indirect" || op === "return_call_indirect") {
|
|
4140
|
+
if (typeof node[1] === "string" && redirects.has(node[1])) {
|
|
4141
|
+
return [op, redirects.get(node[1]), ...node.slice(2)];
|
|
4142
|
+
}
|
|
4143
|
+
if (Array.isArray(node[1]) && node[1][0] === "type" && typeof node[1][1] === "string" && redirects.has(node[1][1])) {
|
|
4144
|
+
return [op, ["type", redirects.get(node[1][1])], ...node.slice(2)];
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
});
|
|
4148
|
+
return result;
|
|
4149
|
+
};
|
|
4150
|
+
var parseDataString = (str2) => {
|
|
4151
|
+
if (typeof str2 !== "string" || str2.length < 2 || str2[0] !== '"') return new Uint8Array();
|
|
4152
|
+
const inner = str2.slice(1, -1);
|
|
4153
|
+
const bytes = [];
|
|
4154
|
+
for (let i = 0; i < inner.length; i++) {
|
|
4155
|
+
if (inner[i] === "\\") {
|
|
4156
|
+
const next = inner[++i];
|
|
4157
|
+
if (next === "x" || next === "X") {
|
|
4158
|
+
bytes.push(parseInt(inner.slice(i + 1, i + 3), 16));
|
|
4159
|
+
i += 2;
|
|
4160
|
+
} else if (/[0-9a-fA-F]/.test(next) && /[0-9a-fA-F]/.test(inner[i + 1])) {
|
|
4161
|
+
bytes.push(parseInt(inner.slice(i, i + 2), 16));
|
|
4162
|
+
i++;
|
|
4163
|
+
} else if (next === "n") bytes.push(10);
|
|
4164
|
+
else if (next === "t") bytes.push(9);
|
|
4165
|
+
else if (next === "r") bytes.push(13);
|
|
4166
|
+
else if (next === "\\") bytes.push(92);
|
|
4167
|
+
else if (next === '"') bytes.push(34);
|
|
4168
|
+
else bytes.push(next.charCodeAt(0));
|
|
4169
|
+
} else {
|
|
4170
|
+
bytes.push(inner.charCodeAt(i));
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
return new Uint8Array(bytes);
|
|
4174
|
+
};
|
|
4175
|
+
var encodeDataString = (bytes) => {
|
|
4176
|
+
let str2 = '"';
|
|
4177
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
4178
|
+
const b = bytes[i];
|
|
4179
|
+
if (b >= 32 && b < 127 && b !== 34 && b !== 92) {
|
|
4180
|
+
str2 += String.fromCharCode(b);
|
|
4181
|
+
} else {
|
|
4182
|
+
str2 += "\\" + b.toString(16).padStart(2, "0");
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
return str2 + '"';
|
|
4186
|
+
};
|
|
4187
|
+
var trimTrailingZeros = (items) => {
|
|
4188
|
+
const bytes = [];
|
|
4189
|
+
for (const item of items) {
|
|
4190
|
+
if (typeof item === "string") {
|
|
4191
|
+
bytes.push(...parseDataString(item));
|
|
4192
|
+
} else if (Array.isArray(item) && item[0] === "i8") {
|
|
4193
|
+
for (let i = 1; i < item.length; i++) bytes.push(Number(item[i]) & 255);
|
|
4194
|
+
} else {
|
|
4195
|
+
return items;
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
let end = bytes.length;
|
|
4199
|
+
while (end > 0 && bytes[end - 1] === 0) end--;
|
|
4200
|
+
if (end === bytes.length) return items;
|
|
4201
|
+
if (end === 0) return [];
|
|
4202
|
+
return [encodeDataString(new Uint8Array(bytes.slice(0, end)))];
|
|
4203
|
+
};
|
|
4204
|
+
var getDataOffset = (node) => {
|
|
4205
|
+
let idx = 1;
|
|
4206
|
+
if (typeof node[idx] === "string" && node[idx][0] === "$") idx++;
|
|
4207
|
+
if (Array.isArray(node[idx]) && node[idx][0] === "memory") {
|
|
4208
|
+
const mem = node[idx][1];
|
|
4209
|
+
idx++;
|
|
4210
|
+
const off2 = node[idx];
|
|
4211
|
+
if (Array.isArray(off2) && (off2[0] === "i32.const" || off2[0] === "i64.const")) {
|
|
4212
|
+
return { memidx: mem, offset: Number(off2[1]) };
|
|
4213
|
+
}
|
|
4214
|
+
return null;
|
|
4215
|
+
}
|
|
4216
|
+
const off = node[idx];
|
|
4217
|
+
if (Array.isArray(off) && (off[0] === "i32.const" || off[0] === "i64.const")) {
|
|
4218
|
+
return { memidx: 0, offset: Number(off[1]) };
|
|
4219
|
+
}
|
|
4220
|
+
return null;
|
|
4221
|
+
};
|
|
4222
|
+
var getDataLength = (node) => {
|
|
4223
|
+
let idx = 1;
|
|
4224
|
+
if (typeof node[idx] === "string" && node[idx][0] === "$") idx++;
|
|
4225
|
+
if (Array.isArray(node[idx]) && node[idx][0] === "memory") idx++;
|
|
4226
|
+
if (Array.isArray(node[idx]) && typeof node[idx][0] === "string" && !node[idx][0].startsWith('"')) idx++;
|
|
4227
|
+
let len = 0;
|
|
4228
|
+
for (let i = idx; i < node.length; i++) {
|
|
4229
|
+
const item = node[i];
|
|
4230
|
+
if (typeof item === "string") len += parseDataString(item).length;
|
|
4231
|
+
else if (Array.isArray(item) && item[0] === "i8") len += item.length - 1;
|
|
4232
|
+
else return null;
|
|
4233
|
+
}
|
|
4234
|
+
return len;
|
|
4235
|
+
};
|
|
4236
|
+
var mergeDataSegments = (a, b) => {
|
|
4237
|
+
let aIdx = 1;
|
|
4238
|
+
if (typeof a[aIdx] === "string" && a[aIdx][0] === "$") aIdx++;
|
|
4239
|
+
if (Array.isArray(a[aIdx]) && a[aIdx][0] === "memory") aIdx++;
|
|
4240
|
+
if (Array.isArray(a[aIdx]) && typeof a[aIdx][0] === "string" && !a[aIdx][0].startsWith('"')) aIdx++;
|
|
4241
|
+
let bIdx = 1;
|
|
4242
|
+
if (typeof b[bIdx] === "string" && b[bIdx][0] === "$") bIdx++;
|
|
4243
|
+
if (Array.isArray(b[bIdx]) && b[bIdx][0] === "memory") bIdx++;
|
|
4244
|
+
if (Array.isArray(b[bIdx]) && typeof b[bIdx][0] === "string" && !b[bIdx][0].startsWith('"')) bIdx++;
|
|
4245
|
+
const aContent = a.slice(aIdx);
|
|
4246
|
+
const bContent = b.slice(bIdx);
|
|
4247
|
+
if (aContent.length === 1 && bContent.length === 1 && typeof aContent[0] === "string" && typeof bContent[0] === "string") {
|
|
4248
|
+
const aBytes = parseDataString(aContent[0]);
|
|
4249
|
+
const bBytes = parseDataString(bContent[0]);
|
|
4250
|
+
const merged = new Uint8Array(aBytes.length + bBytes.length);
|
|
4251
|
+
merged.set(aBytes);
|
|
4252
|
+
merged.set(bBytes, aBytes.length);
|
|
4253
|
+
a.length = aIdx;
|
|
4254
|
+
a.push(encodeDataString(merged));
|
|
4255
|
+
return true;
|
|
4256
|
+
}
|
|
4257
|
+
a.length = aIdx;
|
|
4258
|
+
a.push(...aContent, ...bContent);
|
|
4259
|
+
return true;
|
|
4260
|
+
};
|
|
4261
|
+
var packData = (ast) => {
|
|
4262
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4263
|
+
let result = clone2(ast);
|
|
4264
|
+
for (const node of result) {
|
|
4265
|
+
if (!Array.isArray(node) || node[0] !== "data") continue;
|
|
4266
|
+
let contentStart = 1;
|
|
4267
|
+
if (typeof node[1] === "string" && node[1][0] === "$") contentStart = 2;
|
|
4268
|
+
if (contentStart < node.length && Array.isArray(node[contentStart]) && typeof node[contentStart][0] === "string" && !node[contentStart][0].startsWith('"')) {
|
|
4269
|
+
contentStart++;
|
|
4270
|
+
}
|
|
4271
|
+
const content = node.slice(contentStart);
|
|
4272
|
+
if (content.length === 0) continue;
|
|
4273
|
+
const trimmed = trimTrailingZeros(content);
|
|
4274
|
+
if (trimmed.length !== content.length || trimmed.length > 0 && trimmed[0] !== content[0]) {
|
|
4275
|
+
node.length = contentStart;
|
|
4276
|
+
node.push(...trimmed);
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
const dataNodes = [];
|
|
4280
|
+
for (let i = 0; i < result.length; i++) {
|
|
4281
|
+
const node = result[i];
|
|
4282
|
+
if (Array.isArray(node) && node[0] === "data") {
|
|
4283
|
+
const info = getDataOffset(node);
|
|
4284
|
+
if (info) {
|
|
4285
|
+
const len = getDataLength(node);
|
|
4286
|
+
if (len !== null) dataNodes.push({ ...info, node, index: i, len });
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
dataNodes.sort((a, b) => {
|
|
4291
|
+
const ma = String(a.memidx), mb = String(b.memidx);
|
|
4292
|
+
if (ma !== mb) return ma.localeCompare(mb);
|
|
4293
|
+
return a.offset - b.offset;
|
|
4294
|
+
});
|
|
4295
|
+
const toRemove = /* @__PURE__ */ new Set();
|
|
4296
|
+
for (let i = 0; i < dataNodes.length - 1; i++) {
|
|
4297
|
+
const a = dataNodes[i];
|
|
4298
|
+
const b = dataNodes[i + 1];
|
|
4299
|
+
if (toRemove.has(a.index) || String(a.memidx) !== String(b.memidx)) continue;
|
|
4300
|
+
if (a.offset + a.len !== b.offset) continue;
|
|
4301
|
+
if (mergeDataSegments(a.node, b.node)) {
|
|
4302
|
+
toRemove.add(b.index);
|
|
4303
|
+
a.len = getDataLength(a.node);
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
if (toRemove.size > 0) {
|
|
4307
|
+
result = result.filter((_, i) => !toRemove.has(i));
|
|
4308
|
+
}
|
|
4309
|
+
return result;
|
|
4310
|
+
};
|
|
4311
|
+
var makeShortener = () => {
|
|
4312
|
+
const map = /* @__PURE__ */ new Map();
|
|
4313
|
+
let n = 0;
|
|
4314
|
+
return (name2) => {
|
|
4315
|
+
if (!map.has(name2)) {
|
|
4316
|
+
let id2 = "", x = n++;
|
|
4317
|
+
do {
|
|
4318
|
+
id2 = String.fromCharCode(97 + x % 26) + id2;
|
|
4319
|
+
x = Math.floor(x / 26) - 1;
|
|
4320
|
+
} while (x >= 0);
|
|
4321
|
+
map.set(name2, id2 || "a");
|
|
4322
|
+
}
|
|
4323
|
+
return map.get(name2);
|
|
4324
|
+
};
|
|
4325
|
+
};
|
|
4326
|
+
var minifyImports = (ast) => {
|
|
4327
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4328
|
+
const result = clone2(ast);
|
|
4329
|
+
const shortMod = makeShortener();
|
|
4330
|
+
const shortField = makeShortener();
|
|
4331
|
+
for (const node of result) {
|
|
4332
|
+
if (!Array.isArray(node) || node[0] !== "import") continue;
|
|
4333
|
+
if (typeof node[1] === "string" && node[1][0] === '"') {
|
|
4334
|
+
node[1] = '"' + shortMod(node[1].slice(1, -1)) + '"';
|
|
4335
|
+
}
|
|
4336
|
+
if (typeof node[2] === "string" && node[2][0] === '"') {
|
|
4337
|
+
node[2] = '"' + shortField(node[2].slice(1, -1)) + '"';
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
return result;
|
|
4341
|
+
};
|
|
4342
|
+
var reorderSafe = (ast) => {
|
|
4343
|
+
let safe = true;
|
|
4344
|
+
walk2(ast, (n) => {
|
|
4345
|
+
if (!safe || !Array.isArray(n)) return;
|
|
4346
|
+
const op = n[0];
|
|
4347
|
+
if (op === "func" && (typeof n[1] !== "string" || n[1][0] !== "$")) safe = false;
|
|
4348
|
+
else if ((op === "call" || op === "return_call" || op === "ref.func") && (typeof n[1] !== "string" || n[1][0] !== "$")) safe = false;
|
|
4349
|
+
else if (op === "start" && (typeof n[1] !== "string" || n[1][0] !== "$")) safe = false;
|
|
4350
|
+
else if (op === "elem") {
|
|
4351
|
+
for (const sub of n) {
|
|
4352
|
+
if (typeof sub === "string" && sub[0] !== "$" && /^\d/.test(sub)) {
|
|
4353
|
+
safe = false;
|
|
4354
|
+
break;
|
|
4355
|
+
}
|
|
4356
|
+
if (Array.isArray(sub) && sub[0] === "ref.func" && (typeof sub[1] !== "string" || sub[1][0] !== "$")) {
|
|
4357
|
+
safe = false;
|
|
4358
|
+
break;
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
});
|
|
4363
|
+
return safe;
|
|
4364
|
+
};
|
|
4365
|
+
var reorder = (ast) => {
|
|
4366
|
+
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4367
|
+
if (!reorderSafe(ast)) return ast;
|
|
4368
|
+
const result = clone2(ast);
|
|
4369
|
+
const callCounts = /* @__PURE__ */ new Map();
|
|
4370
|
+
walk2(result, (n) => {
|
|
4371
|
+
if (!Array.isArray(n)) return;
|
|
4372
|
+
if (n[0] === "call" || n[0] === "return_call") {
|
|
4373
|
+
callCounts.set(n[1], (callCounts.get(n[1]) || 0) + 1);
|
|
4374
|
+
}
|
|
4375
|
+
});
|
|
4376
|
+
const imports = [], funcs = [], others = [];
|
|
4377
|
+
for (const node of result.slice(1)) {
|
|
4378
|
+
if (!Array.isArray(node)) {
|
|
4379
|
+
others.push(node);
|
|
4380
|
+
continue;
|
|
4381
|
+
}
|
|
4382
|
+
if (node[0] === "import") imports.push(node);
|
|
4383
|
+
else if (node[0] === "func") funcs.push(node);
|
|
4384
|
+
else others.push(node);
|
|
4385
|
+
}
|
|
4386
|
+
funcs.sort((a, b) => (callCounts.get(b[1]) || 0) - (callCounts.get(a[1]) || 0));
|
|
4387
|
+
return ["module", ...imports, ...funcs, ...others];
|
|
4388
|
+
};
|
|
3640
4389
|
function optimize(ast, opts = true) {
|
|
3641
4390
|
if (typeof ast === "string") ast = parse_default(ast);
|
|
3642
4391
|
ast = clone2(ast);
|
|
3643
4392
|
opts = normalize3(opts);
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
4393
|
+
for (let round = 0; round < 6; round++) {
|
|
4394
|
+
const before = ast;
|
|
4395
|
+
if (opts.stripmut) ast = stripmut(ast);
|
|
4396
|
+
if (opts.globals) ast = globals(ast);
|
|
4397
|
+
if (opts.fold) ast = fold(ast);
|
|
4398
|
+
if (opts.identity) ast = identity(ast);
|
|
4399
|
+
if (opts.peephole) ast = peephole(ast);
|
|
4400
|
+
if (opts.strength) ast = strength(ast);
|
|
4401
|
+
if (opts.branch) ast = branch(ast);
|
|
4402
|
+
if (opts.propagate) ast = propagate(ast);
|
|
4403
|
+
if (opts.inline) ast = inline(ast);
|
|
4404
|
+
if (opts.offset) ast = offset(ast);
|
|
4405
|
+
if (opts.unbranch) ast = unbranch(ast);
|
|
4406
|
+
if (opts.brif) ast = brif(ast);
|
|
4407
|
+
if (opts.foldarms) ast = foldarms(ast);
|
|
4408
|
+
if (opts.deadcode) ast = deadcode(ast);
|
|
4409
|
+
if (opts.vacuum) ast = vacuum(ast);
|
|
4410
|
+
if (opts.locals) ast = localReuse(ast);
|
|
4411
|
+
if (opts.dedupe) ast = dedupe(ast);
|
|
4412
|
+
if (opts.dedupTypes) ast = dedupTypes(ast);
|
|
4413
|
+
if (opts.packData) ast = packData(ast);
|
|
4414
|
+
if (opts.reorder) ast = reorder(ast);
|
|
4415
|
+
if (opts.treeshake) ast = treeshake(ast);
|
|
4416
|
+
if (opts.minifyImports) ast = minifyImports(ast);
|
|
4417
|
+
if (equal(before, ast)) break;
|
|
4418
|
+
}
|
|
3653
4419
|
return ast;
|
|
3654
4420
|
}
|
|
3655
4421
|
|
|
@@ -3717,7 +4483,7 @@ function genImports(imports) {
|
|
|
3717
4483
|
}
|
|
3718
4484
|
function compile2(source, ...values) {
|
|
3719
4485
|
let opts = {};
|
|
3720
|
-
if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === "object" && values[values.length - 1] !== null && !
|
|
4486
|
+
if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === "object" && values[values.length - 1] !== null && !values[values.length - 1].byteLength) {
|
|
3721
4487
|
opts = values.pop();
|
|
3722
4488
|
}
|
|
3723
4489
|
if (Array.isArray(source) && source.raw) {
|
|
@@ -3742,7 +4508,7 @@ function compile2(source, ...values) {
|
|
|
3742
4508
|
}
|
|
3743
4509
|
return parsed;
|
|
3744
4510
|
}
|
|
3745
|
-
if (value
|
|
4511
|
+
if (value.byteLength !== void 0) return [...value];
|
|
3746
4512
|
return value;
|
|
3747
4513
|
}
|
|
3748
4514
|
return node;
|