8000 Merge pull request #53 from scala-js/main · scala-wasm/scala-wasm@dc8de53 · GitHub
[go: up one dir, main page]

Skip to content

Commit dc8de53

Browse files
authored
Merge pull request #53 from scala-js/main
[pull] scala-wasm from scala-js:main
2 parents 923545b + 4c11983 commit dc8de53

File tree

18 files changed

+221
-247
lines changed

18 files changed

+221
-247
lines changed

compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7809,6 +7809,14 @@ private object GenJSCode {
78097809
val T = jstpe.ClassRef(jswkn.BoxedStringClass)
78107810

78117811
val byClass: Map[ClassName, Map[MethodName, JavalibOpBody]] = Map(
7812+
jswkn.BoxedIntegerClass.withSuffix("$") -> Map(
7813+
m("divideUnsigned", List(I, I), I) -> ArgBinaryOp(binop.Int_unsigned_/),
7814+
m("remainderUnsigned", List(I, I), I) -> ArgBinaryOp(binop.Int_unsigned_%)
7815+
),
7816+
jswkn.BoxedLongClass.withSuffix("$") -> Map(
7817+
m("divideUnsigned", List(J, J), J) -> ArgBinaryOp(binop.Long_unsigned_/),
7818+
m("remainderUnsigned", List(J, J), J) -> ArgBinaryOp(binop.Long_unsigned_%)
7819+
),
78127820
jswkn.BoxedFloatClass.withSuffix("$") -> Map(
78137821
m("floatToIntBits", List(F), I) -> ArgUnaryOp(unop.Float_toBits),
78147822
m("intBitsToFloat", List(I), F) -> ArgUnaryOp(unop.Float_fromBits)

ir/shared/src/main/scala/org/scalajs/ir/Printers.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,11 @@ object Printers {
576576
case Double_<= => "<=[double]"
577577
case Double_> => ">[double]"
578578
case Double_>= => ">=[double]"
579+
580+
case Int_unsigned_/ => "unsigned_/[int]"
581+
case Int_unsigned_% => "unsigned_%[int]"
582+
case Long_unsigned_/ => "unsigned_/[long]"
583+
case Long_unsigned_% => "unsigned_%[long]"
579584
})
580585
print(' ')
581586
print(rhs)

ir/shared/src/main/scala/org/scalajs/ir/Trees.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,12 @@ object Trees {
679679
final val Class_cast = 61
680680
final val Class_newArray = 62
681681

682+
// New in 1.20
683+
final val Int_unsigned_/ = 63
684+
final val Int_unsigned_% = 64
685+
final val Long_unsigned_/ = 65
686+
final val Long_unsigned_% = 66
687+
682688
def isClassOp(op: Code): Boolean =
683689
op >= Class_isInstance && op <= Class_newArray
684690

@@ -693,10 +699,12 @@ object Trees {
693699
case String_+ =>
694700
StringType
695701
case Int_+ | Int_- | Int_* | Int_/ | Int_% |
696-
Int_| | Int_& | Int_^ | Int_<< | Int_>>> | Int_>> =>
702+
Int_| | Int_& | Int_^ | Int_<< | Int_>>> | Int_>> |
703+
Int_unsigned_/ | Int_unsigned_% =>
697704
IntType
698705
case Long_+ | Long_- | Long_* | Long_/ | Long_% |
699-
Long_| | Long_& | Long_^ | Long_<< | Long_>>> | Long_>> =>
706+
Long_| | Long_& | Long_^ | Long_<< | Long_>>> | Long_>> |
707+
Long_unsigned_/ | Long_unsigned_% =>
700708
LongType
701709
case Float_+ | Float_- | Float_* | Float_/ | Float_% =>
702710
FloatType

ir/shared/src/test/scala/org/scalajs/ir/PrintersTest.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,15 @@ class PrintersTest {
671671
BinaryOp(Class_isAssignableFrom, classVarRef, ref("y", ClassType(ClassClass, nullable = false))))
672672
assertPrintEquals("cast(x, y)", BinaryOp(Class_cast, classVarRef, ref("y", AnyType)))
673673
assertPrintEquals("newArray(x, y)", BinaryOp(Class_newArray, classVarRef, ref("y", IntType)))
674+
675+
assertPrintEquals("(x unsigned_/[int] y)",
676+
BinaryOp(Int_unsigned_/, ref("x", IntType), ref("y", IntType)))
677+
assertPrintEquals("(x unsigned_%[int] y)",
678+
BinaryOp(Int_unsigned_%, ref("x", IntType), ref("y", IntType)))
679+
assertPrintEquals("(x unsigned_/[long] y)",
680+
BinaryOp(Long_unsigned_/, ref("x", LongType), ref("y", LongType)))
681+
assertPrintEquals("(x unsigned_%[long] y)",
682+
BinaryOp(Long_unsigned_%, ref("x", LongType), ref("y", LongType)))
674683
}
675684

676685
@Test def printNewArray(): Unit = {

javalib/src/main/scala/java/lang/Integer.scala

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,11 @@ object Integer {
243243
(((t2 + (t2 >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24
244244
}
245245

246-
// Wasm intrinsic
247246
@inline def divideUnsigned(dividend: Int, divisor: Int): Int =
248-
if (divisor == 0) 0 / 0
249-
else asInt(asUint(dividend) / asUint(divisor))
247+
throw new Error("stub") // body replaced by the compiler back-end
250248

251-
// Wasm intrinsic
252249
@inline def remainderUnsigned(dividend: Int, divisor: Int): Int =
253-
if (divisor == 0) 0 % 0
254-
else asInt(asUint(dividend) % asUint(divisor))
250+
throw new Error("stub") // body replaced by the compiler back-end
255251

256252
@inline def highestOneBit(i: Int): Int = {
257253
/* The natural way of implementing this is:

javalib/src/main/scala/java/lang/Long.scala

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -348,47 +348,11 @@ object Long {
348348
@inline def compareUnsigned(x: scala.Long, y: scala.Long): scala.Int =
349349
compare(x ^ SignBit, y ^ SignBit)
350350

351-
// Intrinsic, except for JS when using bigint's for longs
352-
def divideUnsigned(dividend: scala.Long, divisor: scala.Long): scala.Long =
353-
divModUnsigned(dividend, divisor, isDivide = true)
354-
355-
// Intrinsic, except for JS when using bigint's for longs
356-
def remainderUnsigned(dividend: scala.Long, divisor: scala.Long): scala.Long =
357-
divModUnsigned(dividend, divisor, isDivide = false)
358-
359-
private def divModUnsigned(a: scala.Long, b: scala.Long,
360-
isDivide: scala.Boolean): scala.Long = {
361-
/* This is a much simplified (and slow) version of
362-
* RuntimeLong.unsignedDivModHelper.
363-
*/
364-
365-
if (b == 0L)
366-
throw new ArithmeticException("/ by zero")
367-
368-
var shift = numberOfLeadingZeros(b) - numberOfLeadingZeros(a)
369-
var bShift = b << shift
370-
371-
var rem = a
372-
var quot = 0L
373-
374-
/* Invariants:
375-
* bShift == b << shift == b * 2^shift
376-
* quot >= 0
377-
* 0 <= rem < 2 * bShift
378-
* quot * b + rem == a
379-
*/
380-
while (shift >= 0 && rem != 0) {
381-
if ((rem ^ SignBit) >= (bShift ^ SignBit)) {
382-
rem -= bShift
383-
quot |= (1L << shift)
384-
}
385-
shift -= 1
386-
bShift >>>= 1
387-
}
351+
@inline def divideUnsigned(dividend: scala.Long, divisor: scala.Long): scala.Long =
352+
throw new Error("stub") // body replaced by the compiler back-end
388353

389-
if (isDivide) quot
390-
else rem
391-
}
354+
@inline def remainderUnsigned(dividend: scala.Long, divisor: scala.Long): scala.Long =
355+
throw new Error("stub") // body replaced by the compiler back-end
392356

393357
@inline
394358
def highestOneBit(i: scala.Long): scala.Long = {

linker/shared/src/main/scala/org/scalajs/linker/analyzer/Infos.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -915,12 +915,12 @@ object Infos {
915915
import BinaryOp._
916916

917917
op match {
918-
case Int_/ | Int_% =>
918+
case Int_/ | Int_% | Int_unsigned_/ | Int_unsigned_% =>
919919
rhs match {
920920
case IntLiteral(r) if r != 0 =>
921921
case _ => builder.addUsedIntLongDivModByMaybeZero()
922922
}
923-
case Long_/ | Long_% =>
923+
case Long_/ | Long_% | Long_unsigned_/ | Long_unsigned_% =>
924924
rhs match {
925925
case LongLiteral(r) if r != 0L =>
926926
case _ => builder.addUsedIntLongDivModByMaybeZero()

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/CoreJSLib.scala

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -919,17 +919,11 @@ private[emitter] object CoreJSLib {
919919
}
920920

921921
condDefs(shouldDefineIntLongDivModFunctions)(
922-
defineFunction2(VarField.intDiv) { (x, y) =>
922+
defineFunction1(VarField.checkIntDivisor) { y =>
923923
If(y === 0, throwDivByZero, {
924-
Return((x / y) | 0)
924+
Return(y)
925925
})
926-
} :::
927-
defineFunction2(VarField.intMod) { (x, y) =>
928-
If(y === 0, throwDivByZero, {
929-
Return((x % y) | 0)
930-
})
931-
} :::
932-
Nil
926+
}
933927
) :::
934928
defineFunction1(VarField.doubleToInt) { x =>
935929
Return(If(x > 2147483647, 2147483647, If(x < -2147483648, -2147483648, x | 0)))
@@ -953,17 +947,11 @@ private[emitter] object CoreJSLib {
953947
}
954948
) :::
955949
condDefs(allowBigIntsForLongs && shouldDefineIntLongDivModFunctions)(
956-
defineFunction2(VarField.longDiv) { (x, y) =>
950+
defineFunction1(VarField.checkLongDivisor) { y =>
957951
If(y === bigInt(0), throwDivByZero, {
958-
Return(wrapBigInt64(x / y))
952+
Return(y)
959953
})
960-
} :::
961-
defineFunction2(VarField.longMod) { (x, y) =>
962-
If(y === bigInt(0), throwDivByZero, {
963-
Return(wrapBigInt64(x % y))
964-
})
965-
} :::
966-
Nil
954+
}
967955
) :::
968956
condDefs(allowBigIntsForLongs)(
969957
defineFunction1(VarField.doubleToLong)(x => Return {

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,12 +1287,14 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) {
12871287
allowSideEffects && test(lhs)
12881288

12891289
// Division and modulo, preserve pureness unless they can divide by 0
1290-
case BinaryOp(BinaryOp.Int_/ | BinaryOp.Int_%, lhs, rhs) if !allowSideEffects =>
1290+
case BinaryOp(BinaryOp.Int_/ | BinaryOp.Int_% | BinaryOp.Int_unsigned_/ | BinaryOp.Int_unsigned_%, lhs, rhs)
1291+
if !allowSideEffects =>
12911292
rhs match {
12921293
case IntLiteral(r) if r != 0 => test(lhs)
12931294
case _ => false
12941295
}
1295-
case BinaryOp(BinaryOp.Long_/ | BinaryOp.Long_%, lhs, rhs) if !allowSideEffects =>
1296+
case BinaryOp(BinaryOp.Long_/ | BinaryOp.Long_% | BinaryOp.Long_unsigned_/ | BinaryOp.Long_unsigned_%, lhs, rhs)
1297+
if !allowSideEffects =>
12961298
rhs match {
12971299
case LongLiteral(r) if r != 0L => test(lhs)
12981300
case _ => false
@@ -2206,6 +2208,9 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) {
22062208
def or0(tree: js.Tree): js.Tree =
22072209
js.BinaryOp(JSBinaryOp.|, tree, js.IntLiteral(0))
22082210

2211+
def shr0(tree: js.Tree): js.Tree =
2212+
js.BinaryOp(JSBinaryOp.>>>, tree, js.IntLiteral(0))
2213+
22092214
def bigIntShiftRhs(tree: js.Tree): js.Tree = {
22102215
tree match {
22112216
case js.IntLiteral(v) =>
@@ -2631,20 +2636,17 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) {
26312636
}
26322637
case Int_* =>
26332638
genCallPolyfillableBuiltin(ImulBuiltin, newLhs, newRhs)
2634-
case Int_/ =>
2635-
rhs match {
2636-
case IntLiteral(r) if r != 0 =>
2637-
or0(js.BinaryOp(JSBinaryOp./, newLhs, newRhs))
2638-
case _ =>
2639-
genCallHelper(VarField.intDiv, newLhs, newRhs)
2640-
}
2641-
case Int_% =>
2642-
rhs match {
2643-
case IntLiteral(r) if r != 0 =>
2644-
or0(js.BinaryOp(JSBinaryOp.%, newLhs, newRhs))
2645-
case _ =>
2646-
genCallHelper(VarField.intMod, newLhs, newRhs)
2639+
case Int_/ | Int_% | Int_unsigned_/ | Int_unsigned_% =>
2640+
val newRhs1 = rhs match {
2641+
case IntLiteral(r) if r != 0 => newRhs
2642+
case _ => genCallHelper(VarField.checkIntDivisor, newRhs)
26472643
}
2644+
or0((op: @switch) match {
2645+
case Int_/ => js.BinaryOp(JSBinaryOp./, newLhs, newRhs1)
2646+
case Int_% => js.BinaryOp(JSBinaryOp.%, newLhs, newRhs1)
2647+
case Int_unsigned_/ => js.BinaryOp(JSBinaryOp./, shr0(newLhs), shr0(newRhs1))
2648+
case Int_unsigned_% => js.BinaryOp(JSBinaryOp.%, shr0(newLhs), shr0(newRhs1))
2649+
})
26482650

26492651
case Int_| => js.BinaryOp(JSBinaryOp.|, newLhs, newRhs)
26502652
case Int_& => js.BinaryOp(JSBinaryOp.&, newLhs, newRhs)
@@ -2685,27 +2687,27 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) {
26852687
wrapBigInt64(js.BinaryOp(JSBinaryOp.*, newLhs, newRhs))
26862688
else
26872689
genApply(newLhs, LongImpl.*, newRhs)
2688-
case Long_/ =>
2690+
case Long_/ | Long_% | Long_unsigned_/ | Long_unsigned_% =>
26892691
if (useBigIntForLongs) {
2690-
rhs match {
2691-
case LongLiteral(r) if r != 0L =>
2692-
wrapBigInt64(js.BinaryOp(JSBinaryOp./, newLhs, newRhs))
2693-
case _ =>
2694-
genCallHelper(VarField.longDiv, newLhs, newRhs)
2692+
val newRhs1 = rhs match {
2693+
case LongLiteral(r) if r != 0L => newRhs
2694+
case _ => genCallHelper(VarField.checkLongDivisor, newRhs)
26952695
}
2696+
wrapBigInt64((op: @switch) match {
2697+
case Long_/ => js.BinaryOp(JSBinaryOp./, newLhs, newRhs1)
2698+
case Long_% => js.BinaryOp(JSBinaryOp.%, newLhs, newRhs1)
2699+
case Long_unsigned_/ => js.BinaryOp(JSBinaryOp./, wrapBigIntU64(newLhs), wrapBigIntU64(newRhs1))
2700+
case Long_unsigned_% => js.BinaryOp(JSBinaryOp.%, wrapBigIntU64(newLhs), wrapBigIntU64(newRhs1))
2701+
})
26962702
} else {
2697-
genApply(newLhs, LongImpl./, newRhs)
2698-
}
2699-
case Long_% =>
2700-
if (useBigIntForLongs) {
2701-
rhs match {
2702-
case LongLiteral(r) if r != 0L =>
2703-
wrapBigInt64(js.BinaryOp(JSBinaryOp.%, newLhs, newRhs))
2704-
case _ =>
2705-
genCallHelper(VarField.longMod, newLhs, newRhs)
2703+
// The zero divisor check is performed by the implementation methods
2704+
val implMethodName = (op: @switch) match {
2705+
case Long_/ => LongImpl./
2706+
case Long_% => LongImpl.%
2707+
case Long_unsigned_/ => LongImpl.divideUnsigned
2708+
case Long_unsigned_% => LongImpl.remainderUnsigned
27062709
}
2707-
} else {
2708-
genApply(newLhs, LongImpl.%, newRhs)
2710+
genApply(newLhs, implMethodName, newRhs)
27092711
}
27102712

27112713
case Long_| =>

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/LongImpl.scala

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ private[linker] object LongImpl {
4747
final val / = binaryOp("$div")
4848
final val % = binaryOp("$percent")
4949

50+
final val divideUnsigned = binaryOp("divideUnsigned")
51+
final val remainderUnsigned = binaryOp("remainderUnsigned")
52+
5053
final val | = binaryOp("$bar")
5154
final val & = binaryOp("$amp")
5255
final val ^ = binaryOp("$up")
@@ -81,8 +84,8 @@ private[linker] object LongImpl {
8184
final val compareToO = MethodName("compareTo", List(ClassRef(ObjectClass)), IntRef)
8285

8386
private val OperatorMethods = Set(
84-
UNARY_-, UNARY_~, this.+, this.-, *, /, %, |, &, ^, <<, >>>, >>,
85-
===, !==, <, <=, >, >=, toInt, toFloat, toDouble, bitsToDouble)
87+
UNARY_-, UNARY_~, this.+, this.-, *, /, %, divideUnsigned, remainderUnsigned,
88+
|, &, ^, <<, >>>, >>, ===, !==, <, <=, >, >=, toInt, toFloat, toDouble, bitsToDouble)
8689

8790
private val BoxedLongMethods = Set(
8891
byteValue, shortValue, intValue, longValue, floatValue, doubleValue,
@@ -92,12 +95,10 @@ private[linker] object LongImpl {
9295

9396
// Methods used for intrinsics
9497

95-
final val compareToRTLong = MethodName("compareTo", List(RTLongRef), IntRef)
96-
final val divideUnsigned = binaryOp("divideUnsigned")
97-
final val remainderUnsigned = binaryOp("remainderUnsigned")
98+
final val compareToRTLong = MethodName("compareTo", List(RTLongRef), IntRef)
9899

99100
val AllIntrinsicMethods = Set(
100-
compareToRTLong, divideUnsigned, remainderUnsigned)
101+
compareToRTLong)
101102

102103
// Constructors
103104

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/VarField.scala

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,16 +259,12 @@ private[emitter] object VarField {
259259

260260
// Arithmetic Call Helpers
261261

262-
final val intDiv = mk("$intDiv")
262+
final val checkIntDivisor = mk("$checkIntDivisor")
263263

264-
final val intMod = mk("$intMod")
264+
final val checkLongDivisor = mk("$checkLongDivisor")
265265

266266
final val longToFloat = mk("$longToFloat")
267267

268-
final val longDiv = mk("$longDiv")
269-
270-
final val longMod = mk("$longMod")
271-
272268
final val doubleToLong = mk("$doubleToLong")
273269

274270
final val doubleToInt = mk("$doubleToInt")

0 commit comments

Comments
 (0)
0