Skip to content

Commit 5fe402b

Browse files
committed
Introduce casts around JSBinaryOps for x | 0 and x >>> 0.
We use these in some low-level routines, notably in `RuntimeLong`. Introducing casts avoids unnecessary `AsInstanceOf`s around them.
1 parent ab9ba4a commit 5fe402b

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,40 @@ private[optimizer] abstract class OptimizerCore(
646646
JSUnaryOp(op, transformExpr(lhs))
647647

648648
case JSBinaryOp(op, lhs, rhs) =>
649-
JSBinaryOp(op, transformExpr(lhs), transformExpr(rhs))
649+
val newTree = JSBinaryOp(op, transformExpr(lhs), transformExpr(rhs))
650+
651+
// Introduce casts for some idioms that are guaranteed to return certain types
652+
653+
// Is `arg` guaranteed to evaluate to a JS `number` (and hence, not a `bigint`)?
654+
def isJSNumber(arg: Tree): Boolean = arg.tpe match {
655+
case IntType | DoubleType | ByteType | ShortType | FloatType => true
656+
case _ => false
657+
}
658+
659+
newTree match {
660+
/* Unless it throws, `x | y` returns either a signed 32-bit integer
661+
* (an `Int`) or a bigint.
662+
*
663+
* The only case in which it returns a bigint is when both arguments
664+
* are (convertible to) bigint's. Custom objects can be converted to
665+
* bigint's if their `valueOf()` method returns a bigint.
666+
*
667+
* Primitive numbers cannot be implicitly converted to bigint's.
668+
* `x | y` throws if one side is a number and the other is (converted
669+
* to) a bigint. Therefore, if at least one of the arguments is known
670+
* to be a primitive number, we know that `x | y` will return a
671+
* signed 32-bit integer (or throw).
672+
*/
673+
case JSBinaryOp(JSBinaryOp.|, x, y) if isJSNumber(x) || isJSNumber(y) =>
674+
makeCast(newTree, IntType)
675+
676+
// >>> always returns a positive number in the unsigned 32-bit range (it rejects bigints)
677+
case JSBinaryOp(JSBinaryOp.>>>, _, _) =>
678+
makeCast(newTree, DoubleType)
679+
680+
case _ =>
681+
newTree
682+
}
650683

651684
case JSArrayConstr(items) =>
652685
JSArrayConstr(transformExprsOrSpreads(items))

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2062,7 +2062,7 @@ object Build {
20622062
Some(ExpectedSizes(
20632063
fastLink = 425000 to 426000,
20642064
fullLink = 282000 to 283000,
2065-
fastLinkGz = 61000 to 62000,
2065+
fastLinkGz = 60000 to 61000,
20662066
fullLinkGz = 43000 to 44000,
20672067
))
20682068
}

0 commit comments

Comments
 (0)