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 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(Math.round(a)),
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": (a) => Math.round(a)
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, (node) => {
3524
- if (!Array.isArray(node) || node[0] !== "func") return;
3525
- const constLocals = /* @__PURE__ */ new Map();
3526
- const processBlock = (block, startIdx = 1) => {
3527
- for (let i = startIdx; i < block.length; i++) {
3528
- const instr2 = block[i];
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.set" && instr2.length === 3) {
3532
- const local = instr2[1];
3533
- const val = instr2[2];
3534
- const c = getConst(val);
3535
- if (c && typeof local === "string") {
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);
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(...clone2(constVal));
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
- 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
- });
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
- processBlock(node);
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 && !(values[values.length - 1] instanceof Uint8Array)) {
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 instanceof Uint8Array) return [...value];
3792
+ if (value.byteLength !== void 0) return [...value];
3746
3793
  return value;
3747
3794
  }
3748
3795
  return node;