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 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, offset, rt;
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
- offset = parts.shift();
1542
- if (offset[0] === "offset") [, offset] = offset;
1543
- offset = expr(offset, ctx);
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 ? offset : (
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), ...offset, 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 ? offset : (
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), ...offset, ...rt] : (
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 offset, memidx = 0;
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
- offset = inits.shift();
1635
- if (offset[0] === "offset") [, offset] = offset;
1636
- offset ?? err("Bad offset", offset);
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(offset, ctx)] : (
1640
+ memidx ? [2, ...uleb(memidx), ...expr(offset2, ctx)] : (
1641
1641
  // active: 0, e=expr
1642
- offset ? [0, ...expr(offset, ctx)] : (
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, offset, k, v;
1858
- while (isMemParam(args[0])) [k, v] = args.shift().split("="), k === "offset" ? offset = +v : k === "align" ? align2 = +v : err(`Unknown param ${k}=${v}`);
1859
- if (offset < 0 || offset > 4294967295) err(`Bad offset ${offset}`);
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, offset];
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 globals = {};
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
- globals[id2] = { type: init[0].split(".")[0], value: init[1] };
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" && globals[node[1]]) {
2366
- const g = globals[node[1]];
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 offset = 4;
2519
+ let offset2 = 4;
2520
2520
  for (let i = 0; i < fieldIdx; i++) {
2521
- offset += TYPE_SIZES[typeDef.fields[i].type] || 4;
2521
+ offset2 += TYPE_SIZES[typeDef.fields[i].type] || 4;
2522
2522
  }
2523
- return offset;
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 offset = fieldOffset(typeDef, i);
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", offset]], args[i] || [`${f.type}.const`, 0]]);
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 offset = fieldOffset(typeDef, i);
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", offset]], zero]);
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 offset = fieldOffset(typeDef, fieldIdx);
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", offset]]];
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 offset = fieldOffset(typeDef, fieldIdx);
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", offset]], val];
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 globals = /* @__PURE__ */ new Map();
2917
- const types = /* @__PURE__ */ new Map();
2918
- const tables = /* @__PURE__ */ new Map();
2919
- const memories = /* @__PURE__ */ new Map();
2920
- const exports = [];
2921
- const starts = [];
2922
- let funcIdx = 0, globalIdx = 0, typeIdx = 0, tableIdx = 0, memIdx = 0, importFuncIdx = 0;
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
- const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : typeIdx;
2928
- types.set(name2, { node, idx: typeIdx, used: false });
2929
- if (typeof name2 === "string") types.set(typeIdx, types.get(name2));
2930
- typeIdx++;
2931
- } else if (kind === "func") {
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) && sub[0] === "func") {
2958
- const name2 = typeof sub[1] === "string" && sub[1][0] === "$" ? sub[1] : importFuncIdx;
2959
- funcs.set(name2, { node, idx: importFuncIdx, used: true, isImport: true });
2960
- if (typeof name2 === "string") funcs.set(importFuncIdx, funcs.get(name2));
2961
- importFuncIdx++;
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
- exports.push(node);
2967
- } else if (kind === "start") {
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" && funcs.has(ref)) funcs.get(ref).used = true;
2976
- else if (kind === "global" && globals.has(ref)) globals.get(ref).used = true;
2977
- else if (kind === "table" && tables.has(ref)) tables.get(ref).used = true;
2978
- else if (kind === "memory" && memories.has(ref)) memories.get(ref).used = true;
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
- if (funcs.has(ref)) funcs.get(ref).used = true;
3045
+ markFunc(ref);
2985
3046
  }
2986
- let hasExports = exports.length > 0 || starts.length > 0;
2987
- if (!hasExports) {
2988
- for (const [, entry] of funcs) if (entry.used) {
2989
- hasExports = true;
2990
- break;
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 (!hasExports) {
3012
- for (const [, entry] of funcs) entry.used = true;
3013
- for (const [, entry] of globals) entry.used = true;
3014
- for (const [, entry] of tables) entry.used = true;
3015
- for (const [, entry] of memories) entry.used = true;
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
- for (const node of ast.slice(1)) {
3018
- if (!Array.isArray(node) || node[0] !== "elem") continue;
3019
- walk2(node, (n) => {
3020
- if (Array.isArray(n) && n[0] === "ref.func") {
3021
- const ref = n[1];
3022
- if (funcs.has(ref)) funcs.get(ref).used = true;
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
- const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
3073
- const entry = name2 ? funcs.get(name2) : [...funcs.values()].find((e) => e.node === node);
3074
- if (entry?.used) result.push(node);
3075
- } else if (kind === "global") {
3076
- const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
3077
- const entry = name2 ? globals.get(name2) : [...globals.values()].find((e) => e.node === node);
3078
- if (entry?.used) result.push(node);
3079
- } else if (kind === "type") {
3080
- result.push(node);
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 ? 1 : 0,
3111
- "i32.ne": (a, b) => a !== b ? 1 : 0,
3112
- "i32.lt_s": (a, b) => a < b ? 1 : 0,
3113
- "i32.lt_u": (a, b) => a >>> 0 < b >>> 0 ? 1 : 0,
3114
- "i32.gt_s": (a, b) => a > b ? 1 : 0,
3115
- "i32.gt_u": (a, b) => a >>> 0 > b >>> 0 ? 1 : 0,
3116
- "i32.le_s": (a, b) => a <= b ? 1 : 0,
3117
- "i32.le_u": (a, b) => a >>> 0 <= b >>> 0 ? 1 : 0,
3118
- "i32.ge_s": (a, b) => a >= b ? 1 : 0,
3119
- "i32.ge_u": (a, b) => a >>> 0 >= b >>> 0 ? 1 : 0,
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 ? 1 : 0,
3147
- "i64.ne": (a, b) => a !== b ? 1 : 0,
3148
- "i64.lt_s": (a, b) => a < b ? 1 : 0,
3149
- "i64.lt_u": (a, b) => BigInt.asUintN(64, a) < BigInt.asUintN(64, b) ? 1 : 0,
3150
- "i64.gt_s": (a, b) => a > b ? 1 : 0,
3151
- "i64.gt_u": (a, b) => BigInt.asUintN(64, a) > BigInt.asUintN(64, b) ? 1 : 0,
3152
- "i64.le_s": (a, b) => a <= b ? 1 : 0,
3153
- "i64.le_u": (a, b) => BigInt.asUintN(64, a) <= BigInt.asUintN(64, b) ? 1 : 0,
3154
- "i64.ge_s": (a, b) => a >= b ? 1 : 0,
3155
- "i64.ge_u": (a, b) => BigInt.asUintN(64, a) >= BigInt.asUintN(64, b) ? 1 : 0,
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
- // f32/f64 - be careful with NaN/precision
3160
- "f32.add": (a, b) => Math.fround(a + b),
3161
- "f32.sub": (a, b) => Math.fround(a - b),
3162
- "f32.mul": (a, b) => Math.fround(a * b),
3163
- "f32.div": (a, b) => Math.fround(a / b),
3164
- "f32.neg": (a) => Math.fround(-a),
3165
- "f32.abs": (a) => Math.fround(Math.abs(a)),
3166
- "f32.sqrt": (a) => Math.fround(Math.sqrt(a)),
3167
- "f32.ceil": (a) => Math.fround(Math.ceil(a)),
3168
- "f32.floor": (a) => Math.fround(Math.floor(a)),
3169
- "f32.trunc": (a) => Math.fround(Math.trunc(a)),
3170
- "f32.nearest": (a) => Math.fround(Math.round(a)),
3171
- "f64.add": (a, b) => a + b,
3172
- "f64.sub": (a, b) => a - b,
3173
- "f64.mul": (a, b) => a * b,
3174
- "f64.div": (a, b) => a / b,
3175
- "f64.neg": (a) => -a,
3176
- "f64.abs": (a) => Math.abs(a),
3177
- "f64.sqrt": (a) => Math.sqrt(a),
3178
- "f64.ceil": (a) => Math.ceil(a),
3179
- "f64.floor": (a) => Math.floor(a),
3180
- "f64.trunc": (a) => Math.trunc(a),
3181
- "f64.nearest": (a) => Math.round(a)
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 op = node[0];
3203
- const fn = FOLDABLE[op];
3204
- if (!fn) return;
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 result = fn(a.value);
3209
- if (result === null) return;
3210
- const resultType = op.startsWith("i64.") && !op.includes("eqz") ? "i64" : op.startsWith("f32.") ? "f32" : op.startsWith("f64.") ? "f64" : "i32";
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 result = fn(a.value, b.value);
3218
- if (result === null) return;
3219
- const isCompare = /\.(eq|ne|[lg][te])/.test(op);
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": (a, b) => {
3228
- const ca = getConst(a), cb = getConst(b);
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": (a, b) => getConst(b)?.value === 0 ? a : null,
3241
- "i64.sub": (a, b) => getConst(b)?.value === 0n ? a : null,
3260
+ "i32.sub": rightIdentity(0),
3261
+ "i64.sub": rightIdentity(0n),
3242
3262
  // x * 1 → x, 1 * x → x
3243
- "i32.mul": (a, b) => {
3244
- const ca = getConst(a), cb = getConst(b);
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": (a, b) => getConst(b)?.value === 1 ? a : null,
3257
- "i32.div_u": (a, b) => getConst(b)?.value === 1 ? a : null,
3258
- "i64.div_s": (a, b) => getConst(b)?.value === 1n ? a : null,
3259
- "i64.div_u": (a, b) => getConst(b)?.value === 1n ? a : null,
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": (a, b) => {
3262
- const ca = getConst(a), cb = getConst(b);
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": (a, b) => {
3275
- const ca = getConst(a), cb = getConst(b);
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": (a, b) => {
3288
- const ca = getConst(a), cb = getConst(b);
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": (a, b) => getConst(b)?.value === 0 ? a : null,
3301
- "i32.shr_s": (a, b) => getConst(b)?.value === 0 ? a : null,
3302
- "i32.shr_u": (a, b) => getConst(b)?.value === 0 ? a : null,
3303
- "i64.shl": (a, b) => getConst(b)?.value === 0n ? a : null,
3304
- "i64.shr_s": (a, b) => getConst(b)?.value === 0n ? a : null,
3305
- "i64.shr_u": (a, b) => getConst(b)?.value === 0n ? a : null
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
- let condIdx = 1;
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
- let thenBranch = null, elseBranch = null;
3393
- for (let i = condIdx + 1; i < node.length; i++) {
3394
- const child = node[i];
3395
- if (Array.isArray(child)) {
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, (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];
3529
- if (!Array.isArray(instr2)) continue;
3530
- 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);
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 <= 2 && body.length === 1) {
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
- if (opts.fold) ast = fold(ast);
3645
- if (opts.identity) ast = identity(ast);
3646
- if (opts.strength) ast = strength(ast);
3647
- if (opts.branch) ast = branch(ast);
3648
- if (opts.propagate) ast = propagate(ast);
3649
- if (opts.inline) ast = inline(ast);
3650
- if (opts.deadcode) ast = deadcode(ast);
3651
- if (opts.locals) ast = localReuse(ast);
3652
- if (opts.treeshake) ast = treeshake(ast);
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 && !(values[values.length - 1] instanceof Uint8Array)) {
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 instanceof Uint8Array) return [...value];
4511
+ if (value.byteLength !== void 0) return [...value];
3746
4512
  return value;
3747
4513
  }
3748
4514
  return node;