Skip to content

Commit 74d7b8d

Browse files
authored
Restore build on different platforms + use Math.multiplyHigh for Scala Native (#1248)
1 parent c31e78a commit 74d7b8d

File tree

4 files changed

+26
-19
lines changed

4 files changed

+26
-19
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ jobs:
2323
- 11
2424
- 21
2525
os:
26+
- macos-14
27+
- windows-2022
2628
- ubuntu-22.04-arm
2729
- ubuntu-22.04
2830
fail-fast: false
@@ -41,6 +43,7 @@ jobs:
4143
- name: Setup Scala with SBT
4244
uses: coursier/setup-action@v1
4345
with:
46+
jvm: temurin:${{ matrix.java }}
4447
apps: sbt
4548
- name: Setup Node.js
4649
uses: actions/setup-node@v4

jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,7 @@ final class JsonReader private[jsoniter_scala](
22872287
else if (e10 >= 310) Double.PositiveInfinity
22882288
else {
22892289
var shift = java.lang.Long.numberOfLeadingZeros(m10)
2290-
var m2 = NativeMath.unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift)
2290+
var m2 = unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift) // FIXME: Use Math.unsignedMultiplyHigh after dropping of JDK 17 support
22912291
var e2 = (e10 * 108853 >> 15) - shift + 1 // (e10 * Math.log(10) / Math.log(2)).toInt - shift + 1
22922292
shift = java.lang.Long.numberOfLeadingZeros(m2)
22932293
m2 <<= shift
@@ -2435,7 +2435,7 @@ final class JsonReader private[jsoniter_scala](
24352435
else if (e10 >= 39) Float.PositiveInfinity
24362436
else {
24372437
var shift = java.lang.Long.numberOfLeadingZeros(m10)
2438-
var m2 = NativeMath.unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift)
2438+
var m2 = unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift) // FIXME: Use Math.unsignedMultiplyHigh after dropping of JDK 17 support
24392439
var e2 = (e10 * 108853 >> 15) - shift + 1 // (e10 * Math.log(10) / Math.log(2)).toInt - shift + 1
24402440
shift = java.lang.Long.numberOfLeadingZeros(m2)
24412441
m2 <<= shift
@@ -2469,6 +2469,9 @@ final class JsonReader private[jsoniter_scala](
24692469
java.lang.Float.parseFloat(new String(buf, 0, offset, pos - offset))
24702470
}
24712471

2472+
private[this] def unsignedMultiplyHigh(x: Long, y: Long): Long =
2473+
Math.multiplyHigh(x, y) + x + y // Use implementation that works only when both params are negative
2474+
24722475
def readBigInt(isToken: Boolean, default: BigInt, digitsLimit: Int): BigInt = {
24732476
var b =
24742477
if (isToken) nextToken(head)
@@ -2837,7 +2840,7 @@ final class JsonReader private[jsoniter_scala](
28372840
i -= 8
28382841
i >= first
28392842
}) {
2840-
x = NativeMath.unsignedMultiplyHigh(m, q) + ((~x & mq) >>> 63)
2843+
x = Math.multiplyHigh(m, q) + (m >> 63 & q) + ((~x & mq) >>> 63) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(m, q) + ((~x & mq) >>> 63)
28412844
}
28422845
}
28432846
var i = 0

jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ final class JsonWriter private[jsoniter_scala](
15601560
pos += digitCount(exp)
15611561
count = pos
15621562
} else {
1563-
q = NativeMath.multiplyHigh(exp, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
1563+
q = Math.multiplyHigh(exp, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
15641564
pos += digitCount(q)
15651565
count = write8Digits(exp - q * 100000000L, pos, buf, ds)
15661566
}
@@ -1696,7 +1696,7 @@ final class JsonWriter private[jsoniter_scala](
16961696
var hours = 0L
16971697
var secsOfHour = totalSecs.toInt
16981698
if (totalSecs >= 3600) {
1699-
hours = NativeMath.multiplyHigh(totalSecs >> 4, 655884233731895169L) >> 3 // divide a positive long by 3600
1699+
hours = Math.multiplyHigh(totalSecs >> 4, 655884233731895169L) >> 3 // divide a positive long by 3600
17001700
secsOfHour = (totalSecs - hours * 3600).toInt
17011701
}
17021702
val minutes = secsOfHour * 17477 >> 20 // divide a small positive int by 60
@@ -1713,7 +1713,7 @@ final class JsonWriter private[jsoniter_scala](
17131713
lastPos += digitCount(hours)
17141714
pos = lastPos
17151715
} else {
1716-
q = NativeMath.multiplyHigh(hours, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
1716+
q = Math.multiplyHigh(hours, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
17171717
lastPos += digitCount(q)
17181718
pos = write8Digits(hours - q * 100000000L, lastPos, buf, ds)
17191719
}
@@ -1766,9 +1766,9 @@ final class JsonWriter private[jsoniter_scala](
17661766
val epochSecond = x.getEpochSecond
17671767
if (epochSecond < 0) writeBeforeEpochInstant(epochSecond, x.getNano)
17681768
else {
1769-
val epochDay = NativeMath.multiplyHigh(epochSecond, 1749024623285053783L) >> 13 // epochSecond / 86400
1769+
val epochDay = Math.multiplyHigh(epochSecond, 1749024623285053783L) >> 13 // epochSecond / 86400
17701770
val marchZeroDay = epochDay + 719468 // 719468 == 719528 - 60 == days 0000 to 1970 - days 1st Jan to 1st Mar
1771-
var year = (NativeMath.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
1771+
var year = (Math.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
17721772
var days = year * 365L
17731773
var year1374389535 = year * 1374389535L
17741774
var century = (year1374389535 >> 37).toInt
@@ -1790,11 +1790,11 @@ final class JsonWriter private[jsoniter_scala](
17901790
}
17911791

17921792
private[this] def writeBeforeEpochInstant(epochSecond: Long, nano: Int): Unit = {
1793-
val epochDay = (NativeMath.multiplyHigh(epochSecond - 86399, 1749024623285053783L) >> 13) + 1 // (epochSecond - 86399) / 86400
1793+
val epochDay = (Math.multiplyHigh(epochSecond - 86399, 1749024623285053783L) >> 13) + 1 // (epochSecond - 86399) / 86400
17941794
var marchZeroDay = epochDay + 719468 // 719468 == 719528 - 60 == days 0000 to 1970 - days 1st Jan to 1st Mar
17951795
val adjust400YearCycles = ((marchZeroDay + 1) * 7525902 >> 40).toInt // ((marchZeroDay + 1) / 146097).toInt - 1
17961796
marchZeroDay -= adjust400YearCycles * 146097L
1797-
var year = (NativeMath.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
1797+
var year = (Math.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
17981798
var days = year * 365L
17991799
var year1374389535 = year * 1374389535L
18001800
var century = (year1374389535 >> 37).toInt
@@ -2140,8 +2140,8 @@ final class JsonWriter private[jsoniter_scala](
21402140

21412141
private[this] def write18Digits(x: Long, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = {
21422142
val m1 = 6189700196426901375L
2143-
val q1 = NativeMath.multiplyHigh(x, m1) >>> 25 // divide a positive long by 100000000
2144-
val q2 = NativeMath.multiplyHigh(q1, m1) >>> 25 // divide a positive long by 100000000
2143+
val q1 = Math.multiplyHigh(x, m1) >>> 25 // divide a positive long by 100000000
2144+
val q2 = Math.multiplyHigh(q1, m1) >>> 25 // divide a positive long by 100000000
21452145
ByteArrayAccess.setShort(buf, pos, ds(q2.toInt))
21462146
write8Digits(x - q1 * 100000000L, write8Digits(q1 - q2 * 100000000L, pos + 2, buf, ds), buf, ds)
21472147
}
@@ -2230,13 +2230,13 @@ final class JsonWriter private[jsoniter_scala](
22302230
pos = lastPos
22312231
} else {
22322232
val m2 = 6189700196426901375L
2233-
val q1 = NativeMath.multiplyHigh(q0, m2) >>> 25 // divide a positive long by 100000000
2233+
val q1 = Math.multiplyHigh(q0, m2) >>> 25 // divide a positive long by 100000000
22342234
if (q1 < m1) {
22352235
q2 = q1
22362236
lastPos += digitCount(q1)
22372237
pos = lastPos
22382238
} else {
2239-
q2 = NativeMath.multiplyHigh(q1, m2) >>> 25 // divide a small positive long by 100000000
2239+
q2 = Math.multiplyHigh(q1, m2) >>> 25 // divide a small positive long by 100000000
22402240
lastPos += digitCount(q2)
22412241
pos = write8Digits(q1 - q2 * m1, lastPos, buf, ds)
22422242
}
@@ -2354,7 +2354,7 @@ final class JsonWriter private[jsoniter_scala](
23542354
}
23552355

23562356
private[this] def rop(g: Long, cp: Int): Int = {
2357-
val x = NativeMath.multiplyHigh(g, cp.toLong << 32)
2357+
val x = Math.multiplyHigh(g, cp.toLong << 32)
23582358
(x >>> 31).toInt | -x.toInt >>> 31
23592359
}
23602360

@@ -2407,7 +2407,7 @@ final class JsonWriter private[jsoniter_scala](
24072407
val vbr = rop(g1, g0, cb + 2 << h) - vbCorr
24082408
var diff = 0
24092409
if (vb < 400 || {
2410-
m10 = NativeMath.multiplyHigh(vb, 461168601842738792L) // divide a positive long by 40
2410+
m10 = Math.multiplyHigh(vb, 461168601842738792L) // divide a positive long by 40
24112411
val vb40 = m10 * 40
24122412
diff = (vbl - vb40).toInt
24132413
((vb40 - vbr).toInt + 40 ^ diff) >= 0
@@ -2470,8 +2470,8 @@ final class JsonWriter private[jsoniter_scala](
24702470
}
24712471

24722472
private[this] def rop(g1: Long, g0: Long, cp: Long): Long = {
2473-
val x = NativeMath.multiplyHigh(g0, cp) + (g1 * cp >>> 1)
2474-
NativeMath.multiplyHigh(g1, cp) + (x >>> 63) | (-x ^ x) >>> 63
2473+
val x = Math.multiplyHigh(g0, cp) + (g1 * cp >>> 1)
2474+
Math.multiplyHigh(g1, cp) + (x >>> 63) | (-x ^ x) >>> 63
24752475
}
24762476

24772477
// Adoption of a nice trick from Daniel Lemire's blog that works for numbers up to 10^18:
@@ -2483,7 +2483,7 @@ final class JsonWriter private[jsoniter_scala](
24832483
var pos = p
24842484
var posLim = pl
24852485
if (q0 != x) {
2486-
val q1 = (NativeMath.multiplyHigh(x, 6189700196426901375L) >>> 25).toInt // divide a positive long by 100000000
2486+
val q1 = (Math.multiplyHigh(x, 6189700196426901375L) >>> 25).toInt // divide a positive long by 100000000
24872487
val r1 = (x - q1 * 100000000L).toInt
24882488
val posm8 = pos - 8
24892489
if (r1 == 0) {

jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriterSpec.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ class JsonWriterSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh
482482
}
483483

484484
Array(
485+
1405345091900L, // See: https://github.com/plokhotnyuk/jsoniter-scala/issues/1247
485486
6950401124099999999L,
486487
7379897853799999999L,
487488
7809394583499999999L,

0 commit comments

Comments
 (0)