watr 4.5.0 → 4.5.3
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 +139 -100
- package/dist/watr.min.js +6 -6
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/compile.js +9 -2
- package/src/const.js +2 -2
- package/src/encode.js +33 -12
- package/src/optimize.js +131 -87
- package/types/src/const.d.ts +2 -0
- package/types/src/encode.d.ts.map +1 -1
- package/types/src/optimize.d.ts +13 -0
- package/types/src/optimize.d.ts.map +1 -1
package/dist/watr.js
CHANGED
|
@@ -140,16 +140,29 @@ var _f64 = new Float64Array(_buf);
|
|
|
140
140
|
var _i64 = new BigInt64Array(_buf);
|
|
141
141
|
i64.parse = (n) => {
|
|
142
142
|
n = cleanInt(n);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
const neg = n[0] === "-";
|
|
144
|
+
const body = neg ? n.slice(1) : n;
|
|
145
|
+
let max;
|
|
146
|
+
if (body[0] === "0" && (body[1] === "x" || body[1] === "X")) {
|
|
147
|
+
const hex = body.slice(2).replace(/^0+/, "") || "0";
|
|
148
|
+
max = neg ? "8000000000000000" : "ffffffffffffffff";
|
|
149
|
+
if (hex.length > 16 || hex.length === 16 && hex.toLowerCase() > max) err(`i64 constant out of range`);
|
|
150
|
+
} else {
|
|
151
|
+
const dec = body.replace(/^0+/, "") || "0";
|
|
152
|
+
max = neg ? "9223372036854775808" : "18446744073709551615";
|
|
153
|
+
if (dec.length > max.length || dec.length === max.length && dec > max) err(`i64 constant out of range`);
|
|
154
|
+
}
|
|
155
|
+
let bi = BigInt(body);
|
|
156
|
+
if (neg) bi = 0n - bi;
|
|
157
|
+
_i64[0] = bi;
|
|
146
158
|
return _i64[0];
|
|
147
159
|
};
|
|
148
160
|
var F32_SIGN = 2147483648;
|
|
149
161
|
var F32_NAN = 2139095040;
|
|
162
|
+
var F32_QUIET = 4194304;
|
|
150
163
|
function f32(input, value, idx) {
|
|
151
|
-
if (typeof input === "string" &&
|
|
152
|
-
value = i32.parse(input.slice(idx + 4));
|
|
164
|
+
if (typeof input === "string" && (idx = input.indexOf("nan")) >= 0) {
|
|
165
|
+
value = input[idx + 3] === ":" ? i32.parse(input.slice(idx + 4)) : F32_QUIET;
|
|
153
166
|
value |= F32_NAN;
|
|
154
167
|
if (input[0] === "-") value |= F32_SIGN;
|
|
155
168
|
_i32[0] = value;
|
|
@@ -161,9 +174,10 @@ function f32(input, value, idx) {
|
|
|
161
174
|
}
|
|
162
175
|
var F64_SIGN = 0x8000000000000000n;
|
|
163
176
|
var F64_NAN = 0x7ff0000000000000n;
|
|
177
|
+
var F64_QUIET = 0x8000000000000n;
|
|
164
178
|
function f64(input, value, idx) {
|
|
165
|
-
if (typeof input === "string" &&
|
|
166
|
-
value = i64.parse(input.slice(idx + 4));
|
|
179
|
+
if (typeof input === "string" && (idx = input.indexOf("nan")) >= 0) {
|
|
180
|
+
value = input[idx + 3] === ":" ? i64.parse(input.slice(idx + 4)) : F64_QUIET;
|
|
167
181
|
value |= F64_NAN;
|
|
168
182
|
if (input[0] === "-") value |= F64_SIGN;
|
|
169
183
|
_i64[0] = value;
|
|
@@ -182,8 +196,11 @@ f64.parse = (input, max = Number.MAX_VALUE) => {
|
|
|
182
196
|
let [sig, exp = "0"] = input.split(/p/i);
|
|
183
197
|
let [int, fract = ""] = sig.split(".");
|
|
184
198
|
let flen = fract.length ?? 0;
|
|
185
|
-
let intVal =
|
|
186
|
-
|
|
199
|
+
let intVal = 0;
|
|
200
|
+
for (let i = int.length - 1; i >= 2; i--) {
|
|
201
|
+
let digit = parseInt(int[i], 16);
|
|
202
|
+
intVal += digit * 16 ** (int.length - 1 - i);
|
|
203
|
+
}
|
|
187
204
|
let fractVal = fract ? parseInt("0x" + fract) / 16 ** flen : 0;
|
|
188
205
|
exp = parseInt(exp, 10);
|
|
189
206
|
let value = sign * (intVal + fractVal) * 2 ** exp;
|
|
@@ -497,9 +514,9 @@ var INSTR = [
|
|
|
497
514
|
"array.init_data typeidx_dataidx",
|
|
498
515
|
"array.init_elem typeidx_elemidx",
|
|
499
516
|
"ref.test reftype",
|
|
500
|
-
"",
|
|
517
|
+
"ref.test_null reftype",
|
|
501
518
|
"ref.cast reftype",
|
|
502
|
-
"",
|
|
519
|
+
"ref.cast_null reftype",
|
|
503
520
|
"br_on_cast reftype2",
|
|
504
521
|
"br_on_cast_fail reftype2",
|
|
505
522
|
"any.convert_extern",
|
|
@@ -1244,6 +1261,7 @@ var TYPE = {
|
|
|
1244
1261
|
i31: 108,
|
|
1245
1262
|
struct: 107,
|
|
1246
1263
|
array: 106,
|
|
1264
|
+
data: 107,
|
|
1247
1265
|
cont: 104,
|
|
1248
1266
|
nocont: 117,
|
|
1249
1267
|
// stack switching (Phase 3)
|
|
@@ -1441,10 +1459,10 @@ function compile(nodes) {
|
|
|
1441
1459
|
if (imported) ctx.import.push([...imported, [kind, ...node]]), node = null;
|
|
1442
1460
|
items.push(node);
|
|
1443
1461
|
});
|
|
1444
|
-
const bin = (kind,
|
|
1462
|
+
const bin = (kind, count2 = true) => {
|
|
1445
1463
|
const items = ctx[kind].filter(Boolean).map((item) => build[kind](item, ctx)).filter(Boolean);
|
|
1446
1464
|
if (kind === SECTION.custom) return items.flatMap((content) => [kind, ...vec(content)]);
|
|
1447
|
-
return !items.length ? [] : [kind, ...vec(
|
|
1465
|
+
return !items.length ? [] : [kind, ...vec(count2 ? vec(items) : items.flat())];
|
|
1448
1466
|
};
|
|
1449
1467
|
const binMeta = () => {
|
|
1450
1468
|
const sections = [];
|
|
@@ -1522,7 +1540,7 @@ function normalize(nodes, ctx) {
|
|
|
1522
1540
|
ctx.datacount && (ctx.datacount[0] = true);
|
|
1523
1541
|
} else if ((node.startsWith("memory.") || node.endsWith("load") || node.endsWith("store")) && isIdx(nodes[0])) out.push(nodes.shift());
|
|
1524
1542
|
} else if (Array.isArray(node)) {
|
|
1525
|
-
|
|
1543
|
+
let op = node[0];
|
|
1526
1544
|
node.loc != null && (err.loc = node.loc);
|
|
1527
1545
|
if (op?.startsWith?.("@metadata.code.")) {
|
|
1528
1546
|
let type = op.slice(15);
|
|
@@ -1556,6 +1574,12 @@ function normalize(nodes, ctx) {
|
|
|
1556
1574
|
out.push(parts.shift());
|
|
1557
1575
|
}
|
|
1558
1576
|
out.push(...normalize(parts, ctx), "end");
|
|
1577
|
+
} else if (op === "ref.test" || op === "ref.cast") {
|
|
1578
|
+
const type = parts[0];
|
|
1579
|
+
const isNullable = !Array.isArray(type) || type[1] === "null" || type[0] !== "ref";
|
|
1580
|
+
if (isNullable) op += "_null";
|
|
1581
|
+
out.push(...normalize(parts.slice(1), ctx), op, type);
|
|
1582
|
+
nodes.unshift(...out.splice(out.length - 2));
|
|
1559
1583
|
} else {
|
|
1560
1584
|
const imm = [];
|
|
1561
1585
|
while (parts.length && (!Array.isArray(parts[0]) || parts[0].valueOf !== Array.prototype.valueOf || "type,param,result,ref,exact,on".includes(parts[0][0]))) imm.push(parts.shift());
|
|
@@ -1845,16 +1869,16 @@ var IMM = {
|
|
|
1845
1869
|
isId(n[0]) && (c.block[n.shift()] = c.block.length + 1);
|
|
1846
1870
|
let blocktype2 = n.shift();
|
|
1847
1871
|
let result = !blocktype2 ? [TYPE.void] : blocktype2[0] === "result" ? reftype(blocktype2[1], c) : uleb(id(blocktype2[1], c.type));
|
|
1848
|
-
let catches = [],
|
|
1872
|
+
let catches = [], count2 = 0;
|
|
1849
1873
|
while (n[0]?.[0] === "catch" || n[0]?.[0] === "catch_ref" || n[0]?.[0] === "catch_all" || n[0]?.[0] === "catch_all_ref") {
|
|
1850
1874
|
let clause = n.shift();
|
|
1851
1875
|
let kind = clause[0] === "catch" ? 0 : clause[0] === "catch_ref" ? 1 : clause[0] === "catch_all" ? 2 : 3;
|
|
1852
1876
|
if (kind <= 1) catches.push(kind, ...uleb(id(clause[1], c.tag)), ...uleb(blockid(clause[2], c.block)));
|
|
1853
1877
|
else catches.push(kind, ...uleb(blockid(clause[1], c.block)));
|
|
1854
|
-
|
|
1878
|
+
count2++;
|
|
1855
1879
|
}
|
|
1856
1880
|
c.block.push(1);
|
|
1857
|
-
return [...result, ...uleb(
|
|
1881
|
+
return [...result, ...uleb(count2), ...catches];
|
|
1858
1882
|
},
|
|
1859
1883
|
end: (_n, c) => (c.block.pop(), []),
|
|
1860
1884
|
call_indirect: (n, c) => {
|
|
@@ -1862,9 +1886,9 @@ var IMM = {
|
|
|
1862
1886
|
return [...uleb(id(idx, c.type)), ...uleb(id(t, c.table))];
|
|
1863
1887
|
},
|
|
1864
1888
|
br_table: (n, c) => {
|
|
1865
|
-
let labels = [],
|
|
1866
|
-
while (n[0] && (!isNaN(n[0]) || isId(n[0]))) labels.push(...uleb(blockid(n.shift(), c.block))),
|
|
1867
|
-
return [...uleb(
|
|
1889
|
+
let labels = [], count2 = 0;
|
|
1890
|
+
while (n[0] && (!isNaN(n[0]) || isId(n[0]))) labels.push(...uleb(blockid(n.shift(), c.block))), count2++;
|
|
1891
|
+
return [...uleb(count2 - 1), ...labels];
|
|
1868
1892
|
},
|
|
1869
1893
|
select: (n, c) => {
|
|
1870
1894
|
let r = n.shift() || [];
|
|
@@ -2006,7 +2030,7 @@ var instr = (nodes, ctx) => {
|
|
|
2006
2030
|
let [...bytes] = INSTR[op] || err(`Unknown instruction ${op}`);
|
|
2007
2031
|
if (HANDLER[op]) {
|
|
2008
2032
|
if (op === "select" && nodes[0]?.length) bytes[0]++;
|
|
2009
|
-
else if (HANDLER[op] === IMM.reftype && (nodes[0][1] === "null" || nodes[0][0] !== "ref")) {
|
|
2033
|
+
else if (HANDLER[op] === IMM.reftype && !op.endsWith("_null") && (nodes[0][1] === "null" || nodes[0][0] !== "ref")) {
|
|
2010
2034
|
bytes[bytes.length - 1]++;
|
|
2011
2035
|
}
|
|
2012
2036
|
bytes.push(...HANDLER[op](nodes, ctx, op));
|
|
@@ -3040,10 +3064,10 @@ var OPTS = {
|
|
|
3040
3064
|
// strength reduction (x * 2 → x << 1)
|
|
3041
3065
|
branch: true,
|
|
3042
3066
|
// simplify constant branches
|
|
3043
|
-
propagate:
|
|
3044
|
-
// constant propagation
|
|
3045
|
-
inline:
|
|
3046
|
-
// inline tiny functions
|
|
3067
|
+
propagate: false,
|
|
3068
|
+
// constant propagation — can duplicate expressions
|
|
3069
|
+
inline: false,
|
|
3070
|
+
// inline tiny functions — can duplicate bodies
|
|
3047
3071
|
vacuum: true,
|
|
3048
3072
|
// remove nops, drop-of-pure, empty branches
|
|
3049
3073
|
peephole: true,
|
|
@@ -3058,14 +3082,12 @@ var OPTS = {
|
|
|
3058
3082
|
// strip mut from never-written globals
|
|
3059
3083
|
brif: true,
|
|
3060
3084
|
// if-then-br → br_if
|
|
3061
|
-
foldarms:
|
|
3062
|
-
// merge identical trailing if arms
|
|
3063
|
-
// minify: true, // NOTE: disabled — renaming $ids has no binary-size effect
|
|
3064
|
-
// without a names section, and risks local-name collisions.
|
|
3085
|
+
foldarms: false,
|
|
3086
|
+
// merge identical trailing if arms — can add block wrapper
|
|
3065
3087
|
dedupe: true,
|
|
3066
3088
|
// eliminate duplicate functions
|
|
3067
|
-
reorder:
|
|
3068
|
-
// put hot functions first
|
|
3089
|
+
reorder: false,
|
|
3090
|
+
// put hot functions first — no AST reduction
|
|
3069
3091
|
dedupTypes: true,
|
|
3070
3092
|
// merge identical type definitions
|
|
3071
3093
|
packData: true,
|
|
@@ -3074,6 +3096,12 @@ var OPTS = {
|
|
|
3074
3096
|
// shorten import names — enable only when you control the host
|
|
3075
3097
|
};
|
|
3076
3098
|
var ALL2 = Object.keys(OPTS);
|
|
3099
|
+
var count = (node) => {
|
|
3100
|
+
if (!Array.isArray(node)) return 1;
|
|
3101
|
+
let n = 1;
|
|
3102
|
+
for (let i = 0; i < node.length; i++) n += count(node[i]);
|
|
3103
|
+
return n;
|
|
3104
|
+
};
|
|
3077
3105
|
var equal = (a, b) => {
|
|
3078
3106
|
if (a === b) return true;
|
|
3079
3107
|
if (typeof a !== typeof b) return false;
|
|
@@ -3088,10 +3116,8 @@ var normalize3 = (opts) => {
|
|
|
3088
3116
|
if (opts === false) return {};
|
|
3089
3117
|
if (typeof opts === "string") {
|
|
3090
3118
|
const set = new Set(opts.split(/\s+/).filter(Boolean));
|
|
3091
|
-
if (set.
|
|
3092
|
-
|
|
3093
|
-
}
|
|
3094
|
-
return Object.fromEntries(ALL2.map((f) => [f, set.has(f) || set.has("all")]));
|
|
3119
|
+
if (set.has("all")) return Object.fromEntries(ALL2.map((f) => [f, true]));
|
|
3120
|
+
return Object.fromEntries(ALL2.map((f) => [f, set.has(f)]));
|
|
3095
3121
|
}
|
|
3096
3122
|
return { ...OPTS, ...opts };
|
|
3097
3123
|
};
|
|
@@ -3401,7 +3427,7 @@ var makeConst = (type, value) => {
|
|
|
3401
3427
|
return null;
|
|
3402
3428
|
};
|
|
3403
3429
|
var fold = (ast) => {
|
|
3404
|
-
return walkPost2(
|
|
3430
|
+
return walkPost2(ast, (node) => {
|
|
3405
3431
|
if (!Array.isArray(node)) return;
|
|
3406
3432
|
const entry = FOLDABLE[node[0]];
|
|
3407
3433
|
if (!entry) return;
|
|
@@ -3464,7 +3490,7 @@ var IDENTITIES = {
|
|
|
3464
3490
|
// f * 1 → x (careful with NaN, skip for floats)
|
|
3465
3491
|
};
|
|
3466
3492
|
var identity = (ast) => {
|
|
3467
|
-
return walkPost2(
|
|
3493
|
+
return walkPost2(ast, (node) => {
|
|
3468
3494
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
3469
3495
|
const fn = IDENTITIES[node[0]];
|
|
3470
3496
|
if (!fn) return;
|
|
@@ -3474,7 +3500,7 @@ var identity = (ast) => {
|
|
|
3474
3500
|
});
|
|
3475
3501
|
};
|
|
3476
3502
|
var strength = (ast) => {
|
|
3477
|
-
return walkPost2(
|
|
3503
|
+
return walkPost2(ast, (node) => {
|
|
3478
3504
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
3479
3505
|
const [op, a, b] = node;
|
|
3480
3506
|
if (op === "i32.mul") {
|
|
@@ -3530,7 +3556,7 @@ var strength = (ast) => {
|
|
|
3530
3556
|
});
|
|
3531
3557
|
};
|
|
3532
3558
|
var branch = (ast) => {
|
|
3533
|
-
return walkPost2(
|
|
3559
|
+
return walkPost2(ast, (node) => {
|
|
3534
3560
|
if (!Array.isArray(node)) return;
|
|
3535
3561
|
const op = node[0];
|
|
3536
3562
|
if (op === "if") {
|
|
@@ -3562,8 +3588,7 @@ var branch = (ast) => {
|
|
|
3562
3588
|
};
|
|
3563
3589
|
var TERMINATORS = /* @__PURE__ */ new Set(["unreachable", "return", "br", "br_table"]);
|
|
3564
3590
|
var deadcode = (ast) => {
|
|
3565
|
-
|
|
3566
|
-
walk2(result, (node) => {
|
|
3591
|
+
walk2(ast, (node) => {
|
|
3567
3592
|
if (!Array.isArray(node)) return;
|
|
3568
3593
|
const kind = node[0];
|
|
3569
3594
|
if (kind === "func" || kind === "block" || kind === "loop") {
|
|
@@ -3577,7 +3602,7 @@ var deadcode = (ast) => {
|
|
|
3577
3602
|
}
|
|
3578
3603
|
}
|
|
3579
3604
|
});
|
|
3580
|
-
return
|
|
3605
|
+
return ast;
|
|
3581
3606
|
};
|
|
3582
3607
|
var eliminateDeadInBlock = (block) => {
|
|
3583
3608
|
let terminated = false;
|
|
@@ -3609,8 +3634,7 @@ var eliminateDeadInBlock = (block) => {
|
|
|
3609
3634
|
}
|
|
3610
3635
|
};
|
|
3611
3636
|
var localReuse = (ast) => {
|
|
3612
|
-
|
|
3613
|
-
walk2(result, (node) => {
|
|
3637
|
+
walk2(ast, (node) => {
|
|
3614
3638
|
if (!Array.isArray(node) || node[0] !== "func") return;
|
|
3615
3639
|
const localDecls = [];
|
|
3616
3640
|
const localTypes = /* @__PURE__ */ new Map();
|
|
@@ -3647,7 +3671,7 @@ var localReuse = (ast) => {
|
|
|
3647
3671
|
}
|
|
3648
3672
|
}
|
|
3649
3673
|
});
|
|
3650
|
-
return
|
|
3674
|
+
return ast;
|
|
3651
3675
|
};
|
|
3652
3676
|
var IMPURE_OPS = /* @__PURE__ */ new Set([
|
|
3653
3677
|
"call",
|
|
@@ -3727,7 +3751,7 @@ var forwardPropagate = (funcNode, params, useCounts) => {
|
|
|
3727
3751
|
if (!Array.isArray(instr2)) continue;
|
|
3728
3752
|
const op = instr2[0];
|
|
3729
3753
|
if (op === "param" || op === "result" || op === "local" || op === "type" || op === "export") continue;
|
|
3730
|
-
if (op === "local.set" && instr2.length === 3 && typeof instr2[1] === "string") {
|
|
3754
|
+
if ((op === "local.set" || op === "local.tee") && instr2.length === 3 && typeof instr2[1] === "string") {
|
|
3731
3755
|
substGets(instr2[2], known);
|
|
3732
3756
|
const uses = getUseCount(instr2[1]);
|
|
3733
3757
|
known.set(instr2[1], {
|
|
@@ -3755,6 +3779,10 @@ var forwardPropagate = (funcNode, params, useCounts) => {
|
|
|
3755
3779
|
const prev = clone2(instr2);
|
|
3756
3780
|
substGets(instr2, known);
|
|
3757
3781
|
if (!equal(prev, instr2)) changed = true;
|
|
3782
|
+
walk2(instr2, (n) => {
|
|
3783
|
+
if (Array.isArray(n) && (n[0] === "local.set" || n[0] === "local.tee") && typeof n[1] === "string")
|
|
3784
|
+
known.delete(n[1]);
|
|
3785
|
+
});
|
|
3758
3786
|
}
|
|
3759
3787
|
}
|
|
3760
3788
|
return changed;
|
|
@@ -3813,8 +3841,7 @@ var eliminateDeadStores = (funcNode, params, useCounts) => {
|
|
|
3813
3841
|
return changed;
|
|
3814
3842
|
};
|
|
3815
3843
|
var propagate = (ast) => {
|
|
3816
|
-
|
|
3817
|
-
walk2(result, (funcNode) => {
|
|
3844
|
+
walk2(ast, (funcNode) => {
|
|
3818
3845
|
if (!Array.isArray(funcNode) || funcNode[0] !== "func") return;
|
|
3819
3846
|
const params = /* @__PURE__ */ new Set();
|
|
3820
3847
|
for (const sub of funcNode)
|
|
@@ -3828,13 +3855,12 @@ var propagate = (ast) => {
|
|
|
3828
3855
|
if (!changed) break;
|
|
3829
3856
|
}
|
|
3830
3857
|
});
|
|
3831
|
-
return
|
|
3858
|
+
return ast;
|
|
3832
3859
|
};
|
|
3833
3860
|
var inline = (ast) => {
|
|
3834
3861
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
3835
|
-
const result = clone2(ast);
|
|
3836
3862
|
const inlinable = /* @__PURE__ */ new Map();
|
|
3837
|
-
for (const node of
|
|
3863
|
+
for (const node of ast.slice(1)) {
|
|
3838
3864
|
if (!Array.isArray(node) || node[0] !== "func") continue;
|
|
3839
3865
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
3840
3866
|
if (!name2) continue;
|
|
@@ -3863,19 +3889,23 @@ var inline = (ast) => {
|
|
|
3863
3889
|
if (params && !hasLocals && !hasExport && params.length <= 4 && body.length === 1) {
|
|
3864
3890
|
const paramNames = new Set(params.map((p) => p.name));
|
|
3865
3891
|
let mutatesParam = false;
|
|
3892
|
+
let hasReturn = false;
|
|
3866
3893
|
walk2(body[0], (n) => {
|
|
3867
3894
|
if (!Array.isArray(n)) return;
|
|
3868
3895
|
if ((n[0] === "local.set" || n[0] === "local.tee") && paramNames.has(n[1])) {
|
|
3869
3896
|
mutatesParam = true;
|
|
3870
3897
|
}
|
|
3898
|
+
if (n[0] === "return" || n[0] === "return_call" || n[0] === "return_call_indirect") {
|
|
3899
|
+
hasReturn = true;
|
|
3900
|
+
}
|
|
3871
3901
|
});
|
|
3872
|
-
if (!mutatesParam) {
|
|
3902
|
+
if (!mutatesParam && !hasReturn) {
|
|
3873
3903
|
inlinable.set(name2, { body: body[0], params });
|
|
3874
3904
|
}
|
|
3875
3905
|
}
|
|
3876
3906
|
}
|
|
3877
|
-
if (inlinable.size === 0) return
|
|
3878
|
-
walkPost2(
|
|
3907
|
+
if (inlinable.size === 0) return ast;
|
|
3908
|
+
walkPost2(ast, (node) => {
|
|
3879
3909
|
if (!Array.isArray(node) || node[0] !== "call") return;
|
|
3880
3910
|
const fname = node[1];
|
|
3881
3911
|
if (!inlinable.has(fname)) return;
|
|
@@ -3895,10 +3925,10 @@ var inline = (ast) => {
|
|
|
3895
3925
|
});
|
|
3896
3926
|
return substituted;
|
|
3897
3927
|
});
|
|
3898
|
-
return
|
|
3928
|
+
return ast;
|
|
3899
3929
|
};
|
|
3900
3930
|
var vacuum = (ast) => {
|
|
3901
|
-
return walkPost2(
|
|
3931
|
+
return walkPost2(ast, (node) => {
|
|
3902
3932
|
if (!Array.isArray(node)) return;
|
|
3903
3933
|
const op = node[0];
|
|
3904
3934
|
if (op === "nop") return ["nop"];
|
|
@@ -3997,7 +4027,7 @@ var PEEPHOLE = {
|
|
|
3997
4027
|
"local.set": (a, b) => Array.isArray(b) && b[0] === "local.get" && b[1] === a ? ["nop"] : null
|
|
3998
4028
|
};
|
|
3999
4029
|
var peephole = (ast) => {
|
|
4000
|
-
return walkPost2(
|
|
4030
|
+
return walkPost2(ast, (node) => {
|
|
4001
4031
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
4002
4032
|
const fn = PEEPHOLE[node[0]];
|
|
4003
4033
|
if (!fn) return;
|
|
@@ -4007,10 +4037,9 @@ var peephole = (ast) => {
|
|
|
4007
4037
|
};
|
|
4008
4038
|
var globals = (ast) => {
|
|
4009
4039
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4010
|
-
const result = clone2(ast);
|
|
4011
4040
|
const constGlobals = /* @__PURE__ */ new Map();
|
|
4012
4041
|
const mutableGlobals = /* @__PURE__ */ new Set();
|
|
4013
|
-
for (const node of
|
|
4042
|
+
for (const node of ast.slice(1)) {
|
|
4014
4043
|
if (!Array.isArray(node) || node[0] !== "global") continue;
|
|
4015
4044
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4016
4045
|
if (!name2) continue;
|
|
@@ -4021,21 +4050,21 @@ var globals = (ast) => {
|
|
|
4021
4050
|
const init = node[initIdx];
|
|
4022
4051
|
if (getConst(init)) constGlobals.set(name2, init);
|
|
4023
4052
|
}
|
|
4024
|
-
walk2(
|
|
4053
|
+
walk2(ast, (n) => {
|
|
4025
4054
|
if (!Array.isArray(n) || n[0] !== "global.set") return;
|
|
4026
4055
|
const ref = n[1];
|
|
4027
4056
|
if (typeof ref === "string" && ref[0] === "$") mutableGlobals.add(ref);
|
|
4028
4057
|
});
|
|
4029
4058
|
for (const name2 of mutableGlobals) constGlobals.delete(name2);
|
|
4030
|
-
if (constGlobals.size === 0) return
|
|
4031
|
-
return walkPost2(
|
|
4059
|
+
if (constGlobals.size === 0) return ast;
|
|
4060
|
+
return walkPost2(ast, (node) => {
|
|
4032
4061
|
if (!Array.isArray(node) || node[0] !== "global.get" || node.length !== 2) return;
|
|
4033
4062
|
const ref = node[1];
|
|
4034
4063
|
if (constGlobals.has(ref)) return clone2(constGlobals.get(ref));
|
|
4035
4064
|
});
|
|
4036
4065
|
};
|
|
4037
4066
|
var offset = (ast) => {
|
|
4038
|
-
return walkPost2(
|
|
4067
|
+
return walkPost2(ast, (node) => {
|
|
4039
4068
|
if (!Array.isArray(node)) return;
|
|
4040
4069
|
const op = node[0];
|
|
4041
4070
|
if (typeof op !== "string" || !op.endsWith("load") && !op.endsWith("store")) return;
|
|
@@ -4086,8 +4115,7 @@ var offset = (ast) => {
|
|
|
4086
4115
|
});
|
|
4087
4116
|
};
|
|
4088
4117
|
var unbranch = (ast) => {
|
|
4089
|
-
|
|
4090
|
-
walk2(result, (node) => {
|
|
4118
|
+
walk2(ast, (node) => {
|
|
4091
4119
|
if (!Array.isArray(node)) return;
|
|
4092
4120
|
const op = node[0];
|
|
4093
4121
|
if (op !== "block") return;
|
|
@@ -4116,16 +4144,15 @@ var unbranch = (ast) => {
|
|
|
4116
4144
|
node.splice(lastIdx, 1);
|
|
4117
4145
|
}
|
|
4118
4146
|
});
|
|
4119
|
-
return
|
|
4147
|
+
return ast;
|
|
4120
4148
|
};
|
|
4121
4149
|
var stripmut = (ast) => {
|
|
4122
4150
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4123
|
-
const result = clone2(ast);
|
|
4124
4151
|
const written = /* @__PURE__ */ new Set();
|
|
4125
|
-
walk2(
|
|
4152
|
+
walk2(ast, (n) => {
|
|
4126
4153
|
if (Array.isArray(n) && n[0] === "global.set" && typeof n[1] === "string") written.add(n[1]);
|
|
4127
4154
|
});
|
|
4128
|
-
return walkPost2(
|
|
4155
|
+
return walkPost2(ast, (node) => {
|
|
4129
4156
|
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
4130
4157
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4131
4158
|
if (!name2 || written.has(name2)) return;
|
|
@@ -4139,7 +4166,7 @@ var stripmut = (ast) => {
|
|
|
4139
4166
|
});
|
|
4140
4167
|
};
|
|
4141
4168
|
var brif = (ast) => {
|
|
4142
|
-
return walkPost2(
|
|
4169
|
+
return walkPost2(ast, (node) => {
|
|
4143
4170
|
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
4144
4171
|
const { cond, thenBranch, elseBranch } = parseIf(node);
|
|
4145
4172
|
const thenEmpty = !thenBranch || thenBranch.length <= 1;
|
|
@@ -4155,7 +4182,7 @@ var brif = (ast) => {
|
|
|
4155
4182
|
});
|
|
4156
4183
|
};
|
|
4157
4184
|
var foldarms = (ast) => {
|
|
4158
|
-
return walkPost2(
|
|
4185
|
+
return walkPost2(ast, (node) => {
|
|
4159
4186
|
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
4160
4187
|
const { thenBranch, elseBranch } = parseIf(node);
|
|
4161
4188
|
if (!thenBranch || !elseBranch) return;
|
|
@@ -4220,10 +4247,9 @@ var hashFunc = (node, localNames) => {
|
|
|
4220
4247
|
};
|
|
4221
4248
|
var dedupe = (ast) => {
|
|
4222
4249
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4223
|
-
const result = clone2(ast);
|
|
4224
4250
|
const signatures = /* @__PURE__ */ new Map();
|
|
4225
4251
|
const redirects = /* @__PURE__ */ new Map();
|
|
4226
|
-
for (const node of
|
|
4252
|
+
for (const node of ast.slice(1)) {
|
|
4227
4253
|
if (!Array.isArray(node) || node[0] !== "func") continue;
|
|
4228
4254
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4229
4255
|
if (!name2) continue;
|
|
@@ -4243,8 +4269,8 @@ var dedupe = (ast) => {
|
|
|
4243
4269
|
signatures.set(hash, name2);
|
|
4244
4270
|
}
|
|
4245
4271
|
}
|
|
4246
|
-
if (redirects.size === 0) return
|
|
4247
|
-
walkPost2(
|
|
4272
|
+
if (redirects.size === 0) return ast;
|
|
4273
|
+
walkPost2(ast, (node) => {
|
|
4248
4274
|
if (!Array.isArray(node)) return;
|
|
4249
4275
|
const op = node[0];
|
|
4250
4276
|
if ((op === "call" || op === "return_call") && redirects.has(node[1])) {
|
|
@@ -4266,14 +4292,13 @@ var dedupe = (ast) => {
|
|
|
4266
4292
|
}
|
|
4267
4293
|
}
|
|
4268
4294
|
});
|
|
4269
|
-
return
|
|
4295
|
+
return ast;
|
|
4270
4296
|
};
|
|
4271
4297
|
var dedupTypes = (ast) => {
|
|
4272
4298
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4273
|
-
const result = clone2(ast);
|
|
4274
4299
|
const signatures = /* @__PURE__ */ new Map();
|
|
4275
4300
|
const redirects = /* @__PURE__ */ new Map();
|
|
4276
|
-
for (const node of
|
|
4301
|
+
for (const node of ast.slice(1)) {
|
|
4277
4302
|
if (!Array.isArray(node) || node[0] !== "type") continue;
|
|
4278
4303
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4279
4304
|
if (!name2) continue;
|
|
@@ -4284,15 +4309,15 @@ var dedupTypes = (ast) => {
|
|
|
4284
4309
|
signatures.set(hash, name2);
|
|
4285
4310
|
}
|
|
4286
4311
|
}
|
|
4287
|
-
if (redirects.size === 0) return
|
|
4288
|
-
for (let i =
|
|
4289
|
-
const node =
|
|
4312
|
+
if (redirects.size === 0) return ast;
|
|
4313
|
+
for (let i = ast.length - 1; i >= 0; i--) {
|
|
4314
|
+
const node = ast[i];
|
|
4290
4315
|
if (Array.isArray(node) && node[0] === "type") {
|
|
4291
4316
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4292
|
-
if (name2 && redirects.has(name2))
|
|
4317
|
+
if (name2 && redirects.has(name2)) ast.splice(i, 1);
|
|
4293
4318
|
}
|
|
4294
4319
|
}
|
|
4295
|
-
walkPost2(
|
|
4320
|
+
walkPost2(ast, (node) => {
|
|
4296
4321
|
if (!Array.isArray(node)) return;
|
|
4297
4322
|
const op = node[0];
|
|
4298
4323
|
if (op === "func") {
|
|
@@ -4325,7 +4350,7 @@ var dedupTypes = (ast) => {
|
|
|
4325
4350
|
}
|
|
4326
4351
|
}
|
|
4327
4352
|
});
|
|
4328
|
-
return
|
|
4353
|
+
return ast;
|
|
4329
4354
|
};
|
|
4330
4355
|
var parseDataString = (str2) => {
|
|
4331
4356
|
if (typeof str2 !== "string" || str2.length < 2 || str2[0] !== '"') return new Uint8Array();
|
|
@@ -4440,8 +4465,7 @@ var mergeDataSegments = (a, b) => {
|
|
|
4440
4465
|
};
|
|
4441
4466
|
var packData = (ast) => {
|
|
4442
4467
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4443
|
-
|
|
4444
|
-
for (const node of result) {
|
|
4468
|
+
for (const node of ast) {
|
|
4445
4469
|
if (!Array.isArray(node) || node[0] !== "data") continue;
|
|
4446
4470
|
let contentStart = 1;
|
|
4447
4471
|
if (typeof node[1] === "string" && node[1][0] === "$") contentStart = 2;
|
|
@@ -4457,8 +4481,8 @@ var packData = (ast) => {
|
|
|
4457
4481
|
}
|
|
4458
4482
|
}
|
|
4459
4483
|
const dataNodes = [];
|
|
4460
|
-
for (let i = 0; i <
|
|
4461
|
-
const node =
|
|
4484
|
+
for (let i = 0; i < ast.length; i++) {
|
|
4485
|
+
const node = ast[i];
|
|
4462
4486
|
if (Array.isArray(node) && node[0] === "data") {
|
|
4463
4487
|
const info = getDataOffset(node);
|
|
4464
4488
|
if (info) {
|
|
@@ -4484,9 +4508,9 @@ var packData = (ast) => {
|
|
|
4484
4508
|
}
|
|
4485
4509
|
}
|
|
4486
4510
|
if (toRemove.size > 0) {
|
|
4487
|
-
|
|
4511
|
+
ast = ast.filter((_, i) => !toRemove.has(i));
|
|
4488
4512
|
}
|
|
4489
|
-
return
|
|
4513
|
+
return ast;
|
|
4490
4514
|
};
|
|
4491
4515
|
var makeShortener = () => {
|
|
4492
4516
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -4505,10 +4529,9 @@ var makeShortener = () => {
|
|
|
4505
4529
|
};
|
|
4506
4530
|
var minifyImports = (ast) => {
|
|
4507
4531
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4508
|
-
const result = clone2(ast);
|
|
4509
4532
|
const shortMod = makeShortener();
|
|
4510
4533
|
const shortField = makeShortener();
|
|
4511
|
-
for (const node of
|
|
4534
|
+
for (const node of ast) {
|
|
4512
4535
|
if (!Array.isArray(node) || node[0] !== "import") continue;
|
|
4513
4536
|
if (typeof node[1] === "string" && node[1][0] === '"') {
|
|
4514
4537
|
node[1] = '"' + shortMod(node[1].slice(1, -1)) + '"';
|
|
@@ -4517,7 +4540,7 @@ var minifyImports = (ast) => {
|
|
|
4517
4540
|
node[2] = '"' + shortField(node[2].slice(1, -1)) + '"';
|
|
4518
4541
|
}
|
|
4519
4542
|
}
|
|
4520
|
-
return
|
|
4543
|
+
return ast;
|
|
4521
4544
|
};
|
|
4522
4545
|
var reorderSafe = (ast) => {
|
|
4523
4546
|
let safe = true;
|
|
@@ -4545,16 +4568,15 @@ var reorderSafe = (ast) => {
|
|
|
4545
4568
|
var reorder = (ast) => {
|
|
4546
4569
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4547
4570
|
if (!reorderSafe(ast)) return ast;
|
|
4548
|
-
const result = clone2(ast);
|
|
4549
4571
|
const callCounts = /* @__PURE__ */ new Map();
|
|
4550
|
-
walk2(
|
|
4572
|
+
walk2(ast, (n) => {
|
|
4551
4573
|
if (!Array.isArray(n)) return;
|
|
4552
4574
|
if (n[0] === "call" || n[0] === "return_call") {
|
|
4553
4575
|
callCounts.set(n[1], (callCounts.get(n[1]) || 0) + 1);
|
|
4554
4576
|
}
|
|
4555
4577
|
});
|
|
4556
4578
|
const imports = [], funcs = [], others = [];
|
|
4557
|
-
for (const node of
|
|
4579
|
+
for (const node of ast.slice(1)) {
|
|
4558
4580
|
if (!Array.isArray(node)) {
|
|
4559
4581
|
others.push(node);
|
|
4560
4582
|
continue;
|
|
@@ -4568,10 +4590,16 @@ var reorder = (ast) => {
|
|
|
4568
4590
|
};
|
|
4569
4591
|
function optimize(ast, opts = true) {
|
|
4570
4592
|
if (typeof ast === "string") ast = parse_default(ast);
|
|
4571
|
-
|
|
4593
|
+
const strictGuard = opts === true;
|
|
4572
4594
|
opts = normalize3(opts);
|
|
4573
|
-
|
|
4574
|
-
|
|
4595
|
+
const log = opts.log ? (msg, delta) => opts.log(msg, delta) : () => {
|
|
4596
|
+
};
|
|
4597
|
+
const verbose = opts.verbose || opts.log;
|
|
4598
|
+
ast = clone2(ast);
|
|
4599
|
+
let beforeRound = null;
|
|
4600
|
+
for (let round = 0; round < 3; round++) {
|
|
4601
|
+
beforeRound = clone2(ast);
|
|
4602
|
+
const sizeBefore = count(ast);
|
|
4575
4603
|
if (opts.stripmut) ast = stripmut(ast);
|
|
4576
4604
|
if (opts.globals) ast = globals(ast);
|
|
4577
4605
|
if (opts.fold) ast = fold(ast);
|
|
@@ -4594,7 +4622,18 @@ function optimize(ast, opts = true) {
|
|
|
4594
4622
|
if (opts.reorder) ast = reorder(ast);
|
|
4595
4623
|
if (opts.treeshake) ast = treeshake(ast);
|
|
4596
4624
|
if (opts.minifyImports) ast = minifyImports(ast);
|
|
4597
|
-
|
|
4625
|
+
const sizeAfter = count(ast);
|
|
4626
|
+
const delta = sizeAfter - sizeBefore;
|
|
4627
|
+
if (verbose || delta !== 0) {
|
|
4628
|
+
log(` round ${round + 1}: ${delta > 0 ? "+" : ""}${delta} nodes`, delta);
|
|
4629
|
+
}
|
|
4630
|
+
const tolerance = strictGuard ? 0 : 5;
|
|
4631
|
+
if (delta > tolerance) {
|
|
4632
|
+
if (verbose) log(` \u26A0 round ${round + 1} inflated by ${delta}, reverting`, delta);
|
|
4633
|
+
ast = beforeRound;
|
|
4634
|
+
break;
|
|
4635
|
+
}
|
|
4636
|
+
if (equal(beforeRound, ast)) break;
|
|
4598
4637
|
}
|
|
4599
4638
|
return ast;
|
|
4600
4639
|
}
|