jz 0.8.1 → 0.9.1
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/README.md +56 -9
- package/bench/README.md +121 -50
- package/bench/bench.svg +23 -23
- package/cli.js +3 -1
- package/dist/interop.js +1 -1
- package/dist/jz.js +7541 -6271
- package/index.js +165 -74
- package/interop.js +189 -17
- package/jzify/arguments.js +32 -1
- package/jzify/async.js +409 -0
- package/jzify/classes.js +136 -18
- package/jzify/generators.js +639 -0
- package/jzify/hoist-vars.js +73 -1
- package/jzify/index.js +123 -4
- package/jzify/names.js +1 -0
- package/jzify/transform.js +239 -1
- package/layout.js +48 -3
- package/module/array.js +299 -44
- package/module/atomics.js +144 -0
- package/module/collection.js +1429 -155
- package/module/core.js +431 -40
- package/module/date.js +142 -120
- package/module/fs.js +144 -0
- package/module/function.js +6 -3
- package/module/index.js +4 -1
- package/module/json.js +270 -49
- package/module/math.js +892 -32
- package/module/number.js +532 -163
- package/module/object.js +353 -95
- package/module/regex.js +157 -7
- package/module/schema.js +100 -2
- package/module/string.js +301 -84
- package/module/typedarray.js +264 -72
- package/module/web.js +36 -0
- package/package.json +5 -5
- package/src/abi/string.js +71 -5
- package/src/ast.js +11 -5
- package/src/autoload.js +28 -1
- package/src/bridge.js +7 -2
- package/src/compile/analyze-scans.js +22 -7
- package/src/compile/analyze.js +136 -30
- package/src/compile/dyn-closure-tables.js +277 -0
- package/src/compile/emit-assign.js +281 -15
- package/src/compile/emit.js +979 -54
- package/src/compile/index.js +271 -29
- package/src/compile/infer.js +34 -3
- package/src/compile/inplace-store.js +329 -0
- package/src/compile/narrow.js +543 -15
- package/src/compile/peel-stencil.js +5 -0
- package/src/compile/plan/index.js +45 -3
- package/src/compile/plan/inline.js +8 -1
- package/src/compile/plan/literals.js +39 -0
- package/src/compile/plan/scope.js +430 -23
- package/src/compile/program-facts.js +732 -38
- package/src/ctx.js +64 -9
- package/src/helper-counters.js +7 -1
- package/src/ir.js +113 -5
- package/src/kind-traits.js +66 -3
- package/src/kind.js +84 -12
- package/src/op-policy.js +7 -4
- package/src/optimize/index.js +1060 -750
- package/src/optimize/recurse.js +2 -2
- package/src/optimize/vectorize.js +972 -67
- package/src/prepare/index.js +792 -63
- package/src/prepare/math-kernel.js +331 -0
- package/src/prepare/pre-eval.js +714 -0
- package/src/snapshot.js +194 -0
- package/src/type.js +1170 -56
- package/src/wat/assemble.js +403 -65
- package/src/wat/codegen.js +74 -14
- package/transform.js +113 -4
- package/wasi.js +3 -0
package/module/number.js
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { typed, asF64, asI32, asI64, toI32, toNumF64, NULL_NAN, UNDEF_NAN, FALSE_NAN, TRUE_NAN, temp, tempI32, tempI64, ptrTypeEq, truthyIR } from '../src/ir.js'
|
|
13
|
-
import { ssoBitI64Hex } from '../layout.js'
|
|
14
|
-
import { emit, bool, deps, reg
|
|
13
|
+
import { ssoBitI64Hex, ptrNanHex } from '../layout.js'
|
|
14
|
+
import { emit, bool, deps, reg } from '../src/bridge.js'
|
|
15
15
|
import { isReassigned } from '../src/ast.js'
|
|
16
16
|
import { valTypeOf } from '../src/kind.js'
|
|
17
17
|
import { VAL } from '../src/reps.js'
|
|
18
|
-
import { inc, PTR, LAYOUT } from '../src/ctx.js'
|
|
18
|
+
import { inc, PTR, LAYOUT, declGlobal } from '../src/ctx.js'
|
|
19
19
|
|
|
20
20
|
// ─── Shared decimal-number parsing fragments ────────────────────────────────
|
|
21
21
|
// `__to_num` (Number coercion) and `__parseFloat` both scan a StrDecimalLiteral
|
|
@@ -89,10 +89,16 @@ const DEC_SIGNIFICAND = `
|
|
|
89
89
|
(if (local.get $dot) (then (local.set $decExp (i32.sub (local.get $decExp) (i32.const 1)))))
|
|
90
90
|
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
91
91
|
(br $numLoop)))
|
|
92
|
-
;; Accumulate the significand in an i64
|
|
93
|
-
;;
|
|
94
|
-
;;
|
|
95
|
-
|
|
92
|
+
;; Accumulate the significand in an i64, UNSIGNED-exact to 19 decimal
|
|
93
|
+
;; digits (2^64-1 ≈ 1.8e19): the first 18 always fit; the 19th joins only
|
|
94
|
+
;; when mant*10+9 cannot overflow (mant ≤ (2^64-1-9)/10). Rounding by
|
|
95
|
+
;; increment only ever applies from the 20th digit on — pre-rounding the
|
|
96
|
+
;; 19th double-rounded 19-digit literals (parseFloat('1152921504606847359')
|
|
97
|
+
;; came out 2 ulp off; the EL consumer is unsigned throughout).
|
|
98
|
+
(if (i32.or
|
|
99
|
+
(i32.lt_s (local.get $sigDigits) (i32.const 18))
|
|
100
|
+
(i32.and (i32.eq (local.get $sigDigits) (i32.const 18))
|
|
101
|
+
(i64.le_u (local.get $mant) (i64.const 1844674407370955160))))
|
|
96
102
|
(then
|
|
97
103
|
(local.set $mant
|
|
98
104
|
(i64.add
|
|
@@ -146,11 +152,28 @@ const sciExponent = (tail) => `
|
|
|
146
152
|
|
|
147
153
|
// Apply the accumulated base-10 exponent to $result via __pow10.
|
|
148
154
|
// Used as fallback when EL cannot determine a unique rounding.
|
|
155
|
+
// Deep exponents split in two steps so the intermediate stays finite/normal:
|
|
156
|
+
// 10^324 overflows f64 (__pow10 → Infinity) and x/Infinity flushed every
|
|
157
|
+
// |exp10| > 308 literal to 0 — including min-normal 2.2250738585072014e-308
|
|
158
|
+
// (17 mantissa digits → decExp −324) and the 5e-324 min subnormal. Dividing
|
|
159
|
+
// by 10^(|e|−308) FIRST keeps the intermediate normal; the final /10^308
|
|
160
|
+
// rounds once into the (sub)normal target. Symmetric split on overflow-side
|
|
161
|
+
// exponents (mant digits can drag decExp past +308 while the value is finite).
|
|
149
162
|
const POW10_SCALE = `
|
|
150
163
|
(if (i32.gt_s (local.get $decExp) (i32.const 0))
|
|
151
|
-
(then
|
|
164
|
+
(then
|
|
165
|
+
(if (i32.gt_s (local.get $decExp) (i32.const 308))
|
|
166
|
+
(then
|
|
167
|
+
(local.set $result (f64.mul (local.get $result) (call $__pow10 (i32.sub (local.get $decExp) (i32.const 308)))))
|
|
168
|
+
(local.set $result (f64.mul (local.get $result) (call $__pow10 (i32.const 308)))))
|
|
169
|
+
(else (local.set $result (f64.mul (local.get $result) (call $__pow10 (local.get $decExp))))))))
|
|
152
170
|
(if (i32.lt_s (local.get $decExp) (i32.const 0))
|
|
153
|
-
(then
|
|
171
|
+
(then
|
|
172
|
+
(if (i32.lt_s (local.get $decExp) (i32.const -308))
|
|
173
|
+
(then
|
|
174
|
+
(local.set $result (f64.div (local.get $result) (call $__pow10 (i32.sub (i32.const -308) (local.get $decExp)))))
|
|
175
|
+
(local.set $result (f64.div (local.get $result) (call $__pow10 (i32.const 308)))))
|
|
176
|
+
(else (local.set $result (f64.div (local.get $result) (call $__pow10 (i32.sub (i32.const 0) (local.get $decExp)))))))))`
|
|
154
177
|
|
|
155
178
|
// Eisel-Lemire correctly-rounded decimal-to-f64.
|
|
156
179
|
// Used in place of FINISH_SIGNIFICAND + POW10_SCALE. Keeps $mant as i64 until after
|
|
@@ -207,17 +230,17 @@ const DEC_TO_F64_WAT = `(func $__dec_to_f64
|
|
|
207
230
|
(local.set $mBits (i32.sub (i32.const 64) (i32.wrap_i64 (i64.clz (local.get $mant)))))
|
|
208
231
|
;; Normalize mant to 64-bit: w = mant << (64 - mBits)
|
|
209
232
|
(local.set $w (i64.shl (local.get $mant) (i64.extend_i32_u (i32.sub (i32.const 64) (local.get $mBits)))))
|
|
210
|
-
;;
|
|
211
|
-
;;
|
|
212
|
-
;;
|
|
213
|
-
;;
|
|
214
|
-
;;
|
|
215
|
-
;;
|
|
216
|
-
(if (i32.or (i32.lt_s (local.get $exp10) (i32.const -
|
|
217
|
-
(i32.gt_s (local.get $exp10) (i32.const
|
|
233
|
+
;; Full-range table: exp10 in [-342..308] — every finite/subnormal f64 decimal
|
|
234
|
+
;; parses correctly rounded (the trimmed [-65..65] table sent deep exponents to
|
|
235
|
+
;; the POW10_SCALE fallback, whose double rounding missed the subnormal boundary
|
|
236
|
+
;; by 1 ulp and whose 10^|e|>308 scale factor overflowed to Infinity, flushing
|
|
237
|
+
;; min-normal-adjacent literals to 0 — watr.wasm's float_literals leg). ~10.4KB
|
|
238
|
+
;; data on programs that pull __to_num; correctness owns the trade.
|
|
239
|
+
(if (i32.or (i32.lt_s (local.get $exp10) (i32.const -342))
|
|
240
|
+
(i32.gt_s (local.get $exp10) (i32.const 308)))
|
|
218
241
|
(then (return (f64.const nan))))
|
|
219
|
-
;; Load 128-bit table entry for exp10: tbl = $__el_tbl + (exp10 +
|
|
220
|
-
(local.set $tbl (i32.add (global.get $__el_tbl) (i32.shl (i32.add (local.get $exp10) (i32.const
|
|
242
|
+
;; Load 128-bit table entry for exp10: tbl = $__el_tbl + (exp10 + 342) * 16
|
|
243
|
+
(local.set $tbl (i32.add (global.get $__el_tbl) (i32.shl (i32.add (local.get $exp10) (i32.const 342)) (i32.const 4))))
|
|
221
244
|
(local.set $tblLo (i64.load (local.get $tbl)))
|
|
222
245
|
(local.set $tblHi (i64.load (i32.add (local.get $tbl) (i32.const 8))))
|
|
223
246
|
;; ─── Two-product: (prodHi:prodLo) = w × tblHi + (w × tblLo >> 64) ──────────
|
|
@@ -363,19 +386,40 @@ const DEC_TO_F64_WAT = `(func $__dec_to_f64
|
|
|
363
386
|
(i64.shl (i64.extend_i32_u (local.get $biased)) (i64.const 52))
|
|
364
387
|
(local.get $mant52))))`
|
|
365
388
|
|
|
389
|
+
// Hex → byte-string via char-array + one join. NOT `s += chr` in a loop: that
|
|
390
|
+
// allocates Σ1..n ≈ n²/2 bytes of dead strings (54 MB for the 10.4 KB EL table),
|
|
391
|
+
// and setup runs PER COMPILE inside the self-host kernel — a warm no-_clear
|
|
392
|
+
// instance exhausted its heap after ~70 compiles. join is linear: ~n boxes of
|
|
393
|
+
// array + 1-char strings plus the result.
|
|
394
|
+
const hexToBytes = (hex) => {
|
|
395
|
+
const chars = []
|
|
396
|
+
for (let i = 0; i < hex.length; i += 2) chars.push(String.fromCharCode(parseInt(hex.slice(i, i + 2), 16)))
|
|
397
|
+
return chars.join('')
|
|
398
|
+
}
|
|
399
|
+
|
|
366
400
|
export default (ctx) => {
|
|
367
401
|
deps({
|
|
368
402
|
__mkstr: ['__alloc'],
|
|
369
|
-
|
|
370
|
-
|
|
403
|
+
// own edge: __static_str's body calls $__mkstr — without it the helper
|
|
404
|
+
// rides the self-host-unreliable auto-scan (test/selfhost-includes.js)
|
|
405
|
+
__static_str: ['__mkstr'],
|
|
406
|
+
__ftoa: ['__itoa', '__pow10', '__mkstr', '__static_str', '__ftoa_shortest'],
|
|
407
|
+
__ftoa_shortest: ['__mkstr', '__static_str', '__alloc', '__itoa', '__ryu_mulshift', '__ryu_pow5', '__ryu_pow5div'],
|
|
408
|
+
__ryu_pow5: ['__ryu_mulhi'],
|
|
409
|
+
__ryu_mulshift: ['__ryu_mulhi'],
|
|
410
|
+
__ryu_mulhi: [],
|
|
411
|
+
__ryu_pow5div: [],
|
|
412
|
+
__i32_to_str: ['__itoa_s', '__mkstr'],
|
|
413
|
+
__itoa_s: ['__itoa'],
|
|
414
|
+
__ilen: [],
|
|
371
415
|
__toExp: ['__itoa', '__pow10', '__mkstr', '__static_str'],
|
|
372
416
|
__radix_str: ['__mkstr'],
|
|
373
417
|
__num_radix: ['__ftoa', '__mkstr'],
|
|
374
418
|
__to_num: ['__char_at', '__str_byteLen', '__pow10', '__dec_to_f64', '__to_str', '__skipws', '__ptr_aux'],
|
|
375
419
|
__skipws: ['__char_at', '__strws'],
|
|
376
420
|
__to_bigint: ['__char_at', '__str_byteLen', '__num_to_bigint'],
|
|
377
|
-
__parseInt: ['__char_at', '__str_byteLen'],
|
|
378
|
-
__parseFloat: ['__char_at', '__str_byteLen', '__pow10', '__dec_to_f64', '__to_str'],
|
|
421
|
+
__parseInt: ['__char_at', '__str_byteLen', '__skipws', '__to_str'],
|
|
422
|
+
__parseFloat: ['__char_at', '__str_byteLen', '__pow10', '__dec_to_f64', '__to_str', '__skipws'],
|
|
379
423
|
})
|
|
380
424
|
|
|
381
425
|
|
|
@@ -428,25 +472,52 @@ export default (ctx) => {
|
|
|
428
472
|
${reverseBytesWat()}
|
|
429
473
|
(local.get $len))`
|
|
430
474
|
|
|
475
|
+
// __ilen(val: i32) → i32 — exact byte length of ToString(val): sign + decimal
|
|
476
|
+
// digits over the unsigned magnitude (INT_MIN negates to itself; read unsigned the
|
|
477
|
+
// ladder still lands on 10). Must agree with __itoa_s byte-for-byte: the fused
|
|
478
|
+
// concat emitters alloc from __ilen totals and render with __itoa_s at the cursor —
|
|
479
|
+
// a one-byte disagreement is heap corruption (pinned differentially in test/strings.js).
|
|
480
|
+
ctx.core.stdlib['__ilen'] = `(func $__ilen (param $val i32) (result i32)
|
|
481
|
+
(local $u i32) (local $n i32)
|
|
482
|
+
(local.set $u (local.get $val))
|
|
483
|
+
(if (i32.lt_s (local.get $val) (i32.const 0))
|
|
484
|
+
(then
|
|
485
|
+
(local.set $u (i32.sub (i32.const 0) (local.get $val)))
|
|
486
|
+
(local.set $n (i32.const 1))))
|
|
487
|
+
(if (i32.lt_u (local.get $u) (i32.const 10)) (then (return (i32.add (local.get $n) (i32.const 1)))))
|
|
488
|
+
(if (i32.lt_u (local.get $u) (i32.const 100)) (then (return (i32.add (local.get $n) (i32.const 2)))))
|
|
489
|
+
(if (i32.lt_u (local.get $u) (i32.const 1000)) (then (return (i32.add (local.get $n) (i32.const 3)))))
|
|
490
|
+
(if (i32.lt_u (local.get $u) (i32.const 10000)) (then (return (i32.add (local.get $n) (i32.const 4)))))
|
|
491
|
+
(if (i32.lt_u (local.get $u) (i32.const 100000)) (then (return (i32.add (local.get $n) (i32.const 5)))))
|
|
492
|
+
(if (i32.lt_u (local.get $u) (i32.const 1000000)) (then (return (i32.add (local.get $n) (i32.const 6)))))
|
|
493
|
+
(if (i32.lt_u (local.get $u) (i32.const 10000000)) (then (return (i32.add (local.get $n) (i32.const 7)))))
|
|
494
|
+
(if (i32.lt_u (local.get $u) (i32.const 100000000)) (then (return (i32.add (local.get $n) (i32.const 8)))))
|
|
495
|
+
(if (i32.lt_u (local.get $u) (i32.const 1000000000)) (then (return (i32.add (local.get $n) (i32.const 9)))))
|
|
496
|
+
(i32.add (local.get $n) (i32.const 10)))`
|
|
497
|
+
|
|
498
|
+
// __itoa_s(val: i32, buf: i32) → i32 (bytes written) — signed decimal render at
|
|
499
|
+
// buf: '-' + digits over the unsigned magnitude. The render core shared by
|
|
500
|
+
// __i32_to_str (temp-string ToString) and the fused concat emitters (render
|
|
501
|
+
// directly at the destination cursor — no temp string, no copy).
|
|
502
|
+
ctx.core.stdlib['__itoa_s'] = `(func $__itoa_s (param $val i32) (param $buf i32) (result i32)
|
|
503
|
+
(if (i32.lt_s (local.get $val) (i32.const 0))
|
|
504
|
+
(then
|
|
505
|
+
(i32.store8 (local.get $buf) (i32.const 45)) ;; '-'
|
|
506
|
+
;; magnitude as unsigned: negate via 0 - val (INT_MIN maps to itself, __itoa reads unsigned)
|
|
507
|
+
(return (i32.add
|
|
508
|
+
(call $__itoa (i32.sub (i32.const 0) (local.get $val)) (i32.add (local.get $buf) (i32.const 1)))
|
|
509
|
+
(i32.const 1)))))
|
|
510
|
+
(call $__itoa (local.get $val) (local.get $buf)))`
|
|
511
|
+
|
|
431
512
|
// __i32_to_str(val: i32) → f64 (NaN-boxed string) — ToString for a value the
|
|
432
513
|
// compiler proved is a signed i32. The whole point is to bypass __ftoa's float
|
|
433
514
|
// machinery (shortest-repr search, __toExp, __pow10): a known integer renders with
|
|
434
|
-
// just
|
|
515
|
+
// just __itoa_s over a scratch buffer. Lets `"id " + (n|0)` and integer
|
|
435
516
|
// templates skip the ~2 KB float formatter the generic ToString hard-pulls.
|
|
436
517
|
ctx.core.stdlib['__i32_to_str'] = `(func $__i32_to_str (param $val i32) (result f64)
|
|
437
|
-
(local $buf i32)
|
|
518
|
+
(local $buf i32)
|
|
438
519
|
(local.set $buf (call $__alloc (i32.const 12)))
|
|
439
|
-
(
|
|
440
|
-
(then
|
|
441
|
-
(i32.store8 (local.get $buf) (i32.const 45)) ;; '-'
|
|
442
|
-
;; magnitude as unsigned: negate via 0 - val (INT_MIN maps to itself, read u below)
|
|
443
|
-
(local.set $u (i32.sub (i32.const 0) (local.get $val)))
|
|
444
|
-
(local.set $len (call $__itoa (local.get $u) (i32.add (local.get $buf) (i32.const 1))))
|
|
445
|
-
(return (call $__mkstr (local.get $buf) (i32.add (local.get $len) (i32.const 1)))))
|
|
446
|
-
(else
|
|
447
|
-
(local.set $len (call $__itoa (local.get $val) (local.get $buf)))
|
|
448
|
-
(return (call $__mkstr (local.get $buf) (local.get $len)))))
|
|
449
|
-
(f64.const 0))`
|
|
520
|
+
(call $__mkstr (local.get $buf) (call $__itoa_s (local.get $val) (local.get $buf))))`
|
|
450
521
|
|
|
451
522
|
// __radix_str(val: i64, radix: i32) → f64 (NaN-boxed string)
|
|
452
523
|
// Signed integer → radix string for BigInt.prototype.toString(radix). Digits go
|
|
@@ -554,11 +625,12 @@ export default (ctx) => {
|
|
|
554
625
|
// Hot (~60M calls in watr self-host via __ftoa). bulk memory.copy is ~10× faster than
|
|
555
626
|
// a hand-rolled byte loop (wasm2c lowers it to memcpy under PGO+LTO).
|
|
556
627
|
ctx.core.stdlib['__mkstr'] = `(func $__mkstr (param $buf i32) (param $len i32) (result f64)
|
|
557
|
-
(local $off i32) (local $i i32) (local $packed
|
|
558
|
-
;; SSO fast path: ≤
|
|
628
|
+
(local $off i32) (local $i i32) (local $packed i64) (local $b i32)
|
|
629
|
+
;; SSO fast path: ≤6 ASCII bytes pack into the pointer with no allocation, so a
|
|
559
630
|
;; number-format result doesn't displace a heap-top accumulator — keeping the
|
|
560
631
|
;; canonical \`s += n.toString(r)\` builder O(n) via the bump-extend path.
|
|
561
|
-
|
|
632
|
+
;; ≤6-ASCII⇒SSO is also the string-module INVARIANT __str_eq relies on.
|
|
633
|
+
(if (i32.le_u (local.get $len) (i32.const 6))
|
|
562
634
|
(then
|
|
563
635
|
(block $heap
|
|
564
636
|
(loop $pk
|
|
@@ -566,11 +638,16 @@ export default (ctx) => {
|
|
|
566
638
|
(then
|
|
567
639
|
(local.set $b (i32.load8_u (i32.add (local.get $buf) (local.get $i))))
|
|
568
640
|
(br_if $heap (i32.ge_u (local.get $b) (i32.const 0x80)))
|
|
569
|
-
;; 7-bit ASCII SSO: char i at bit i*7
|
|
570
|
-
(local.set $packed (
|
|
641
|
+
;; 7-bit ASCII SSO: char i at payload bit i*7; len at payload bits 42-44.
|
|
642
|
+
(local.set $packed (i64.or (local.get $packed)
|
|
643
|
+
(i64.shl (i64.extend_i32_u (local.get $b)) (i64.mul (i64.extend_i32_u (local.get $i)) (i64.const 7)))))
|
|
571
644
|
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
572
645
|
(br $pk))))
|
|
573
|
-
(return (
|
|
646
|
+
(return (f64.reinterpret_i64 (i64.or
|
|
647
|
+
(i64.or
|
|
648
|
+
(i64.const ${ptrNanHex(PTR.STRING, LAYOUT.SSO_BIT)})
|
|
649
|
+
(i64.shl (i64.extend_i32_u (local.get $len)) (i64.const 42)))
|
|
650
|
+
(local.get $packed)))))))
|
|
574
651
|
(local.set $off (call $__alloc (i32.add (i32.const 4) (local.get $len))))
|
|
575
652
|
(i32.store (local.get $off) (local.get $len))
|
|
576
653
|
(local.set $off (i32.add (local.get $off) (i32.const 4)))
|
|
@@ -590,17 +667,10 @@ export default (ctx) => {
|
|
|
590
667
|
(if (f64.ne (local.get $val) (local.get $val)) (then (return (call $__static_str (i32.const 0)))))
|
|
591
668
|
(if (f64.eq (local.get $val) (f64.const inf)) (then (return (call $__static_str (i32.const 1)))))
|
|
592
669
|
(if (f64.eq (local.get $val) (f64.const -inf)) (then (return (call $__static_str (i32.const 2)))))
|
|
593
|
-
;;
|
|
594
|
-
;;
|
|
595
|
-
;; Fewer digits than ECMAScript shortest-repr ideal, but valid output.
|
|
670
|
+
;; Default mode: ES-exact shortest round-trip digits + notation (Ryū core) —
|
|
671
|
+
;; the rest of this function serves mode 1 (toFixed/toPrecision) only.
|
|
596
672
|
(if (i32.eqz (local.get $mode))
|
|
597
|
-
(then
|
|
598
|
-
(if (f64.ge (f64.abs (local.get $val)) (f64.const 1e21))
|
|
599
|
-
(then (return (call $__toExp (local.get $val) (i32.const 8) (i32.const 1)))))
|
|
600
|
-
(if (i32.and
|
|
601
|
-
(f64.gt (f64.abs (local.get $val)) (f64.const 0))
|
|
602
|
-
(f64.lt (f64.abs (local.get $val)) (f64.const 1e-6)))
|
|
603
|
-
(then (return (call $__toExp (local.get $val) (i32.const 8) (i32.const 1)))))))
|
|
673
|
+
(then (return (call $__ftoa_shortest (local.get $val)))))
|
|
604
674
|
(local.set $buf (call $__alloc (i32.const 40)))
|
|
605
675
|
;; Sign
|
|
606
676
|
(if (f64.lt (local.get $val) (f64.const 0))
|
|
@@ -610,9 +680,6 @@ export default (ctx) => {
|
|
|
610
680
|
(if (local.get $neg)
|
|
611
681
|
(then (i32.store8 (local.get $buf) (i32.const 45))
|
|
612
682
|
(local.set $pos (i32.const 1))))
|
|
613
|
-
;; Default mode: auto-select precision (up to 9 digits, must fit i32 when scaled)
|
|
614
|
-
(if (i32.eqz (local.get $mode))
|
|
615
|
-
(then (local.set $prec (i32.const 9))))
|
|
616
683
|
;; Round and scale to integer: scaled = nearest(val * 10^prec).
|
|
617
684
|
;; NOTE: toFixed/toPrecision round ties-to-even here (f64.nearest), which differs from
|
|
618
685
|
;; JS's round-half-away-from-zero on exact halves like (2.5).toFixed(0) → '2' vs '3'.
|
|
@@ -634,25 +701,7 @@ export default (ctx) => {
|
|
|
634
701
|
(then
|
|
635
702
|
(local.set $int (i32.trunc_f64_u (f64.div (local.get $scaled) (local.get $scale))))
|
|
636
703
|
(local.set $frac (i32.trunc_f64_u (f64.sub (local.get $scaled)
|
|
637
|
-
(f64.mul (f64.convert_i32_u (local.get $int)) (local.get $scale)))))
|
|
638
|
-
;; Default mode, fit loop reduced prec to 0: the rounded integer is ready, but the
|
|
639
|
-
;; original val may still have a fractional part that was discarded. Recover it:
|
|
640
|
-
;; frac_f = val - trunc(val); since frac_f ∈ [0,1), frac_f*10^9 < 10^9 < 2^31 — safe.
|
|
641
|
-
(if (i32.and (i32.eqz (local.get $mode)) (i32.eqz (local.get $prec)))
|
|
642
|
-
(then
|
|
643
|
-
(local.set $abs (f64.sub (local.get $val) (f64.trunc (local.get $val))))
|
|
644
|
-
(if (f64.gt (local.get $abs) (f64.const 0))
|
|
645
|
-
(then
|
|
646
|
-
;; $int was taken from f64.nearest(val), which rounds .5+ UP (999999999.9 → 1e9),
|
|
647
|
-
;; but $abs/$frac below derive from f64.trunc(val). Re-derive $int from the same
|
|
648
|
-
;; trunc so integer and fraction agree — else String(999999999.9) → "1000000000.9".
|
|
649
|
-
(local.set $int (i32.trunc_f64_u (f64.trunc (local.get $val))))
|
|
650
|
-
(local.set $prec (i32.const 9))
|
|
651
|
-
(local.set $scale (call $__pow10 (i32.const 9)))
|
|
652
|
-
;; round: trunc_u(x+0.5) == floor(x+0.5) for the positive frac scale
|
|
653
|
-
(local.set $frac (i32.trunc_f64_u (f64.add
|
|
654
|
-
(f64.mul (local.get $abs) (f64.const 1000000000))
|
|
655
|
-
(f64.const 0.5)))))))))
|
|
704
|
+
(f64.mul (f64.convert_i32_u (local.get $int)) (local.get $scale))))))
|
|
656
705
|
(else
|
|
657
706
|
(local.set $int (i32.const 0))
|
|
658
707
|
(local.set $frac (i32.const 0))
|
|
@@ -682,43 +731,6 @@ export default (ctx) => {
|
|
|
682
731
|
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
683
732
|
(local.set $j (i32.sub (local.get $j) (i32.const 1)))
|
|
684
733
|
(br $rl)))
|
|
685
|
-
;; Default mode: emit fractional part if val has one (large-int path skipped it before).
|
|
686
|
-
;; frac_f = val - trunc(val); since frac_f ∈ [0,1), frac_f*10^9 < 10^9 < 2^31 — safe.
|
|
687
|
-
(if (i32.eqz (local.get $mode))
|
|
688
|
-
(then
|
|
689
|
-
(local.set $abs (f64.sub (local.get $val) (f64.trunc (local.get $val))))
|
|
690
|
-
(if (f64.gt (local.get $abs) (f64.const 0))
|
|
691
|
-
(then
|
|
692
|
-
;; round: trunc_u(x+0.5) == floor(x+0.5) for the positive frac scale
|
|
693
|
-
(local.set $frac (i32.trunc_f64_u (f64.add
|
|
694
|
-
(f64.mul (local.get $abs) (f64.const 1000000000))
|
|
695
|
-
(f64.const 0.5))))
|
|
696
|
-
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 46))
|
|
697
|
-
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
698
|
-
;; 9 fractional digits from $frac, high-to-low
|
|
699
|
-
(local.set $i (i32.const 8))
|
|
700
|
-
(block $fd2 (loop $fl2
|
|
701
|
-
(br_if $fd2 (i32.lt_s (local.get $i) (i32.const 0)))
|
|
702
|
-
(local.set $j (i32.div_u (local.get $frac) (i32.trunc_f64_u (call $__pow10 (local.get $i)))))
|
|
703
|
-
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
704
|
-
(i32.add (i32.const 48) (i32.rem_u (local.get $j) (i32.const 10))))
|
|
705
|
-
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
706
|
-
(local.set $i (i32.sub (local.get $i) (i32.const 1)))
|
|
707
|
-
(br $fl2)))
|
|
708
|
-
;; Strip trailing zeros
|
|
709
|
-
(block $sz2 (loop $sl2
|
|
710
|
-
(br_if $sz2 (i32.le_s (local.get $pos) (i32.const 0)))
|
|
711
|
-
(br_if $sz2 (i32.ne
|
|
712
|
-
(i32.load8_u (i32.add (local.get $buf) (i32.sub (local.get $pos) (i32.const 1))))
|
|
713
|
-
(i32.const 48)))
|
|
714
|
-
(local.set $pos (i32.sub (local.get $pos) (i32.const 1)))
|
|
715
|
-
(br $sl2)))
|
|
716
|
-
;; Strip trailing dot
|
|
717
|
-
(if (i32.and (i32.gt_s (local.get $pos) (i32.const 0))
|
|
718
|
-
(i32.eq
|
|
719
|
-
(i32.load8_u (i32.add (local.get $buf) (i32.sub (local.get $pos) (i32.const 1))))
|
|
720
|
-
(i32.const 46)))
|
|
721
|
-
(then (local.set $pos (i32.sub (local.get $pos) (i32.const 1)))))))))
|
|
722
734
|
(return (call $__mkstr (local.get $buf) (local.get $pos)))))
|
|
723
735
|
;; Write integer part
|
|
724
736
|
(local.set $ilen (call $__itoa (local.get $int) (i32.add (local.get $buf) (local.get $pos))))
|
|
@@ -737,19 +749,6 @@ export default (ctx) => {
|
|
|
737
749
|
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
738
750
|
(local.set $i (i32.sub (local.get $i) (i32.const 1)))
|
|
739
751
|
(br $fl)))))
|
|
740
|
-
;; Default mode: strip trailing zeros and dot — only when a fractional part was emitted.
|
|
741
|
-
;; Gating on $prec>0 prevents stripping zeros from the integer part (e.g. 1079623680 → 107962368)
|
|
742
|
-
;; for values where auto-fit reduced prec to 0 because the scaled integer wouldn't fit i32.
|
|
743
|
-
(if (i32.and (i32.eqz (local.get $mode)) (i32.gt_s (local.get $prec) (i32.const 0)))
|
|
744
|
-
(then
|
|
745
|
-
(block $sd (loop $sl
|
|
746
|
-
(br_if $sd (i32.le_s (local.get $pos) (i32.const 0)))
|
|
747
|
-
(br_if $sd (i32.ne (i32.load8_u (i32.add (local.get $buf) (i32.sub (local.get $pos) (i32.const 1)))) (i32.const 48)))
|
|
748
|
-
(local.set $pos (i32.sub (local.get $pos) (i32.const 1)))
|
|
749
|
-
(br $sl)))
|
|
750
|
-
(if (i32.and (i32.gt_s (local.get $pos) (i32.const 0))
|
|
751
|
-
(i32.eq (i32.load8_u (i32.add (local.get $buf) (i32.sub (local.get $pos) (i32.const 1)))) (i32.const 46)))
|
|
752
|
-
(then (local.set $pos (i32.sub (local.get $pos) (i32.const 1)))))))
|
|
753
752
|
(call $__mkstr (local.get $buf) (local.get $pos)))`
|
|
754
753
|
|
|
755
754
|
// __toExp(val: f64, prec: i32, strip: i32) → f64 (NaN-boxed string)
|
|
@@ -837,7 +836,12 @@ export default (ctx) => {
|
|
|
837
836
|
|
|
838
837
|
// __static_str(id: i32) → f64 — create heap string from data segment
|
|
839
838
|
// 0=NaN 1=Infinity 2=-Infinity 3=true 4=false 5=null 6=undefined 7=[Array] 8=[Object]
|
|
840
|
-
|
|
839
|
+
// Thunked: shared memory has no active data segment at 0 — the static-string
|
|
840
|
+
// region is memory.init'd into __alloc'd space at start (compile/index.js) and
|
|
841
|
+
// reads rebase off $__staticBase. Owned memory keeps absolute offsets (base 0).
|
|
842
|
+
ctx.core.stdlib['__static_str'] = () => {
|
|
843
|
+
if (ctx.memory.shared && !ctx.scope.globals.has('__staticBase')) declGlobal('__staticBase', 'i32')
|
|
844
|
+
return `(func $__static_str (param $id i32) (result f64)
|
|
841
845
|
(local $src i32) (local $len i32)
|
|
842
846
|
(local.set $src (i32.const 0)) (local.set $len (i32.const 0))
|
|
843
847
|
(if (i32.eqz (local.get $id)) (then (local.set $len (i32.const 3))))
|
|
@@ -849,11 +853,16 @@ export default (ctx) => {
|
|
|
849
853
|
(if (i32.eq (local.get $id) (i32.const 6)) (then (local.set $src (i32.const 33)) (local.set $len (i32.const 9))))
|
|
850
854
|
(if (i32.eq (local.get $id) (i32.const 7)) (then (local.set $src (i32.const 42)) (local.set $len (i32.const 7))))
|
|
851
855
|
(if (i32.eq (local.get $id) (i32.const 8)) (then (local.set $src (i32.const 49)) (local.set $len (i32.const 8))))
|
|
852
|
-
(
|
|
856
|
+
(if (i32.eq (local.get $id) (i32.const 9)) (then (local.set $src (i32.const 57)) (local.set $len (i32.const 2))))
|
|
857
|
+
(if (i32.eq (local.get $id) (i32.const 10)) (then (local.set $src (i32.const 59)) (local.set $len (i32.const 9))))
|
|
858
|
+
(if (i32.eq (local.get $id) (i32.const 11)) (then (local.set $src (i32.const 68)) (local.set $len (i32.const 9))))
|
|
859
|
+
(call $__mkstr ${ctx.memory.shared ? '(i32.add (global.get $__staticBase) (local.get $src))' : '(local.get $src)'} (local.get $len)))`
|
|
860
|
+
}
|
|
853
861
|
|
|
854
862
|
// R: Static strings seeded at address 0. Compile.js strips if __static_str unused.
|
|
855
863
|
// 0=NaN 1=Infinity 2=-Infinity 3=true 4=false 5=null 6=undefined 7=[Array] 8=[Object]
|
|
856
|
-
|
|
864
|
+
// 9=ok 10=not-equal 11=timed-out (Atomics.wait results, module/atomics.js)
|
|
865
|
+
const staticStr = 'NaNInfinity-Infinitytruefalsenullundefined[Array][Object]oknot-equaltimed-out'
|
|
857
866
|
ctx.runtime.staticDataLen = staticStr.length
|
|
858
867
|
ctx.runtime.data = (ctx.runtime.data || '') + staticStr
|
|
859
868
|
|
|
@@ -865,18 +874,380 @@ export default (ctx) => {
|
|
|
865
874
|
// 2096-byte data segment out of modules that don't do decimal→f64 conversion.
|
|
866
875
|
// TRIMMED to exp10 in [-65..65] (see __dec_to_f64 range check). Each entry: 8
|
|
867
876
|
// bytes tblLo (LE) + 8 bytes tblHi (LE), for exp10 = -65 + i.
|
|
868
|
-
const EL_TABLE_HEX = 'e9b4c29f1247e998eaba94ea52bbcc862462b347d798233fa5e939a527ea7fa8ad3aa0190d7fec8e0e64888eb1e49fd2ac24043068cf5319893e15f9eeeea383d72d053c42c3a85f2b8e5ab7aaea8ca44d7906cb12f49237b63131655525b0cdd00be4be8bd8bbe211bf3e5f55178e80c40e9daeaece6a5bd66e0eb72a9db1a07552445a5a8245f28b0ad2647504dec81267d5f0f0e2d6ee2e8d06be928515fb6b608596d64d46553d18c4b67b73ed9c86b8263c4ce197aa4c1e75a45ad028c4a866304b9fd93dd5df65924d710433f52940fe8e03a846e5ab7f7bd0c6e23f9933d0bd72045298de965f9a8478db8fbf40446d8f85663e967cf7c0a556d273efa84aa4791300e7ddad9a98277663a895525d0d5818c0605559c17eb1537c12bba6b4106e1ef0b8aaaf71de9d681bd7e9e870ca041396b3ca0d07ab6221712692220dfdc5977b603dd1c855bb690db0b66a507cb77d9ab88c053b2b2ac4105ce442b2ad928e60f377e3045b9a7a8ab98ed31e5937b238f0551cc6f14019ed67b288662fc5de466c6ba3372e915fe801df15a03d3b4bac2323c6e2bcba3b31618b1a080d0a5e97ecab771b6ca98a7d39ae214a908c35bde7965522c753eddcc7d9542eda7741d6507e75755c5414ea1c88e9b9d0d5d10be5ddd2927369992424aa64e8444bc64e5e958777d0c3bf2dadd43e110bef3bf15abdb44a62da973cec848ed5cdea8aadb1ec61ddfad0bd4b27a6f24a81a5ed18de67ba943945ad1eb1cfd7ce708794cfea80f4fc434b2cb3ce818d024da9798325a131fc145ef75f42a23043a01358e46e093e3b9a35f5f7d2cafc5388186e9dca8b0dca0083f2b587fd7d3455cf64a25e77487ee091b7d1749e9d812a03fe4a3695da9d5876250612c60422f583bddd833a51c5eed3ae8796f742357972966a92c4523b7544cd14be9a9382170f3c05b775278a9295009a6dc13863dd128bc62453b12cf7ba8000c9f1035ecaeb16fcf6d3ee7bda7450a01d9784f5bca61cbbf488ea1a11926408e5bce5326cd0e3e9312ba56195b67d4a1eeccf9f43622e32ff3a075d1d928eee9293c287d4fab9febe0949b4a43632aa77b8b3a9897968be2e4c5be14dc4be9495e6100af64b01379d0fd9acb03af77c1d90948cf39ec18484530fd85c0935dc24b4b96fb006f2a56528130eb44b42132ee1d3452e44b7873ff9cb88506f09ccbc8c48d73915a5698ff7feaa24cb0bffebaf1b4d885a0e4473b5bed5edbdcefee6db303095f8880a683197a5b436415f70893d7cba362b0dc2fdfcce61841177ccab4c1b69047690323dbc427ae5d594bfd60fb1c1c2499a3fa6b5696caf05bd3786531d7233dc80cf0f2384471b47acc5a7a8a44e401361c3d32b6519e25817b7d1e9263108ac1c5a643bdf4f8d976e1283a3703d0ad7a3703d0ad7a3703d0ad7a3cccccccccccccccccccccccccccccccc00000000000000000000000000000080000000000000000000000000000000a0000000000000000000000000000000c8000000000000000000000000000000fa0000000000000000000000000000409c000000000000000000000000000050c3000000000000000000000000000024f4000000000000000000000000008096980000000000000000000000000020bcbe00000000000000000000000000286bee00000000000000000000000000f9029500000000000000000000000040b743ba00000000000000000000000010a5d4e80000000000000000000000002ae78491000000000000000000000080f420e6b50000000000000000000000a031a95fe3000000000000000000000004bfc91b8e0000000000000000000000c52ebca2b10000000000000000000040763a6b0bde00000000000000000000e8890423c78a0000000000000000000062acc5eb78ad000000000000000000807a17b726d7d800000000000000000090ac6e32788687000000000000000000b4570a3f1668a9000000000000000000a1edccce1bc2d30000000000000000a0841440615159840000000000000000c8a51990b9a56fa500000000000000003a0f20f4278fcbce0000000000000040840994f878393f810000000000000050e50bb936d7078fa100000000000000a4de4e6704cdc9f2c9000000000000004d96228145407c6ffc00000000000020f09db5702ba8adc59d000000000000286c05e34c36121937c500000000000032c7c61be0c356df84f60000000000407f3c5c116c3a960b139a0000000000109f4bb31507c97bce97c00000000000d4861e20db48bb1ac2bdf00000000080441413f4880db55099769600000000a055d91731eb50e2a43f14bc0000000008abcf5dfd25e51a8e4f19eb00000000e5caa15abe37cfd0b8d1ef92000000409e3d4af1ad05030527c6abb7000000d005cd9c6d19c743c6b0b796e5000000a2230082e46f5cea7bce327e8f0000808a2c80a2dd8bf3e41a82bf5db3000020ad37200bd56e309ea1622f35e0000034cc22f4264545de02a59d3d218c0000417f2bb17096d695430e058d29af0040115f76dd0c3c4c7bd45146f0f3da00c86afb690a88a50fcd24f32b76d888007a457a040dea8e5300eeefb6930eab80d8d6984590a4726880e9aba438d2d55047867f2bdaa64741f071eb6663a38524d9675fb6909099516c4ea6403c0ca76dcf41f7e3b4f4ff6507e2cf504bcfd0a421897a0ef1f8bf9f44ed81128f81820d6a2b19522df7afc7956822d7f221a39044769fa6f8f49b39bb02eb8c6feacbb4d55347d036f202086ac325700be5fe9065942c4262d70145229a1726274f9ff57eb9b7d23a4d42d6aa809deff022c7b2dea7658789e0d28bd5e0842badebf82feb889ff455cc6377850c333b4c939bfb256bc7716bbf3cd5a6cfff491f78c27aef45394e46ef8b8a90c37f1c2716f3'
|
|
869
|
-
// Pre-decode the EL table bytes
|
|
877
|
+
const EL_TABLE_HEX = '3f3ba10629aa3f115ad63b92d653f4ee07c524a459cac74af865651b66b4589549f62d0df0bc795d76bf3ea27fe1aebadc7379102c2cd8f4536fce8adf995ae969e84b8a9b1b07799405c1b62ba0d89184e2de6c82e24897f94671a436c84eb6259b1608231b1bfdb7988d4d447ae2e3f7200ee5f5f030fe727f78b06a8c6d8e35a9515e332dbdbd4f9f965c85ef08b28213e63580782cad2347bcb3662b8bde31ccaf2150cb3b4c76ac553020fb168b3dbf1b2a24be4adf93176b3ce8b9dcad0dafa234ad6d1dd778dd854b62e853d968ade5408c6472866baa336f3d71d487c2181f51affd0e68069500cb8c8dc9a9f2de66251bbd120248bac0fdeff03bd4574b60f730b64b016d7498fe9576a5842d5e3835bda39e4188913e7e3bd4cea5b9758682ac4c0652ea35ce5d4a8942cf930994d1ebef4373b2e1a07ace958981f80bf9c5e6eb14101f1a491942fbeba1f64e7777e0261ad4a6609b9f12fa66cab422559598b02089d038824797b800fdb035555d5f6eb4558263b18c5e73209e1d83aa34f78921eb62bcdd2f3690a8c5e423d50175ece9a57b2bd5bb43b412f76e362521c933b2472d3b6555aab06b9a0a846e69bbc09e99f889beead49c06c10d25ca43ea7006c0762c6e250a4448f128575e6a92060438cadb6457862acd96f2ecf504370805c6bc123eed277580bc2e6833c6444a86f76b978de87192a0eb1d21e0fb6aeeb37aa37e5831875b44936429d8ba05ea60594c9eaefd687215b8bd338e298724b96fdf451a3d03cf1ae656e0f879d4b6d3a5ab6b300662c1d08f6c18779889a4488f9686bc87baf1c4b387de94feabcd1a333ca8ab29292eb6e0140b1d7f8bc0f09f25490bbad9dc718cd94de45eaef0ec076f1b8e2810548eaf50619df6d92ce8c94aa2b13214e971dbd25c223a081c31be6e05af9fac31278906f4aa480a63bd6dcac69ac717fe70ab08b1d5daccbb2c097d7881b99d3d4dd6a58ec50860f5bb254eebf0938246f0854ef2f60ab8f22aaf2126ed3823586ca7e1aeb40d66aff51aaa6f28072c6e47d14ded90c89f8dd950ca457984dba4cc82a028b5ba07f10fe53c97976512ce7fa3c87262a949ed531e0c7dfdfe96c15fcc7a0fbb139ce8e8254fdcbcbefcb177fface9548c6191b177b10936f73dcfaa9f17246aefb9f59dd51d8c03750d8395c71dad446b2873054b256f44d2d0e37af932ec0a43f967e34e77c56a8362ceec9b3fa7cd93f7419c22d5764524fb01e8c20f11c1787552436b8ad456ed7902a2f3a9aa786b89130a83d64456348c41459853d556c66b98cc230cd66b41ef9156bea88aecb786bebf2c8fcbc6116b36eceda9d6f33214d7f77b393f1ceb02a2b39453ccb03fd9ccf5da074fe3a5838ae0b968ff9c8f0f40b3d1c9225c8f24ad58e8a11fc2b909081023be9599d9366c37918aa732280c0ad4ab2dfbff8f444785b56c513f328f0cc916f9f9ffb31599e6e2e392677fd9a73dae3bfc7f90ad1fd08d9c7741dfcf11cd994afb9ff4982744b183d511d7435640401dfac7317f3195dd72256b66ea35284852fc1c7fef3e7d8acfee0500654332da663be45eab8e1cad826a07403ed4be90404a9d3656b263d891a204e8a644775a684e22e2754f3e8736cb05a2d015157102e2aa5a53e30da9033e87ca445b5a0d839a5531285c51d3c28694fe0a7958e89180d51e99d9128472a839be4d976e62b6e08a66ff8f17a58f12c82d213d0afbe3982d40ff735dce990b9dbc3466e67c8e7f1c887f68fa80804ec4ebc1ff1f1c729f236a9f0239a12062b566b2ff27a34e87ac44474387c9a8ba62009ffff14b22a9d7151914e9fba9b43d60c33f776fb5c9a6ad8fac719dd3214d38b40f55cb227c1099b317cec4486a6046a1532a7e2b9b547fa09d01f66d42fccb4474da2efbe0944f8402c1990853fbfe551191fa39197a63254331c0ca27ba7eab553579889f58bcee933df0de58342f8b55c14bb563b735757c2696166f01fbedaab19ea23c2583921bb0bbdccac179a9155e46cb8bee2377229ceac91e19ec89cdfa0b5f1775768a95a1927b661f67ec80f9ce365d1214edfa49b71a40e78027e1b78284f41659a8791ce5108890b0b8ecb2d1d258ae3709cc318f15aab4dce6a71f8607ef99850b3ffeb29ad4e193e091a767c96a0067cecebddfe0246d5c2cbbc8e0bd42600041a1d68b186e8873f7e9fa586d5378409149ccae9e896a5075a439af48689690f55b7fda03964252c906846d2d015e7a79998f88833bd3a67b08e5c87881f5d8d77fb3aa640a88909a4a1efbd6e132cfcd5f60d57f06559aa0eef25c26cd7fa1e03b5c851e48eac048aa2ff46fc0dfc9d84ab3a626da24f1da943bf18bb057fc8e1d60d05808b7d6083dc57657ceb65d79123c826eca640c4b8c7654ed8124b51717cba209fd7dcf5d2f94a968a26da2dddc7dcb4c7c5d43353bf9d3020b090b15545dfeaf6d1a4a01c57bc4e1a6e5268d54fa9e1b09a19c41b69a359a109f70b0e9b8c6624bc903d26301c3c0d4c68c1c2467f81dcf5d4263dee079f844fcd79176409be442f512fc1559983656fb4d369410c29d93b2177b5b6f3ec42b7ae143b994f2429ccfee2c9905a75a5bec6ccaf39c975383832a78ffc65031722708bd3084bd2864243556bff8a4bd4e314aec3ce5ec99be36e195771b8736d15eae13460f943f6e84597b55e2288485f699981713b9cf89e52fdaea1a33e52674c07edd57e72176ef5dc8d2f03f4f9848386fea9690a9536b757a07ed0f63be5a060ba5bcb49428c6125949e8d3fb6df1c74dceebe15cd9bbabd72d7164bde4f69cf060338db3cfaa964d798dbdec9d34c42c3980b0a08355fca0d7f0ec67c541f57747a0dc4472b59dc48616f4601b49f9aa2ce489d5ce22c575281c3139629bb7d5375dac8b826b369332637dc73a8225cb8574d7973103029cff5daebc6471f79ed3a886fcfd8302837ff5d9ebbd4db5860853a87bfd24c363df72d0662da162a8ca67d26d1ef7599ecb474260bca43da9de808308e674f085bed95278eb0d8d531661a48b1f926c272e906756665170e85b79cdb653dba3d81cba00f6df324671d96b80a428d2cc0ea4e880f397bf97cdcf86a0cdb2068012cd2261f07daffdc083a8c8815f082057806b796c5d1b3db1a4d2fab03b05743630e3cb631a31c6eea6c39c9c8a061144fcdbbefc60bd77aa90f4c3442d481555fb92ee3bb9ac15d5b4f1f44a1c4d2d15dd1b75c5f38b2d051117995d63a0785ad462d2b6f0ee7846d55cbf347cc8167189fb86e4ac2a17980a34efa04d3daee6355dd40eac7a0e9f86809509a1cc5960837489125719d246a8e0ba4bc93f7038a4d12bd7ac9f8658d298e9cfdd2746a306637b06cc23547783ff9142d5b1174cc83b1a08bf2c2955647fb6934a9e1d5fbaca20caee77736a3d1fe49cee82727bb47e543ef52a886286938e43aa234f9a619ee98db2352afb6738b2d494ece200fa0564311fc3f4f981c6de04ddd38d40bc83de7ef3f9383c113c8b45d448b150ab24965e7038478b150bae57099bdd24d6ad3b768c0619eeda8dd9d6e5800ad7a54ce5c917a4cfd4a8f8874c1f21cd4ccf9f5ebc1d8d030ad3f6a91f67690020c347762b657084cc8774d473e04100f4d9ec293b3fc6d2dfd4c88490585200711068f409cf77c7170afba5b4ee66408d148271ccc255b99dcc79cf30554048d84cf1c6bf99d593e21fac817c6a505a0ea0adb82f00cb38db2717a21c85e4f01108d9a63bc0fd06d2f19cca63a61d6d164a8f904a30bd88462e44fdfe8732044e8e599a2e3e7615ec9c4a9efd293f85e1f1ef40bacdd31a2744ddc57cf48ee659ee2bd128c188e1309554f7ce581930f874bb82b978f58c3edd949a01af1f3c36526ae3e7d632308e143ac1c19a27cbc3e644dca18c3fbcb19988f1b9c0f85e3a10ab29e5b7a7150f60f596e7f0b6f648d41574dea511db12b8b2bc21ad64345b491b11560fd6911766dfeb34ecbe00d90db1ca95c925bbce9f6b9342a7ee404f515d3dfb3bef69c28746b812512a11a3a5b40cfa0a6b04b32958e6ab72baea85e7f047dce6c2e20f1af78f560f69656721ed5993a073db93e0f4b32c53c33ec1696830b88850d2b818f2e0fb133ac71842411e73557283734f978cfa9808f99e92d1e5cfea4e645023bdaf39bf4ab746f745df83a5627d246cacdb83b78e328cba8b6b72a75dce96c34b896465323f2fa96e064f11f5817cb49eabbdfefe0e7b530ac8a25572a29b6186d6365f5fe92c7406bd8575874501fd13860437b7233811482ce752e99641fc98a7c504a52c86155af7a0a7a3fc513b7fd1fb22e7db734d989ac448e63d1385ef82baebe0d2d0603ec1f5da5f0d5866aba3a826990705f98d31b3d1b710ee3f96cc52707f494677f1fd1fc6e594e9cfbbff33a6efed8beab6fed39b0ffdf161d59fc08f6be92ea564fec882537c6ebacac7b073c6a37acefd3d7b63681b0a69bdf94e085ca60ca1be062d3e2151a661169c620af3cf4f496e48b88d69e50ffa1bc3faccefc3a3db895a26f1c3de93f8e2f31ce0755a462996f8b7763a6b5cdb6d98235813f197b3bbf665140986335289be2c2e58ed7da06a747f598b67c0a62beedc1c57b44ea4c2a8ef17b7403848db9413e46c61624df392ebdde450461a12ba171dc8f9ba20b07766151ee5d7a096e82e121ddc7414ce0a60cd32ef86245e91ba5624139299810db880ffaaa8adb5b5696ced97f6ffe110e660bfd5121923e3c163f41efa3f8dca8f9c97c5abeff58db27cb1a6f88f30bdb383fdb6966b73b1dedb5dd0f6b37caca0e4bc647c46d0dd6ba93a427af0cd6be40ef6be0d2ca28ac653c9d2986cc1869d92b32e11b74aadb7a87b07bfc771e84477607ad5649dd87249ad64d71c47118b4a7c6c055f6287cf9bd83d0de498d52d5d9bc7c6f63aa9c3c24e8d101dff4a7934827978b489d3ba3951582a72dfcecb60f14bcb103684288865eeb44e97c2feb8ed1efe9443a532eafe2962223d733e27a9a63d7a94ce5f523f5a7d35060887b8298866cc1c81f726cfb0dcc207caa826342a80ff63a1b5f002dd93b389fc5230c13460ffbcc9e2ac43d47820acbb677cf141383f2cfc0d4caa844b944bd5c0ed362983a79b9d11dfd4655e799e0a31a984f3639102c5d5164affb517464d7dd365f0bc3543f6454e8ebfd1ce4b502ea43f169601ea99d6e1712f86c25ee4398dcf9bfb8164c04c5a4ebb2773765d8870c3827aa27df06ff810d5f8076a3a5526ba918c854e968b36550af7890489eaaf28b6ef26e2bb2e84eacc74ac452be5dbb2a3abb0daea9d921200c98b0b3b6fc94f466baec89244371740bb6ece09cbbbe31706da7ab715051d106a0a42ccbdaadc9d879059e52d23124a8246a99fb6eaa9c254fa578ff9ab96dc22989347646554f3e9f82db3f756bc932b7e7859bd7e29702477f9df5ab6553cdb4eeb5736ef19c676eafb8bf1236b0b9222e6ed036ba07714e5faaeedec458e36ab5fe9c4858895599eb9da14b4eb1802cbdb119b5375fdf702b48819a1269fc2bd52d681a8d2fcb503e1aa5f49f046336de74ba252077ca34499d5db2d560c40a4706fa593842de6ca7f8552b96b0f50cd4ccb8eb8e5b89fbddfa6a7a74613a400207eb2261fa707ad97d0c8280c8c6600d48e2f7873c824cc5e82fa320f2f800089723b5690fa2d7ff6a2b9ffd23aa0402b4fca6b3479f91eb4cba8bf8749c810f6e2bc8681d7b726a1fec9d7f42d7dcad90d36f4b0e632b8249fbb0d72791c3d509143315da03fe6edc62a91ce97634ca475947d7488cf5fa9f8ba1ae13ebeaf86c97cce48b5e1db699b686199cead5be8fb1b029b22da5244c2c3b93f429972e2faa2c241ab9067d5f21ad467c99f87cddca519096bba60c59720c9c1bb87e900540f60cb05e9b8b6bd683bb2aae923012913383e47236724ed2165af0a72b6a0f90be3860c76c03694693e5b8d0ee408f8ce9ba88f937044b9040eb230121d0bb6c2c29273b88c95e7c2486f5e2bf2c6b1b9b93b48f377bd90f31a0b36b6ae381e28a84a1af0d5ecb4b0e18dc363dac6253252dd206c0b28e20ead385a7e489c575f538a942307598d51d8c6f09d5a832d37e8ac79ec48afb0658ef86c4531e4f844221898271bdbdcff581b64cb9e8e1b6b150fbff8f0088a3f2f223d7e4672e2c5dad2ee362d8bac0fbb6acc1dd80e5b779187aa84f8add7e9b4c29f1247e998eaba94ea52bbcc862462b347d798233fa5e939a527ea7fa8ad3aa0190d7fec8e0e64888eb1e49fd2ac24043068cf5319893e15f9eeeea383d72d053c42c3a85f2b8e5ab7aaea8ca44d7906cb12f49237b63131655525b0cdd00be4be8bd8bbe211bf3e5f55178e80c40e9daeaece6a5bd66e0eb72a9db1a07552445a5a8245f28b0ad2647504dec81267d5f0f0e2d6ee2e8d06be928515fb6b608596d64d46553d18c4b67b73ed9c86b8263c4ce197aa4c1e75a45ad028c4a866304b9fd93dd5df65924d710433f52940fe8e03a846e5ab7f7bd0c6e23f9933d0bd72045298de965f9a8478db8fbf40446d8f85663e967cf7c0a556d273efa84aa4791300e7ddad9a98277663a895525d0d5818c0605559c17eb1537c12bba6b4106e1ef0b8aaaf71de9d681bd7e9e870ca041396b3ca0d07ab6221712692220dfdc5977b603dd1c855bb690db0b66a507cb77d9ab88c053b2b2ac4105ce442b2ad928e60f377e3045b9a7a8ab98ed31e5937b238f0551cc6f14019ed67b288662fc5de466c6ba3372e915fe801df15a03d3b4bac2323c6e2bcba3b31618b1a080d0a5e97ecab771b6ca98a7d39ae214a908c35bde7965522c753eddcc7d9542eda7741d6507e75755c5414ea1c88e9b9d0d5d10be5ddd2927369992424aa64e8444bc64e5e958777d0c3bf2dadd43e110bef3bf15abdb44a62da973cec848ed5cdea8aadb1ec61ddfad0bd4b27a6f24a81a5ed18de67ba943945ad1eb1cfd7ce708794cfea80f4fc434b2cb3ce818d024da9798325a131fc145ef75f42a23043a01358e46e093e3b9a35f5f7d2cafc5388186e9dca8b0dca0083f2b587fd7d3455cf64a25e77487ee091b7d1749e9d812a03fe4a3695da9d5876250612c60422f583bddd833a51c5eed3ae8796f742357972966a92c4523b7544cd14be9a9382170f3c05b775278a9295009a6dc13863dd128bc62453b12cf7ba8000c9f1035ecaeb16fcf6d3ee7bda7450a01d9784f5bca61cbbf488ea1a11926408e5bce5326cd0e3e9312ba56195b67d4a1eeccf9f43622e32ff3a075d1d928eee9293c287d4fab9febe0949b4a43632aa77b8b3a9897968be2e4c5be14dc4be9495e6100af64b01379d0fd9acb03af77c1d90948cf39ec18484530fd85c0935dc24b4b96fb006f2a56528130eb44b42132ee1d3452e44b7873ff9cb88506f09ccbc8c48d73915a5698ff7feaa24cb0bffebaf1b4d885a0e4473b5bed5edbdcefee6db303095f8880a683197a5b436415f70893d7cba362b0dc2fdfcce61841177ccab4c1b69047690323dbc427ae5d594bfd60fb1c1c2499a3fa6b5696caf05bd3786531d7233dc80cf0f2384471b47acc5a7a8a44e401361c3d32b6519e25817b7d1e9263108ac1c5a643bdf4f8d976e1283a3703d0ad7a3703d0ad7a3703d0ad7a3cccccccccccccccccccccccccccccccc00000000000000000000000000000080000000000000000000000000000000a0000000000000000000000000000000c8000000000000000000000000000000fa0000000000000000000000000000409c000000000000000000000000000050c3000000000000000000000000000024f4000000000000000000000000008096980000000000000000000000000020bcbe00000000000000000000000000286bee00000000000000000000000000f9029500000000000000000000000040b743ba00000000000000000000000010a5d4e80000000000000000000000002ae78491000000000000000000000080f420e6b50000000000000000000000a031a95fe3000000000000000000000004bfc91b8e0000000000000000000000c52ebca2b10000000000000000000040763a6b0bde00000000000000000000e8890423c78a0000000000000000000062acc5eb78ad000000000000000000807a17b726d7d800000000000000000090ac6e32788687000000000000000000b4570a3f1668a9000000000000000000a1edccce1bc2d30000000000000000a0841440615159840000000000000000c8a51990b9a56fa500000000000000003a0f20f4278fcbce0000000000000040840994f878393f810000000000000050e50bb936d7078fa100000000000000a4de4e6704cdc9f2c9000000000000004d96228145407c6ffc00000000000020f09db5702ba8adc59d000000000000286c05e34c36121937c500000000000032c7c61be0c356df84f60000000000407f3c5c116c3a960b139a0000000000109f4bb31507c97bce97c00000000000d4861e20db48bb1ac2bdf00000000080441413f4880db55099769600000000a055d91731eb50e2a43f14bc0000000008abcf5dfd25e51a8e4f19eb00000000e5caa15abe37cfd0b8d1ef92000000409e3d4af1ad05030527c6abb7000000d005cd9c6d19c743c6b0b796e5000000a2230082e46f5cea7bce327e8f0000808a2c80a2dd8bf3e41a82bf5db3000020ad37200bd56e309ea1622f35e0000034cc22f4264545de02a59d3d218c0000417f2bb17096d695430e058d29af0040115f76dd0c3c4c7bd45146f0f3da00c86afb690a88a50fcd24f32b76d888007a457a040dea8e5300eeefb6930eab80d8d6984590a4726880e9aba438d2d55047867f2bdaa64741f071eb6663a38524d9675fb6909099516c4ea6403c0ca76dcf41f7e3b4f4ff6507e2cf504bcfd0a421897a0ef1f8bf9f44ed81128f81820d6a2b19522df7afc7956822d7f221a39044769fa6f8f49b39bb02eb8c6feacbb4d55347d036f202086ac325700be5fe9065942c4262d70145229a1726274f9ff57eb9b7d23a4d42d6aa809deff022c7b2dea7658789e0d28bd5e0842badebf82feb889ff455cc6377850c333b4c939bfb256bc7716bbf3cd5a6cfff491f78c27aef45394e46ef8b8a90c37f1c2716f3acb5cbe3f08b7597563adacf71d8ed9717a3be1cedee523decc8d0438e4ee9bddd4bee63a8aaa74c27fbc4d431a263ed6aef743ea9cae88ff81cfb245f455e94442b128e53fde2b336e439eeb6d675b916b69671a8bcdb60445dc8a9644cd3e7cd31fe46e95589bc4a3a1deabe0fe49041bebd9863abab6bdd88a4a4ae131db5d12ded7e3c9696c614abcd4d9a5864e2a23c54cfe51d1efcec8aa07060b77e8dcb4b29435fa5253ba8adc88c3865deb0be9ef313b70eef4912d9faaf86fe15dd3743786c3269356eabc7fc2d14bf2d8a045496077fc3c24996f97b39d92eb9ac06e97bc95e7433dcfbf7da878f7ae7d7a371ed3dbb28a069fddae8b499acf0860cce680dea3208c4bc112322c0d7aca89001c390a43f0af52bd6ab2ab00dd8d2fae079dac6672679db65ab1a8e08c78338591891b8017057523f56a1b1cab8a4866f5eb526024ced26cfab095efde6cdb4055b3158814f5478610bc65a5eb08021c7b13dae616369d6398e77f175dca0e9381ecd193abc034cc871d56d9313c923c76540a048ab045f3ace4a497858fb769c3f28640deb627be4c0ce2d4b179d94834f32bdd0a53b9a1d7142f91d5dc47964e37eec448fca00650d93776574f5cb1e4ecf138b997e205fe8bb6abf68997ea621c3d8ed3f9ee876e26a45efc2bf1e10eaf34ee9cfc5a2149bc516abb3ef124a7258d1f1a1bbe5ec803bee4ad09597dc8eae456e8a2a1f2861caa95d44bbbd93321ad7092df52672f93c147515ea569c5f7026263c5958e71ba62c694d926c83770cb02f8b6f2ee1a2cf77c3e0b64764950f9cfb6d0b7a998bc355f498e4ac5ebd8941bd2447ec3f379ab598df8e57b62cec91eced58e70fc500e37e97b2ede33767b667292fe153f6c09b5e3ddf74ee8200d2e079bd6cf49958215b868b11aaa3800659d8ec8771c0aee9f167ae9594cc20486f0ee8e98d701a64ee01dadddc7f148d050931b2588690fe34418815d49f59f0464bbddeeea7343e8251aa1ac90770ac189e6c96ead1c1cde2e5d4b0dd04c66bcfe2039e322399c0ad0f851c1586b74683db8445ff6bbf309953a6639a6765186412e616ff46ef7c7fe8cf7ec0603f8f7ecb4f6e5f8c15ae4ff1819df0380f335ebee34977ef9a99a36da2c52c07d3bff5ad5c1c55ab01800c09cbf6f7c8c72f73d973632a1602a04fcbfdfa9adddcfde767287eda4d01c4119f9eb8011554fde181b21d51a10135d646c626421aa97c5a221f65a50942c28bd8f75869b0e98d7875335f0746695957e79aae831c64b1d65200378997c32f2da1c19aa423bd5d8c67c0846b7db47b7809f2e0463696bab740f83263ce504deb459798d8c33ba9e550b6fffb01a5206617bdbeceb48a131fe5a3ff7a42cea83f5dec3701b1366c336fc6df8ce980c947ba9384415d4447000bb817f023e1bbd9a8b8e591741559c00da61dec6cd92a10d3e62fdb68ad3798c8879213e4c71aea4390fb11c39845beba297718dd79a1e454b47ad6f3fed66d29f4945e54d8c91d6ae10c66585fa6e499181dbb34279e52e28c8f7f2ef7cf5dc05ee4e901b145e71ab0731ffaf4437570765d64421d17a121dca8531c794a49066aba7e4972ae049589926863179ddb870469dedb0eda45faabb6423c5d84d2a94503d6929250d7f8d6b2a945ba92238a0bc2c59b5b92865b861e14d76877ac6c8e32b782f23668f2a726d90c4395d70732ff6423af4402efd1b807e849bde6447f1f1f76ed6a613583a609629c6c20165fe7a6d3a8c5b902a40f8c7ac387a8db36a1900813376803cd89972cda544949c2645ae56b222122806cbdb710aa9bdbf2fdb0de066ba92aa0c7ace5949482926f3d5d96c8c55335c8f9171fba392377cb8cf4bb3ab7a842fafb6e531404762affd778b58472a9699cba4a68198513f5fe0dd7e225cf1384c3695dc25f6658b27ed18c5befc21865f4617ad9fb3f772fef023899d5792fbf98fad8cffa0f55fbaa0386ff4a58fbeebe38cf83f9532aba958467bf5d2ebaaaee8361f27b745a94ddb2a097fa5cb42a95e4f9ee9a1171f994df883d39746175ba5db8aa0156cd377a17eb8c47d1b912e93ab30ac155e062acee12b8cc22b4ab9109604d316b987b57aa17e67f2ba116b60bb8a0fd857e5aed949ddf5f76499ce3077384be138f58147dc2ebfbe9ad418ec88f25aed8b26e591cb3e67a6419d2b1bbf3aed98e5fca6fe35fa099bd9f46de54580d48b97bde25ee3b0480d623ec8a6aae109aa71a56afe94a0520cc2ca7ad04da948051a12b1ba49d0628fff710d942085df0d244fb9086220479ff9aaa87534a74ac07163a35282b4557bf4195a9e85c9197899b8842f275162d2f92fad311dabafe35619569b7092e7c5d9b7c849590697e83b9fa43258c39db34c29ba5bbf4035ee467f9942eef0712c2b202cff578c2baeee01b1d7df5444bb9af6181321773692ad96264dc32169ea71bbaa1fedccf03758f7b7d93bf9b8591a228ca3ed4c3445273da5c78af02e735cbb2fca764fa6a1388083aabad61b001bfef9dd0fdb84518aa8a0816197a1cc2ae6bc5453d27579e54ad8a5b9f98a3729ac6f64b8678f6e254ac3699633fa687203c9adda716b41b6a57847f3ccf8fa928cbc0d5511ca1a2446d659f0bc3f3d3f2fdf025b3b1a4e54a649f43e75978c4b79e96ee1fde0d9f5d3d8714617096b56546bceaa755d106b50ca959790cfc22ff57ebf288d54224f1a709d8cb87dd75ff16932feb8a536ded110ccebee95453bfdcb7faa56da8c868168f812e242a28efd3e5bc8744697d016ef9109d561a7975a48faca995c3dc81c9375544ec60d7928db317147bf453e2bb856a5527398df770e08eeccc78746d95936295b843b89a468cb2270097d1c87a38bbbaa654664158af9e31c0fc057b99066a69d0e9bf512edb031ff8bde3ec1f44e24122f217f3fc88c32676ad1ce827d55ad2aaeedd2f3cab74b0d3d823e2718af186556ad53b0bd6494e8467562d87f6567475626505c785db616501acf828b46cd112bbbec638a752babe01d73633e1c785d7696ef806d1733417614602c0ec9cb32602455ba48290015df9d702f0278460b04216724da3f441b4f78d03ec31a5785cd39bce20cc7152a1757104677ece9633c8420229ff86d384e9c662000f413e20bd69a1799f6808e6a3787bc052d14d682cc40958c7828adfcc569a70a745618237350c2ef991b60b407660a688cb7cb142a1c7bc9b35a40ed093f8cf6afedb5d9389f9abc2434d12c4b8f68305fe5235f8ebf756f34a708b7a337a72c3de53217bf35a16985c4c2e59c0184f74d6a8e959b0f11bbe73df796ff0de62110c1364701ceea2eda82bac4556cbdd8ae78b3ec6d1d48594923617d72b3e956de12ece37064aa7b93704ddccb68dfac899bac1c5871c11e8a2220a4092989c1da01499dbd4b10a914bab0cd0b6be0325c8597f124a5e4db51dd60f8464ae442e3a301f97dcb5a0e2d2e589d2feecea5c247e73dea971a48d475f2c873ea82574ad5d1056148e0db11977f7284e122fd11875946b99f150dd6faa9ad9706bbd822fc93ce3ff96528a0b5501104dc66c637bfb0bdcbf3ce7ac4eaa0154e0f7473c5afa0ed3ef0b21d8710a8134ecfaac65785ce9e375a714870d4da141a739187f96b3e35c53d1d9a850a009121148de1e7ca01c34a84510d3320446ab0aed4a934de49120892bea833f8517564da81df8605db6686bb6e4a48e669dab60122536b9f4e34206e41dce1960426b7c2bd7c1f378cee983aed2801ff812865bf64cb2301742e4245a07a127b69767f233e0defc9c521dae3049c9b1a37d01ef4098163c44a7a4d97c9bfb4e86ee6095281f8ea58ae806082e419de2272ab9baf2a6f14eada2088a7991c4dbb1746769af10aea258cb8aecd7b5f529efa8e0a16dcaac6517bfd6f3a69199f32ad3580a09fd173fdd6eccb010f6bfb0f507ef4c4bfcdd8e948affdc94f3ef8ef9641510afbd4ad99cb61f0a3df895f137be1ad41a6d9d0f44a4a74c4c76bbedc56d218961c88413558dd15fdf53eab49be4b4f53cfd322c55f8e29b6b7492a1c21d22338cbc3f776ab6db828611b74a33a5ea3fafab0f1505a49223e8d5e40e40a7f2874dcb292d83a63b16b1058f121051efe9203e74f82390ca5b1dc7b21654256b24a94d91f62c34bdb2e478df8e54f7c2b689d01a1a9c40b6ef8eab8bb129b57324ac84a120c3d0a3ab7296ae1e74a2902dd7e5c9e8f3c48c560f3cda9288657a7ca62f7e7118fb1796896588b7eafe981b90bbdd8ddef99dfbeb7eaa65a53e7f22742a5531567885faa61ed55f27878f95883ad5de356b935c28338537f168f3ba2a898a560346b873f27fa6852d43b069752b2d2c8457a610ef1fd073fc290e62293b9c9bb2f6676af513828f7bb491baf34983425ff401c5f298a2739a2136a9701c2413777142762f3fcb1001aa83d38c23edd7d40dd353fb0efeaa404a32043836f406a5e863145dc99ed5d0dc3e05c643b148cee27c59b47bc60a05948e86b794ddda811bdc6fa11af826831c19b4f27cca283191e9e5a4109bf0a3631f612f1cfd727df5631fced4c1ec8c3c67393b63bccfdcf23ca7014af213d885e00305bed501ca178608416e97184ea7d844862d4b82bc9da74ad149bd9e21d10ed6e7f8dda22b85519d459cec03b542c9e590bbca453bf35282abe1934362933b1f756a3d170ab0e76216dab8d43a780a6712c50c9d0c9ca1fb9b10e7c5248b66802bfb27e28701457d616a90f6ed2d8060f6f9b1dae94196dcf984b4736939a0f873785e5164d2bb5338a6e1e8e123647b480bdbb27e635534e3078d62da2c3d9a1ace915f5ebc6a01dc49b0fb1078cc40a14176f7756bc501535cdc9d0acb7fc804e9a9ba29631be1b3b98944cdbd9ffa45635429f43b62d92028ac9540ad4779177ca933f1caba0f2932d75d48ccccab8eed49c0d6bed4a9597f86745affbf56f2685c708cee4914301fa81131ff6fec2e83738c2f6a5c19fc26d2ab7effc553fd31c8b75dc2d98f5d5883555e7fb7a87c3eba25f532d0f3742ea4eb355fe5d21bce286fb23fc430123acdb3815bcf63d1807985cfa77a5e4b44801f6232c3bc05e1d766c35119365e55a0a7fafef32b47d98d4034a69fc3b56ac851b9fef0f6984fb150c18f87346385fad3339f569abfd16ed2d8b9d4005e939cc80047ec802f860a074fe8098135b8c3fac0582761bb27cdc862624ce142a6f49c7897b81cd53880bd7dbdcfcce9e798c356bde6630a47e02cddac0340e421bf74ac6ce0fccc581878149804505deaeec8eb430c1e80370fcb0cdf02527a5295bae6548f256005d3fdcf9683e618a7ba69202af32eb8c647fd837c2420df50e94154fa571d33dc4c7ed2cd16748bd29152e9f8ade43f13e01d47811c512e47b6a62377d9dd0f1858e598a163e5f9d8e34876eaa7ea090f578fff445e2f9c678e'
|
|
878
|
+
// Pre-decode the EL table bytes and stash in ctx.runtime.
|
|
870
879
|
// src/compile/index.js appends elTable to ctx.runtime.data only when
|
|
871
880
|
// __dec_to_f64 is actually pulled in via deps (lazy, keeps small modules clean).
|
|
872
|
-
|
|
873
|
-
for (let i = 0; i < EL_TABLE_HEX.length; i += 2)
|
|
874
|
-
elTableBytes += String.fromCharCode(parseInt(EL_TABLE_HEX.slice(i, i + 2), 16))
|
|
875
|
-
ctx.runtime.elTable = elTableBytes
|
|
881
|
+
ctx.runtime.elTable = hexToBytes(EL_TABLE_HEX)
|
|
876
882
|
|
|
877
883
|
// Register the stdlib function (no data appended here — see compile/index.js hook)
|
|
878
884
|
ctx.core.stdlib['__dec_to_f64'] = DEC_TO_F64_WAT
|
|
879
885
|
|
|
886
|
+
// === Ryū shortest round-trip float→decimal (Adams, PLDI'18) ===
|
|
887
|
+
// Digit core for the default String(number)/template/JSON.stringify path: the
|
|
888
|
+
// unique shortest digit string that parses back to the same f64 bits, with ES
|
|
889
|
+
// Number::toString notation rules applied on top. Ported from the reference
|
|
890
|
+
// d2s.c (github.com/ulfjack/ryu, Apache-2.0/Boost-1.0), full-table variant.
|
|
891
|
+
//
|
|
892
|
+
// Size-optimized table (reference RYU_OPTIMIZE_SIZE, d2s_small_table.h):
|
|
893
|
+
// instead of all 618 required 128-bit powers of 5 (~9.7KB), store every 26th
|
|
894
|
+
// power (plus 5^0..5^25 as u64 and 2-bit rounding-error offsets) and rebuild
|
|
895
|
+
// any entry with one extra 64×128 multiply per call ($__ryu_pow5) — verified
|
|
896
|
+
// entry-exact against the full reference tables for all 618 indices.
|
|
897
|
+
// Seed layout at $__ryu_tbl (828 bytes, LE):
|
|
898
|
+
// +0 DOUBLE_POW5_INV_SPLIT2[15] (lo,hi u64 pairs — 1/5^(26k), 126-bit)
|
|
899
|
+
// +240 DOUBLE_POW5_SPLIT2[13] (lo,hi u64 pairs — 5^(26k), 125-bit)
|
|
900
|
+
// +448 DOUBLE_POW5_TABLE[26] (5^0..5^25 as u64)
|
|
901
|
+
// +656 POW5_INV_OFFSETS[22] (u32 bitmaps, 2 bits per index)
|
|
902
|
+
// +744 POW5_OFFSETS[21] (u32 bitmaps, 2 bits per index)
|
|
903
|
+
const RYU_SEED_HEX = '01000000000000000000000000000020345065c05fc9a652bb13cbaec440c21806c8df7100d5a87cf56f0fda58fc27136e4756357d24206502c7e768e48ca41de9e60268d7cd39617977fcc2405bef16798cde43ffa751f991f3b278f5bdbe11e857e9d6e8bee87bb054ac8f848d751bea23a499e9f9d38bb7a3714061da3e15cee33ecb73f948088c97b427d51b7010a2bfefb9eb8532154db44db49bbb6f1996b6076cf8e7eead36d9b4f59135ae13222218af4e6a684d91daaa3d4f40741e9fbd9ee006a1c09857c2a7fda40e90170e7d497173e3208fb220d87605143b12853d7434811343b0ad297a5f27f4351c000000000000000000000000000000100000000000000000b9340332b7f4ad1410db1ab30892540e0d307d951447ba1a66088f4d26adc66df598bf85e2b74511ca96853d92bd1debfca11860dcef52163c92ae220bb8c1b4839d2d5b0562da1c304c7e8f4e8bb25b16f4529f8b56a512fbd4827643ed8af08fe7f9311565191850f19bd94a13eeb4284cf0a686c1251f035fc270cb9e4916e642889c44eb2014b0650836ad6ea58585f0ca14e2fd031a0b899979d5b13d09d8da973a35ebcf10ac363f5e73bb38cf3e6752fa44afba150100000000000000050000000000000019000000000000007d000000000000007102000000000000350c000000000000093d0000000000002d31010000000000e1f505000000000065cd1d0000000000f902950000000000dd0ee90200000000514a8d0e000000009573c24800000000e941cc6b010000008d49fd1a07000000c16ff28623000000c52ebca2b1000000d9e9ac2d780300003d9160e45811000031d6e275bc560000f52e6e4daeb10100c9ea268367780800ed95c28f055a2a00a1edccce1bc2d30025a4000a8bca220454455454455505040010041014044000000001405555154154040000440001000000004041000044504445505400555554556551004000400100000100050100115451515455550500154150000004401001040500000000000000000000000000000000000000000000004095596959555554551555555604051541105455404551554440455044505555450040004040044496655556554540455451411540559155555555405105010000'
|
|
904
|
+
ctx.runtime.ryuTable = hexToBytes(RYU_SEED_HEX)
|
|
905
|
+
|
|
906
|
+
// 64×64 → high 64 bits, via 32-bit limb products (wasm has no mul-high).
|
|
907
|
+
ctx.core.stdlib['__ryu_mulhi'] = `(func $__ryu_mulhi (param $a i64) (param $b i64) (result i64)
|
|
908
|
+
(local $a0 i64) (local $a1 i64) (local $b0 i64) (local $b1 i64) (local $mid i64) (local $mid2 i64)
|
|
909
|
+
(local.set $a0 (i64.and (local.get $a) (i64.const 0xFFFFFFFF)))
|
|
910
|
+
(local.set $a1 (i64.shr_u (local.get $a) (i64.const 32)))
|
|
911
|
+
(local.set $b0 (i64.and (local.get $b) (i64.const 0xFFFFFFFF)))
|
|
912
|
+
(local.set $b1 (i64.shr_u (local.get $b) (i64.const 32)))
|
|
913
|
+
(local.set $mid (i64.add (i64.mul (local.get $a1) (local.get $b0))
|
|
914
|
+
(i64.shr_u (i64.mul (local.get $a0) (local.get $b0)) (i64.const 32))))
|
|
915
|
+
(local.set $mid2 (i64.add (i64.mul (local.get $a0) (local.get $b1))
|
|
916
|
+
(i64.and (local.get $mid) (i64.const 0xFFFFFFFF))))
|
|
917
|
+
(i64.add (i64.add (i64.mul (local.get $a1) (local.get $b1))
|
|
918
|
+
(i64.shr_u (local.get $mid) (i64.const 32)))
|
|
919
|
+
(i64.shr_u (local.get $mid2) (i64.const 32))))`
|
|
920
|
+
|
|
921
|
+
// (m × entry) >> j for a 128-bit table entry at $tbl (lo, hi LE u64 pair);
|
|
922
|
+
// 64 < j < 128, result proven to fit u64 (ryu d2s_intrinsics.h).
|
|
923
|
+
ctx.core.stdlib['__ryu_mulshift'] = `(func $__ryu_mulshift (param $m i64) (param $tbl i32) (param $j i32) (result i64)
|
|
924
|
+
(local $hi i64) (local $h0 i64) (local $sum i64) (local $high1 i64) (local $d i64)
|
|
925
|
+
(local.set $hi (i64.load (i32.add (local.get $tbl) (i32.const 8))))
|
|
926
|
+
(local.set $h0 (call $__ryu_mulhi (local.get $m) (i64.load (local.get $tbl))))
|
|
927
|
+
(local.set $sum (i64.add (local.get $h0) (i64.mul (local.get $m) (local.get $hi))))
|
|
928
|
+
(local.set $high1 (i64.add (call $__ryu_mulhi (local.get $m) (local.get $hi))
|
|
929
|
+
(i64.extend_i32_u (i64.lt_u (local.get $sum) (local.get $h0)))))
|
|
930
|
+
(local.set $d (i64.extend_i32_u (i32.sub (local.get $j) (i32.const 64))))
|
|
931
|
+
(i64.or (i64.shr_u (local.get $sum) (local.get $d))
|
|
932
|
+
(i64.shl (local.get $high1) (i64.sub (i64.const 64) (local.get $d)))))`
|
|
933
|
+
|
|
934
|
+
// Rebuild the 128-bit power-of-5 entry for index $i into 16 bytes at $out:
|
|
935
|
+
// seed × 5^offset, shifted back into the 125/126-bit window, plus the stored
|
|
936
|
+
// 2-bit rounding offset (reference double_computePow5/double_computeInvPow5).
|
|
937
|
+
ctx.core.stdlib['__ryu_pow5'] = () => {
|
|
938
|
+
if (!ctx.scope.globals.has('__ryu_tbl')) declGlobal('__ryu_tbl', 'i32')
|
|
939
|
+
return `(func $__ryu_pow5 (param $i i32) (param $inv i32) (param $out i32) (result i32)
|
|
940
|
+
(local $base i32) (local $base2 i32) (local $off i32) (local $mul i32)
|
|
941
|
+
(local $mlo i64) (local $mhi i64) (local $m i64) (local $a i64)
|
|
942
|
+
(local $lo0 i64) (local $hi0 i64) (local $lo2 i64) (local $hi2 i64)
|
|
943
|
+
(local $delta i64) (local $sLo i64) (local $sHi i64) (local $tLo i64) (local $tHi i64)
|
|
944
|
+
(local $rLo i64) (local $rHi i64) (local $e i64)
|
|
945
|
+
(if (local.get $inv)
|
|
946
|
+
(then
|
|
947
|
+
(local.set $base (i32.div_u (i32.add (local.get $i) (i32.const 25)) (i32.const 26)))
|
|
948
|
+
(local.set $base2 (i32.mul (local.get $base) (i32.const 26)))
|
|
949
|
+
(local.set $off (i32.sub (local.get $base2) (local.get $i)))
|
|
950
|
+
(local.set $mul (i32.add (global.get $__ryu_tbl) (i32.shl (local.get $base) (i32.const 4)))))
|
|
951
|
+
(else
|
|
952
|
+
(local.set $base (i32.div_u (local.get $i) (i32.const 26)))
|
|
953
|
+
(local.set $base2 (i32.mul (local.get $base) (i32.const 26)))
|
|
954
|
+
(local.set $off (i32.sub (local.get $i) (local.get $base2)))
|
|
955
|
+
(local.set $mul (i32.add (i32.add (global.get $__ryu_tbl) (i32.const 240)) (i32.shl (local.get $base) (i32.const 4))))))
|
|
956
|
+
(local.set $mlo (i64.load (local.get $mul)))
|
|
957
|
+
(local.set $mhi (i64.load (i32.add (local.get $mul) (i32.const 8))))
|
|
958
|
+
(if (i32.eqz (local.get $off))
|
|
959
|
+
(then
|
|
960
|
+
(i64.store (local.get $out) (local.get $mlo))
|
|
961
|
+
(i64.store (i32.add (local.get $out) (i32.const 8)) (local.get $mhi))
|
|
962
|
+
(return (local.get $out))))
|
|
963
|
+
(local.set $m (i64.load (i32.add (i32.add (global.get $__ryu_tbl) (i32.const 448)) (i32.shl (local.get $off) (i32.const 3)))))
|
|
964
|
+
;; b0 = m·(mulLo - inv); b2 = m·mulHi (inv subtracts 1 per the reference)
|
|
965
|
+
(local.set $a (i64.sub (local.get $mlo) (i64.extend_i32_u (local.get $inv))))
|
|
966
|
+
(local.set $lo0 (i64.mul (local.get $m) (local.get $a)))
|
|
967
|
+
(local.set $hi0 (call $__ryu_mulhi (local.get $m) (local.get $a)))
|
|
968
|
+
(local.set $lo2 (i64.mul (local.get $m) (local.get $mhi)))
|
|
969
|
+
(local.set $hi2 (call $__ryu_mulhi (local.get $m) (local.get $mhi)))
|
|
970
|
+
;; delta = |pow5bits(i) - pow5bits(base2)| ∈ (0, 64)
|
|
971
|
+
(local.set $delta (i64.extend_i32_u (i32.sub
|
|
972
|
+
(i32.shr_u (i32.mul (select (local.get $base2) (local.get $i) (local.get $inv)) (i32.const 1217359)) (i32.const 19))
|
|
973
|
+
(i32.shr_u (i32.mul (select (local.get $i) (local.get $base2) (local.get $inv)) (i32.const 1217359)) (i32.const 19)))))
|
|
974
|
+
;; (b0 >> delta) + (b2 << (64-delta)) as a 128-bit sum
|
|
975
|
+
(local.set $sLo (i64.or (i64.shr_u (local.get $lo0) (local.get $delta))
|
|
976
|
+
(i64.shl (local.get $hi0) (i64.sub (i64.const 64) (local.get $delta)))))
|
|
977
|
+
(local.set $sHi (i64.shr_u (local.get $hi0) (local.get $delta)))
|
|
978
|
+
(local.set $tLo (i64.shl (local.get $lo2) (i64.sub (i64.const 64) (local.get $delta))))
|
|
979
|
+
(local.set $tHi (i64.or (i64.shl (local.get $hi2) (i64.sub (i64.const 64) (local.get $delta)))
|
|
980
|
+
(i64.shr_u (local.get $lo2) (local.get $delta))))
|
|
981
|
+
(local.set $rLo (i64.add (local.get $sLo) (local.get $tLo)))
|
|
982
|
+
(local.set $rHi (i64.add (i64.add (local.get $sHi) (local.get $tHi))
|
|
983
|
+
(i64.extend_i32_u (i64.lt_u (local.get $rLo) (local.get $sLo)))))
|
|
984
|
+
;; + stored 2-bit error (+1 more for the inverse table)
|
|
985
|
+
(local.set $e (i64.add
|
|
986
|
+
(i64.and (i64.extend_i32_u (i32.shr_u
|
|
987
|
+
(i32.load (i32.add (i32.add (global.get $__ryu_tbl) (select (i32.const 656) (i32.const 744) (local.get $inv)))
|
|
988
|
+
(i32.shl (i32.div_u (local.get $i) (i32.const 16)) (i32.const 2))))
|
|
989
|
+
(i32.shl (i32.rem_u (local.get $i) (i32.const 16)) (i32.const 1)))) (i64.const 3))
|
|
990
|
+
(i64.extend_i32_u (local.get $inv))))
|
|
991
|
+
(local.set $a (i64.add (local.get $rLo) (local.get $e)))
|
|
992
|
+
(local.set $rHi (i64.add (local.get $rHi) (i64.extend_i32_u (i64.lt_u (local.get $a) (local.get $rLo)))))
|
|
993
|
+
(i64.store (local.get $out) (local.get $a))
|
|
994
|
+
(i64.store (i32.add (local.get $out) (i32.const 8)) (local.get $rHi))
|
|
995
|
+
(local.get $out))`
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// divisible by 5^p?
|
|
999
|
+
ctx.core.stdlib['__ryu_pow5div'] = `(func $__ryu_pow5div (param $v i64) (param $p i32) (result i32)
|
|
1000
|
+
(block $out (loop $l
|
|
1001
|
+
(br_if $out (i32.le_s (local.get $p) (i32.const 0)))
|
|
1002
|
+
(if (i64.ne (i64.rem_u (local.get $v) (i64.const 5)) (i64.const 0)) (then (return (i32.const 0))))
|
|
1003
|
+
(local.set $v (i64.div_u (local.get $v) (i64.const 5)))
|
|
1004
|
+
(local.set $p (i32.sub (local.get $p) (i32.const 1)))
|
|
1005
|
+
(br $l)))
|
|
1006
|
+
(i32.const 1))`
|
|
1007
|
+
|
|
1008
|
+
// Shortest-round-trip ToString(number). Transcribes d2s.c's d2d (same local
|
|
1009
|
+
// names where possible: mv/vp/vr/vm, q, e10, acceptBounds≡$even) and renders
|
|
1010
|
+
// per ES Number::toString: n = e10+len is the decimal-point position; k≤n≤21
|
|
1011
|
+
// plain integer, 0<n≤21 embedded point, -6<n≤0 leading zeros, else d.dddde±k.
|
|
1012
|
+
ctx.core.stdlib['__ftoa_shortest'] = () => `(func $__ftoa_shortest (param $val f64) (result f64)
|
|
1013
|
+
(local $bits i64) (local $ieeeM i64) (local $ieeeE i32)
|
|
1014
|
+
(local $e2 i32) (local $m2 i64) (local $even i32) (local $mmShift i64) (local $mv i64)
|
|
1015
|
+
(local $vr i64) (local $vp i64) (local $vm i64) (local $h0 i64) (local $t i64) (local $d10 i64)
|
|
1016
|
+
(local $e10 i32) (local $q i32) (local $k i32) (local $sh i32) (local $tbl i32)
|
|
1017
|
+
(local $vmTZ i32) (local $vrTZ i32) (local $removed i32) (local $last i32) (local $roundUp i32)
|
|
1018
|
+
(local $out i64) (local $buf i32) (local $scr i32) (local $pos i32) (local $olen i32) (local $n i32) (local $i i32)
|
|
1019
|
+
(if (f64.ne (local.get $val) (local.get $val)) (then (return (call $__static_str (i32.const 0)))))
|
|
1020
|
+
(if (f64.eq (local.get $val) (f64.const inf)) (then (return (call $__static_str (i32.const 1)))))
|
|
1021
|
+
(if (f64.eq (local.get $val) (f64.const -inf)) (then (return (call $__static_str (i32.const 2)))))
|
|
1022
|
+
(local.set $buf (call $__alloc (i32.const 96)))
|
|
1023
|
+
(local.set $scr (i32.add (local.get $buf) (i32.const 64)))
|
|
1024
|
+
(if (f64.eq (local.get $val) (f64.const 0))
|
|
1025
|
+
(then
|
|
1026
|
+
(i32.store8 (local.get $buf) (i32.const 48))
|
|
1027
|
+
(return (call $__mkstr (local.get $buf) (i32.const 1)))))
|
|
1028
|
+
(local.set $bits (i64.reinterpret_f64 (local.get $val)))
|
|
1029
|
+
(if (i64.lt_s (local.get $bits) (i64.const 0))
|
|
1030
|
+
(then
|
|
1031
|
+
(i32.store8 (local.get $buf) (i32.const 45))
|
|
1032
|
+
(local.set $pos (i32.const 1))))
|
|
1033
|
+
(local.set $ieeeM (i64.and (local.get $bits) (i64.const 0xFFFFFFFFFFFFF)))
|
|
1034
|
+
(local.set $ieeeE (i32.wrap_i64 (i64.and (i64.shr_u (local.get $bits) (i64.const 52)) (i64.const 0x7FF))))
|
|
1035
|
+
;; m2·2^e2 = |val|·2^-2 — two extra bits for the halfway-boundary math
|
|
1036
|
+
(if (i32.eqz (local.get $ieeeE))
|
|
1037
|
+
(then
|
|
1038
|
+
(local.set $e2 (i32.const -1076))
|
|
1039
|
+
(local.set $m2 (local.get $ieeeM)))
|
|
1040
|
+
(else
|
|
1041
|
+
(local.set $e2 (i32.sub (local.get $ieeeE) (i32.const 1077)))
|
|
1042
|
+
(local.set $m2 (i64.or (i64.const 0x10000000000000) (local.get $ieeeM)))))
|
|
1043
|
+
(local.set $even (i64.eqz (i64.and (local.get $m2) (i64.const 1))))
|
|
1044
|
+
(local.set $mv (i64.shl (local.get $m2) (i64.const 2)))
|
|
1045
|
+
(local.set $mmShift (i64.extend_i32_u (i32.or
|
|
1046
|
+
(i64.ne (local.get $ieeeM) (i64.const 0))
|
|
1047
|
+
(i32.le_s (local.get $ieeeE) (i32.const 1)))))
|
|
1048
|
+
(if (i32.ge_s (local.get $e2) (i32.const 0))
|
|
1049
|
+
(then
|
|
1050
|
+
;; q = log10Pow2(e2) - (e2 > 3); shift = -e2 + q + 125 + (pow5bits(q)-1)
|
|
1051
|
+
(local.set $q (i32.sub
|
|
1052
|
+
(i32.shr_u (i32.mul (local.get $e2) (i32.const 78913)) (i32.const 18))
|
|
1053
|
+
(i32.gt_s (local.get $e2) (i32.const 3))))
|
|
1054
|
+
(local.set $e10 (local.get $q))
|
|
1055
|
+
(local.set $sh (i32.add
|
|
1056
|
+
(i32.add (i32.sub (local.get $q) (local.get $e2)) (i32.const 125))
|
|
1057
|
+
(i32.shr_u (i32.mul (local.get $q) (i32.const 1217359)) (i32.const 19))))
|
|
1058
|
+
(local.set $tbl (call $__ryu_pow5 (local.get $q) (i32.const 1) (i32.add (local.get $buf) (i32.const 48))))
|
|
1059
|
+
(local.set $vr (call $__ryu_mulshift (local.get $mv) (local.get $tbl) (local.get $sh)))
|
|
1060
|
+
(local.set $vp (call $__ryu_mulshift (i64.add (local.get $mv) (i64.const 2)) (local.get $tbl) (local.get $sh)))
|
|
1061
|
+
(local.set $vm (call $__ryu_mulshift (i64.sub (i64.sub (local.get $mv) (i64.const 1)) (local.get $mmShift)) (local.get $tbl) (local.get $sh)))
|
|
1062
|
+
(if (i32.le_u (local.get $q) (i32.const 21))
|
|
1063
|
+
(then
|
|
1064
|
+
(if (i64.eqz (i64.rem_u (local.get $mv) (i64.const 5)))
|
|
1065
|
+
(then (local.set $vrTZ (call $__ryu_pow5div (local.get $mv) (local.get $q))))
|
|
1066
|
+
(else
|
|
1067
|
+
(if (local.get $even)
|
|
1068
|
+
(then (local.set $vmTZ (call $__ryu_pow5div (i64.sub (i64.sub (local.get $mv) (i64.const 1)) (local.get $mmShift)) (local.get $q))))
|
|
1069
|
+
(else (local.set $vp (i64.sub (local.get $vp)
|
|
1070
|
+
(i64.extend_i32_u (call $__ryu_pow5div (i64.add (local.get $mv) (i64.const 2)) (local.get $q))))))))))))
|
|
1071
|
+
(else
|
|
1072
|
+
;; q = log10Pow5(-e2) - (-e2 > 1); i = -e2-q (in $k); shift = q - (pow5bits(i)-125)
|
|
1073
|
+
(local.set $q (i32.sub
|
|
1074
|
+
(i32.shr_u (i32.mul (i32.sub (i32.const 0) (local.get $e2)) (i32.const 732923)) (i32.const 20))
|
|
1075
|
+
(i32.gt_s (i32.sub (i32.const 0) (local.get $e2)) (i32.const 1))))
|
|
1076
|
+
(local.set $e10 (i32.add (local.get $q) (local.get $e2)))
|
|
1077
|
+
(local.set $k (i32.sub (i32.sub (i32.const 0) (local.get $e2)) (local.get $q)))
|
|
1078
|
+
(local.set $sh (i32.add (i32.sub (local.get $q)
|
|
1079
|
+
(i32.add (i32.shr_u (i32.mul (local.get $k) (i32.const 1217359)) (i32.const 19)) (i32.const 1)))
|
|
1080
|
+
(i32.const 125)))
|
|
1081
|
+
(local.set $tbl (call $__ryu_pow5 (local.get $k) (i32.const 0) (i32.add (local.get $buf) (i32.const 48))))
|
|
1082
|
+
(local.set $vr (call $__ryu_mulshift (local.get $mv) (local.get $tbl) (local.get $sh)))
|
|
1083
|
+
(local.set $vp (call $__ryu_mulshift (i64.add (local.get $mv) (i64.const 2)) (local.get $tbl) (local.get $sh)))
|
|
1084
|
+
(local.set $vm (call $__ryu_mulshift (i64.sub (i64.sub (local.get $mv) (i64.const 1)) (local.get $mmShift)) (local.get $tbl) (local.get $sh)))
|
|
1085
|
+
(if (i32.le_u (local.get $q) (i32.const 1))
|
|
1086
|
+
(then
|
|
1087
|
+
(local.set $vrTZ (i32.const 1))
|
|
1088
|
+
(if (local.get $even)
|
|
1089
|
+
(then (local.set $vmTZ (i64.eq (local.get $mmShift) (i64.const 1))))
|
|
1090
|
+
(else (local.set $vp (i64.sub (local.get $vp) (i64.const 1))))))
|
|
1091
|
+
(else
|
|
1092
|
+
(if (i32.lt_u (local.get $q) (i32.const 63))
|
|
1093
|
+
(then (local.set $vrTZ (i64.eqz (i64.and (local.get $mv)
|
|
1094
|
+
(i64.sub (i64.shl (i64.const 1) (i64.extend_i32_u (local.get $q))) (i64.const 1)))))))))))
|
|
1095
|
+
;; shortest digits within [vm, vp]
|
|
1096
|
+
(if (i32.or (local.get $vmTZ) (local.get $vrTZ))
|
|
1097
|
+
(then
|
|
1098
|
+
;; rare general path: tracks trailing zeros for exact ties
|
|
1099
|
+
(block $g1 (loop $gl1
|
|
1100
|
+
(local.set $t (i64.div_u (local.get $vp) (i64.const 10)))
|
|
1101
|
+
(local.set $d10 (i64.div_u (local.get $vm) (i64.const 10)))
|
|
1102
|
+
(br_if $g1 (i64.le_u (local.get $t) (local.get $d10)))
|
|
1103
|
+
(local.set $vmTZ (i32.and (local.get $vmTZ)
|
|
1104
|
+
(i64.eqz (i64.sub (local.get $vm) (i64.mul (local.get $d10) (i64.const 10))))))
|
|
1105
|
+
(local.set $vrTZ (i32.and (local.get $vrTZ) (i32.eqz (local.get $last))))
|
|
1106
|
+
(local.set $h0 (i64.div_u (local.get $vr) (i64.const 10)))
|
|
1107
|
+
(local.set $last (i32.wrap_i64 (i64.sub (local.get $vr) (i64.mul (local.get $h0) (i64.const 10)))))
|
|
1108
|
+
(local.set $vr (local.get $h0))
|
|
1109
|
+
(local.set $vp (local.get $t))
|
|
1110
|
+
(local.set $vm (local.get $d10))
|
|
1111
|
+
(local.set $removed (i32.add (local.get $removed) (i32.const 1)))
|
|
1112
|
+
(br $gl1)))
|
|
1113
|
+
(if (local.get $vmTZ)
|
|
1114
|
+
(then (block $g2 (loop $gl2
|
|
1115
|
+
(local.set $d10 (i64.div_u (local.get $vm) (i64.const 10)))
|
|
1116
|
+
(br_if $g2 (i64.ne (i64.sub (local.get $vm) (i64.mul (local.get $d10) (i64.const 10))) (i64.const 0)))
|
|
1117
|
+
(local.set $vrTZ (i32.and (local.get $vrTZ) (i32.eqz (local.get $last))))
|
|
1118
|
+
(local.set $h0 (i64.div_u (local.get $vr) (i64.const 10)))
|
|
1119
|
+
(local.set $last (i32.wrap_i64 (i64.sub (local.get $vr) (i64.mul (local.get $h0) (i64.const 10)))))
|
|
1120
|
+
(local.set $vr (local.get $h0))
|
|
1121
|
+
(local.set $vp (i64.div_u (local.get $vp) (i64.const 10)))
|
|
1122
|
+
(local.set $vm (local.get $d10))
|
|
1123
|
+
(local.set $removed (i32.add (local.get $removed) (i32.const 1)))
|
|
1124
|
+
(br $gl2)))))
|
|
1125
|
+
;; exact .5 tail rounds to even
|
|
1126
|
+
(if (i32.and (i32.and (local.get $vrTZ) (i32.eq (local.get $last) (i32.const 5)))
|
|
1127
|
+
(i64.eqz (i64.and (local.get $vr) (i64.const 1))))
|
|
1128
|
+
(then (local.set $last (i32.const 4))))
|
|
1129
|
+
(local.set $out (i64.add (local.get $vr) (i64.extend_i32_u (i32.or
|
|
1130
|
+
(i32.and (i64.eq (local.get $vr) (local.get $vm))
|
|
1131
|
+
(i32.or (i32.eqz (local.get $even)) (i32.eqz (local.get $vmTZ))))
|
|
1132
|
+
(i32.ge_s (local.get $last) (i32.const 5)))))))
|
|
1133
|
+
(else
|
|
1134
|
+
;; common fast path (~99.3%): two digits at a time first
|
|
1135
|
+
(local.set $t (i64.div_u (local.get $vp) (i64.const 100)))
|
|
1136
|
+
(local.set $d10 (i64.div_u (local.get $vm) (i64.const 100)))
|
|
1137
|
+
(if (i64.gt_u (local.get $t) (local.get $d10))
|
|
1138
|
+
(then
|
|
1139
|
+
(local.set $h0 (i64.div_u (local.get $vr) (i64.const 100)))
|
|
1140
|
+
(local.set $roundUp (i64.ge_u (i64.sub (local.get $vr) (i64.mul (local.get $h0) (i64.const 100))) (i64.const 50)))
|
|
1141
|
+
(local.set $vr (local.get $h0))
|
|
1142
|
+
(local.set $vp (local.get $t))
|
|
1143
|
+
(local.set $vm (local.get $d10))
|
|
1144
|
+
(local.set $removed (i32.add (local.get $removed) (i32.const 2)))))
|
|
1145
|
+
(block $f1 (loop $fl1
|
|
1146
|
+
(local.set $t (i64.div_u (local.get $vp) (i64.const 10)))
|
|
1147
|
+
(local.set $d10 (i64.div_u (local.get $vm) (i64.const 10)))
|
|
1148
|
+
(br_if $f1 (i64.le_u (local.get $t) (local.get $d10)))
|
|
1149
|
+
(local.set $h0 (i64.div_u (local.get $vr) (i64.const 10)))
|
|
1150
|
+
(local.set $roundUp (i64.ge_u (i64.sub (local.get $vr) (i64.mul (local.get $h0) (i64.const 10))) (i64.const 5)))
|
|
1151
|
+
(local.set $vr (local.get $h0))
|
|
1152
|
+
(local.set $vp (local.get $t))
|
|
1153
|
+
(local.set $vm (local.get $d10))
|
|
1154
|
+
(local.set $removed (i32.add (local.get $removed) (i32.const 1)))
|
|
1155
|
+
(br $fl1)))
|
|
1156
|
+
(local.set $out (i64.add (local.get $vr) (i64.extend_i32_u
|
|
1157
|
+
(i32.or (i64.eq (local.get $vr) (local.get $vm)) (local.get $roundUp)))))))
|
|
1158
|
+
(local.set $e10 (i32.add (local.get $e10) (local.get $removed)))
|
|
1159
|
+
;; digits, least-significant first, into scratch
|
|
1160
|
+
(local.set $t (local.get $out))
|
|
1161
|
+
(block $dd (loop $dl
|
|
1162
|
+
(local.set $h0 (i64.div_u (local.get $t) (i64.const 10)))
|
|
1163
|
+
(i32.store8 (i32.add (local.get $scr) (local.get $olen))
|
|
1164
|
+
(i32.add (i32.const 48) (i32.wrap_i64 (i64.sub (local.get $t) (i64.mul (local.get $h0) (i64.const 10))))))
|
|
1165
|
+
(local.set $olen (i32.add (local.get $olen) (i32.const 1)))
|
|
1166
|
+
(local.set $t (local.get $h0))
|
|
1167
|
+
(br_if $dd (i64.eqz (local.get $t)))
|
|
1168
|
+
(br $dl)))
|
|
1169
|
+
;; ES notation: n = decimal-point position
|
|
1170
|
+
(local.set $n (i32.add (local.get $e10) (local.get $olen)))
|
|
1171
|
+
(if (i32.and (i32.le_s (local.get $olen) (local.get $n)) (i32.le_s (local.get $n) (i32.const 21)))
|
|
1172
|
+
(then
|
|
1173
|
+
(local.set $i (i32.const 0))
|
|
1174
|
+
(block $b1d (loop $b1l
|
|
1175
|
+
(br_if $b1d (i32.ge_s (local.get $i) (local.get $olen)))
|
|
1176
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
1177
|
+
(i32.load8_u (i32.add (local.get $scr) (i32.sub (i32.sub (local.get $olen) (i32.const 1)) (local.get $i)))))
|
|
1178
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1179
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1180
|
+
(br $b1l)))
|
|
1181
|
+
(block $z1d (loop $z1l
|
|
1182
|
+
(br_if $z1d (i32.ge_s (local.get $i) (local.get $n)))
|
|
1183
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 48))
|
|
1184
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1185
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1186
|
+
(br $z1l))))
|
|
1187
|
+
(else (if (i32.and (i32.gt_s (local.get $n) (i32.const 0)) (i32.le_s (local.get $n) (i32.const 21)))
|
|
1188
|
+
(then
|
|
1189
|
+
(local.set $i (i32.const 0))
|
|
1190
|
+
(block $b2d (loop $b2l
|
|
1191
|
+
(br_if $b2d (i32.ge_s (local.get $i) (local.get $olen)))
|
|
1192
|
+
(if (i32.eq (local.get $i) (local.get $n))
|
|
1193
|
+
(then
|
|
1194
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 46))
|
|
1195
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))))
|
|
1196
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
1197
|
+
(i32.load8_u (i32.add (local.get $scr) (i32.sub (i32.sub (local.get $olen) (i32.const 1)) (local.get $i)))))
|
|
1198
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1199
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1200
|
+
(br $b2l))))
|
|
1201
|
+
(else (if (i32.and (i32.gt_s (local.get $n) (i32.const -6)) (i32.le_s (local.get $n) (i32.const 0)))
|
|
1202
|
+
(then
|
|
1203
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 48))
|
|
1204
|
+
(i32.store8 (i32.add (local.get $buf) (i32.add (local.get $pos) (i32.const 1))) (i32.const 46))
|
|
1205
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 2)))
|
|
1206
|
+
(local.set $i (i32.const 0))
|
|
1207
|
+
(block $z3d (loop $z3l
|
|
1208
|
+
(br_if $z3d (i32.ge_s (local.get $i) (i32.sub (i32.const 0) (local.get $n))))
|
|
1209
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 48))
|
|
1210
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1211
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1212
|
+
(br $z3l)))
|
|
1213
|
+
(local.set $i (i32.const 0))
|
|
1214
|
+
(block $b3d (loop $b3l
|
|
1215
|
+
(br_if $b3d (i32.ge_s (local.get $i) (local.get $olen)))
|
|
1216
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
1217
|
+
(i32.load8_u (i32.add (local.get $scr) (i32.sub (i32.sub (local.get $olen) (i32.const 1)) (local.get $i)))))
|
|
1218
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1219
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1220
|
+
(br $b3l))))
|
|
1221
|
+
(else
|
|
1222
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
1223
|
+
(i32.load8_u (i32.add (local.get $scr) (i32.sub (local.get $olen) (i32.const 1)))))
|
|
1224
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1225
|
+
(if (i32.gt_s (local.get $olen) (i32.const 1))
|
|
1226
|
+
(then
|
|
1227
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 46))
|
|
1228
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1229
|
+
(local.set $i (i32.const 1))
|
|
1230
|
+
(block $b4d (loop $b4l
|
|
1231
|
+
(br_if $b4d (i32.ge_s (local.get $i) (local.get $olen)))
|
|
1232
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos))
|
|
1233
|
+
(i32.load8_u (i32.add (local.get $scr) (i32.sub (i32.sub (local.get $olen) (i32.const 1)) (local.get $i)))))
|
|
1234
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1235
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1236
|
+
(br $b4l)))))
|
|
1237
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 101))
|
|
1238
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1239
|
+
(local.set $n (i32.sub (local.get $n) (i32.const 1)))
|
|
1240
|
+
(if (i32.lt_s (local.get $n) (i32.const 0))
|
|
1241
|
+
(then
|
|
1242
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 45))
|
|
1243
|
+
(local.set $n (i32.sub (i32.const 0) (local.get $n))))
|
|
1244
|
+
(else (i32.store8 (i32.add (local.get $buf) (local.get $pos)) (i32.const 43))))
|
|
1245
|
+
(local.set $pos (i32.add (local.get $pos) (i32.const 1)))
|
|
1246
|
+
(local.set $pos (i32.add (local.get $pos)
|
|
1247
|
+
(call $__itoa (local.get $n) (i32.add (local.get $buf) (local.get $pos)))))))))))
|
|
1248
|
+
(call $__mkstr (local.get $buf) (local.get $pos)))`
|
|
1249
|
+
|
|
1250
|
+
|
|
880
1251
|
// === Number constants ===
|
|
881
1252
|
|
|
882
1253
|
// Each folds to inline (f64.const …), no stdlib dep. Written out (not a table
|
|
@@ -951,21 +1322,30 @@ export default (ctx) => {
|
|
|
951
1322
|
(local $off i32) (local $len i32) (local $i i32) (local $c i32) (local $neg i32)
|
|
952
1323
|
(local $digit i32) (local $seen i32) (local $f f64)
|
|
953
1324
|
(local $acc i64) (local $rad i64) (local $ovf i32) (local $exp i32) (local $sticky i32) (local $k i32) (local $e i32)
|
|
1325
|
+
;; Invalid radix (nonzero and outside 2..36 after ToInt32) → NaN regardless of input.
|
|
1326
|
+
(if (i32.and (i32.ne (local.get $radix) (i32.const 0))
|
|
1327
|
+
(i32.or (i32.lt_s (local.get $radix) (i32.const 2)) (i32.gt_s (local.get $radix) (i32.const 36))))
|
|
1328
|
+
(then (return (f64.const nan))))
|
|
954
1329
|
(local.set $f (f64.reinterpret_i64 (local.get $str)))
|
|
955
|
-
;;
|
|
956
|
-
|
|
1330
|
+
;; Number input takes ToString like any other value. In the plain-decimal range
|
|
1331
|
+
;; (finite, 1e-6 ≤ |x| < 1e21, or ±0) ToString has no exponent, so parsing its
|
|
1332
|
+
;; leading digits IS trunc — keep that as the fast path. Outside it ("1e+21",
|
|
1333
|
+
;; "1e-7", "Infinity") route through the real formatter: parseInt(1e21) is 1,
|
|
1334
|
+
;; parseInt(Infinity) is NaN.
|
|
1335
|
+
(if (f64.eq (local.get $f) (local.get $f)) (then
|
|
1336
|
+
;; ±0 → +0: ToString(-0) is "0", no sign survives.
|
|
1337
|
+
(if (f64.eq (local.get $f) (f64.const 0)) (then (return (f64.const 0))))
|
|
1338
|
+
(if (i32.and (f64.lt (f64.abs (local.get $f)) (f64.const 1e21))
|
|
1339
|
+
(f64.ge (f64.abs (local.get $f)) (f64.const 0.000001)))
|
|
1340
|
+
(then (return (f64.trunc (local.get $f)))))
|
|
1341
|
+
(local.set $str (call $__to_str (local.get $str)))))
|
|
957
1342
|
;; If NaN-boxed but not a string → return NaN
|
|
958
1343
|
(if (i32.ne (call $__ptr_type (local.get $str)) (i32.const 4))
|
|
959
1344
|
(then (return (f64.const nan))))
|
|
960
1345
|
(local.set $off (call $__ptr_offset (local.get $str)))
|
|
961
1346
|
(local.set $len (call $__str_byteLen (local.get $str)))
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
(block $ws (loop $wsl
|
|
965
|
-
(br_if $ws (i32.ge_s (local.get $i) (local.get $len)))
|
|
966
|
-
(br_if $ws (i32.gt_s (call $__char_at (local.get $str) (local.get $i)) (i32.const 32)))
|
|
967
|
-
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
968
|
-
(br $wsl)))
|
|
1347
|
+
;; Skip StrWhiteSpace (UTF-8-decoded: NBSP, LS/PS, Zs — not just ASCII).
|
|
1348
|
+
(local.set $i (call $__skipws (local.get $str) (i32.const 0) (local.get $len)))
|
|
969
1349
|
;; Sign
|
|
970
1350
|
(if (i32.and (i32.lt_s (local.get $i) (local.get $len))
|
|
971
1351
|
(i32.eq (call $__char_at (local.get $str) (local.get $i)) (i32.const 45)))
|
|
@@ -1309,12 +1689,8 @@ export default (ctx) => {
|
|
|
1309
1689
|
(then (return (f64.const nan))))))
|
|
1310
1690
|
(local.set $len (call $__str_byteLen (local.get $v)))
|
|
1311
1691
|
${SBASE_INIT}
|
|
1312
|
-
;; Skip leading
|
|
1313
|
-
(
|
|
1314
|
-
(br_if $ws (i32.ge_s (local.get $i) (local.get $len)))
|
|
1315
|
-
(br_if $ws (i32.gt_s ${chAt('(local.get $i)')} (i32.const 32)))
|
|
1316
|
-
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
1317
|
-
(br $wsl)))
|
|
1692
|
+
;; Skip leading StrWhiteSpace (UTF-8-decoded: NBSP, LS/PS, Zs — not just ASCII).
|
|
1693
|
+
(local.set $i (call $__skipws (local.get $v) (i32.const 0) (local.get $len)))
|
|
1318
1694
|
;; Sign.
|
|
1319
1695
|
(if (i32.eq ${chAtSafe('(local.get $i)')} (i32.const 45))
|
|
1320
1696
|
(then (local.set $neg (i32.const 1)) (local.set $i (i32.add (local.get $i) (i32.const 1)))))
|
|
@@ -1339,28 +1715,21 @@ export default (ctx) => {
|
|
|
1339
1715
|
// (string already, number/object ToPrimitive) stay out of scope per the runner.
|
|
1340
1716
|
const strInputI64 = (x) => valTypeOf(x) === VAL.BOOL ? asI64(bool(x)) : asI64(emit(x))
|
|
1341
1717
|
|
|
1718
|
+
// Native for EVERY host (formerly host-imported off-wasi): the wasm-side
|
|
1719
|
+
// parsers are exact (u64 round-once accumulation / Eisel-Lemire), while a
|
|
1720
|
+
// host round-trip re-decodes the string box in the embedder — the bench
|
|
1721
|
+
// runner's decoder mishandled SSO lanes and slice views, silently corrupting
|
|
1722
|
+
// watr's parseInt(hex) calls. Self-contained also means browsers/shells
|
|
1723
|
+
// need no env.parseInt/parseFloat import at all.
|
|
1342
1724
|
ctx.core.emit['Number.parseInt'] = (x, radix) => {
|
|
1343
|
-
|
|
1344
|
-
inc('__parseInt')
|
|
1345
|
-
const radixIR = radix == null ? ['i32.const', 0] : toI32(toNumF64(radix, emit(radix)))
|
|
1346
|
-
return typed(['call', '$__parseInt', strInputI64(x), radixIR], 'f64')
|
|
1347
|
-
}
|
|
1348
|
-
needParseInt()
|
|
1725
|
+
inc('__parseInt')
|
|
1349
1726
|
const radixIR = radix == null ? ['i32.const', 0] : toI32(toNumF64(radix, emit(radix)))
|
|
1350
1727
|
return typed(['call', '$__parseInt', strInputI64(x), radixIR], 'f64')
|
|
1351
1728
|
}
|
|
1352
1729
|
ctx.core.emit['parseInt'] = ctx.core.emit['Number.parseInt']
|
|
1353
|
-
const needParseFloat = () => hostImport('env', 'parseFloat',
|
|
1354
|
-
['func', '$__parseFloat', ['param', 'i64'], ['result', 'f64']])
|
|
1355
|
-
const needParseInt = () => hostImport('env', 'parseInt',
|
|
1356
|
-
['func', '$__parseInt', ['param', 'i64'], ['param', 'i32'], ['result', 'f64']])
|
|
1357
1730
|
|
|
1358
1731
|
ctx.core.emit['Number.parseFloat'] = (x) => {
|
|
1359
|
-
|
|
1360
|
-
inc('__parseFloat')
|
|
1361
|
-
return typed(['call', '$__parseFloat', strInputI64(x)], 'f64')
|
|
1362
|
-
}
|
|
1363
|
-
needParseFloat()
|
|
1732
|
+
inc('__parseFloat')
|
|
1364
1733
|
return typed(['call', '$__parseFloat', strInputI64(x)], 'f64')
|
|
1365
1734
|
}
|
|
1366
1735
|
ctx.core.emit['parseFloat'] = ctx.core.emit['Number.parseFloat']
|