@@ -263,29 +263,8 @@ private[optimizer] abstract class OptimizerCore(
263
263
264
264
private val isSubclassFun = isSubclass _
265
265
266
- private def isSubtype (lhs : Type , rhs : Type ): Boolean = {
267
- assert(lhs != VoidType )
268
- assert(rhs != VoidType )
269
-
270
- Types .isSubtype(lhs, rhs)(isSubclassFun) || {
271
- (lhs, rhs) match {
272
- case (LongType , ClassType (LongImpl .RuntimeLongClass , _)) =>
273
- true
274
- case (ClassType (LongImpl .RuntimeLongClass , false ), LongType ) =>
275
- true
276
- case (ClassType (BoxedLongClass , lhsNullable),
277
- ClassType (LongImpl .RuntimeLongClass , rhsNullable)) =>
278
- rhsNullable || ! lhsNullable
279
-
280
- case (ClassType (LongImpl .RuntimeLongClass , lhsNullable),
281
- ClassType (BoxedLongClass , rhsNullable)) =>
282
- rhsNullable || ! lhsNullable
283
-
284
- case _ =>
285
- false
286
- }
287
- }
288
- }
266
+ private def isSubtype (lhs : Type , rhs : Type ): Boolean =
267
+ Types .isSubtype(lhs, rhs)(isSubclassFun)
289
268
290
269
/** Transforms a statement.
291
270
*
@@ -577,8 +556,16 @@ private[optimizer] abstract class OptimizerCore(
577
556
case IsInstanceOf (expr, testType) =>
578
557
trampoline {
579
558
pretransformExpr(expr) { texpr =>
559
+ val texprType = texpr.tpe.base.toNonNullable
560
+
561
+ // Note: Disregards nullability because we can optimize null-check only.
562
+ val staticSubtype = {
563
+ isSubtype(texprType, testType) ||
564
+ (useRuntimeLong && isRTLong(testType) && isRTLong(texprType))
565
+ }
566
+
580
567
val result = {
581
- if (isSubtype(texpr.tpe.base.toNonNullable, testType) ) {
568
+ if (staticSubtype ) {
582
569
if (texpr.tpe.isNullable)
583
570
BinaryOp (BinaryOp .!== , finishTransformExpr(texpr), Null ())
584
571
else
@@ -762,10 +749,23 @@ private[optimizer] abstract class OptimizerCore(
762
749
def addCaptureParam (newName : LocalName ): LocalDef = {
763
750
val newOriginalName = originalNameForFresh(paramName, originalName, newName)
764
751
752
+ val captureTpe = {
753
+ /* Do not refine the capture type for longs:
754
+ * The pretransform might be a stack allocated RuntimeLong.
755
+ * We cannot (trivially) capture it in stack allocated form.
756
+ * Therefore, we keep the primitive type and let finishTransformExpr
757
+ * allocate a RuntimeLong.
758
+ *
759
+ * TODO: Improve this and allocate two capture params for lo/hi?
760
+ */
761
+ if (useRuntimeLong && paramDef.ptpe == LongType ) RefinedType (LongType )
762
+ else tcaptureValue.tpe
763
+ }
764
+
765
765
val replacement = ReplaceWithVarRef (newName, newSimpleState(Unused ))
766
- val localDef = LocalDef (tcaptureValue.tpe , mutable, replacement)
766
+ val localDef = LocalDef (captureTpe , mutable, replacement)
767
767
val localIdent = LocalIdent (newName)(ident.pos)
768
- val newParamDef = ParamDef (localIdent, newOriginalName, tcaptureValue.tpe .base, mutable)(paramDef.pos)
768
+ val newParamDef = ParamDef (localIdent, newOriginalName, captureTpe .base, mutable)(paramDef.pos)
769
769
770
770
/* Note that the binding will never create a fresh name for a
771
771
* ReplaceWithVarRef. So this will not put our name alignment at risk.
@@ -1297,12 +1297,22 @@ private[optimizer] abstract class OptimizerCore(
1297
1297
}
1298
1298
1299
1299
if (lhsStructure.className == LongImpl .RuntimeLongClass && trhs.tpe.base == LongType ) {
1300
- /* The lhs is a stack-allocated RuntimeLong, but the rhs is a
1301
- * primitive Long. We expand the primitive Long into a new
1302
- * stack-allocated RuntimeLong so that we do not need to cancel.
1303
- */
1304
- expandLongValue(trhs) { expandedRhs =>
1305
- buildInner(expandedRhs)
1300
+ // The lhs is a stack-allocated RuntimeLong, the rhs is *typed* as primitive long.
1301
+
1302
+ trhs match {
1303
+ case PreTransCast (trhs : PreTransRecordTree , _) =>
1304
+ /* The rhs is also a stack allocated Long but was cast back to
1305
+ * a primitive Long (due to method inlining). Remove the cast.
1306
+ */
1307
+ buildInner(trhs)
1308
+
1309
+ case _ =>
1310
+ /* The rhs is a primitive Long. We expand the primitive Long into
1311
+ * a new stack-allocated RuntimeLong so that we do not need to cancel.
1312
+ */
1313
+ expandLongValue(trhs) { expandedRhs =>
1314
+ buildInner(expandedRhs)
1315
+ }
1306
1316
}
1307
1317
} else {
1308
1318
buildInner(trhs)
@@ -5291,7 +5301,16 @@ private[optimizer] abstract class OptimizerCore(
5291
5301
def mayRequireUnboxing : Boolean =
5292
5302
arg.tpe.isNullable && tpe.isInstanceOf [PrimType ]
5293
5303
5294
- if (semantics.asInstanceOfs == CheckedBehavior .Unchecked && ! mayRequireUnboxing)
5304
+ /* In methods on RuntimeLong, we often asInstanceOf Long to RuntimeLong and
5305
+ * vice versa. We know that these are the same at runtime, so we lower to casts.
5306
+ */
5307
+ val castForRTLong : Boolean = useRuntimeLong && {
5308
+ val vtpe = arg.tpe.base
5309
+ (! vtpe.isNullable || tpe.isNullable) &&
5310
+ isRTLong(arg.tpe.base) && isRTLong(tpe)
5311
+ }
5312
+
5313
+ if (semantics.asInstanceOfs == CheckedBehavior .Unchecked && ! mayRequireUnboxing || castForRTLong)
5295
5314
foldCast(arg, tpe)
5296
5315
else if (isSubtype(arg.tpe.base, tpe))
5297
5316
arg
@@ -5825,6 +5844,16 @@ private[optimizer] abstract class OptimizerCore(
5825
5844
else upperBound
5826
5845
}
5827
5846
5847
+ /** Whether the given type is a RuntimeLong long at runtime.
5848
+ *
5849
+ * Assumes useRuntimeLong.
5850
+ */
5851
+ private def isRTLong (tpe : Type ) = tpe match {
5852
+ case LongType => true
5853
+ case ClassType (LongImpl .RuntimeLongClass | BoxedLongClass , _) => true
5854
+ case _ => false
5855
+ }
5856
+
5828
5857
/** Trampolines a pretransform */
5829
5858
private def trampoline (tailrec : => TailRec [Tree ]): Tree = {
5830
5859
// scalastyle:off return
@@ -6687,8 +6716,8 @@ private[optimizer] object OptimizerCore {
6687
6716
private def createNewLong (lo : Tree , hi : Tree )(
6688
6717
implicit pos : Position ): Tree = {
6689
6718
6690
- New (LongImpl .RuntimeLongClass , MethodIdent (LongImpl .initFromParts),
6691
- List (lo, hi))
6719
+ makeCast( New (LongImpl .RuntimeLongClass , MethodIdent (LongImpl .initFromParts),
6720
+ List (lo, hi)), LongType )
6692
6721
}
6693
6722
6694
6723
/** Tests whether `x + y` is valid without falling out of range. */
0 commit comments