watr 4.7.0 → 4.7.2

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
@@ -1381,7 +1381,7 @@ var cleanup = (node, result) => {
1381
1381
  result.loc = node.loc;
1382
1382
  return result.length === 1 && result[0]?.[0] === "module" ? result[0] : result;
1383
1383
  };
1384
- function compile(nodes) {
1384
+ function assemble(nodes, sizeOnly) {
1385
1385
  if (typeof nodes === "string") err.src = nodes, nodes = parse_default(nodes) || [];
1386
1386
  else err.src = "";
1387
1387
  err.loc = 0;
@@ -1389,8 +1389,11 @@ function compile(nodes) {
1389
1389
  let idx = 0;
1390
1390
  if (nodes[0] === "module") idx++, isId(nodes[idx]) && idx++;
1391
1391
  else if (typeof nodes[0] === "string") nodes = [nodes];
1392
- if (nodes[idx] === "binary") return Uint8Array.from(nodes.slice(++idx).flat());
1393
- if (nodes[idx] === "quote") return compile(nodes.slice(++idx).map((v) => v.valueOf().slice(1, -1)).flat().join(""));
1392
+ if (nodes[idx] === "binary") {
1393
+ const b = Uint8Array.from(nodes.slice(++idx).flat());
1394
+ return sizeOnly ? b.length : b;
1395
+ }
1396
+ if (nodes[idx] === "quote") return assemble(nodes.slice(++idx).map((v) => v.valueOf().slice(1, -1)).flat().join(""), sizeOnly);
1394
1397
  nodes = nodes.flatMap((n, i) => {
1395
1398
  if (i < idx || !Array.isArray(n) || n[0] !== "import") return [n];
1396
1399
  const [, mod, ...rest] = n;
@@ -1503,6 +1506,32 @@ function compile(nodes) {
1503
1506
  };
1504
1507
  const globalSection = bin(SECTION.global);
1505
1508
  const elemSection = bin(SECTION.elem);
1509
+ if (sizeOnly) {
1510
+ const codeSizes = ctx.code.filter(Boolean).map((item) => codeItemSize(item, ctx));
1511
+ const innerLen = codeSizes.length ? ulebSize(codeSizes.length) + codeSizes.reduce((a, b) => a + b, 0) : 0;
1512
+ const codeSecLen = codeSizes.length ? 1 + ulebSize(innerLen) + innerLen : 0;
1513
+ const metaSection2 = binMeta();
1514
+ const dataSection2 = bin(SECTION.data);
1515
+ const stringsSection2 = ctx.strings.length ? [SECTION.strings, ...vec([0, ...vec(ctx.strings.map((s) => vec(s)))])] : [];
1516
+ const others = [
1517
+ bin(SECTION.custom),
1518
+ bin(SECTION.type),
1519
+ bin(SECTION.import),
1520
+ bin(SECTION.func),
1521
+ bin(SECTION.table),
1522
+ bin(SECTION.memory),
1523
+ bin(SECTION.tag),
1524
+ stringsSection2,
1525
+ globalSection,
1526
+ bin(SECTION.export),
1527
+ bin(SECTION.start, false),
1528
+ elemSection,
1529
+ bin(SECTION.datacount, false),
1530
+ metaSection2,
1531
+ dataSection2
1532
+ ];
1533
+ return 8 + codeSecLen + others.reduce((s, sec) => s + sec.length, 0);
1534
+ }
1506
1535
  const codeItems = ctx.code.filter(Boolean).map((item) => build[SECTION.code](item, ctx)).filter(Boolean);
1507
1536
  const codeSection = codeItems.length ? [SECTION.code, ...vec(vec(codeItems))] : [];
1508
1537
  const metaSection = binMeta();
@@ -1566,6 +1595,12 @@ function compile(nodes) {
1566
1595
  return out;
1567
1596
  }
1568
1597
  }
1598
+ function compile(nodes) {
1599
+ return assemble(nodes);
1600
+ }
1601
+ function size(nodes) {
1602
+ return assemble(nodes, true);
1603
+ }
1569
1604
  var isIdx = (n) => n?.[0] === "$" || !isNaN(n);
1570
1605
  var isId = (n) => n?.[0] === "$";
1571
1606
  var isMemParam = (n) => n?.[0] === "a" || n?.[0] === "o";
@@ -2105,6 +2140,62 @@ var instr = (nodes, ctx) => {
2105
2140
  }
2106
2141
  return out.push(11), out;
2107
2142
  };
2143
+ var ulebSize = (n) => uleb(n).length;
2144
+ var instrSize = (nodes, ctx) => {
2145
+ let size2 = 0, meta = [];
2146
+ while (nodes?.length) {
2147
+ let op = nodes.shift();
2148
+ if (op?.[0] === "@metadata") {
2149
+ meta.push(op.slice(1));
2150
+ continue;
2151
+ }
2152
+ if (Array.isArray(op)) {
2153
+ op.loc != null && (err.loc = op.loc);
2154
+ err(`Unknown instruction ${op[0]}`);
2155
+ }
2156
+ const opc = INSTR[op] || err(`Unknown instruction ${op}`);
2157
+ let n = opc.length;
2158
+ if (HANDLER[op]) n += HANDLER[op](nodes, ctx, op).length;
2159
+ if (meta.length) {
2160
+ for (const [type, data] of meta) (ctx.meta[type] ??= []).push([size2, data]);
2161
+ meta = [];
2162
+ }
2163
+ size2 += n;
2164
+ }
2165
+ return size2 + 1;
2166
+ };
2167
+ var codeItemSize = (body, ctx) => {
2168
+ let [typeidx, param] = body.shift();
2169
+ if (!param) [, [param]] = ctx.type[id(typeidx, ctx.type)];
2170
+ ctx.local = Object.create(param);
2171
+ ctx.block = [];
2172
+ ctx.local.name = "local";
2173
+ ctx.block.name = "block";
2174
+ if (ctx._codeIdx === void 0) ctx._codeIdx = 0;
2175
+ let codeIdx = ctx._codeIdx++;
2176
+ while (body[0]?.[0] === "local") {
2177
+ let [, ...types] = body.shift();
2178
+ if (isId(types[0])) {
2179
+ let nm = types.shift();
2180
+ if (nm in ctx.local) err(`Duplicate local ${nm}`);
2181
+ else ctx.local[nm] = ctx.local.length;
2182
+ }
2183
+ ctx.local.push(...types);
2184
+ }
2185
+ ctx.meta = {};
2186
+ const bytesLen = instrSize(body, ctx);
2187
+ let loctypes = ctx.local.slice(param.length).reduce((a, type) => (type == a[a.length - 1]?.[1] ? a[a.length - 1][0]++ : a.push([1, type]), a), []);
2188
+ const locals = vec(loctypes.map(([n, t]) => [...uleb(n), ...reftype(t, ctx)]));
2189
+ const funcIdx = ctx.import.filter((imp) => imp[2][0] === "func").length + codeIdx;
2190
+ for (const type in ctx.meta) {
2191
+ for (const inst of ctx.meta[type]) inst[0] += locals.length;
2192
+ ((ctx.metadata ??= {})[type] ??= []).push([funcIdx, ctx.meta[type]]);
2193
+ }
2194
+ ctx.local = ctx.block = ctx.meta = null;
2195
+ const bodyLen = locals.length + bytesLen;
2196
+ (ctx.codeSizePrefix ??= [])[codeIdx] = ulebSize(bodyLen);
2197
+ return ulebSize(bodyLen) + bodyLen;
2198
+ };
2108
2199
  var expr = (node, ctx) => instr(normalize([node], ctx), ctx);
2109
2200
  var id = (nm, list, n) => (n = isId(nm) ? list[nm] : +nm, n in list ? n : err(`Unknown ${list.name} ${nm}`));
2110
2201
  var blockid = (nm, block, i) => (i = isId(nm) ? block.length - block[nm] : +nm, isNaN(i) || i > block.length ? err(`Bad label ${nm}`) : i);
@@ -2671,11 +2762,11 @@ var gc = (ast, ctx) => {
2671
2762
  ];
2672
2763
  ast.push(allocFunc);
2673
2764
  const structSize = (typeDef) => {
2674
- let size = 4;
2765
+ let size2 = 4;
2675
2766
  for (const f of typeDef.fields) {
2676
- size += TYPE_SIZES[f.type] || 4;
2767
+ size2 += TYPE_SIZES[f.type] || 4;
2677
2768
  }
2678
- return size;
2769
+ return size2;
2679
2770
  };
2680
2771
  const fieldOffset = (typeDef, fieldIdx) => {
2681
2772
  let offset2 = 4;
@@ -2732,12 +2823,12 @@ var gc = (ast, ctx) => {
2732
2823
  const typeId = node[1];
2733
2824
  const typeDef = types.get(typeId);
2734
2825
  if (!typeDef || typeDef.kind !== "struct") return;
2735
- const size = structSize(typeDef);
2826
+ const size2 = structSize(typeDef);
2736
2827
  const typeTag = typeIndices.get(typeId);
2737
2828
  const args = node.slice(2);
2738
2829
  const ptrLocal = "$__gc_ptr";
2739
2830
  const stores = [
2740
- ["local.set", ptrLocal, ["call", allocId, ["i32.const", size]]],
2831
+ ["local.set", ptrLocal, ["call", allocId, ["i32.const", size2]]],
2741
2832
  ["i32.store", ["local.get", ptrLocal], ["i32.const", typeTag]]
2742
2833
  // store type tag
2743
2834
  ];
@@ -3118,7 +3209,7 @@ var resultType2 = (op) => {
3118
3209
  };
3119
3210
  var binarySize = (ast) => {
3120
3211
  try {
3121
- return compile(ast).length;
3212
+ return size(ast);
3122
3213
  } catch {
3123
3214
  return Infinity;
3124
3215
  }
@@ -4500,7 +4591,7 @@ var buildInline = (params, locals, inlResult, cBody, args) => {
4500
4591
  };
4501
4592
  var INLINE_MAX_NODES = 90;
4502
4593
  var isV128SimdHelper = (params, inlResult) => inlResult === "v128" && params.length > 0 && params.every((p) => p.type === "v128");
4503
- var inline = (ast, { simdOnly = false } = {}) => {
4594
+ var inline = (ast, { simdOnly = false, pin = EMPTY_SET } = {}) => {
4504
4595
  if (!Array.isArray(ast) || ast[0] !== "module") return ast;
4505
4596
  const skip = /* @__PURE__ */ new Set();
4506
4597
  for (let round = 0; round < MAX_INLINE_ROUNDS; round++) {
@@ -4520,7 +4611,7 @@ var inline = (ast, { simdOnly = false } = {}) => {
4520
4611
  for (const n of ast) if (!Array.isArray(n) || n[0] !== "func") inlCollectPinned(n, pinned);
4521
4612
  let calleeName = null, parsed = null;
4522
4613
  for (const [name2, fn] of funcByName) {
4523
- if (skip.has(name2) || pinned.has(name2) || otherRef.has(name2) || SIMD_PROTECTED.has(name2)) continue;
4614
+ if (skip.has(name2) || pinned.has(name2) || otherRef.has(name2) || pin.has(name2)) continue;
4524
4615
  if (!(callRefs.get(name2) >= 1)) continue;
4525
4616
  if (inlBodySize(fn) > INLINE_MAX_NODES) continue;
4526
4617
  if (inlCallsSelf(fn, name2)) continue;
@@ -4789,8 +4880,7 @@ var devirt = (ast) => {
4789
4880
  }
4790
4881
  return ast;
4791
4882
  };
4792
- var SIMD_PROTECTED = /* @__PURE__ */ new Set(["$math.sin_core", "$math.cos_core", "$math.sin", "$math.cos", "$math.pow", "$math.atan2", "$math.hypot", "$math.log"]);
4793
- var inlineOnce = (ast) => {
4883
+ var inlineOnce = (ast, { pin = EMPTY_SET } = {}) => {
4794
4884
  if (!Array.isArray(ast) || ast[0] !== "module") return ast;
4795
4885
  const bodyStart = inlBodyStart, callsSelf = inlCallsSelf, unsafe = inlUnsafe, isBranch = inlIsBranch;
4796
4886
  const zeroFor = inlZeroFor, needsReset = inlNeedsReset;
@@ -4812,7 +4902,7 @@ var inlineOnce = (ast) => {
4812
4902
  for (const [name2, fn] of funcByName) {
4813
4903
  if (pinned.has(name2) || otherRef.has(name2)) continue;
4814
4904
  if (callRefs.get(name2) !== 1) continue;
4815
- if (SIMD_PROTECTED.has(name2)) continue;
4905
+ if (pin.has(name2)) continue;
4816
4906
  if (callsSelf(fn, name2)) continue;
4817
4907
  let ok = true, nResult = 0;
4818
4908
  for (let i = 2; i < fn.length; i++) {
@@ -5999,13 +6089,14 @@ function optimize(ast, opts = true) {
5999
6089
  if (typeof ast === "string") ast = parse_default(ast);
6000
6090
  const strictGuard = opts === true;
6001
6091
  opts = normalize3(opts);
6092
+ opts.pin = opts.pin instanceof Set ? opts.pin : new Set(opts.pin || []);
6002
6093
  const log = opts.log ? (msg, delta) => opts.log(msg, delta) : () => {
6003
6094
  };
6004
6095
  const verbose = opts.verbose || opts.log;
6005
6096
  ast = clone2(ast);
6006
6097
  const runInline = (a) => {
6007
6098
  if (!opts.inline) return a;
6008
- a = inline(a, { simdOnly: opts.inline === "simd" });
6099
+ a = inline(a, { simdOnly: opts.inline === "simd", pin: opts.pin });
6009
6100
  if (opts.propagate) a = propagate(a);
6010
6101
  if (opts.mergeBlocks) a = mergeBlocks(a);
6011
6102
  if (opts.vacuum) a = vacuum(a);
@@ -6019,7 +6110,7 @@ function optimize(ast, opts = true) {
6019
6110
  if (!((opts.inlineOnce || opts.inline) && mayInline(ast))) {
6020
6111
  for (let round = 0; round < 3; round++) {
6021
6112
  const beforeRound2 = clone2(ast);
6022
- for (const [key, fn] of PASSES) if (opts[key] && key !== "inlineOnce" && key !== "inline" && key !== "devirt") ast = fn(ast);
6113
+ for (const [key, fn] of PASSES) if (opts[key] && key !== "inlineOnce" && key !== "inline" && key !== "devirt") ast = fn(ast, opts);
6023
6114
  if (equal(beforeRound2, ast)) break;
6024
6115
  if (verbose) log(` round ${round + 1} applied`);
6025
6116
  }
@@ -6029,7 +6120,7 @@ function optimize(ast, opts = true) {
6029
6120
  let sizeBefore = binarySize(ast);
6030
6121
  for (let round = 0; round < 3; round++) {
6031
6122
  beforeRound = clone2(ast);
6032
- for (const [key, fn] of PASSES) if (opts[key] && key !== "devirt" && key !== "inline") ast = fn(ast);
6123
+ for (const [key, fn] of PASSES) if (opts[key] && key !== "devirt" && key !== "inline") ast = fn(ast, opts);
6033
6124
  if (opts.propagate && (opts.inlineOnce || opts.inline)) ast = propagate(ast);
6034
6125
  if (equal(beforeRound, ast)) break;
6035
6126
  const sizeAfter = binarySize(ast);