Skip to content

Commit

Permalink
Compiler support for JEP-193 VarHandle polymorphic signatures
Browse files Browse the repository at this point in the history
VarHandles bring a host of new "polymorphic signature" methods to
the Java 9 standard library. This commit updates the way we detect
such methods to look at the absense/presense of the
`PolymorphicSignature` annotation, so as to include these (and any
future additions.)

When we see applications of such methods, we disable adaptation
of argument and return types.

Tested manually with JDK9-ea:

```
Welcome to Scala 2.12.2-20161208-165912-3de1c0c (Java HotSpot(TM) 64-Bit Server VM, Java 9-ea).
Type in expressions for evaluation. Or try :help.

scala> import java.lang.invoke._, scala.runtime.IntRef
import java.lang.invoke._
import scala.runtime.IntRef

scala> val varHandle = MethodHandles.lookup().in(classOf[IntRef]).findVarHandle(classOf[IntRef], "elem", classOf[Int]);
varHandle: java.lang.invoke.VarHandle = java.lang.invoke.VarHandleInts$FieldInstanceReadWrite@7112ce6

scala> varHandle.getAndSet(ref, 1): Int
res5: Int = 0

scala> varHandle.getAndSet(ref, 1): Int
res6: Int = 1

```

Inspecting bytecode shows the absense of box/unboxing:

```
object Test {
  import java.lang.invoke._, scala.runtime.IntRef
  val varHandle = MethodHandles.lookup().in(classOf[IntRef]).findVarHandle(classOf[IntRef], "elem", classOf[Int]);

  def main(args: Array[String]): Unit = {
    val i : Int = varHandle.getAndSet(IntRef.zero, 1)
  }
}

```

```
  public void main(java.lang.String[]);
    Code:
       0: aload_0
       1: invokevirtual #28                 // Method varHandle:()Ljava/lang/invoke/VarHandle;
       4: invokestatic  #34                 // Method scala/runtime/IntRef.zero:()Lscala/runtime/IntRef;
       7: iconst_1
       8: invokevirtual #40                 // Method java/lang/invoke/VarHandle.getAndSet:(Lscala/runtime/IntRef;I)I
      11: istore_2
      12: return
```
  • Loading branch information
retronym committed Dec 12, 2016
1 parent 3de1c0c commit 1ff714b
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3401,7 +3401,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// governed by a) the argument types and b) the expected type
val args1 = typedArgs(args, forArgMode(fun, mode))
val pts = args1.map(_.tpe.deconst)
val clone = fun.symbol.cloneSymbol
val clone = fun.symbol.cloneSymbol.withoutAnnotations
val cloneParams = pts map (pt => clone.newValueParameter(currentUnit.freshTermName()).setInfo(pt))
val resultType = if (isFullyDefined(pt)) pt else ObjectTpe
clone.modifyInfo(mt => copyMethodType(mt, cloneParams, resultType))
Expand Down
10 changes: 7 additions & 3 deletions src/reflect/scala/reflect/internal/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,8 @@ trait Definitions extends api.StandardDefinitions {
lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature]
lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature]

lazy val MethodHandle = getClassIfDefined("java.lang.invoke.MethodHandle")
lazy val MethodHandleClass = getClassIfDefined("java.lang.invoke.MethodHandle")
lazy val VarHandleClass = getClassIfDefined("java.lang.invoke.VarHandle")

// Option classes
lazy val OptionClass: ClassSymbol = requiredClass[Option[_]]
Expand Down Expand Up @@ -1567,9 +1568,12 @@ trait Definitions extends api.StandardDefinitions {

lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest)
lazy val ManifestSymbols = Set[Symbol](PartialManifestClass, FullManifestClass, OptManifestClass)
private lazy val PolymorphicSignatureClass = MethodHandleClass.companionModule.info.decl(TypeName("PolymorphicSignature"))

def isPolymorphicSignature(sym: Symbol) = PolySigMethods(sym)
private lazy val PolySigMethods: Set[Symbol] = Set[Symbol](MethodHandle.info.decl(sn.Invoke), MethodHandle.info.decl(sn.InvokeExact)).filter(_.exists)
def isPolymorphicSignature(sym: Symbol) = sym != null && sym.isJavaDefined && {
val owner = sym.safeOwner
(owner == MethodHandleClass || owner == VarHandleClass) && sym.hasAnnotation(PolymorphicSignatureClass)
}

lazy val Scala_Java8_CompatPackage = rootMirror.getPackageIfDefined("scala.runtime.java8")
}
Expand Down
3 changes: 2 additions & 1 deletion src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.QuasiquoteClass_api_unapply
definitions.ScalaSignatureAnnotation
definitions.ScalaLongSignatureAnnotation
definitions.MethodHandle
definitions.MethodHandleClass
definitions.VarHandleClass
definitions.OptionClass
definitions.OptionModule
definitions.SomeClass
Expand Down

0 comments on commit 1ff714b

Please sign in to comment.