@@ -2544,7 +2544,7 @@ final class JsonWriter private[jsoniter_scala](
25442544 else (e2 * 315653 ) >> 20
25452545 val h = (((e10 + 1 ) * - 217707 ) >> 16 ) + e2
25462546 val pow10 = floatPow10s(31 - e10)
2547- val hi64 = unsignedMultiplyHigh1 (pow10, m2.toLong << (h + 37 )) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10, m2.toLong << (h + 37))
2547+ val hi64 = unsignedMultiplyHigh (pow10, m2.toLong << (h + 37 )) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10, m2.toLong << (h + 37))
25482548 m10 = (hi64 >>> 36 ).toInt * 10
25492549 val dotOne = hi64 & 0xFFFFFFFFFL
25502550 val halfUlpPlusEven = (pow10 >>> (28 - h)) + ((m2IEEE + 1 ) & 1 )
@@ -2613,10 +2613,6 @@ final class JsonWriter private[jsoniter_scala](
26132613 count = pos
26142614 }
26152615
2616- @ inline
2617- private [this ] def unsignedMultiplyHigh1 (x : Long , y : Long ): Long =
2618- Math .multiplyHigh(x, y) + y // Use implementation that works only when x is negative and y is positive
2619-
26202616 // Based on the ingenious work of Xiang JunBo and Wang TieJun
26212617 // "xjb: Fast Float to String Algorithm": https://github.com/xjb714/xjb/blob/4852e533287bd0e8d554c2a9f4cc6eaa93ca799f/fast_f2s.pdf
26222618 // Sources with the license are here: https://github.com/xjb714/xjb
@@ -2656,35 +2652,37 @@ final class JsonWriter private[jsoniter_scala](
26562652 val pow10_1 = pow10s(i)
26572653 val pow10_2 = pow10s(i + 1 )
26582654 val cb = m2 << (h + 7 )
2659- val lo64_1 = unsignedMultiplyHigh2 (pow10_2, cb) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10_2, cb)
2655+ val lo64_1 = unsignedMultiplyHigh (pow10_2, cb) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10_2, cb)
26602656 val lo64_2 = pow10_1 * cb
2661- var hi64 = unsignedMultiplyHigh2 (pow10_1, cb) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10_1, cb)
2657+ var hi64 = unsignedMultiplyHigh (pow10_1, cb) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(pow10_1, cb)
26622658 val lo64 = lo64_1 + lo64_2
26632659 hi64 += java.lang.Long .compareUnsigned(lo64, lo64_1) >>> 31
26642660 val dotOne = (hi64 << 58 ) | (lo64 >>> 6 )
26652661 val halfUlp = pow10_1 >>> - h
2666- val even = (m2 + 1L ) & 1L
2667- m10 = hi64 >>> 6
2668- m10 = ( m10 << 3 ) + (m10 << 1 )
2669- if (java.lang. Long .compareUnsigned(halfUlp + even, - 1 - dotOne) > 0 ) m10 += 10L
2670- else if (m2IEEE != 0 ) {
2671- if (java.lang.Long .compareUnsigned(halfUlp + even, dotOne) <= 0 ) {
2672- m10 = (unsignedMultiplyHigh2(lo64, 10L ) + ( hi64 << 3 ) + (hi64 << 1 ) + { // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(lo64, 10L)
2673- if (dotOne == 0x4000000000000000L) 0x1FL
2674- else 0x20L
2675- }) >>> 6
2662+ val even = (m2.toInt + 1 ) & 1
2663+ if (java.lang. Long .compareUnsigned(halfUlp + even, - 1 - dotOne) > 0 ) {
2664+ m10 = hi64 >>> 6
2665+ m10 = (m10 << 3 ) + ( m10 << 1 ) + 10L
2666+ } else if (m2IEEE != 0 ) {
2667+ if (java.lang.Long .compareUnsigned(halfUlp + even, dotOne) > 0 ) {
2668+ m10 = hi64 >>> 6
2669+ m10 = (m10 << 3 ) + (m10 << 1 )
2670+ } else {
2671+ m10 = calculateM10(hi64, lo64, dotOne)
26762672 }
26772673 } else {
26782674 var tmp1 = dotOne >>> 4
26792675 tmp1 = (tmp1 << 3 ) + (tmp1 << 1 )
26802676 var tmp2 = halfUlp >>> 4
26812677 tmp2 += tmp2 << 2
2682- if (java.lang.Long .compareUnsigned((tmp1 << 4 ) >>> 4 , tmp2) > 0 ) m10 += (tmp1 >>> 60 ).toInt + 1
2683- else if (java.lang.Long .compareUnsigned(halfUlp >>> 1 , dotOne) <= 0 ) {
2684- m10 = (unsignedMultiplyHigh2(lo64, 10L ) + (hi64 << 3 ) + (hi64 << 1 ) + { // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(lo64, 10L)
2685- if (dotOne == 0x4000000000000000L) 0x1FL
2686- else 0x20L
2687- }) >>> 6
2678+ if (java.lang.Long .compareUnsigned((tmp1 << 4 ) >>> 4 , tmp2) > 0 ) {
2679+ m10 = hi64 >>> 6
2680+ m10 = (m10 << 3 ) + (m10 << 1 ) + ((tmp1 >>> 60 ).toInt + 1 )
2681+ } else if (java.lang.Long .compareUnsigned(halfUlp >>> 1 , dotOne) > 0 ) {
2682+ m10 = hi64 >>> 6
2683+ m10 = (m10 << 3 ) + (m10 << 1 )
2684+ } else {
2685+ m10 = calculateM10(hi64, lo64, dotOne)
26882686 }
26892687 }
26902688 }
@@ -2743,9 +2741,25 @@ final class JsonWriter private[jsoniter_scala](
27432741 count = pos
27442742 }
27452743
2744+ // 64-bit unsigned multiplication was adopted from the great Hacker's Delight function
2745+ // (Henry S. Warren, Hacker's Delight, Addison-Wesley, 2nd edition, Fig. 8.2)
2746+ // https://doc.lagout.org/security/Hackers%20Delight.pdf
2747+ @ inline
2748+ private [this ] def unsignedMultiplyHigh (x : Long , y : Long ): Long = {
2749+ val xl = x & 0xFFFFFFFFL
2750+ val xh = x >>> 32
2751+ val yl = y & 0xFFFFFFFFL
2752+ val yh = y >>> 32
2753+ val t = xh * yl + (xl * yl >>> 32 )
2754+ xh * yh + (t >>> 32 ) + (xl * yh + (t & 0xFFFFFFFFL) >>> 32 )
2755+ }
2756+
27462757 @ inline
2747- private [this ] def unsignedMultiplyHigh2 (x : Long , y : Long ): Long =
2748- Math .multiplyHigh(x, y) + (y & (x >> 63 )) // Use implementation that works only when y is positive
2758+ private [this ] def calculateM10 (hi : Long , lo : Long , dotOne : Long ): Long = ((hi << 3 ) + (hi << 1 ) +
2759+ ((lo >>> 61 ).toInt + (lo >>> 63 ).toInt + (java.lang.Long .compareUnsigned((lo << 3 ) + (lo << 1 ), lo << 1 ) >>> 31 ) + {
2760+ if (dotOne == 0x4000000000000000L) 0x1F
2761+ else 0x20
2762+ })) >>> 6
27492763
27502764 @ inline
27512765 private [this ] def digitCount (x : Long ): Int =
0 commit comments