watr 4.6.6 → 4.6.8
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 +340 -405
- package/dist/watr.min.js +6 -6
- package/dist/watr.wasm +0 -0
- package/package.json +1 -1
- package/src/const.js +23 -0
- package/src/encode.js +1 -1
- package/src/optimize.js +179 -236
- package/src/polyfill.js +91 -135
- package/src/template.js +245 -0
- package/src/util.js +43 -7
- package/types/src/const.d.ts +1 -0
- package/types/src/const.d.ts.map +1 -1
- package/types/src/optimize.d.ts +7 -29
- package/types/src/optimize.d.ts.map +1 -1
- package/types/src/polyfill.d.ts +8 -14
- package/types/src/polyfill.d.ts.map +1 -1
- package/types/src/template.d.ts +22 -0
- package/types/src/template.d.ts.map +1 -0
- package/types/src/util.d.ts +3 -1
- package/types/src/util.d.ts.map +1 -1
- package/types/watr.d.ts +4 -10
- package/types/watr.d.ts.map +1 -1
- package/watr.js +9 -224
package/dist/watr.js
CHANGED
|
@@ -56,6 +56,17 @@ var str = (s) => {
|
|
|
56
56
|
return bytes;
|
|
57
57
|
};
|
|
58
58
|
var unescape = (s) => tdec.decode(new Uint8Array(str(s)));
|
|
59
|
+
var clone = (node) => Array.isArray(node) ? node.map(clone) : node;
|
|
60
|
+
var walk = (node, fn, parent, idx) => {
|
|
61
|
+
fn(node, parent, idx);
|
|
62
|
+
if (Array.isArray(node)) for (let i = 0; i < node.length; i++) walk(node[i], fn, node, i);
|
|
63
|
+
};
|
|
64
|
+
var walkPost = (node, fn, parent, idx) => {
|
|
65
|
+
if (Array.isArray(node)) for (let i = 0; i < node.length; i++) walkPost(node[i], fn, node, i);
|
|
66
|
+
const result = fn(node, parent, idx);
|
|
67
|
+
if (result !== void 0 && parent) parent[idx] = result;
|
|
68
|
+
return result !== void 0 ? result : node;
|
|
69
|
+
};
|
|
59
70
|
|
|
60
71
|
// src/encode.js
|
|
61
72
|
var uleb = (n, buffer = []) => {
|
|
@@ -141,7 +152,7 @@ var _i64 = new BigInt64Array(_buf);
|
|
|
141
152
|
i64.parse = (n) => {
|
|
142
153
|
n = cleanInt(n);
|
|
143
154
|
const neg = n[0] === "-";
|
|
144
|
-
const body = neg ? n.slice(1) : n;
|
|
155
|
+
const body = neg || n[0] === "+" ? n.slice(1) : n;
|
|
145
156
|
let max;
|
|
146
157
|
if (body[0] === "0" && (body[1] === "x" || body[1] === "X")) {
|
|
147
158
|
const hex = body.slice(2).replace(/^0+/, "") || "0";
|
|
@@ -1243,6 +1254,17 @@ var INSTR = [
|
|
|
1243
1254
|
"i64.atomic.rmw32.cmpxchg_u memarg"
|
|
1244
1255
|
]
|
|
1245
1256
|
];
|
|
1257
|
+
var resultType = (op) => {
|
|
1258
|
+
if (typeof op !== "string") return null;
|
|
1259
|
+
const dot = op.indexOf(".");
|
|
1260
|
+
if (dot < 0) return null;
|
|
1261
|
+
const prefix = op.slice(0, dot);
|
|
1262
|
+
const scalar = prefix === "i32" || prefix === "i64" || prefix === "f32" || prefix === "f64";
|
|
1263
|
+
if (scalar && /^(eqz?|ne|[lg][te])(_[su])?$/.test(op.slice(dot + 1))) return "i32";
|
|
1264
|
+
if (scalar || prefix === "v128") return prefix;
|
|
1265
|
+
if (op === "memory.size" || op === "memory.grow") return "i32";
|
|
1266
|
+
return null;
|
|
1267
|
+
};
|
|
1246
1268
|
var SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, tag: 13, strings: 14, global: 6, export: 7, start: 8, elem: 9, datacount: 12, code: 10, data: 11 };
|
|
1247
1269
|
var TYPE = {
|
|
1248
1270
|
// Value types
|
|
@@ -2177,91 +2199,6 @@ function print(tree, options = {}) {
|
|
|
2177
2199
|
}
|
|
2178
2200
|
|
|
2179
2201
|
// src/polyfill.js
|
|
2180
|
-
var FEATURES = {
|
|
2181
|
-
funcref: ["ref.func", "call_ref", "return_call_ref"],
|
|
2182
|
-
sign_ext: ["i32.extend8_s", "i32.extend16_s", "i64.extend8_s", "i64.extend16_s", "i64.extend32_s"],
|
|
2183
|
-
nontrapping: [
|
|
2184
|
-
"i32.trunc_sat_f32_s",
|
|
2185
|
-
"i32.trunc_sat_f32_u",
|
|
2186
|
-
"i32.trunc_sat_f64_s",
|
|
2187
|
-
"i32.trunc_sat_f64_u",
|
|
2188
|
-
"i64.trunc_sat_f32_s",
|
|
2189
|
-
"i64.trunc_sat_f32_u",
|
|
2190
|
-
"i64.trunc_sat_f64_s",
|
|
2191
|
-
"i64.trunc_sat_f64_u"
|
|
2192
|
-
],
|
|
2193
|
-
bulk_memory: ["memory.copy", "memory.fill"],
|
|
2194
|
-
return_call: ["return_call", "return_call_indirect"],
|
|
2195
|
-
i31ref: ["ref.i31", "i31.get_s", "i31.get_u"],
|
|
2196
|
-
extended_const: ["global.get"],
|
|
2197
|
-
// in const context - detected specially
|
|
2198
|
-
multi_value: [],
|
|
2199
|
-
// detected by result count
|
|
2200
|
-
gc: [
|
|
2201
|
-
"struct.new",
|
|
2202
|
-
"struct.get",
|
|
2203
|
-
"struct.set",
|
|
2204
|
-
"array.new",
|
|
2205
|
-
"array.get",
|
|
2206
|
-
"array.set",
|
|
2207
|
-
"array.len",
|
|
2208
|
-
"struct.new_default",
|
|
2209
|
-
"array.new_default",
|
|
2210
|
-
"array.new_fixed",
|
|
2211
|
-
"array.copy"
|
|
2212
|
-
],
|
|
2213
|
-
ref_cast: ["ref.test", "ref.cast", "br_on_cast", "br_on_cast_fail"]
|
|
2214
|
-
};
|
|
2215
|
-
var ALL = Object.keys(FEATURES);
|
|
2216
|
-
var normalize2 = (opts) => {
|
|
2217
|
-
if (opts === true) return Object.fromEntries(ALL.map((f) => [f, true]));
|
|
2218
|
-
if (opts === false) return {};
|
|
2219
|
-
if (typeof opts === "string") {
|
|
2220
|
-
const set = new Set(opts.split(/\s+/).filter(Boolean));
|
|
2221
|
-
return Object.fromEntries(ALL.map((f) => [f, set.has(f) || set.has("all")]));
|
|
2222
|
-
}
|
|
2223
|
-
return { ...opts };
|
|
2224
|
-
};
|
|
2225
|
-
var walk = (node, fn, parent, idx) => {
|
|
2226
|
-
fn(node, parent, idx);
|
|
2227
|
-
if (Array.isArray(node)) for (let i = 0; i < node.length; i++) walk(node[i], fn, node, i);
|
|
2228
|
-
};
|
|
2229
|
-
var walkPost = (node, fn, parent, idx) => {
|
|
2230
|
-
if (Array.isArray(node)) for (let i = 0; i < node.length; i++) walkPost(node[i], fn, node, i);
|
|
2231
|
-
fn(node, parent, idx);
|
|
2232
|
-
};
|
|
2233
|
-
var detect = (ast) => {
|
|
2234
|
-
const used = /* @__PURE__ */ new Set();
|
|
2235
|
-
walk(ast, (node) => {
|
|
2236
|
-
if (typeof node !== "string") return;
|
|
2237
|
-
for (const [feat, ops] of Object.entries(FEATURES)) {
|
|
2238
|
-
if (ops.some((op) => node === op || node.startsWith(op + " "))) used.add(feat);
|
|
2239
|
-
}
|
|
2240
|
-
});
|
|
2241
|
-
walk(ast, (node) => {
|
|
2242
|
-
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
2243
|
-
for (const init of node) {
|
|
2244
|
-
if (!Array.isArray(init)) continue;
|
|
2245
|
-
if (init[0] === "i32.add" || init[0] === "i32.sub" || init[0] === "i32.mul" || init[0] === "i64.add" || init[0] === "i64.sub" || init[0] === "i64.mul") {
|
|
2246
|
-
walk(init, (inner) => {
|
|
2247
|
-
if (Array.isArray(inner) && inner[0] === "global.get") used.add("extended_const");
|
|
2248
|
-
});
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
});
|
|
2252
|
-
walk(ast, (node) => {
|
|
2253
|
-
if (!Array.isArray(node) || node[0] !== "func") return;
|
|
2254
|
-
let resultCount = 0;
|
|
2255
|
-
for (const part of node) {
|
|
2256
|
-
if (Array.isArray(part) && part[0] === "result") {
|
|
2257
|
-
resultCount += part.length - 1;
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
if (resultCount > 1) used.add("multi_value");
|
|
2261
|
-
});
|
|
2262
|
-
return used;
|
|
2263
|
-
};
|
|
2264
|
-
var clone = (node) => Array.isArray(node) ? node.map(clone) : node;
|
|
2265
2202
|
var findNodes = (ast, kind) => {
|
|
2266
2203
|
const nodes = [];
|
|
2267
2204
|
const start = ast[0] === "module" ? 1 : 0;
|
|
@@ -2319,7 +2256,6 @@ var funcref = (ast, ctx) => {
|
|
|
2319
2256
|
});
|
|
2320
2257
|
return ast;
|
|
2321
2258
|
};
|
|
2322
|
-
var transforms = { funcref };
|
|
2323
2259
|
var SIGN_EXT_SHIFTS = {
|
|
2324
2260
|
"i32.extend8_s": ["i32", 24],
|
|
2325
2261
|
"i32.extend16_s": ["i32", 16],
|
|
@@ -2342,7 +2278,6 @@ var sign_ext = (ast, ctx) => {
|
|
|
2342
2278
|
});
|
|
2343
2279
|
return ast;
|
|
2344
2280
|
};
|
|
2345
|
-
transforms.sign_ext = sign_ext;
|
|
2346
2281
|
var TRUNC_SAT_INFO = {
|
|
2347
2282
|
"i32.trunc_sat_f32_s": { itype: "i32", ftype: "f32", signed: true, min: -2147483648, max: 2147483647 },
|
|
2348
2283
|
"i32.trunc_sat_f32_u": { itype: "i32", ftype: "f32", signed: false, min: 0, max: 4294967295 },
|
|
@@ -2410,7 +2345,6 @@ var nontrapping = (ast, ctx) => {
|
|
|
2410
2345
|
});
|
|
2411
2346
|
return ast;
|
|
2412
2347
|
};
|
|
2413
|
-
transforms.nontrapping = nontrapping;
|
|
2414
2348
|
var bulk_memory = (ast, ctx) => {
|
|
2415
2349
|
const needsCopy = /* @__PURE__ */ new Set(), needsFill = /* @__PURE__ */ new Set();
|
|
2416
2350
|
walk(ast, (node) => {
|
|
@@ -2502,7 +2436,6 @@ var bulk_memory = (ast, ctx) => {
|
|
|
2502
2436
|
});
|
|
2503
2437
|
return ast;
|
|
2504
2438
|
};
|
|
2505
|
-
transforms.bulk_memory = bulk_memory;
|
|
2506
2439
|
var return_call_transform = (ast, ctx) => {
|
|
2507
2440
|
let hasAnyTailCall = false;
|
|
2508
2441
|
walk(ast, (node) => {
|
|
@@ -2522,7 +2455,6 @@ var return_call_transform = (ast, ctx) => {
|
|
|
2522
2455
|
});
|
|
2523
2456
|
return ast;
|
|
2524
2457
|
};
|
|
2525
|
-
transforms.return_call = return_call_transform;
|
|
2526
2458
|
var i31ref = (ast, ctx) => {
|
|
2527
2459
|
walkPost(ast, (node, parent, idx) => {
|
|
2528
2460
|
if (!Array.isArray(node) || !parent) return;
|
|
@@ -2539,7 +2471,6 @@ var i31ref = (ast, ctx) => {
|
|
|
2539
2471
|
});
|
|
2540
2472
|
return ast;
|
|
2541
2473
|
};
|
|
2542
|
-
transforms.i31ref = i31ref;
|
|
2543
2474
|
var extended_const = (ast, ctx) => {
|
|
2544
2475
|
const globals2 = {};
|
|
2545
2476
|
walk(ast, (node) => {
|
|
@@ -2602,7 +2533,6 @@ var extended_const = (ast, ctx) => {
|
|
|
2602
2533
|
});
|
|
2603
2534
|
return ast;
|
|
2604
2535
|
};
|
|
2605
|
-
transforms.extended_const = extended_const;
|
|
2606
2536
|
var multi_value = (ast, ctx) => {
|
|
2607
2537
|
const multiResultFuncs = /* @__PURE__ */ new Map();
|
|
2608
2538
|
const returnGlobals = [];
|
|
@@ -2651,7 +2581,6 @@ var multi_value = (ast, ctx) => {
|
|
|
2651
2581
|
});
|
|
2652
2582
|
return ast;
|
|
2653
2583
|
};
|
|
2654
|
-
transforms.multi_value = multi_value;
|
|
2655
2584
|
var TYPE_SIZES = { i32: 4, i64: 8, f32: 4, f64: 8 };
|
|
2656
2585
|
var gc = (ast, ctx) => {
|
|
2657
2586
|
const types = /* @__PURE__ */ new Map();
|
|
@@ -2895,7 +2824,6 @@ var gc = (ast, ctx) => {
|
|
|
2895
2824
|
});
|
|
2896
2825
|
return ast;
|
|
2897
2826
|
};
|
|
2898
|
-
transforms.gc = gc;
|
|
2899
2827
|
var ref_cast = (ast, ctx) => {
|
|
2900
2828
|
const typeIndices = /* @__PURE__ */ new Map();
|
|
2901
2829
|
let typeIdx = 1;
|
|
@@ -3039,77 +2967,94 @@ var ref_cast = (ast, ctx) => {
|
|
|
3039
2967
|
});
|
|
3040
2968
|
return ast;
|
|
3041
2969
|
};
|
|
3042
|
-
|
|
2970
|
+
var POLYFILLS = [
|
|
2971
|
+
["funcref", ["ref.func", "call_ref", "return_call_ref"], funcref],
|
|
2972
|
+
["sign_ext", ["i32.extend8_s", "i32.extend16_s", "i64.extend8_s", "i64.extend16_s", "i64.extend32_s"], sign_ext],
|
|
2973
|
+
["nontrapping", [
|
|
2974
|
+
"i32.trunc_sat_f32_s",
|
|
2975
|
+
"i32.trunc_sat_f32_u",
|
|
2976
|
+
"i32.trunc_sat_f64_s",
|
|
2977
|
+
"i32.trunc_sat_f64_u",
|
|
2978
|
+
"i64.trunc_sat_f32_s",
|
|
2979
|
+
"i64.trunc_sat_f32_u",
|
|
2980
|
+
"i64.trunc_sat_f64_s",
|
|
2981
|
+
"i64.trunc_sat_f64_u"
|
|
2982
|
+
], nontrapping],
|
|
2983
|
+
["bulk_memory", ["memory.copy", "memory.fill"], bulk_memory],
|
|
2984
|
+
["return_call", ["return_call", "return_call_indirect"], return_call_transform],
|
|
2985
|
+
["i31ref", ["ref.i31", "i31.get_s", "i31.get_u"], i31ref],
|
|
2986
|
+
["extended_const", ["global.get"], extended_const],
|
|
2987
|
+
// global.get in a const initializer — also detected specially
|
|
2988
|
+
["multi_value", [], multi_value],
|
|
2989
|
+
// functions with >1 result — detected by result count
|
|
2990
|
+
["gc", [
|
|
2991
|
+
"struct.new",
|
|
2992
|
+
"struct.get",
|
|
2993
|
+
"struct.set",
|
|
2994
|
+
"array.new",
|
|
2995
|
+
"array.get",
|
|
2996
|
+
"array.set",
|
|
2997
|
+
"array.len",
|
|
2998
|
+
"struct.new_default",
|
|
2999
|
+
"array.new_default",
|
|
3000
|
+
"array.new_fixed",
|
|
3001
|
+
"array.copy"
|
|
3002
|
+
], gc],
|
|
3003
|
+
["ref_cast", ["ref.test", "ref.cast", "br_on_cast", "br_on_cast_fail"], ref_cast]
|
|
3004
|
+
];
|
|
3005
|
+
var FEATURES = Object.fromEntries(POLYFILLS.map((p) => [p[0], p[1]]));
|
|
3006
|
+
var normalize2 = (opts) => {
|
|
3007
|
+
if (opts === false) return {};
|
|
3008
|
+
if (opts !== true && typeof opts !== "string") return { ...opts };
|
|
3009
|
+
const set = typeof opts === "string" ? new Set(opts.split(/\s+/).filter(Boolean)) : null;
|
|
3010
|
+
const m = {};
|
|
3011
|
+
for (const p of POLYFILLS) m[p[0]] = set ? set.has("all") || set.has(p[0]) : true;
|
|
3012
|
+
return m;
|
|
3013
|
+
};
|
|
3014
|
+
var detect = (ast) => {
|
|
3015
|
+
const used = /* @__PURE__ */ new Set();
|
|
3016
|
+
walk(ast, (node) => {
|
|
3017
|
+
if (typeof node !== "string") return;
|
|
3018
|
+
for (const p of POLYFILLS) {
|
|
3019
|
+
const ops = p[1];
|
|
3020
|
+
if (ops.some((op) => node === op || node.startsWith(op + " "))) used.add(p[0]);
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
walk(ast, (node) => {
|
|
3024
|
+
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
3025
|
+
for (const init of node) {
|
|
3026
|
+
if (!Array.isArray(init)) continue;
|
|
3027
|
+
if (init[0] === "i32.add" || init[0] === "i32.sub" || init[0] === "i32.mul" || init[0] === "i64.add" || init[0] === "i64.sub" || init[0] === "i64.mul") {
|
|
3028
|
+
walk(init, (inner) => {
|
|
3029
|
+
if (Array.isArray(inner) && inner[0] === "global.get") used.add("extended_const");
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
});
|
|
3034
|
+
walk(ast, (node) => {
|
|
3035
|
+
if (!Array.isArray(node) || node[0] !== "func") return;
|
|
3036
|
+
let resultCount = 0;
|
|
3037
|
+
for (const part of node) {
|
|
3038
|
+
if (Array.isArray(part) && part[0] === "result") resultCount += part.length - 1;
|
|
3039
|
+
}
|
|
3040
|
+
if (resultCount > 1) used.add("multi_value");
|
|
3041
|
+
});
|
|
3042
|
+
return used;
|
|
3043
|
+
};
|
|
3043
3044
|
function polyfill(ast, opts = true) {
|
|
3044
3045
|
if (typeof ast === "string") ast = parse_default(ast);
|
|
3045
3046
|
ast = clone(ast);
|
|
3046
3047
|
opts = normalize2(opts);
|
|
3047
3048
|
const used = detect(ast);
|
|
3048
3049
|
const ctx = { uid: 0 };
|
|
3049
|
-
for (const
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
}
|
|
3050
|
+
for (const p of POLYFILLS) {
|
|
3051
|
+
const fn = p[2];
|
|
3052
|
+
if (used.has(p[0]) && opts[p[0]] !== false) ast = fn(ast, ctx);
|
|
3053
3053
|
}
|
|
3054
3054
|
return ast;
|
|
3055
3055
|
}
|
|
3056
3056
|
|
|
3057
3057
|
// src/optimize.js
|
|
3058
|
-
var OPTS = {
|
|
3059
|
-
treeshake: true,
|
|
3060
|
-
// remove unused funcs/globals/types/tables
|
|
3061
|
-
fold: true,
|
|
3062
|
-
// constant folding
|
|
3063
|
-
deadcode: true,
|
|
3064
|
-
// eliminate dead code after unreachable/br/return
|
|
3065
|
-
locals: true,
|
|
3066
|
-
// remove unused locals
|
|
3067
|
-
identity: true,
|
|
3068
|
-
// remove identity ops (x + 0 → x)
|
|
3069
|
-
strength: true,
|
|
3070
|
-
// strength reduction (x * 2 → x << 1)
|
|
3071
|
-
branch: true,
|
|
3072
|
-
// simplify constant branches
|
|
3073
|
-
propagate: true,
|
|
3074
|
-
// forward-propagate single-use locals & tiny consts (never inflates)
|
|
3075
|
-
inline: false,
|
|
3076
|
-
// inline tiny functions — can duplicate bodies
|
|
3077
|
-
inlineOnce: true,
|
|
3078
|
-
// inline single-call functions into their lone caller (never duplicates)
|
|
3079
|
-
vacuum: true,
|
|
3080
|
-
// remove nops, drop-of-pure, empty branches
|
|
3081
|
-
mergeBlocks: true,
|
|
3082
|
-
// unwrap `(block $L …)` whose label is never targeted
|
|
3083
|
-
coalesce: true,
|
|
3084
|
-
// share local slots between same-type non-overlapping locals
|
|
3085
|
-
peephole: true,
|
|
3086
|
-
// x-x→0, x&0→0, etc.
|
|
3087
|
-
globals: true,
|
|
3088
|
-
// propagate immutable global constants
|
|
3089
|
-
offset: true,
|
|
3090
|
-
// fold add+const into load/store offset
|
|
3091
|
-
unbranch: true,
|
|
3092
|
-
// remove redundant br at end of own block
|
|
3093
|
-
loopify: true,
|
|
3094
|
-
// collapse block+loop+brif while-idiom into loop+if
|
|
3095
|
-
stripmut: true,
|
|
3096
|
-
// strip mut from never-written globals
|
|
3097
|
-
brif: true,
|
|
3098
|
-
// if-then-br → br_if
|
|
3099
|
-
foldarms: false,
|
|
3100
|
-
// merge identical trailing if arms — can add block wrapper
|
|
3101
|
-
dedupe: true,
|
|
3102
|
-
// eliminate duplicate functions
|
|
3103
|
-
reorder: false,
|
|
3104
|
-
// put hot functions first — no AST reduction
|
|
3105
|
-
dedupTypes: true,
|
|
3106
|
-
// merge identical type definitions
|
|
3107
|
-
packData: true,
|
|
3108
|
-
// trim trailing zeros, merge adjacent data segments
|
|
3109
|
-
minifyImports: false
|
|
3110
|
-
// shorten import names — enable only when you control the host
|
|
3111
|
-
};
|
|
3112
|
-
var ALL2 = Object.keys(OPTS);
|
|
3113
3058
|
var binarySize = (ast) => {
|
|
3114
3059
|
try {
|
|
3115
3060
|
return compile(ast).length;
|
|
@@ -3126,34 +3071,6 @@ var equal = (a, b) => {
|
|
|
3126
3071
|
for (let i = 0; i < a.length; i++) if (!equal(a[i], b[i])) return false;
|
|
3127
3072
|
return true;
|
|
3128
3073
|
};
|
|
3129
|
-
var normalize3 = (opts) => {
|
|
3130
|
-
if (opts === true) return { ...OPTS };
|
|
3131
|
-
if (opts === false) return {};
|
|
3132
|
-
if (typeof opts === "string") {
|
|
3133
|
-
const set = new Set(opts.split(/\s+/).filter(Boolean));
|
|
3134
|
-
if (set.has("all")) return Object.fromEntries(ALL2.map((f) => [f, true]));
|
|
3135
|
-
return Object.fromEntries(ALL2.map((f) => [f, set.has(f)]));
|
|
3136
|
-
}
|
|
3137
|
-
return { ...OPTS, ...opts };
|
|
3138
|
-
};
|
|
3139
|
-
var clone2 = (node) => {
|
|
3140
|
-
if (!Array.isArray(node)) return node;
|
|
3141
|
-
return node.map(clone2);
|
|
3142
|
-
};
|
|
3143
|
-
var walk2 = (node, fn, parent, idx) => {
|
|
3144
|
-
fn(node, parent, idx);
|
|
3145
|
-
if (Array.isArray(node)) for (let i = 0; i < node.length; i++) walk2(node[i], fn, node, i);
|
|
3146
|
-
};
|
|
3147
|
-
var walkPost2 = (node, fn, parent, idx) => {
|
|
3148
|
-
if (Array.isArray(node)) {
|
|
3149
|
-
for (let i = 0; i < node.length; i++) {
|
|
3150
|
-
const result2 = walkPost2(node[i], fn, node, i);
|
|
3151
|
-
if (result2 !== void 0) node[i] = result2;
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
const result = fn(node, parent, idx);
|
|
3155
|
-
return result !== void 0 ? result : node;
|
|
3156
|
-
};
|
|
3157
3074
|
var parseIf = (node) => {
|
|
3158
3075
|
let condIdx = 1;
|
|
3159
3076
|
while (condIdx < node.length) {
|
|
@@ -3254,7 +3171,7 @@ var treeshake = (ast) => {
|
|
|
3254
3171
|
markFunc(ref);
|
|
3255
3172
|
}
|
|
3256
3173
|
for (const elem of elems) {
|
|
3257
|
-
|
|
3174
|
+
walk(elem, (n) => {
|
|
3258
3175
|
if (Array.isArray(n) && n[0] === "ref.func") markFunc(n[1]);
|
|
3259
3176
|
else if (typeof n === "string" && n[0] === "$") markFunc(n);
|
|
3260
3177
|
});
|
|
@@ -3276,7 +3193,7 @@ var treeshake = (ast) => {
|
|
|
3276
3193
|
if (entry.scanned) continue;
|
|
3277
3194
|
entry.scanned = true;
|
|
3278
3195
|
if (entry.isImport) continue;
|
|
3279
|
-
|
|
3196
|
+
walk(entry.node, (n) => {
|
|
3280
3197
|
if (!Array.isArray(n)) {
|
|
3281
3198
|
if (typeof n === "string" && n[0] === "$") markFunc(n);
|
|
3282
3199
|
return;
|
|
@@ -3348,120 +3265,120 @@ var i64c = (fn) => (a, b) => fn(a, b) ? 1 : 0;
|
|
|
3348
3265
|
var u64c = (fn) => (a, b) => fn(BigInt.asUintN(64, a), BigInt.asUintN(64, b)) ? 1 : 0;
|
|
3349
3266
|
var FOLDABLE = {
|
|
3350
3267
|
// i32 arithmetic
|
|
3351
|
-
"i32.add":
|
|
3352
|
-
"i32.sub":
|
|
3353
|
-
"i32.mul":
|
|
3354
|
-
"i32.div_s":
|
|
3355
|
-
"i32.div_u":
|
|
3356
|
-
"i32.rem_s":
|
|
3357
|
-
"i32.rem_u":
|
|
3358
|
-
"i32.and":
|
|
3359
|
-
"i32.or":
|
|
3360
|
-
"i32.xor":
|
|
3361
|
-
"i32.shl":
|
|
3362
|
-
"i32.shr_s":
|
|
3363
|
-
"i32.shr_u":
|
|
3364
|
-
"i32.rotl":
|
|
3268
|
+
"i32.add": (a, b) => a + b | 0,
|
|
3269
|
+
"i32.sub": (a, b) => a - b | 0,
|
|
3270
|
+
"i32.mul": (a, b) => Math.imul(a, b),
|
|
3271
|
+
"i32.div_s": (a, b) => b !== 0 ? a / b | 0 : null,
|
|
3272
|
+
"i32.div_u": (a, b) => b !== 0 ? (a >>> 0) / (b >>> 0) | 0 : null,
|
|
3273
|
+
"i32.rem_s": (a, b) => b !== 0 ? a % b | 0 : null,
|
|
3274
|
+
"i32.rem_u": (a, b) => b !== 0 ? (a >>> 0) % (b >>> 0) | 0 : null,
|
|
3275
|
+
"i32.and": (a, b) => a & b,
|
|
3276
|
+
"i32.or": (a, b) => a | b,
|
|
3277
|
+
"i32.xor": (a, b) => a ^ b,
|
|
3278
|
+
"i32.shl": (a, b) => a << (b & 31),
|
|
3279
|
+
"i32.shr_s": (a, b) => a >> (b & 31),
|
|
3280
|
+
"i32.shr_u": (a, b) => a >>> (b & 31),
|
|
3281
|
+
"i32.rotl": (a, b) => {
|
|
3365
3282
|
b &= 31;
|
|
3366
3283
|
return a << b | a >>> 32 - b | 0;
|
|
3367
|
-
},
|
|
3368
|
-
"i32.rotr":
|
|
3284
|
+
},
|
|
3285
|
+
"i32.rotr": (a, b) => {
|
|
3369
3286
|
b &= 31;
|
|
3370
3287
|
return a >>> b | a << 32 - b | 0;
|
|
3371
|
-
},
|
|
3372
|
-
"i32.eq":
|
|
3373
|
-
"i32.ne":
|
|
3374
|
-
"i32.lt_s":
|
|
3375
|
-
"i32.lt_u":
|
|
3376
|
-
"i32.gt_s":
|
|
3377
|
-
"i32.gt_u":
|
|
3378
|
-
"i32.le_s":
|
|
3379
|
-
"i32.le_u":
|
|
3380
|
-
"i32.ge_s":
|
|
3381
|
-
"i32.ge_u":
|
|
3382
|
-
"i32.eqz":
|
|
3383
|
-
"i32.clz":
|
|
3384
|
-
"i32.ctz":
|
|
3385
|
-
"i32.popcnt":
|
|
3288
|
+
},
|
|
3289
|
+
"i32.eq": i32c((a, b) => a === b),
|
|
3290
|
+
"i32.ne": i32c((a, b) => a !== b),
|
|
3291
|
+
"i32.lt_s": i32c((a, b) => a < b),
|
|
3292
|
+
"i32.lt_u": u32c((a, b) => a < b),
|
|
3293
|
+
"i32.gt_s": i32c((a, b) => a > b),
|
|
3294
|
+
"i32.gt_u": u32c((a, b) => a > b),
|
|
3295
|
+
"i32.le_s": i32c((a, b) => a <= b),
|
|
3296
|
+
"i32.le_u": u32c((a, b) => a <= b),
|
|
3297
|
+
"i32.ge_s": i32c((a, b) => a >= b),
|
|
3298
|
+
"i32.ge_u": u32c((a, b) => a >= b),
|
|
3299
|
+
"i32.eqz": (a) => a === 0 ? 1 : 0,
|
|
3300
|
+
"i32.clz": (a) => Math.clz32(a),
|
|
3301
|
+
"i32.ctz": (a) => a === 0 ? 32 : 31 - Math.clz32(a & -a),
|
|
3302
|
+
"i32.popcnt": (a) => {
|
|
3386
3303
|
let c = 0;
|
|
3387
3304
|
while (a) {
|
|
3388
3305
|
c += a & 1;
|
|
3389
3306
|
a >>>= 1;
|
|
3390
3307
|
}
|
|
3391
3308
|
return c;
|
|
3392
|
-
},
|
|
3393
|
-
"i32.wrap_i64":
|
|
3394
|
-
"i32.extend8_s":
|
|
3395
|
-
"i32.extend16_s":
|
|
3309
|
+
},
|
|
3310
|
+
"i32.wrap_i64": (a) => Number(BigInt.asIntN(32, a)),
|
|
3311
|
+
"i32.extend8_s": (a) => a << 24 >> 24,
|
|
3312
|
+
"i32.extend16_s": (a) => a << 16 >> 16,
|
|
3396
3313
|
// i64 (using BigInt)
|
|
3397
|
-
"i64.add":
|
|
3398
|
-
"i64.sub":
|
|
3399
|
-
"i64.mul":
|
|
3400
|
-
"i64.div_s":
|
|
3401
|
-
"i64.div_u":
|
|
3402
|
-
"i64.rem_s":
|
|
3403
|
-
"i64.rem_u":
|
|
3404
|
-
"i64.and":
|
|
3405
|
-
"i64.or":
|
|
3406
|
-
"i64.xor":
|
|
3407
|
-
"i64.shl":
|
|
3408
|
-
"i64.shr_s":
|
|
3409
|
-
"i64.shr_u":
|
|
3410
|
-
"i64.eq":
|
|
3411
|
-
"i64.ne":
|
|
3412
|
-
"i64.lt_s":
|
|
3413
|
-
"i64.lt_u":
|
|
3414
|
-
"i64.gt_s":
|
|
3415
|
-
"i64.gt_u":
|
|
3416
|
-
"i64.le_s":
|
|
3417
|
-
"i64.le_u":
|
|
3418
|
-
"i64.ge_s":
|
|
3419
|
-
"i64.ge_u":
|
|
3420
|
-
"i64.eqz":
|
|
3421
|
-
"i64.extend_i32_s":
|
|
3422
|
-
"i64.extend_i32_u":
|
|
3423
|
-
"i64.extend8_s":
|
|
3424
|
-
"i64.extend16_s":
|
|
3425
|
-
"i64.extend32_s":
|
|
3314
|
+
"i64.add": (a, b) => BigInt.asIntN(64, a + b),
|
|
3315
|
+
"i64.sub": (a, b) => BigInt.asIntN(64, a - b),
|
|
3316
|
+
"i64.mul": (a, b) => BigInt.asIntN(64, a * b),
|
|
3317
|
+
"i64.div_s": (a, b) => b !== 0n ? BigInt.asIntN(64, a / b) : null,
|
|
3318
|
+
"i64.div_u": (a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b)) : null,
|
|
3319
|
+
"i64.rem_s": (a, b) => b !== 0n ? BigInt.asIntN(64, a % b) : null,
|
|
3320
|
+
"i64.rem_u": (a, b) => b !== 0n ? BigInt.asUintN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b)) : null,
|
|
3321
|
+
"i64.and": (a, b) => BigInt.asIntN(64, a & b),
|
|
3322
|
+
"i64.or": (a, b) => BigInt.asIntN(64, a | b),
|
|
3323
|
+
"i64.xor": (a, b) => BigInt.asIntN(64, a ^ b),
|
|
3324
|
+
"i64.shl": (a, b) => BigInt.asIntN(64, a << (b & 63n)),
|
|
3325
|
+
"i64.shr_s": (a, b) => BigInt.asIntN(64, a >> (b & 63n)),
|
|
3326
|
+
"i64.shr_u": (a, b) => BigInt.asUintN(64, BigInt.asUintN(64, a) >> (b & 63n)),
|
|
3327
|
+
"i64.eq": i64c((a, b) => a === b),
|
|
3328
|
+
"i64.ne": i64c((a, b) => a !== b),
|
|
3329
|
+
"i64.lt_s": i64c((a, b) => a < b),
|
|
3330
|
+
"i64.lt_u": u64c((a, b) => a < b),
|
|
3331
|
+
"i64.gt_s": i64c((a, b) => a > b),
|
|
3332
|
+
"i64.gt_u": u64c((a, b) => a > b),
|
|
3333
|
+
"i64.le_s": i64c((a, b) => a <= b),
|
|
3334
|
+
"i64.le_u": u64c((a, b) => a <= b),
|
|
3335
|
+
"i64.ge_s": i64c((a, b) => a >= b),
|
|
3336
|
+
"i64.ge_u": u64c((a, b) => a >= b),
|
|
3337
|
+
"i64.eqz": (a) => a === 0n ? 1 : 0,
|
|
3338
|
+
"i64.extend_i32_s": (a) => BigInt(a),
|
|
3339
|
+
"i64.extend_i32_u": (a) => BigInt(a >>> 0),
|
|
3340
|
+
"i64.extend8_s": (a) => BigInt.asIntN(64, BigInt.asIntN(8, a)),
|
|
3341
|
+
"i64.extend16_s": (a) => BigInt.asIntN(64, BigInt.asIntN(16, a)),
|
|
3342
|
+
"i64.extend32_s": (a) => BigInt.asIntN(64, BigInt.asIntN(32, a)),
|
|
3426
3343
|
// f32/f64 (NaN/precision-aware via Math.fround)
|
|
3427
|
-
"f32.add":
|
|
3428
|
-
"f32.sub":
|
|
3429
|
-
"f32.mul":
|
|
3430
|
-
"f32.div":
|
|
3431
|
-
"f32.neg":
|
|
3432
|
-
"f32.abs":
|
|
3433
|
-
"f32.sqrt":
|
|
3434
|
-
"f32.ceil":
|
|
3435
|
-
"f32.floor":
|
|
3436
|
-
"f32.trunc":
|
|
3437
|
-
"f32.nearest":
|
|
3438
|
-
"f64.add":
|
|
3439
|
-
"f64.sub":
|
|
3440
|
-
"f64.mul":
|
|
3441
|
-
"f64.div":
|
|
3442
|
-
"f64.neg":
|
|
3443
|
-
"f64.abs":
|
|
3444
|
-
"f64.sqrt":
|
|
3445
|
-
"f64.ceil":
|
|
3446
|
-
"f64.floor":
|
|
3447
|
-
"f64.trunc":
|
|
3448
|
-
"f64.nearest":
|
|
3344
|
+
"f32.add": (a, b) => Math.fround(a + b),
|
|
3345
|
+
"f32.sub": (a, b) => Math.fround(a - b),
|
|
3346
|
+
"f32.mul": (a, b) => Math.fround(a * b),
|
|
3347
|
+
"f32.div": (a, b) => Math.fround(a / b),
|
|
3348
|
+
"f32.neg": (a) => Math.fround(-a),
|
|
3349
|
+
"f32.abs": (a) => Math.fround(Math.abs(a)),
|
|
3350
|
+
"f32.sqrt": (a) => Math.fround(Math.sqrt(a)),
|
|
3351
|
+
"f32.ceil": (a) => Math.fround(Math.ceil(a)),
|
|
3352
|
+
"f32.floor": (a) => Math.fround(Math.floor(a)),
|
|
3353
|
+
"f32.trunc": (a) => Math.fround(Math.trunc(a)),
|
|
3354
|
+
"f32.nearest": (a) => Math.fround(roundEven(a)),
|
|
3355
|
+
"f64.add": (a, b) => a + b,
|
|
3356
|
+
"f64.sub": (a, b) => a - b,
|
|
3357
|
+
"f64.mul": (a, b) => a * b,
|
|
3358
|
+
"f64.div": (a, b) => a / b,
|
|
3359
|
+
"f64.neg": (a) => -a,
|
|
3360
|
+
"f64.abs": Math.abs,
|
|
3361
|
+
"f64.sqrt": Math.sqrt,
|
|
3362
|
+
"f64.ceil": Math.ceil,
|
|
3363
|
+
"f64.floor": Math.floor,
|
|
3364
|
+
"f64.trunc": Math.trunc,
|
|
3365
|
+
"f64.nearest": roundEven,
|
|
3449
3366
|
// Bit-exact reinterprets (preserve NaN payloads)
|
|
3450
|
-
"i32.reinterpret_f32":
|
|
3451
|
-
"f32.reinterpret_i32":
|
|
3452
|
-
"i64.reinterpret_f64":
|
|
3453
|
-
"f64.reinterpret_i64":
|
|
3367
|
+
"i32.reinterpret_f32": i32FromF32,
|
|
3368
|
+
"f32.reinterpret_i32": f32FromI32,
|
|
3369
|
+
"i64.reinterpret_f64": i64FromF64,
|
|
3370
|
+
"f64.reinterpret_i64": f64FromI64,
|
|
3454
3371
|
// Numeric conversions (value-preserving where representable)
|
|
3455
|
-
"f32.convert_i32_s":
|
|
3456
|
-
"f32.convert_i32_u":
|
|
3457
|
-
"f32.convert_i64_s":
|
|
3458
|
-
"f32.convert_i64_u":
|
|
3459
|
-
"f64.convert_i32_s":
|
|
3460
|
-
"f64.convert_i32_u":
|
|
3461
|
-
"f64.convert_i64_s":
|
|
3462
|
-
"f64.convert_i64_u":
|
|
3463
|
-
"f32.demote_f64":
|
|
3464
|
-
"f64.promote_f32":
|
|
3372
|
+
"f32.convert_i32_s": (a) => Math.fround(a | 0),
|
|
3373
|
+
"f32.convert_i32_u": (a) => Math.fround(a >>> 0),
|
|
3374
|
+
"f32.convert_i64_s": (a) => Math.fround(Number(BigInt.asIntN(64, a))),
|
|
3375
|
+
"f32.convert_i64_u": (a) => Math.fround(Number(BigInt.asUintN(64, a))),
|
|
3376
|
+
"f64.convert_i32_s": (a) => a | 0,
|
|
3377
|
+
"f64.convert_i32_u": (a) => a >>> 0,
|
|
3378
|
+
"f64.convert_i64_s": (a) => Number(BigInt.asIntN(64, a)),
|
|
3379
|
+
"f64.convert_i64_u": (a) => Number(BigInt.asUintN(64, a)),
|
|
3380
|
+
"f32.demote_f64": (a) => Math.fround(a),
|
|
3381
|
+
"f64.promote_f32": (a) => Math.fround(a)
|
|
3465
3382
|
};
|
|
3466
3383
|
var _parseNanF64 = (s, i = s?.indexOf?.("nan")) => {
|
|
3467
3384
|
if (i < 0 || i == null) return null;
|
|
@@ -3478,8 +3395,8 @@ var _parseNanF32 = (s, i = s?.indexOf?.("nan")) => {
|
|
|
3478
3395
|
var getConst = (node) => {
|
|
3479
3396
|
if (!Array.isArray(node) || node.length !== 2) return null;
|
|
3480
3397
|
const [op, val] = node;
|
|
3481
|
-
if (op === "i32.const") return { type: "i32", value:
|
|
3482
|
-
if (op === "i64.const") return { type: "i64", value: BigInt(val) };
|
|
3398
|
+
if (op === "i32.const") return { type: "i32", value: (typeof val === "string" ? i32.parse(val) : val) | 0 };
|
|
3399
|
+
if (op === "i64.const") return { type: "i64", value: typeof val === "string" ? i64.parse(val) : BigInt(val) };
|
|
3483
3400
|
if (op === "f32.const") {
|
|
3484
3401
|
const n = _parseNanF32(val);
|
|
3485
3402
|
return { type: "f32", value: n !== null ? n : Math.fround(Number(val)) };
|
|
@@ -3498,24 +3415,23 @@ var makeConst = (type, value) => {
|
|
|
3498
3415
|
return null;
|
|
3499
3416
|
};
|
|
3500
3417
|
var fold = (ast) => {
|
|
3501
|
-
return
|
|
3418
|
+
return walkPost(ast, (node) => {
|
|
3502
3419
|
if (!Array.isArray(node)) return;
|
|
3503
|
-
const
|
|
3504
|
-
if (!
|
|
3505
|
-
const [fn, t] = entry;
|
|
3420
|
+
const fn = FOLDABLE[node[0]];
|
|
3421
|
+
if (!fn) return;
|
|
3506
3422
|
if (fn.length === 1 && node.length === 2) {
|
|
3507
3423
|
const a = getConst(node[1]);
|
|
3508
3424
|
if (!a) return;
|
|
3509
3425
|
const r = fn(a.value);
|
|
3510
3426
|
if (r === null) return;
|
|
3511
|
-
return makeConst(
|
|
3427
|
+
return makeConst(resultType(node[0]), r);
|
|
3512
3428
|
}
|
|
3513
3429
|
if (fn.length === 2 && node.length === 3) {
|
|
3514
3430
|
const a = getConst(node[1]), b = getConst(node[2]);
|
|
3515
3431
|
if (!a || !b) return;
|
|
3516
3432
|
const r = fn(a.value, b.value);
|
|
3517
3433
|
if (r === null) return;
|
|
3518
|
-
return makeConst(
|
|
3434
|
+
return makeConst(resultType(node[0]), r);
|
|
3519
3435
|
}
|
|
3520
3436
|
});
|
|
3521
3437
|
};
|
|
@@ -3561,7 +3477,7 @@ var IDENTITIES = {
|
|
|
3561
3477
|
// f * 1 → x (careful with NaN, skip for floats)
|
|
3562
3478
|
};
|
|
3563
3479
|
var identity = (ast) => {
|
|
3564
|
-
return
|
|
3480
|
+
return walkPost(ast, (node) => {
|
|
3565
3481
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
3566
3482
|
const fn = IDENTITIES[node[0]];
|
|
3567
3483
|
if (!fn) return;
|
|
@@ -3571,7 +3487,7 @@ var identity = (ast) => {
|
|
|
3571
3487
|
});
|
|
3572
3488
|
};
|
|
3573
3489
|
var strength = (ast) => {
|
|
3574
|
-
return
|
|
3490
|
+
return walkPost(ast, (node) => {
|
|
3575
3491
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
3576
3492
|
const [op, a, b] = node;
|
|
3577
3493
|
if (op === "i32.mul") {
|
|
@@ -3627,7 +3543,7 @@ var strength = (ast) => {
|
|
|
3627
3543
|
});
|
|
3628
3544
|
};
|
|
3629
3545
|
var branch = (ast) => {
|
|
3630
|
-
return
|
|
3546
|
+
return walkPost(ast, (node) => {
|
|
3631
3547
|
if (!Array.isArray(node)) return;
|
|
3632
3548
|
const op = node[0];
|
|
3633
3549
|
if (op === "if") {
|
|
@@ -3659,7 +3575,7 @@ var branch = (ast) => {
|
|
|
3659
3575
|
};
|
|
3660
3576
|
var TERMINATORS = /* @__PURE__ */ new Set(["unreachable", "return", "br", "br_table"]);
|
|
3661
3577
|
var deadcode = (ast) => {
|
|
3662
|
-
|
|
3578
|
+
walk(ast, (node) => {
|
|
3663
3579
|
if (!Array.isArray(node)) return;
|
|
3664
3580
|
const kind = node[0];
|
|
3665
3581
|
if (kind === "func" || kind === "block" || kind === "loop") {
|
|
@@ -3705,7 +3621,7 @@ var eliminateDeadInBlock = (block) => {
|
|
|
3705
3621
|
}
|
|
3706
3622
|
};
|
|
3707
3623
|
var localReuse = (ast) => {
|
|
3708
|
-
|
|
3624
|
+
walk(ast, (node) => {
|
|
3709
3625
|
if (!Array.isArray(node) || node[0] !== "func") return;
|
|
3710
3626
|
const localDecls = [];
|
|
3711
3627
|
const localTypes = /* @__PURE__ */ new Map();
|
|
@@ -3726,7 +3642,7 @@ var localReuse = (ast) => {
|
|
|
3726
3642
|
}
|
|
3727
3643
|
}
|
|
3728
3644
|
}
|
|
3729
|
-
|
|
3645
|
+
walk(node, (n) => {
|
|
3730
3646
|
if (!Array.isArray(n)) return;
|
|
3731
3647
|
const op = n[0];
|
|
3732
3648
|
if (op === "local.get" || op === "local.set" || op === "local.tee") {
|
|
@@ -3799,7 +3715,7 @@ var countLocalUses = (node) => {
|
|
|
3799
3715
|
if (!counts.has(name2)) counts.set(name2, { gets: 0, sets: 0, tees: 0 });
|
|
3800
3716
|
return counts.get(name2);
|
|
3801
3717
|
};
|
|
3802
|
-
|
|
3718
|
+
walk(node, (n) => {
|
|
3803
3719
|
if (!Array.isArray(n) || n.length < 2 || typeof n[1] !== "string") return;
|
|
3804
3720
|
if (n[0] === "local.get") ensure(n[1]).gets++;
|
|
3805
3721
|
else if (n[0] === "local.set") ensure(n[1]).sets++;
|
|
@@ -3824,7 +3740,7 @@ var canSubst = (k) => k.pure && k.singleUse || isTinyConst(k.val);
|
|
|
3824
3740
|
var purgeRefs = (known, name2) => {
|
|
3825
3741
|
for (const [key, tracked] of known) {
|
|
3826
3742
|
let refs = false;
|
|
3827
|
-
|
|
3743
|
+
walk(tracked.val, (n) => {
|
|
3828
3744
|
if (Array.isArray(n) && (n[0] === "local.get" || n[0] === "local.tee") && n[1] === name2) refs = true;
|
|
3829
3745
|
});
|
|
3830
3746
|
if (refs) known.delete(key);
|
|
@@ -3854,13 +3770,13 @@ var substGets = (node, known) => {
|
|
|
3854
3770
|
const op = node[0];
|
|
3855
3771
|
if (op === "local.get" && node.length === 2) {
|
|
3856
3772
|
const k = typeof node[1] === "string" && known.get(node[1]);
|
|
3857
|
-
if (k && canSubst(k)) return
|
|
3773
|
+
if (k && canSubst(k)) return clone(k.val);
|
|
3858
3774
|
return node;
|
|
3859
3775
|
}
|
|
3860
3776
|
let inner = known;
|
|
3861
3777
|
if (op === "block" || op === "loop" || op === "if") {
|
|
3862
3778
|
let cloned = null;
|
|
3863
|
-
|
|
3779
|
+
walk(node, (n) => {
|
|
3864
3780
|
if (!Array.isArray(n)) return;
|
|
3865
3781
|
if ((n[0] === "local.set" || n[0] === "local.tee") && typeof n[1] === "string" && known.has(n[1])) {
|
|
3866
3782
|
if (!cloned) cloned = new Map(known);
|
|
@@ -3873,7 +3789,7 @@ var substGets = (node, known) => {
|
|
|
3873
3789
|
const r = substGets(node[i], inner);
|
|
3874
3790
|
if (r !== node[i]) node[i] = r;
|
|
3875
3791
|
if (i + 1 < node.length && Array.isArray(node[i])) {
|
|
3876
|
-
|
|
3792
|
+
walk(node[i], (n) => {
|
|
3877
3793
|
if (!Array.isArray(n)) return;
|
|
3878
3794
|
if ((n[0] === "local.set" || n[0] === "local.tee") && typeof n[1] === "string") {
|
|
3879
3795
|
if (inner === known) inner = new Map(known);
|
|
@@ -3920,7 +3836,7 @@ var forwardPropagate = (funcNode, params, useCounts) => {
|
|
|
3920
3836
|
if (op === "local.get" && instr2.length === 2 && typeof instr2[1] === "string") {
|
|
3921
3837
|
const tracked = known.get(instr2[1]);
|
|
3922
3838
|
if (tracked && canSubst(tracked)) {
|
|
3923
|
-
const replacement =
|
|
3839
|
+
const replacement = clone(tracked.val);
|
|
3924
3840
|
instr2.length = 0;
|
|
3925
3841
|
instr2.push(...Array.isArray(replacement) ? replacement : [replacement]);
|
|
3926
3842
|
changed = true;
|
|
@@ -3928,10 +3844,10 @@ var forwardPropagate = (funcNode, params, useCounts) => {
|
|
|
3928
3844
|
}
|
|
3929
3845
|
}
|
|
3930
3846
|
if (op !== "block" && op !== "loop" && op !== "if") {
|
|
3931
|
-
const prev =
|
|
3847
|
+
const prev = clone(instr2);
|
|
3932
3848
|
substGets(instr2, known);
|
|
3933
3849
|
if (!equal(prev, instr2)) changed = true;
|
|
3934
|
-
|
|
3850
|
+
walk(instr2, (n) => {
|
|
3935
3851
|
if (Array.isArray(n) && (n[0] === "local.set" || n[0] === "local.tee") && typeof n[1] === "string") {
|
|
3936
3852
|
known.delete(n[1]);
|
|
3937
3853
|
purgeRefs(known, n[1]);
|
|
@@ -3955,7 +3871,7 @@ var eliminateSetGetPairs = (funcNode, params, useCounts) => {
|
|
|
3955
3871
|
if (getNode[1] !== name2 || params.has(name2)) continue;
|
|
3956
3872
|
const uses = useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3957
3873
|
if (uses.sets !== 1 || uses.gets !== 1 || uses.tees !== 0) continue;
|
|
3958
|
-
const expr2 =
|
|
3874
|
+
const expr2 = clone(setNode[2]);
|
|
3959
3875
|
funcNode.splice(i, 2, ...Array.isArray(expr2) ? [expr2] : [expr2]);
|
|
3960
3876
|
changed = true;
|
|
3961
3877
|
i--;
|
|
@@ -3973,7 +3889,7 @@ var createLocalTees = (funcNode, params, useCounts) => {
|
|
|
3973
3889
|
if (getNode[1] !== name2 || params.has(name2)) continue;
|
|
3974
3890
|
const uses = useCounts.get(name2) || { gets: 0, sets: 0, tees: 0 };
|
|
3975
3891
|
if (uses.sets + uses.gets + uses.tees <= 2) continue;
|
|
3976
|
-
funcNode.splice(i, 2, ["local.tee", name2,
|
|
3892
|
+
funcNode.splice(i, 2, ["local.tee", name2, clone(setNode[2])]);
|
|
3977
3893
|
changed = true;
|
|
3978
3894
|
}
|
|
3979
3895
|
return changed;
|
|
@@ -4006,13 +3922,13 @@ var eliminateDeadStores = (funcNode, params, useCounts) => {
|
|
|
4006
3922
|
};
|
|
4007
3923
|
var isScopeNode = (n) => Array.isArray(n) && (n[0] === "func" || n[0] === "block" || n[0] === "loop" || n[0] === "then" || n[0] === "else");
|
|
4008
3924
|
var propagate = (ast) => {
|
|
4009
|
-
|
|
3925
|
+
walk(ast, (funcNode) => {
|
|
4010
3926
|
if (!Array.isArray(funcNode) || funcNode[0] !== "func") return;
|
|
4011
3927
|
const params = /* @__PURE__ */ new Set();
|
|
4012
3928
|
for (const sub of funcNode)
|
|
4013
3929
|
if (Array.isArray(sub) && sub[0] === "param" && typeof sub[1] === "string") params.add(sub[1]);
|
|
4014
3930
|
const scopes = [];
|
|
4015
|
-
|
|
3931
|
+
walkPost(funcNode, (n) => {
|
|
4016
3932
|
if (isScopeNode(n)) scopes.push(n);
|
|
4017
3933
|
});
|
|
4018
3934
|
for (let round = 0; round < 6; round++) {
|
|
@@ -4062,7 +3978,7 @@ var inline = (ast) => {
|
|
|
4062
3978
|
const paramNames = new Set(params.map((p) => p.name));
|
|
4063
3979
|
let mutatesParam = false;
|
|
4064
3980
|
let hasReturn = false;
|
|
4065
|
-
|
|
3981
|
+
walk(body[0], (n) => {
|
|
4066
3982
|
if (!Array.isArray(n)) return;
|
|
4067
3983
|
if ((n[0] === "local.set" || n[0] === "local.tee") && paramNames.has(n[1])) {
|
|
4068
3984
|
mutatesParam = true;
|
|
@@ -4077,22 +3993,21 @@ var inline = (ast) => {
|
|
|
4077
3993
|
}
|
|
4078
3994
|
}
|
|
4079
3995
|
if (inlinable.size === 0) return ast;
|
|
4080
|
-
|
|
3996
|
+
walkPost(ast, (node) => {
|
|
4081
3997
|
if (!Array.isArray(node) || node[0] !== "call") return;
|
|
4082
3998
|
const fname = node[1];
|
|
4083
3999
|
if (!inlinable.has(fname)) return;
|
|
4084
4000
|
const { body, params } = inlinable.get(fname);
|
|
4085
4001
|
const args = node.slice(2);
|
|
4086
4002
|
if (params.length === 0) {
|
|
4087
|
-
return
|
|
4003
|
+
return clone(body);
|
|
4088
4004
|
}
|
|
4089
|
-
const substituted =
|
|
4090
|
-
walkPost2(substituted, (n) => {
|
|
4005
|
+
const substituted = walkPost(clone(body), (n) => {
|
|
4091
4006
|
if (!Array.isArray(n) || n[0] !== "local.get") return;
|
|
4092
4007
|
const local = n[1];
|
|
4093
4008
|
const paramIdx = params.findIndex((p) => p.name === local);
|
|
4094
4009
|
if (paramIdx !== -1 && args[paramIdx]) {
|
|
4095
|
-
return
|
|
4010
|
+
return clone(args[paramIdx]);
|
|
4096
4011
|
}
|
|
4097
4012
|
});
|
|
4098
4013
|
return substituted;
|
|
@@ -4231,13 +4146,13 @@ var inlineOnce = (ast) => {
|
|
|
4231
4146
|
if (!calleeName) break;
|
|
4232
4147
|
const callee = funcByName.get(calleeName);
|
|
4233
4148
|
const params = [], locals = [];
|
|
4234
|
-
let
|
|
4149
|
+
let inlResult = null;
|
|
4235
4150
|
for (let i = 2; i < callee.length; i++) {
|
|
4236
4151
|
const c = callee[i];
|
|
4237
4152
|
if (typeof c === "string" || !Array.isArray(c)) continue;
|
|
4238
4153
|
if (c[0] === "param") params.push({ name: c[1], type: c[2] });
|
|
4239
4154
|
else if (c[0] === "result") {
|
|
4240
|
-
if (c.length > 1)
|
|
4155
|
+
if (c.length > 1) inlResult = c[1];
|
|
4241
4156
|
} else if (c[0] === "local") locals.push({ name: c[1], type: c[2] });
|
|
4242
4157
|
else if (c[0] === "export" || c[0] === "type") continue;
|
|
4243
4158
|
else break;
|
|
@@ -4273,7 +4188,7 @@ var inlineOnce = (ast) => {
|
|
|
4273
4188
|
if (fn === callee || done) continue;
|
|
4274
4189
|
const start = bodyStart(fn);
|
|
4275
4190
|
for (let i = start; i < fn.length; i++) {
|
|
4276
|
-
const replaced =
|
|
4191
|
+
const replaced = walkPost(fn[i], (n) => {
|
|
4277
4192
|
if (done || !Array.isArray(n) || n[0] !== "call" || n[1] !== calleeName) return;
|
|
4278
4193
|
const args = n.slice(2);
|
|
4279
4194
|
if (args.length !== params.length) return;
|
|
@@ -4281,7 +4196,7 @@ var inlineOnce = (ast) => {
|
|
|
4281
4196
|
const resets = locals.filter((l) => needsReset(cBody, l.name)).map((l) => ["local.set", rename.get(l.name), zeroFor(l.type)]);
|
|
4282
4197
|
const inner = cBody.map(sub);
|
|
4283
4198
|
done = true;
|
|
4284
|
-
return
|
|
4199
|
+
return inlResult ? ["block", exit, ["result", inlResult], ...setup, ...resets, ...inner] : ["block", exit, ...setup, ...resets, ...inner];
|
|
4285
4200
|
});
|
|
4286
4201
|
if (replaced !== fn[i]) fn[i] = replaced;
|
|
4287
4202
|
if (done) {
|
|
@@ -4338,7 +4253,7 @@ var targetsLabel = (body, label) => {
|
|
|
4338
4253
|
return found;
|
|
4339
4254
|
};
|
|
4340
4255
|
var mergeBlocks = (ast) => {
|
|
4341
|
-
|
|
4256
|
+
walkPost(ast, (node) => {
|
|
4342
4257
|
if (!Array.isArray(node) || node[0] !== "block") return;
|
|
4343
4258
|
let bi = 1, label = null;
|
|
4344
4259
|
if (typeof node[1] === "string" && node[1][0] === "$") {
|
|
@@ -4367,7 +4282,7 @@ var mergeBlocks = (ast) => {
|
|
|
4367
4282
|
node.length = 0;
|
|
4368
4283
|
for (const tok of only) node.push(tok);
|
|
4369
4284
|
});
|
|
4370
|
-
|
|
4285
|
+
walk(ast, (node) => {
|
|
4371
4286
|
if (!isScopeNode(node)) return;
|
|
4372
4287
|
let i = 1;
|
|
4373
4288
|
while (i < node.length) {
|
|
@@ -4441,7 +4356,7 @@ var mergeBlocks = (ast) => {
|
|
|
4441
4356
|
return ast;
|
|
4442
4357
|
};
|
|
4443
4358
|
var coalesceLocals = (ast) => {
|
|
4444
|
-
|
|
4359
|
+
walk(ast, (funcNode) => {
|
|
4445
4360
|
if (!Array.isArray(funcNode) || funcNode[0] !== "func") return;
|
|
4446
4361
|
const decls = /* @__PURE__ */ new Map();
|
|
4447
4362
|
for (const sub of funcNode) {
|
|
@@ -4513,7 +4428,7 @@ var coalesceLocals = (ast) => {
|
|
|
4513
4428
|
} else slots.push({ primary: name2, type, end: range.end });
|
|
4514
4429
|
}
|
|
4515
4430
|
if (rename.size === 0) return;
|
|
4516
|
-
|
|
4431
|
+
walk(funcNode, (n) => {
|
|
4517
4432
|
if (Array.isArray(n) && (n[0] === "local.get" || n[0] === "local.set" || n[0] === "local.tee") && rename.has(n[1])) {
|
|
4518
4433
|
n[1] = rename.get(n[1]);
|
|
4519
4434
|
}
|
|
@@ -4522,7 +4437,7 @@ var coalesceLocals = (ast) => {
|
|
|
4522
4437
|
return ast;
|
|
4523
4438
|
};
|
|
4524
4439
|
var vacuum = (ast) => {
|
|
4525
|
-
return
|
|
4440
|
+
return walkPost(ast, (node) => {
|
|
4526
4441
|
if (!Array.isArray(node)) return;
|
|
4527
4442
|
const op = node[0];
|
|
4528
4443
|
if (op === "nop") return ["nop"];
|
|
@@ -4562,10 +4477,6 @@ var PEEPHOLE = {
|
|
|
4562
4477
|
"i64.sub": (a, b) => equal(a, b) ? ["i64.const", 0n] : null,
|
|
4563
4478
|
"i32.xor": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
4564
4479
|
"i64.xor": (a, b) => equal(a, b) ? ["i64.const", 0n] : null,
|
|
4565
|
-
"i32.and": (a, b) => equal(a, b) ? a : null,
|
|
4566
|
-
"i64.and": (a, b) => equal(a, b) ? a : null,
|
|
4567
|
-
"i32.or": (a, b) => equal(a, b) ? a : null,
|
|
4568
|
-
"i64.or": (a, b) => equal(a, b) ? a : null,
|
|
4569
4480
|
"i32.eq": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
4570
4481
|
"i64.eq": (a, b) => equal(a, b) ? ["i32.const", 1] : null,
|
|
4571
4482
|
"i32.ne": (a, b) => equal(a, b) ? ["i32.const", 0] : null,
|
|
@@ -4598,21 +4509,25 @@ var PEEPHOLE = {
|
|
|
4598
4509
|
return null;
|
|
4599
4510
|
},
|
|
4600
4511
|
"i32.and": (a, b) => {
|
|
4512
|
+
if (equal(a, b)) return a;
|
|
4601
4513
|
const ca = getConst(a), cb = getConst(b);
|
|
4602
4514
|
if (ca?.value === 0 || cb?.value === 0) return ["i32.const", 0];
|
|
4603
4515
|
return null;
|
|
4604
4516
|
},
|
|
4605
4517
|
"i64.and": (a, b) => {
|
|
4518
|
+
if (equal(a, b)) return a;
|
|
4606
4519
|
const ca = getConst(a), cb = getConst(b);
|
|
4607
4520
|
if (ca?.value === 0n || cb?.value === 0n) return ["i64.const", 0n];
|
|
4608
4521
|
return null;
|
|
4609
4522
|
},
|
|
4610
4523
|
"i32.or": (a, b) => {
|
|
4524
|
+
if (equal(a, b)) return a;
|
|
4611
4525
|
const ca = getConst(a), cb = getConst(b);
|
|
4612
4526
|
if (ca?.value === -1 || cb?.value === -1) return ["i32.const", -1];
|
|
4613
4527
|
return null;
|
|
4614
4528
|
},
|
|
4615
4529
|
"i64.or": (a, b) => {
|
|
4530
|
+
if (equal(a, b)) return a;
|
|
4616
4531
|
const ca = getConst(a), cb = getConst(b);
|
|
4617
4532
|
if (ca?.value === -1n || cb?.value === -1n) return ["i64.const", -1n];
|
|
4618
4533
|
return null;
|
|
@@ -4621,7 +4536,7 @@ var PEEPHOLE = {
|
|
|
4621
4536
|
"local.set": (a, b) => Array.isArray(b) && b[0] === "local.get" && b[1] === a ? ["nop"] : null
|
|
4622
4537
|
};
|
|
4623
4538
|
var peephole = (ast) => {
|
|
4624
|
-
return
|
|
4539
|
+
return walkPost(ast, (node) => {
|
|
4625
4540
|
if (!Array.isArray(node) || node.length !== 3) return;
|
|
4626
4541
|
const fn = PEEPHOLE[node[0]];
|
|
4627
4542
|
if (!fn) return;
|
|
@@ -4678,7 +4593,7 @@ var globals = (ast) => {
|
|
|
4678
4593
|
}
|
|
4679
4594
|
if (constGlobals.size === 0) return ast;
|
|
4680
4595
|
const reads = /* @__PURE__ */ new Map();
|
|
4681
|
-
|
|
4596
|
+
walk(ast, (n) => {
|
|
4682
4597
|
if (!Array.isArray(n)) return;
|
|
4683
4598
|
const ref = n[1];
|
|
4684
4599
|
if (typeof ref !== "string" || ref[0] !== "$") return;
|
|
@@ -4696,9 +4611,9 @@ var globals = (ast) => {
|
|
|
4696
4611
|
if (after <= before) propagate2.add(name2);
|
|
4697
4612
|
}
|
|
4698
4613
|
if (propagate2.size === 0) return ast;
|
|
4699
|
-
|
|
4614
|
+
walkPost(ast, (node) => {
|
|
4700
4615
|
if (!Array.isArray(node) || node[0] !== "global.get" || node.length !== 2) return;
|
|
4701
|
-
if (propagate2.has(node[1])) return
|
|
4616
|
+
if (propagate2.has(node[1])) return clone(constGlobals.get(node[1]));
|
|
4702
4617
|
});
|
|
4703
4618
|
for (let i = ast.length - 1; i >= 1; i--) {
|
|
4704
4619
|
const n = ast[i];
|
|
@@ -4707,7 +4622,7 @@ var globals = (ast) => {
|
|
|
4707
4622
|
return ast;
|
|
4708
4623
|
};
|
|
4709
4624
|
var offset = (ast) => {
|
|
4710
|
-
return
|
|
4625
|
+
return walkPost(ast, (node) => {
|
|
4711
4626
|
if (!Array.isArray(node)) return;
|
|
4712
4627
|
const op = node[0];
|
|
4713
4628
|
if (typeof op !== "string" || !op.endsWith("load") && !op.endsWith("store")) return;
|
|
@@ -4758,7 +4673,7 @@ var offset = (ast) => {
|
|
|
4758
4673
|
});
|
|
4759
4674
|
};
|
|
4760
4675
|
var unbranch = (ast) => {
|
|
4761
|
-
|
|
4676
|
+
walk(ast, (node) => {
|
|
4762
4677
|
if (!Array.isArray(node)) return;
|
|
4763
4678
|
const op = node[0];
|
|
4764
4679
|
if (op !== "block") return;
|
|
@@ -4790,7 +4705,7 @@ var unbranch = (ast) => {
|
|
|
4790
4705
|
return ast;
|
|
4791
4706
|
};
|
|
4792
4707
|
var loopify = (ast) => {
|
|
4793
|
-
|
|
4708
|
+
walk(ast, (node) => {
|
|
4794
4709
|
if (!Array.isArray(node) || node[0] !== "block") return;
|
|
4795
4710
|
let bi = 1, label = null;
|
|
4796
4711
|
if (typeof node[1] === "string" && node[1][0] === "$") {
|
|
@@ -4849,10 +4764,10 @@ var loopify = (ast) => {
|
|
|
4849
4764
|
var stripmut = (ast) => {
|
|
4850
4765
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
4851
4766
|
const written = /* @__PURE__ */ new Set();
|
|
4852
|
-
|
|
4767
|
+
walk(ast, (n) => {
|
|
4853
4768
|
if (Array.isArray(n) && n[0] === "global.set" && typeof n[1] === "string") written.add(n[1]);
|
|
4854
4769
|
});
|
|
4855
|
-
return
|
|
4770
|
+
return walkPost(ast, (node) => {
|
|
4856
4771
|
if (!Array.isArray(node) || node[0] !== "global") return;
|
|
4857
4772
|
const name2 = typeof node[1] === "string" && node[1][0] === "$" ? node[1] : null;
|
|
4858
4773
|
if (!name2 || written.has(name2)) return;
|
|
@@ -4866,7 +4781,7 @@ var stripmut = (ast) => {
|
|
|
4866
4781
|
});
|
|
4867
4782
|
};
|
|
4868
4783
|
var brif = (ast) => {
|
|
4869
|
-
return
|
|
4784
|
+
return walkPost(ast, (node) => {
|
|
4870
4785
|
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
4871
4786
|
const { cond, thenBranch, elseBranch } = parseIf(node);
|
|
4872
4787
|
const thenEmpty = !thenBranch || thenBranch.length <= 1;
|
|
@@ -4882,7 +4797,7 @@ var brif = (ast) => {
|
|
|
4882
4797
|
});
|
|
4883
4798
|
};
|
|
4884
4799
|
var foldarms = (ast) => {
|
|
4885
|
-
return
|
|
4800
|
+
return walkPost(ast, (node) => {
|
|
4886
4801
|
if (!Array.isArray(node) || node[0] !== "if") return;
|
|
4887
4802
|
const { thenBranch, elseBranch } = parseIf(node);
|
|
4888
4803
|
if (!thenBranch || !elseBranch) return;
|
|
@@ -4955,7 +4870,7 @@ var dedupe = (ast) => {
|
|
|
4955
4870
|
if (!name2) continue;
|
|
4956
4871
|
const localNames = /* @__PURE__ */ new Set();
|
|
4957
4872
|
if (typeof node[1] === "string" && node[1][0] === "$") localNames.add(node[1]);
|
|
4958
|
-
|
|
4873
|
+
walk(node, (n) => {
|
|
4959
4874
|
if (!Array.isArray(n) || typeof n[1] !== "string" || n[1][0] !== "$") return;
|
|
4960
4875
|
const op = n[0];
|
|
4961
4876
|
if (op === "param" || op === "local" || op === "block" || op === "loop" || op === "if") {
|
|
@@ -4970,7 +4885,7 @@ var dedupe = (ast) => {
|
|
|
4970
4885
|
}
|
|
4971
4886
|
}
|
|
4972
4887
|
if (redirects.size === 0) return ast;
|
|
4973
|
-
|
|
4888
|
+
walkPost(ast, (node) => {
|
|
4974
4889
|
if (!Array.isArray(node)) return;
|
|
4975
4890
|
const op = node[0];
|
|
4976
4891
|
if ((op === "call" || op === "return_call") && redirects.has(node[1])) {
|
|
@@ -5017,7 +4932,7 @@ var dedupTypes = (ast) => {
|
|
|
5017
4932
|
if (name2 && redirects.has(name2)) ast.splice(i, 1);
|
|
5018
4933
|
}
|
|
5019
4934
|
}
|
|
5020
|
-
|
|
4935
|
+
walkPost(ast, (node) => {
|
|
5021
4936
|
if (!Array.isArray(node)) return;
|
|
5022
4937
|
const op = node[0];
|
|
5023
4938
|
if (op === "func") {
|
|
@@ -5244,7 +5159,7 @@ var minifyImports = (ast) => {
|
|
|
5244
5159
|
};
|
|
5245
5160
|
var reorderSafe = (ast) => {
|
|
5246
5161
|
let safe = true;
|
|
5247
|
-
|
|
5162
|
+
walk(ast, (n) => {
|
|
5248
5163
|
if (!safe || !Array.isArray(n)) return;
|
|
5249
5164
|
const op = n[0];
|
|
5250
5165
|
if (op === "func" && (typeof n[1] !== "string" || n[1][0] !== "$")) safe = false;
|
|
@@ -5269,7 +5184,7 @@ var reorder = (ast) => {
|
|
|
5269
5184
|
if (!Array.isArray(ast) || ast[0] !== "module") return ast;
|
|
5270
5185
|
if (!reorderSafe(ast)) return ast;
|
|
5271
5186
|
const callCounts = /* @__PURE__ */ new Map();
|
|
5272
|
-
|
|
5187
|
+
walk(ast, (n) => {
|
|
5273
5188
|
if (!Array.isArray(n)) return;
|
|
5274
5189
|
if (n[0] === "call" || n[0] === "return_call") {
|
|
5275
5190
|
callCounts.set(n[1], (callCounts.get(n[1]) || 0) + 1);
|
|
@@ -5288,6 +5203,47 @@ var reorder = (ast) => {
|
|
|
5288
5203
|
funcs.sort((a, b) => (callCounts.get(b[1]) || 0) - (callCounts.get(a[1]) || 0));
|
|
5289
5204
|
return ["module", ...imports, ...funcs, ...others];
|
|
5290
5205
|
};
|
|
5206
|
+
var PASSES = [
|
|
5207
|
+
["stripmut", stripmut, true, "strip mut from never-written globals"],
|
|
5208
|
+
["globals", globals, true, "propagate immutable global constants"],
|
|
5209
|
+
["fold", fold, true, "constant folding"],
|
|
5210
|
+
["identity", identity, true, "remove identity ops (x + 0 \u2192 x)"],
|
|
5211
|
+
["peephole", peephole, true, "x-x\u21920, x&0\u21920, etc."],
|
|
5212
|
+
["strength", strength, true, "strength reduction (x * 2 \u2192 x << 1)"],
|
|
5213
|
+
["branch", branch, true, "simplify constant branches"],
|
|
5214
|
+
["propagate", propagate, true, "forward-propagate single-use locals & tiny consts (never inflates)"],
|
|
5215
|
+
["inlineOnce", inlineOnce, true, "inline single-call functions into their lone caller (never duplicates)"],
|
|
5216
|
+
["inline", inline, false, "inline tiny functions \u2014 can duplicate bodies"],
|
|
5217
|
+
["offset", offset, true, "fold add+const into load/store offset"],
|
|
5218
|
+
["unbranch", unbranch, true, "remove redundant br at end of own block"],
|
|
5219
|
+
["loopify", loopify, true, "collapse block+loop+brif while-idiom into loop+if"],
|
|
5220
|
+
["brif", brif, true, "if-then-br \u2192 br_if"],
|
|
5221
|
+
["foldarms", foldarms, false, "merge identical trailing if arms \u2014 can add block wrapper"],
|
|
5222
|
+
["deadcode", deadcode, true, "eliminate dead code after unreachable/br/return"],
|
|
5223
|
+
["vacuum", vacuum, true, "remove nops, drop-of-pure, empty branches"],
|
|
5224
|
+
["mergeBlocks", mergeBlocks, true, "unwrap `(block $L \u2026)` whose label is never targeted"],
|
|
5225
|
+
["coalesce", coalesceLocals, true, "share local slots between same-type non-overlapping locals"],
|
|
5226
|
+
["locals", localReuse, true, "remove unused locals"],
|
|
5227
|
+
["dedupe", dedupe, true, "eliminate duplicate functions"],
|
|
5228
|
+
["dedupTypes", dedupTypes, true, "merge identical type definitions"],
|
|
5229
|
+
["packData", packData, true, "trim trailing zeros, merge adjacent data segments"],
|
|
5230
|
+
["reorder", reorder, false, "put hot functions first \u2014 no AST reduction"],
|
|
5231
|
+
["treeshake", treeshake, true, "remove unused funcs/globals/types/tables"],
|
|
5232
|
+
["minifyImports", minifyImports, false, "shorten import names \u2014 enable only when you control the host"]
|
|
5233
|
+
];
|
|
5234
|
+
var OPTS = Object.fromEntries(PASSES.map((p) => [p[0], p[2]]));
|
|
5235
|
+
var normalize3 = (opts) => {
|
|
5236
|
+
if (opts === false) return {};
|
|
5237
|
+
if (opts !== true && typeof opts !== "string") {
|
|
5238
|
+
const m2 = { ...opts };
|
|
5239
|
+
for (const p of PASSES) if (m2[p[0]] === void 0) m2[p[0]] = p[2];
|
|
5240
|
+
return m2;
|
|
5241
|
+
}
|
|
5242
|
+
const set = typeof opts === "string" ? new Set(opts.split(/\s+/).filter(Boolean)) : null;
|
|
5243
|
+
const m = {};
|
|
5244
|
+
for (const p of PASSES) m[p[0]] = set ? set.has("all") || set.has(p[0]) : p[2];
|
|
5245
|
+
return m;
|
|
5246
|
+
};
|
|
5291
5247
|
function optimize(ast, opts = true) {
|
|
5292
5248
|
if (typeof ast === "string") ast = parse_default(ast);
|
|
5293
5249
|
const strictGuard = opts === true;
|
|
@@ -5295,37 +5251,12 @@ function optimize(ast, opts = true) {
|
|
|
5295
5251
|
const log = opts.log ? (msg, delta) => opts.log(msg, delta) : () => {
|
|
5296
5252
|
};
|
|
5297
5253
|
const verbose = opts.verbose || opts.log;
|
|
5298
|
-
ast =
|
|
5254
|
+
ast = clone(ast);
|
|
5299
5255
|
let beforeRound = null;
|
|
5300
5256
|
for (let round = 0; round < 3; round++) {
|
|
5301
|
-
beforeRound =
|
|
5257
|
+
beforeRound = clone(ast);
|
|
5302
5258
|
const sizeBefore = binarySize(ast);
|
|
5303
|
-
if (opts
|
|
5304
|
-
if (opts.globals) ast = globals(ast);
|
|
5305
|
-
if (opts.fold) ast = fold(ast);
|
|
5306
|
-
if (opts.identity) ast = identity(ast);
|
|
5307
|
-
if (opts.peephole) ast = peephole(ast);
|
|
5308
|
-
if (opts.strength) ast = strength(ast);
|
|
5309
|
-
if (opts.branch) ast = branch(ast);
|
|
5310
|
-
if (opts.propagate) ast = propagate(ast);
|
|
5311
|
-
if (opts.inlineOnce) ast = inlineOnce(ast);
|
|
5312
|
-
if (opts.inline) ast = inline(ast);
|
|
5313
|
-
if (opts.offset) ast = offset(ast);
|
|
5314
|
-
if (opts.unbranch) ast = unbranch(ast);
|
|
5315
|
-
if (opts.loopify) ast = loopify(ast);
|
|
5316
|
-
if (opts.brif) ast = brif(ast);
|
|
5317
|
-
if (opts.foldarms) ast = foldarms(ast);
|
|
5318
|
-
if (opts.deadcode) ast = deadcode(ast);
|
|
5319
|
-
if (opts.vacuum) ast = vacuum(ast);
|
|
5320
|
-
if (opts.mergeBlocks) ast = mergeBlocks(ast);
|
|
5321
|
-
if (opts.coalesce) ast = coalesceLocals(ast);
|
|
5322
|
-
if (opts.locals) ast = localReuse(ast);
|
|
5323
|
-
if (opts.dedupe) ast = dedupe(ast);
|
|
5324
|
-
if (opts.dedupTypes) ast = dedupTypes(ast);
|
|
5325
|
-
if (opts.packData) ast = packData(ast);
|
|
5326
|
-
if (opts.reorder) ast = reorder(ast);
|
|
5327
|
-
if (opts.treeshake) ast = treeshake(ast);
|
|
5328
|
-
if (opts.minifyImports) ast = minifyImports(ast);
|
|
5259
|
+
for (const [key, fn] of PASSES) if (opts[key]) ast = fn(ast);
|
|
5329
5260
|
if (opts.propagate && (opts.inlineOnce || opts.inline)) ast = propagate(ast);
|
|
5330
5261
|
const sizeAfter = binarySize(ast);
|
|
5331
5262
|
const delta = sizeAfter - sizeBefore;
|
|
@@ -5343,32 +5274,25 @@ function optimize(ast, opts = true) {
|
|
|
5343
5274
|
return ast;
|
|
5344
5275
|
}
|
|
5345
5276
|
|
|
5346
|
-
//
|
|
5277
|
+
// src/template.js
|
|
5347
5278
|
var PUA = "\uE000";
|
|
5348
|
-
var instrType = (op) => {
|
|
5349
|
-
if (!op || typeof op !== "string") return null;
|
|
5350
|
-
const prefix = op.split(".")[0];
|
|
5351
|
-
if (/^[if](32|64)|v128/.test(prefix)) return prefix;
|
|
5352
|
-
if (/\.(eq|ne|[lg][te]|eqz)/.test(op)) return "i32";
|
|
5353
|
-
if (op === "memory.size" || op === "memory.grow") return "i32";
|
|
5354
|
-
return null;
|
|
5355
|
-
};
|
|
5356
5279
|
var exprType = (node, ctx = {}) => {
|
|
5357
5280
|
if (!Array.isArray(node)) {
|
|
5358
5281
|
if (typeof node === "string" && node[0] === "$" && ctx.locals?.[node]) return ctx.locals[node];
|
|
5359
5282
|
return null;
|
|
5360
5283
|
}
|
|
5361
5284
|
const [op, ...args] = node;
|
|
5362
|
-
|
|
5285
|
+
const rt = resultType(op);
|
|
5286
|
+
if (rt) return rt;
|
|
5363
5287
|
if (op === "local.get" && ctx.locals?.[args[0]]) return ctx.locals[args[0]];
|
|
5364
5288
|
if (op === "call" && ctx.funcs?.[args[0]]) return ctx.funcs[args[0]].result?.[0];
|
|
5365
5289
|
return null;
|
|
5366
5290
|
};
|
|
5367
|
-
function
|
|
5291
|
+
function walk2(node, fn) {
|
|
5368
5292
|
node = fn(node);
|
|
5369
5293
|
if (Array.isArray(node)) {
|
|
5370
5294
|
for (let i = 0; i < node.length; i++) {
|
|
5371
|
-
let child =
|
|
5295
|
+
let child = walk2(node[i], fn);
|
|
5372
5296
|
if (child?._splice) node.splice(i, 1, ...child), i += child.length - 1;
|
|
5373
5297
|
else node[i] = child;
|
|
5374
5298
|
}
|
|
@@ -5378,7 +5302,7 @@ function walk3(node, fn) {
|
|
|
5378
5302
|
function inferImports(ast, funcs) {
|
|
5379
5303
|
const imports = [];
|
|
5380
5304
|
const importMap = /* @__PURE__ */ new Map();
|
|
5381
|
-
|
|
5305
|
+
walk2(ast, (node) => {
|
|
5382
5306
|
if (!Array.isArray(node)) return node;
|
|
5383
5307
|
if (node[0] === "call" && typeof node[1] === "function") {
|
|
5384
5308
|
const fn = node[1];
|
|
@@ -5405,7 +5329,8 @@ function genImports(imports) {
|
|
|
5405
5329
|
({ name: name2, params }) => ["import", '"env"', `"${name2.slice(1)}"`, ["func", name2, ...params.map((t) => ["param", t])]]
|
|
5406
5330
|
);
|
|
5407
5331
|
}
|
|
5408
|
-
function compile2(source,
|
|
5332
|
+
function compile2(backend2, source, values) {
|
|
5333
|
+
const { parse, compile: emit, optimize: optimize2, polyfill: polyfill2 } = backend2;
|
|
5409
5334
|
let opts = {};
|
|
5410
5335
|
if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === "object" && values[values.length - 1] !== null && !values[values.length - 1].byteLength) {
|
|
5411
5336
|
opts = values.pop();
|
|
@@ -5415,10 +5340,10 @@ function compile2(source, ...values) {
|
|
|
5415
5340
|
for (let i = 0; i < values.length; i++) {
|
|
5416
5341
|
src += PUA + source[i + 1];
|
|
5417
5342
|
}
|
|
5418
|
-
let ast =
|
|
5343
|
+
let ast = parse(src);
|
|
5419
5344
|
const funcsToImport = [];
|
|
5420
5345
|
let idx = 0;
|
|
5421
|
-
ast =
|
|
5346
|
+
ast = walk2(ast, (node) => {
|
|
5422
5347
|
if (node === PUA) {
|
|
5423
5348
|
const value = values[idx++];
|
|
5424
5349
|
if (typeof value === "function") {
|
|
@@ -5426,13 +5351,14 @@ function compile2(source, ...values) {
|
|
|
5426
5351
|
return value;
|
|
5427
5352
|
}
|
|
5428
5353
|
if (typeof value === "string" && (value[0] === "(" || /^\s*\(/.test(value))) {
|
|
5429
|
-
const parsed =
|
|
5354
|
+
const parsed = parse(value);
|
|
5430
5355
|
if (Array.isArray(parsed) && Array.isArray(parsed[0])) {
|
|
5431
5356
|
parsed._splice = true;
|
|
5432
5357
|
}
|
|
5433
5358
|
return parsed;
|
|
5434
5359
|
}
|
|
5435
|
-
if (value
|
|
5360
|
+
if (value?.byteLength !== void 0) return [...value];
|
|
5361
|
+
if (typeof value === "bigint") return value.toString();
|
|
5436
5362
|
return value;
|
|
5437
5363
|
}
|
|
5438
5364
|
return node;
|
|
@@ -5455,33 +5381,42 @@ function compile2(source, ...values) {
|
|
|
5455
5381
|
}
|
|
5456
5382
|
}
|
|
5457
5383
|
}
|
|
5458
|
-
if (opts.polyfill) ast =
|
|
5459
|
-
if (opts.optimize) ast =
|
|
5460
|
-
const binary =
|
|
5384
|
+
if (opts.polyfill) ast = polyfill2(ast, opts.polyfill);
|
|
5385
|
+
if (opts.optimize) ast = optimize2(ast, opts.optimize);
|
|
5386
|
+
const binary = emit(ast);
|
|
5461
5387
|
if (importObjs) binary._imports = importObjs;
|
|
5462
5388
|
return binary;
|
|
5463
5389
|
}
|
|
5464
5390
|
if (opts.polyfill || opts.optimize) {
|
|
5465
|
-
let ast = typeof source === "string" ?
|
|
5466
|
-
if (opts.polyfill) ast =
|
|
5467
|
-
if (opts.optimize) ast =
|
|
5468
|
-
return
|
|
5391
|
+
let ast = typeof source === "string" ? parse(source) : source;
|
|
5392
|
+
if (opts.polyfill) ast = polyfill2(ast, opts.polyfill);
|
|
5393
|
+
if (opts.optimize) ast = optimize2(ast, opts.optimize);
|
|
5394
|
+
return emit(ast);
|
|
5469
5395
|
}
|
|
5470
|
-
return
|
|
5396
|
+
return emit(source);
|
|
5471
5397
|
}
|
|
5472
|
-
function watr(
|
|
5473
|
-
const binary = compile2(
|
|
5398
|
+
function watr(backend2, source, values) {
|
|
5399
|
+
const binary = compile2(backend2, source, values);
|
|
5474
5400
|
const module = new WebAssembly.Module(binary);
|
|
5475
5401
|
const instance = new WebAssembly.Instance(module, binary._imports);
|
|
5476
5402
|
return instance.exports;
|
|
5477
5403
|
}
|
|
5478
|
-
|
|
5404
|
+
|
|
5405
|
+
// watr.js
|
|
5406
|
+
var backend = { parse: parse_default, compile, optimize, polyfill };
|
|
5407
|
+
function compile3(source, ...values) {
|
|
5408
|
+
return compile2(backend, source, values);
|
|
5409
|
+
}
|
|
5410
|
+
function watr2(source, ...values) {
|
|
5411
|
+
return watr(backend, source, values);
|
|
5412
|
+
}
|
|
5413
|
+
var watr_default = watr2;
|
|
5479
5414
|
export {
|
|
5480
|
-
|
|
5415
|
+
compile3 as compile,
|
|
5481
5416
|
watr_default as default,
|
|
5482
5417
|
optimize,
|
|
5483
5418
|
parse_default as parse,
|
|
5484
5419
|
polyfill,
|
|
5485
5420
|
print,
|
|
5486
|
-
watr
|
|
5421
|
+
watr2 as watr
|
|
5487
5422
|
};
|