Skip to content

Scala 2 emits Object VarHandle call site for asInstanceOf[Int] #13184

Description

@He-Pin

Reproduction

Using Scala 2.13.18:

import java.lang.invoke.{ MethodHandles, VarHandle }

final class Repro {
  @volatile var state: Int = 42

  def typedLocal(): Int = {
    val v: Int = Repro.stateHandle.getVolatile(this)
    v
  }

  def castResult(): Int =
    Repro.stateHandle.getVolatile(this).asInstanceOf[Int]
}

object Repro {
  val stateHandle: VarHandle = {
    val lookup = MethodHandles.privateLookupIn(classOf[Repro], MethodHandles.lookup())
    lookup.findVarHandle(classOf[Repro], "state", Integer.TYPE)
  }
}

Compile and inspect bytecode:

scalac -d classes Repro.scala
javap -classpath classes -c -p Repro

Actual bytecode

typedLocal() keeps the signature-polymorphic VarHandle call site typed as primitive int:

public int typedLocal();
  Code:
     0: getstatic     #18                 // Field Repro$.MODULE$:LRepro$;
     3: invokevirtual #20                 // Method Repro$.stateHandle:()Ljava/lang/invoke/VarHandle;
     6: aload_0
     7: invokevirtual #35                 // Method java/lang/invoke/VarHandle.getVolatile:(LRepro;)I
    10: istore_1
    11: iload_1
    12: ireturn

castResult() generates an Object call site and then unboxes:

public int castResult();
  Code:
     0: getstatic     #18                 // Field Repro$.MODULE$:LRepro$;
     3: invokevirtual #20                 // Method Repro$.stateHandle:()Ljava/lang/invoke/VarHandle;
     6: aload_0
     7: invokevirtual #40                 // Method java/lang/invoke/VarHandle.getVolatile:(LRepro;)Ljava/lang/Object;
    10: invokestatic  #46                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
    13: ireturn

The generated code runs correctly, but it uses the object-returning VarHandle signature and adds an unnecessary unbox on a hot path.

Expected behavior

asInstanceOf[Int] should let the compiler emit the primitive int VarHandle call-site signature, matching the method result type and Java's behavior for (int) STATE_HANDLE.getVolatile(this).

For comparison, javac emits:

public int castResult();
  Code:
     0: getstatic     #13                 // Field STATE_HANDLE:Ljava/lang/invoke/VarHandle;
     3: aload_0
     4: invokevirtual #17                 // Method java/lang/invoke/VarHandle.getVolatile:(LJavaRepro;)I
     7: ireturn

Environment

  • Scala: 2.13.18
  • JVM used for the reproduction: Java 25.0.1

This came up in Apache Pekko while using VarHandle for a volatile Int state field. The workaround is to assign the result to a typed local first:

val v: Int = handle.getVolatile(this)
v

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions