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.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watr",
3
- "version": "4.7.0",
3
+ "version": "4.7.2",
4
4
  "description": "Light & fast WAT compiler – WebAssembly Text to binary, parse, print, transform",
5
5
  "main": "watr.js",
6
6
  "bin": {
package/src/compile.js CHANGED
@@ -37,17 +37,10 @@ const cleanup = (node, result) => {
37
37
  }
38
38
 
39
39
 
40
- /**
41
- * Converts a WebAssembly Text Format (WAT) tree to a WebAssembly binary format (WASM).
42
- *
43
- * @param {string|Array} nodes - The WAT tree or string to be compiled to WASM binary.
44
- * @returns {Uint8Array} The compiled WASM binary. When the WAT carries
45
- * `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
46
- * property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
47
- * instruction's position in the final binary. That's the hook a source-map
48
- * emitter needs to correlate generated wasm back to its source.
49
- */
50
- export default function compile(nodes) {
40
+ // Internal: assemble the module. sizeOnly=false → wasm bytes (Uint8Array); sizeOnly=true →
41
+ // just the byte LENGTH, skipping materialization of the multi-MB binary that's size()'s
42
+ // reason to exist (the optimizer's size-revert guard can't afford to build bytes it discards).
43
+ function assemble(nodes, sizeOnly) {
51
44
  // normalize to (module ...) form
52
45
  if (typeof nodes === 'string') err.src = nodes, nodes = parse(nodes) || []
53
46
  else err.src = '' // clear source if AST passed directly
@@ -63,10 +56,10 @@ export default function compile(nodes) {
63
56
  else if (typeof nodes[0] === 'string') nodes = [nodes]
64
57
 
65
58
  // binary abbr "\00" "\0x61" ...
66
- if (nodes[idx] === 'binary') return Uint8Array.from(nodes.slice(++idx).flat())
59
+ if (nodes[idx] === 'binary') { const b = Uint8Array.from(nodes.slice(++idx).flat()); return sizeOnly ? b.length : b }
67
60
 
68
61
  // quote "a" "b"
69
- if (nodes[idx] === 'quote') return compile(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''))
62
+ if (nodes[idx] === 'quote') return assemble(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''), sizeOnly)
70
63
 
71
64
  // expand grouped imports: (import "mod" (item "name" type)*) -> individual imports
72
65
  // compact import section (Phase 3)
@@ -241,6 +234,26 @@ export default function compile(nodes) {
241
234
  // pre-compute sections that may collect string constants (for strings section ordering)
242
235
  const globalSection = bin(SECTION.global)
243
236
  const elemSection = bin(SECTION.elem)
237
+ // measure: byte LENGTH only — skip building + materializing the multi-MB code byte array
238
+ // (the optimizer's size-revert guard only needs the count). Sizes the code section via
239
+ // codeItemSize; other sections are small, built normally + summed. Same string-collection
240
+ // ORDER as the emit path (global, elem, code, meta, data → strings).
241
+ if (sizeOnly) {
242
+ const codeSizes = ctx.code.filter(Boolean).map(item => codeItemSize(item, ctx))
243
+ const innerLen = codeSizes.length ? ulebSize(codeSizes.length) + codeSizes.reduce((a, b) => a + b, 0) : 0
244
+ const codeSecLen = codeSizes.length ? 1 + ulebSize(innerLen) + innerLen : 0 // SECTION.code + vec(vec(items))
245
+ const metaSection = binMeta()
246
+ const dataSection = bin(SECTION.data)
247
+ const stringsSection = ctx.strings.length ? [SECTION.strings, ...vec([0x00, ...vec(ctx.strings.map(s => vec(s)))])] : []
248
+ const others = [
249
+ bin(SECTION.custom), bin(SECTION.type), bin(SECTION.import), bin(SECTION.func),
250
+ bin(SECTION.table), bin(SECTION.memory), bin(SECTION.tag), stringsSection,
251
+ globalSection, bin(SECTION.export), bin(SECTION.start, false), elemSection,
252
+ bin(SECTION.datacount, false), metaSection, dataSection
253
+ ]
254
+ return 8 + codeSecLen + others.reduce((s, sec) => s + sec.length, 0) // 8 = magic + version
255
+ }
256
+
244
257
  // inline bin(code) so the per-function item bytes survive — with ctx.codeSizePrefix
245
258
  // they let us lift code-metadata positions to absolute binary offsets below
246
259
  const codeItems = ctx.code.filter(Boolean).map(item => build[SECTION.code](item, ctx)).filter(Boolean)
@@ -317,6 +330,19 @@ export default function compile(nodes) {
317
330
  }
318
331
  }
319
332
 
333
+ /**
334
+ * Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
335
+ * `@metadata.code.<type>` annotations the result also exposes `.metadata` —
336
+ * `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
337
+ */
338
+ export default function compile(nodes) { return assemble(nodes) }
339
+
340
+ /**
341
+ * Byte size of `compile(nodes)` without materializing the binary — a peer transform for
342
+ * tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
343
+ * summed from section sizes instead of building them (invariant-tested).
344
+ */
345
+ export function size(nodes) { return assemble(nodes, true) }
320
346
 
321
347
  /** Check if node is a valid index reference ($name or number) */
322
348
  const isIdx = n => n?.[0] === '$' || !isNaN(n)
@@ -1062,6 +1088,59 @@ const instr = (nodes, ctx) => {
1062
1088
  return out.push(0x0b), out
1063
1089
  }
1064
1090
 
1091
+ // LEB128 byte-width of an unsigned integer (exact, reuses uleb so it can never drift).
1092
+ const ulebSize = (n) => uleb(n).length
1093
+
1094
+ // Size-only twin of instr(): the byte LENGTH of the encoded instruction stream,
1095
+ // WITHOUT building the (multi-MB) byte array. Reuses every HANDLER for exact
1096
+ // immediate widths + index resolution — only `out.push(...bytes)` accumulation is
1097
+ // replaced by integer summation (the dominant cost on large modules). The
1098
+ // opcode-value tweaks in instr() (typed-select / nullable-reftype) change a byte
1099
+ // VALUE, not the length, so they're irrelevant here. MUST equal instr(...).length
1100
+ // (asserted by the byteSize↔compile invariant test).
1101
+ const instrSize = (nodes, ctx) => {
1102
+ let size = 0, meta = []
1103
+ while (nodes?.length) {
1104
+ let op = nodes.shift()
1105
+ if (op?.[0] === '@metadata') { meta.push(op.slice(1)); continue }
1106
+ if (Array.isArray(op)) { op.loc != null && (err.loc = op.loc); err(`Unknown instruction ${op[0]}`) }
1107
+ const opc = INSTR[op] || err(`Unknown instruction ${op}`)
1108
+ let n = opc.length
1109
+ if (HANDLER[op]) n += HANDLER[op](nodes, ctx, op).length
1110
+ if (meta.length) { for (const [type, data] of meta) ((ctx.meta[type] ??= []).push([size, data])); meta = [] }
1111
+ size += n
1112
+ }
1113
+ return size + 1 // trailing 0x0b (end)
1114
+ }
1115
+
1116
+ // Size-only twin of build[SECTION.code]: byte LENGTH of one function's code item.
1117
+ // Mirrors the builder exactly (local setup, squash, metadata bookkeeping, vec
1118
+ // framing) but uses instrSize for the body — so locals/strings/metadata side
1119
+ // effects on ctx stay identical, only the body byte array is never materialized.
1120
+ const codeItemSize = (body, ctx) => {
1121
+ let [typeidx, param] = body.shift()
1122
+ if (!param) [, [param]] = ctx.type[id(typeidx, ctx.type)]
1123
+ ctx.local = Object.create(param); ctx.block = []
1124
+ ctx.local.name = 'local'; ctx.block.name = 'block'
1125
+ if (ctx._codeIdx === undefined) ctx._codeIdx = 0
1126
+ let codeIdx = ctx._codeIdx++
1127
+ while (body[0]?.[0] === 'local') {
1128
+ let [, ...types] = body.shift()
1129
+ if (isId(types[0])) { let nm = types.shift(); if (nm in ctx.local) err(`Duplicate local ${nm}`); else ctx.local[nm] = ctx.local.length }
1130
+ ctx.local.push(...types)
1131
+ }
1132
+ ctx.meta = {}
1133
+ const bytesLen = instrSize(body, ctx)
1134
+ 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), [])
1135
+ const locals = vec(loctypes.map(([n, t]) => [...uleb(n), ...reftype(t, ctx)]))
1136
+ const funcIdx = ctx.import.filter(imp => imp[2][0] === 'func').length + codeIdx
1137
+ for (const type in ctx.meta) { for (const inst of ctx.meta[type]) inst[0] += locals.length; ((ctx.metadata ??= {})[type] ??= []).push([funcIdx, ctx.meta[type]]) }
1138
+ ctx.local = ctx.block = ctx.meta = null
1139
+ const bodyLen = locals.length + bytesLen
1140
+ ;(ctx.codeSizePrefix ??= [])[codeIdx] = ulebSize(bodyLen) // = vec prefix width
1141
+ return ulebSize(bodyLen) + bodyLen // vec([...locals, ...bytes]).length
1142
+ }
1143
+
1065
1144
  // instantiation time value initializer (consuming) - normalize then encode + add end byte
1066
1145
  const expr = (node, ctx) => instr(normalize([node], ctx), ctx)
1067
1146
 
package/src/optimize.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * @module wat/optimize
8
8
  */
9
9
 
10
- import compile from './compile.js'
10
+ import compile, { size } from './compile.js'
11
11
  import parse from './parse.js'
12
12
 
13
13
  // Fixpoint round caps — empirical convergence bounds, not correctness limits.
@@ -68,7 +68,10 @@ const count = (node) => {
68
68
  * @returns {number}
69
69
  */
70
70
  const binarySize = (ast) => {
71
- try { return compile(ast).length } catch { return Infinity }
71
+ // `size` = byte length without materializing the binary the size-revert guard only needs
72
+ // the count, and re-encoding the whole module each round is the optimizer's dominant cost on
73
+ // large modules. Exactly compile(ast).length (invariant-tested).
74
+ try { return size(ast) } catch { return Infinity }
72
75
  }
73
76
 
74
77
  /**
@@ -1873,7 +1876,7 @@ const buildInline = (params, locals, inlResult, cBody, args) => {
1873
1876
  *
1874
1877
  * A callee qualifies when it is small (≤ INLINE_MAX_NODES IR nodes), named with
1875
1878
  * named params/locals, single-result-or-void, non-recursive, not pinned
1876
- * (export/start/elem/ref.func), not a SIMD_PROTECTED transcendental, and free of
1879
+ * (export/start/elem/ref.func), not in the caller's `pin` set, and free of
1877
1880
  * depth-relative branches / tail calls (the inlParse + inlUnsafe liftability
1878
1881
  * contract). Runs to a fixpoint so small-helper chains (sdf → sdRep) collapse.
1879
1882
  *
@@ -1893,7 +1896,7 @@ const buildInline = (params, locals, inlResult, cBody, args) => {
1893
1896
  const INLINE_MAX_NODES = 90
1894
1897
  const isV128SimdHelper = (params, inlResult) =>
1895
1898
  inlResult === 'v128' && params.length > 0 && params.every(p => p.type === 'v128')
1896
- const inline = (ast, { simdOnly = false } = {}) => {
1899
+ const inline = (ast, { simdOnly = false, pin = EMPTY_SET } = {}) => {
1897
1900
  if (!Array.isArray(ast) || ast[0] !== 'module') return ast
1898
1901
 
1899
1902
  const skip = new Set() // callees with a non-inlinable site (arity mismatch) — don't re-pick
@@ -1917,7 +1920,7 @@ const inline = (ast, { simdOnly = false } = {}) => {
1917
1920
  // Pick a small, liftable, non-recursive callee with ≥1 plain-call site.
1918
1921
  let calleeName = null, parsed = null
1919
1922
  for (const [name, fn] of funcByName) {
1920
- if (skip.has(name) || pinned.has(name) || otherRef.has(name) || SIMD_PROTECTED.has(name)) continue
1923
+ if (skip.has(name) || pinned.has(name) || otherRef.has(name) || pin.has(name)) continue
1921
1924
  if (!(callRefs.get(name) >= 1)) continue
1922
1925
  if (inlBodySize(fn) > INLINE_MAX_NODES) continue
1923
1926
  if (inlCallsSelf(fn, name)) continue
@@ -2254,12 +2257,7 @@ const devirt = (ast) => {
2254
2257
  * @param {Array} ast
2255
2258
  * @returns {Array}
2256
2259
  */
2257
- // Scalar transcendental helpers the auto-vectorizer rewrites to f64x2 mirrors (PPC_CALL2 in
2258
- // src/optimize/vectorize.js). inlineOnce must NOT dissolve their call nodes when single-caller —
2259
- // the post-phase lift needs the call to rewrite it. Keep in sync with PPC_CALL2's keys.
2260
- const SIMD_PROTECTED = new Set(['$math.sin_core', '$math.cos_core', '$math.sin', '$math.cos', '$math.pow', '$math.atan2', '$math.hypot', '$math.log'])
2261
-
2262
- const inlineOnce = (ast) => {
2260
+ const inlineOnce = (ast, { pin = EMPTY_SET } = {}) => {
2263
2261
  if (!Array.isArray(ast) || ast[0] !== 'module') return ast
2264
2262
 
2265
2263
  // Lift primitives are shared with `inline` (defined once above buildInline). inlineOnce
@@ -2291,11 +2289,10 @@ const inlineOnce = (ast) => {
2291
2289
  for (const [name, fn] of funcByName) {
2292
2290
  if (pinned.has(name) || otherRef.has(name)) continue
2293
2291
  if (callRefs.get(name) !== 1) continue
2294
- // Keep the scalar transcendentals that the auto-vectorizer maps to f64x2 mirrors (PPC_CALL2 in
2295
- // src/optimize/vectorize.js): inlining a single-caller $math.atan2/hypot/log would dissolve the
2296
- // call node before the post-phase lift can rewrite it to $math.atan2_2/hypot_2/log_v. Keep in
2297
- // sync with PPC_CALL2's keys.
2298
- if (SIMD_PROTECTED.has(name)) continue
2292
+ // Caller-pinned functions stay intact: inlining a single-caller helper would dissolve the
2293
+ // call node, and a consumer may rely on it surviving (e.g. jz pins the scalar transcendentals
2294
+ // its auto-vectorizer later rewrites to f64x2 mirrors). The policy lives with the caller.
2295
+ if (pin.has(name)) continue
2299
2296
  if (callsSelf(fn, name)) continue
2300
2297
  // named params/locals only (we'll rename them); reject locals with types
2301
2298
  // we can't zero-init on block re-entry.
@@ -3867,6 +3864,10 @@ export default function optimize(ast, opts = true) {
3867
3864
  if (typeof ast === 'string') ast = parse(ast) // accept WAT source directly
3868
3865
  const strictGuard = opts === true // default: zero tolerance for bloat
3869
3866
  opts = normalize(opts)
3867
+ // `pin`: caller-supplied function names that inlineOnce/inline must NOT dissolve. Keeps
3868
+ // optimizer policy with the CALLER — e.g. jz pins the scalar transcendentals its own
3869
+ // auto-vectorizer later rewrites to f64x2 mirrors, so no consumer-specific names live here.
3870
+ opts.pin = opts.pin instanceof Set ? opts.pin : new Set(opts.pin || [])
3870
3871
 
3871
3872
  const log = opts.log ? (msg, delta) => opts.log(msg, delta) : () => {}
3872
3873
  const verbose = opts.verbose || opts.log
@@ -3888,7 +3889,7 @@ export default function optimize(ast, opts = true) {
3888
3889
  if (!opts.inline) return a
3889
3890
  // `inline: 'simd'` → SIMD-helper-only (jz's speed tier, avoids general bloat);
3890
3891
  // `inline: true` / `'all'` → general inlining of tiny functions.
3891
- a = inline(a, { simdOnly: opts.inline === 'simd' })
3892
+ a = inline(a, { simdOnly: opts.inline === 'simd', pin: opts.pin })
3892
3893
  if (opts.propagate) a = propagate(a)
3893
3894
  if (opts.mergeBlocks) a = mergeBlocks(a)
3894
3895
  if (opts.vacuum) a = vacuum(a)
@@ -3909,7 +3910,7 @@ export default function optimize(ast, opts = true) {
3909
3910
  // propagate, and it would only confirm what `mayInline` already proved.
3910
3911
  for (let round = 0; round < 3; round++) {
3911
3912
  const beforeRound = clone(ast)
3912
- for (const [key, fn] of PASSES) if (opts[key] && key !== 'inlineOnce' && key !== 'inline' && key !== 'devirt') ast = fn(ast)
3913
+ for (const [key, fn] of PASSES) if (opts[key] && key !== 'inlineOnce' && key !== 'inline' && key !== 'devirt') ast = fn(ast, opts)
3913
3914
  if (equal(beforeRound, ast)) break // fixpoint
3914
3915
  if (verbose) log(` round ${round + 1} applied`)
3915
3916
  }
@@ -3926,7 +3927,7 @@ export default function optimize(ast, opts = true) {
3926
3927
  for (let round = 0; round < 3; round++) {
3927
3928
  beforeRound = clone(ast)
3928
3929
 
3929
- for (const [key, fn] of PASSES) if (opts[key] && key !== 'devirt' && key !== 'inline') ast = fn(ast)
3930
+ for (const [key, fn] of PASSES) if (opts[key] && key !== 'devirt' && key !== 'inline') ast = fn(ast, opts)
3930
3931
  // Second propagate sweep: `inlineOnce`/`inline` (above) leave fresh
3931
3932
  // `(local.set $p arg) … (local.get $p)` wrappers around each inlined call;
3932
3933
  // re-running propagation collapses them within this same round, so the size
@@ -1,12 +1,13 @@
1
1
  /**
2
- * Converts a WebAssembly Text Format (WAT) tree to a WebAssembly binary format (WASM).
3
- *
4
- * @param {string|Array} nodes - The WAT tree or string to be compiled to WASM binary.
5
- * @returns {Uint8Array} The compiled WASM binary. When the WAT carries
6
- * `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
7
- * property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
8
- * instruction's position in the final binary. That's the hook a source-map
9
- * emitter needs to correlate generated wasm back to its source.
2
+ * Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
3
+ * `@metadata.code.<type>` annotations the result also exposes `.metadata` —
4
+ * `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
10
5
  */
11
- export default function compile(nodes: string | any[]): Uint8Array;
6
+ export default function compile(nodes: any): any;
7
+ /**
8
+ * Byte size of `compile(nodes)` without materializing the binary — a peer transform for
9
+ * tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
10
+ * summed from section sizes instead of building them (invariant-tested).
11
+ */
12
+ export function size(nodes: any): any;
12
13
  //# sourceMappingURL=compile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AAuCA;;;;;;;;;GASG;AACH,uCAPW,MAAM,QAAM,GACV,UAAU,CAkRtB"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA4UA;;;;GAIG;AACH,iDAAiE;AAEjE;;;;GAIG;AACH,sCAA4D"}
@@ -56,10 +56,42 @@ export function strength(ast: any[]): any[];
56
56
  */
57
57
  export function branch(ast: any[]): any[];
58
58
  export function propagate(ast: any): any;
59
- export function inline(ast: any, { simdOnly }?: {
59
+ export function inline(ast: any, { simdOnly, pin }?: {
60
60
  simdOnly?: boolean;
61
+ pin?: any;
61
62
  }): any;
62
- export function inlineOnce(ast: any): any;
63
+ /**
64
+ * Inline functions that are called from exactly one place into their lone caller,
65
+ * then delete them. Unlike {@link inline} (which duplicates tiny stateless bodies),
66
+ * this never duplicates code and never inflates: each inlined function drops a
67
+ * function-section entry, a type-section entry (if now unused), and a `call`
68
+ * instruction, paying back only a `block`/`local.set` wrapper. This is what
69
+ * `wasm-opt -Oz` does — collapsing helper chains down to a couple of functions —
70
+ * and it's the bulk of the gap between hand-tuned WASM and naive codegen.
71
+ *
72
+ * A function `$f` qualifies when it is, all of:
73
+ * • named, with named params and locals (numeric indices can't be safely renamed);
74
+ * • referenced exactly once across the whole module, by a plain `call` (no
75
+ * `return_call`, `ref.func`, `elem`, `export`, or `start` reference, and not
76
+ * recursive);
77
+ * • single-result or void (a multi-value result can't be modeled as `(block (result …))`);
78
+ * • free of numeric (depth-relative) branch labels — those would shift under the
79
+ * extra block nesting — and of `return_call*` in its body.
80
+ *
81
+ * `(call $f a0 a1 …)` becomes
82
+ * (block $__inlN (result T)?
83
+ * (local.set $__inlN_p0 a0) (local.set $__inlN_p1 a1) … ;; args evaluated once, in order
84
+ * …body, params/locals renamed to $__inlN_*, `return X` → `br $__inlN X`…)
85
+ * and the renamed params+locals are appended to the caller's `local` decls; the
86
+ * body's own block/loop/if labels are renamed too so they can't shadow the caller's.
87
+ * Runs to a fixpoint so helper chains fully collapse.
88
+ *
89
+ * @param {Array} ast
90
+ * @returns {Array}
91
+ */
92
+ export function inlineOnce(ast: any[], { pin }?: {
93
+ pin?: any;
94
+ }): any[];
63
95
  /**
64
96
  * Devirtualize `call_indirect` through NaN-boxed closure values with a statically
65
97
  * known candidate set. `let f = c ? a : b; … f(x)` emits a select of two i64
@@ -1 +1 @@
1
- {"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAyxHA,gEAyFC;AA9zHD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAIlB;AA8CD;;;;;GAKG;AACH,6CAgJC;AAwUD;;;;GAIG;AACH,wCAkDC;AA0YD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AAndD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CAwDC;AAID;;;;GAIG;AACH,0CA6CC;AAuyBD,yCAqCC;AAmND;;QAqEC;AAySD,0CAgJC;AArbD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,sCAwOC;AAghDD;;;;;;;;GAQG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAc/B;AAvBD,qEAAqE;AACrE,uBAA8D;AArlC9D;;;;;GAKG;AACH,0CA8DC;AA+ED;;;;GAIG;AACH,4CAQC;AAiCD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAwWD,uCAyBC;AA7XD;;;;;GAKG;AACH,8CAyEC;AA2ID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AA/sCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+CAiFC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}
1
+ {"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAsxHA,gEA6FC;AA/zHD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAOlB;AA8CD;;;;;GAKG;AACH,6CAgJC;AAwUD;;;;GAIG;AACH,wCAkDC;AA0YD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AAndD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CAwDC;AAID;;;;GAIG;AACH,0CA6CC;AAuyBD,yCAqCC;AAmND;;;QAqEC;AAuQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;UA+IC;AA/aD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,sCAwOC;AA0gDD;;;;;;;;GAQG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAc/B;AAvBD,qEAAqE;AACrE,uBAA8D;AArlC9D;;;;;GAKG;AACH,0CA8DC;AA+ED;;;;GAIG;AACH,4CAQC;AAiCD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAwWD,uCAyBC;AA7XD;;;;;GAKG;AACH,8CAyEC;AA2ID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AA/sCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+CAiFC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}