Skip to content

Automatic untupling introduces extra unnecessary CheckCast Instructions #24997

@nmichael44

Description

@nmichael44

I saw this in some cats effect code when using resources. I minimised it to the code below.

Compiler version

3.7.4

Minimized code

package app

object Example:
  private class Wrapper[A](value: A):
    def use[B](f: A => B): B = f(value)
  end Wrapper

  def run: Int =
    val tupleWrapper = Wrapper((42, "Answer"))

    // tupleWrapper.use { case (number, _) => number }
    tupleWrapper.use { (number, _) => number }
  end run
end Example

Output

When using the case for the inner lambda the code produced for it is this:

private final static synthetic run$$anonfun$1(Lscala/Tuple2;)I
    // parameter final  x$1
   L0
    LINENUMBER 12 L0
    ALOAD 0
    ASTORE 1
    ALOAD 1
    INVOKEVIRTUAL scala/Tuple2._1 ()Ljava/lang/Object;
    INVOKESTATIC scala/runtime/BoxesRunTime.unboxToInt (Ljava/lang/Object;)I
    ISTORE 2
   L1
    ILOAD 2
    IRETURN

which is what one would expect. Only the first element of the pair is referenced since it is the only one used. But when the case keyword is not there (in which case automatic untupling takes place), we get the following:

private final static synthetic run$$anonfun$1(Lscala/Tuple2;)I
    // parameter final  x$1
   L0
    LINENUMBER 12 L0
    ALOAD 0
    INVOKEVIRTUAL scala/Tuple2._1 ()Ljava/lang/Object;
    INVOKESTATIC scala/runtime/BoxesRunTime.unboxToInt (Ljava/lang/Object;)I
    ISTORE 1
   L1
    ALOAD 0
    INVOKEVIRTUAL scala/Tuple2._2 ()Ljava/lang/Object;
    CHECKCAST java/lang/String
    ASTORE 2
   L2
    ILOAD 1
    IRETURN

As you can see now we fetch the second unused elements of the pair and we do a CHECKCAST on it (and so the JVM cannot remove references to it, since CHECKCAST is side-effecting -- throws exceptions). If you had 10 ignored args you get 10 CHECKCAST instructions.

Expectation

I would expect to get the same code in both cases. In the words of @som-snytt why is it that can't we have nice things...

Metadata

Metadata

Assignees

No one assigned

    Labels

    itype:bugstat:needs triageEvery issue needs to have an "area" and "itype" label

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions