watr 4.3.3 → 4.3.4
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 +92 -45
- package/dist/watr.min.js +6 -6
- package/dist/watr.wat +128517 -0
- package/package.json +1 -1
- package/src/optimize.js +108 -60
- package/types/src/optimize.d.ts +4 -5
- package/types/src/optimize.d.ts.map +1 -1
- package/watr.js +2 -2
package/dist/watr.js
CHANGED
|
@@ -3084,6 +3084,7 @@ var treeshake = (ast) => {
|
|
|
3084
3084
|
}
|
|
3085
3085
|
return result;
|
|
3086
3086
|
};
|
|
3087
|
+
var roundEven = (x) => x - Math.floor(x) !== 0.5 ? Math.round(x) : 2 * Math.round(x / 2);
|
|
3087
3088
|
var FOLDABLE = {
|
|
3088
3089
|
// i32
|
|
3089
3090
|
"i32.add": (a, b) => a + b | 0,
|
|
@@ -3167,7 +3168,7 @@ var FOLDABLE = {
|
|
|
3167
3168
|
"f32.ceil": (a) => Math.fround(Math.ceil(a)),
|
|
3168
3169
|
"f32.floor": (a) => Math.fround(Math.floor(a)),
|
|
3169
3170
|
"f32.trunc": (a) => Math.fround(Math.trunc(a)),
|
|
3170
|
-
"f32.nearest": (a) => Math.fround(
|
|
3171
|
+
"f32.nearest": (a) => Math.fround(roundEven(a)),
|
|
3171
3172
|
"f64.add": (a, b) => a + b,
|
|
3172
3173
|
"f64.sub": (a, b) => a - b,
|
|
3173
3174
|
"f64.mul": (a, b) => a * b,
|
|
@@ -3178,7 +3179,7 @@ var FOLDABLE = {
|
|
|
3178
3179
|
"f64.ceil": (a) => Math.ceil(a),
|
|
3179
3180
|
"f64.floor": (a) => Math.floor(a),
|
|
3180
3181
|
"f64.trunc": (a) => Math.trunc(a),
|
|
3181
|
-
"f64.nearest":
|
|
3182
|
+
"f64.nearest": roundEven
|
|
3182
3183
|
};
|
|
3183
3184
|
var getConst = (node) => {
|
|
3184
3185
|
if (!Array.isArray(node) || node.length !== 2) return null;
|
|
@@ -3518,55 +3519,101 @@ var localReuse = (ast) => {
|
|
|
3518
3519
|
});
|
|
3519
3520
|
return result;
|
|
3520
3521
|
};
|
|
3522
|
+
var isPure = (node) => {
|
|
3523
|
+
if (!Array.isArray(node)) return true;
|
|
3524
|
+
const op = node[0];
|
|
3525
|
+
if (typeof op !== "string") return false;
|
|
3526
|
+
if (op === "call" || op === "call_indirect" || op === "return_call" || op === "return_call_indirect") return false;
|
|
3527
|
+
if (op.includes(".store") || op.includes(".load") || op.includes("memory.")) return false;
|
|
3528
|
+
if (op === "global.set") return false;
|
|
3529
|
+
for (let i = 1; i < node.length; i++) if (Array.isArray(node[i]) && !isPure(node[i])) return false;
|
|
3530
|
+
return true;
|
|
3531
|
+
};
|
|
3532
|
+
var countLocalUses = (node) => {
|
|
3533
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3534
|
+
const ensure = (name2) => {
|
|
3535
|
+
if (!counts.has(name2)) counts.set(name2, { gets: 0, sets: 0, tees: 0 });
|
|
3536
|
+
return counts.get(name2);
|
|
3537
|
+
};
|
|
3538
|
+
walk2(node, (n) => {
|
|
3539
|
+
if (!Array.isArray(n) || n.length < 2 || typeof n[1] !== "string") return;
|
|
3540
|
+
if (n[0] === "local.get") ensure(n[1]).gets++;
|
|
3541
|
+
else if (n[0] === "local.set") ensure(n[1]).sets++;
|
|
3542
|
+
else if (n[0] === "local.tee") ensure(n[1]).tees++;
|
|
3543
|
+
});
|
|
3544
|
+
return counts;
|
|
3545
|
+
};
|
|
3546
|
+
var canSubst = (k) => getConst(k.val) || k.pure && k.singleUse;
|
|
3547
|
+
var substGets = (node, known) => walkPost2(node, (n) => {
|
|
3548
|
+
if (!Array.isArray(n) || n[0] !== "local.get" || n.length !== 2) return;
|
|
3549
|
+
const k = typeof n[1] === "string" && known.get(n[1]);
|
|
3550
|
+
if (k && canSubst(k)) return clone2(k.val);
|
|
3551
|
+
});
|
|
3521
3552
|
var propagate = (ast) => {
|
|
3522
3553
|
const result = clone2(ast);
|
|
3523
|
-
walk2(result, (
|
|
3524
|
-
if (!Array.isArray(
|
|
3525
|
-
const
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3554
|
+
walk2(result, (funcNode) => {
|
|
3555
|
+
if (!Array.isArray(funcNode) || funcNode[0] !== "func") return;
|
|
3556
|
+
const params = /* @__PURE__ */ new Set();
|
|
3557
|
+
for (const sub of funcNode)
|
|
3558
|
+
if (Array.isArray(sub) && sub[0] === "param" && typeof sub[1] === "string") params.add(sub[1]);
|
|
3559
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
3560
|
+
let changed = false;
|
|
3561
|
+
const uses = countLocalUses(funcNode);
|
|
3562
|
+
const getUses = (name2) => uses.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3563
|
+
const known = /* @__PURE__ */ new Map();
|
|
3564
|
+
for (let i = 1; i < funcNode.length; i++) {
|
|
3565
|
+
const instr2 = funcNode[i];
|
|
3529
3566
|
if (!Array.isArray(instr2)) continue;
|
|
3530
3567
|
const op = instr2[0];
|
|
3531
|
-
if (op === "local
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
const
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
const local = instr2[1];
|
|
3551
|
-
if (typeof local === "string" && constLocals.has(local)) {
|
|
3552
|
-
const constVal = constLocals.get(local);
|
|
3568
|
+
if (op === "param" || op === "result" || op === "local" || op === "type" || op === "export") continue;
|
|
3569
|
+
if (op === "local.set" && instr2.length === 3 && typeof instr2[1] === "string") {
|
|
3570
|
+
substGets(instr2[2], known);
|
|
3571
|
+
const u = getUses(instr2[1]);
|
|
3572
|
+
known.set(instr2[1], {
|
|
3573
|
+
val: instr2[2],
|
|
3574
|
+
pure: isPure(instr2[2]),
|
|
3575
|
+
singleUse: u.gets <= 1 && u.sets <= 1 && u.tees === 0
|
|
3576
|
+
});
|
|
3577
|
+
continue;
|
|
3578
|
+
}
|
|
3579
|
+
if (op === "block" || op === "loop" || op === "if") known.clear();
|
|
3580
|
+
if (op === "call" || op === "call_indirect" || op === "return_call" || op === "return_call_indirect") {
|
|
3581
|
+
for (const [k, v] of known) if (!getConst(v.val)) known.delete(k);
|
|
3582
|
+
}
|
|
3583
|
+
if (op === "local.get" && instr2.length === 2 && typeof instr2[1] === "string") {
|
|
3584
|
+
const k = known.get(instr2[1]);
|
|
3585
|
+
if (k && canSubst(k)) {
|
|
3586
|
+
const r = clone2(k.val);
|
|
3553
3587
|
instr2.length = 0;
|
|
3554
|
-
instr2.push(...
|
|
3588
|
+
instr2.push(...Array.isArray(r) ? r : [r]);
|
|
3589
|
+
changed = true;
|
|
3590
|
+
continue;
|
|
3555
3591
|
}
|
|
3556
|
-
} else if (op === "block" || op === "loop" || op === "if" || op === "call" || op === "call_indirect") {
|
|
3557
|
-
constLocals.clear();
|
|
3558
3592
|
}
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
if (
|
|
3563
|
-
|
|
3564
|
-
return clone2(constVal);
|
|
3565
|
-
}
|
|
3566
|
-
});
|
|
3593
|
+
if (op !== "block" && op !== "loop" && op !== "if") {
|
|
3594
|
+
const prev = JSON.stringify(instr2);
|
|
3595
|
+
substGets(instr2, known);
|
|
3596
|
+
if (JSON.stringify(instr2) !== prev) changed = true;
|
|
3597
|
+
}
|
|
3567
3598
|
}
|
|
3568
|
-
|
|
3569
|
-
|
|
3599
|
+
const postUses = countLocalUses(funcNode);
|
|
3600
|
+
const pu = (name2) => postUses.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3601
|
+
for (let i = funcNode.length - 1; i >= 1; i--) {
|
|
3602
|
+
const sub = funcNode[i];
|
|
3603
|
+
if (!Array.isArray(sub)) continue;
|
|
3604
|
+
const name2 = typeof sub[1] === "string" ? sub[1] : null;
|
|
3605
|
+
if (!name2 || params.has(name2)) continue;
|
|
3606
|
+
const u = pu(name2);
|
|
3607
|
+
if (sub[0] === "local.set" && u.gets === 0 && u.tees === 0 && isPure(sub[2])) {
|
|
3608
|
+
funcNode.splice(i, 1);
|
|
3609
|
+
changed = true;
|
|
3610
|
+
} else if (sub[0] === "local" && name2[0] === "$" && u.gets === 0 && u.sets === 0 && u.tees === 0) {
|
|
3611
|
+
funcNode.splice(i, 1);
|
|
3612
|
+
changed = true;
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
if (!changed) break;
|
|
3616
|
+
}
|
|
3570
3617
|
});
|
|
3571
3618
|
return result;
|
|
3572
3619
|
};
|
|
@@ -3717,7 +3764,7 @@ function genImports(imports) {
|
|
|
3717
3764
|
}
|
|
3718
3765
|
function compile2(source, ...values) {
|
|
3719
3766
|
let opts = {};
|
|
3720
|
-
if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === "object" && values[values.length - 1] !== null && !
|
|
3767
|
+
if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === "object" && values[values.length - 1] !== null && !values[values.length - 1].byteLength) {
|
|
3721
3768
|
opts = values.pop();
|
|
3722
3769
|
}
|
|
3723
3770
|
if (Array.isArray(source) && source.raw) {
|
|
@@ -3742,7 +3789,7 @@ function compile2(source, ...values) {
|
|
|
3742
3789
|
}
|
|
3743
3790
|
return parsed;
|
|
3744
3791
|
}
|
|
3745
|
-
if (value
|
|
3792
|
+
if (value.byteLength !== void 0) return [...value];
|
|
3746
3793
|
return value;
|
|
3747
3794
|
}
|
|
3748
3795
|
return node;
|