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 +108 -17
- package/dist/watr.min.js +6 -6
- package/dist/watr.wasm +0 -0
- package/package.json +1 -1
- package/src/compile.js +92 -13
- package/src/optimize.js +20 -19
- package/types/src/compile.d.ts +10 -9
- package/types/src/compile.d.ts.map +1 -1
- package/types/src/optimize.d.ts +34 -2
- package/types/src/optimize.d.ts.map +1 -1
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
|
|
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")
|
|
1393
|
-
|
|
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
|
|
2765
|
+
let size2 = 4;
|
|
2675
2766
|
for (const f of typeDef.fields) {
|
|
2676
|
-
|
|
2767
|
+
size2 += TYPE_SIZES[f.type] || 4;
|
|
2677
2768
|
}
|
|
2678
|
-
return
|
|
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
|
|
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",
|
|
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
|
|
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) ||
|
|
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
|
|
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 (
|
|
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);
|