summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2009-03-30 08:45:39 +0000
committerIulian Dragos <jaguarul@gmail.com>2009-03-30 08:45:39 +0000
commit532147c333a8dab79fc77c20162a4d752c6f6780 (patch)
treed18c5275381e34655b0dad967f6304ba63c4416e
parent1c72ffaee5e0faeeb6d046216e5e76c86a6a41ff (diff)
downloadscala-532147c333a8dab79fc77c20162a4d752c6f6780.tar.gz
scala-532147c333a8dab79fc77c20162a4d752c6f6780.tar.bz2
scala-532147c333a8dab79fc77c20162a4d752c6f6780.zip
Code to support invoke-dynamic for structural t...
Code to support invoke-dynamic for structural types. Not yet complete, built around the JSR 292 spec of December 2008.
-rw-r--r--lib/fjbg.jar.desired.sha12
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala26
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala5
-rw-r--r--src/library/scala/runtime/DynamicDispatch.java42
8 files changed, 99 insertions, 7 deletions
diff --git a/lib/fjbg.jar.desired.sha1 b/lib/fjbg.jar.desired.sha1
index 55b4cb29b0..d6bf323a06 100644
--- a/lib/fjbg.jar.desired.sha1
+++ b/lib/fjbg.jar.desired.sha1
@@ -1 +1 @@
-a22d30fd058e068c86526b4a4cb16f7529583324 ?fjbg.jar
+7f3fa70c5792a945bea5fd1fbad53be0a75541b6 ?fjbg.jar
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 8f8ddec2d9..f13e1cfa21 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -673,7 +673,7 @@ trait ScalacSettings
val stop = PhasesSetting ("-Ystop", "Stop after phase")
val refinementMethodDispatch =
ChoiceSetting ("-Ystruct-dispatch", "Selects dispatch method for structural refinement method calls",
- List("no-cache", "mono-cache", "poly-cache"), "poly-cache") .
+ List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") .
withHelpSyntax("-Ystruct-dispatch:<method>")
val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 69f0d1f826..471a7cc6f7 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -846,6 +846,7 @@ abstract class GenICode extends SubComponent {
}
case ApplyDynamic(qual, args) =>
+ ctx.clazz.bootstrapClass = Some("scala.runtime.DynamicDispatch")
val ctx1 = genLoad(qual, ctx, ANY_REF_CLASS)
genLoadArguments(args, tree.symbol.info.paramTypes, ctx1)
ctx1.bb.emit(CALL_METHOD(tree.symbol, InvokeDynamic), tree.pos)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index c2096fe161..8f17c000ee 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -72,7 +72,10 @@ abstract class GenJVM extends SubComponent {
val BoxesRunTime = "scala.runtime.BoxesRunTime"
val StringBuilderType = new JObjectType(StringBuilderClass)
- val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
+ val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
+ val MethodTypeType = new JObjectType("java.dyn.MethodType")
+ val JavaLangClassType = new JObjectType("java.lang.Class")
+ val MethodHandleType = new JObjectType("java.dyn.MethodHandle")
// Scala attributes
val SerializableAttr = definitions.SerializableAttr
@@ -191,7 +194,7 @@ abstract class GenJVM extends SubComponent {
if (jclass.getName.endsWith("$"))
jclass.addAttribute(getMarkerAttr(jclass))
- if (isStaticModule(c.symbol) || serialVUID != None) {
+ if (isStaticModule(c.symbol) || serialVUID != None || clasz.bootstrapClass.isDefined) {
if (isStaticModule(c.symbol))
addModuleInstanceField;
addStaticInit(jclass)
@@ -212,6 +215,7 @@ abstract class GenJVM extends SubComponent {
}
}
+ if (clasz.bootstrapClass.isDefined) jclass.setBootstrapClass(clasz.bootstrapClass.get)
clasz.fields foreach genField
clasz.methods foreach genMethod
@@ -675,9 +679,27 @@ abstract class GenJVM extends SubComponent {
case None => ()
}
+ if (clasz.bootstrapClass.isDefined) emitBootstrapMethodInstall(clinit)
+
clinit.emitRETURN()
}
+ /** Emit code that installs a boostrap method for invoke dynamic. It installs the default
+ * method, found in scala.runtime.DynamicDispatch.
+ */
+ def emitBootstrapMethodInstall(jcode: JExtendedCode) {
+ jcode.emitPUSH(jclass.getType.asInstanceOf[JReferenceType])
+ jcode.emitPUSH(new JObjectType("scala.runtime.DynamicDispatch"))
+ jcode.emitPUSH("bootstrapInvokeDynamic")
+ jcode.emitGETSTATIC("java.dyn.Linkage", "BOOTSTRAP_METHOD_TYPE", MethodTypeType)
+ jcode.emitDUP
+ jcode.emitINVOKESTATIC("scala.Console", "println", new JMethodType(JType.VOID, Array(JObjectType.JAVA_LANG_OBJECT)))
+ jcode.emitINVOKESTATIC("java.dyn.MethodHandles", "findStatic",
+ new JMethodType(MethodHandleType, Array(JavaLangClassType, JObjectType.JAVA_LANG_STRING, MethodTypeType)))
+ jcode.emitINVOKESTATIC("java.dyn.Linkage", "registerBootstrapMethod",
+ new JMethodType(JType.VOID, Array(JavaLangClassType, MethodHandleType)))
+ }
+
/** Add a forwarder for method m */
def addForwarder(jclass: JClass, module: Symbol, m: Symbol) {
import JAccessFlags._
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 0cecbc03c4..6623a41992 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -127,6 +127,13 @@ trait Definitions {
def methodCache_find = getMember(MethodCacheClass, nme.find_)
def methodCache_add = getMember(MethodCacheClass, nme.add_)
lazy val EmptyMethodCacheClass: Symbol = getClass("scala.runtime.EmptyMethodCache")
+
+ // invoke dynamic support
+ lazy val LinkageModule: Symbol = getModule("java.dyn.Linkage")
+ lazy val Linkage_invalidateCallerClass = getMember(LinkageModule, "invalidateCallerClass")
+ lazy val DynamicDispatchClass: Symbol = getModule("scala.runtime.DynamicDispatch")
+ lazy val DynamicDispatch_DontSetTarget: Symbol = getMember(DynamicDispatchClass, "DontSetTarget")
+
lazy val PredefModule: Symbol = getModule("scala.Predef")
def Predef_classOf = getMember(PredefModule, nme.classOf)
def Predef_classOfType(classType: Type): Type =
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index db88df5dc5..23496807d8 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -592,6 +592,25 @@ abstract class CleanUp extends Transform {
)
}
+ def getClass(q: Tree): Tree =
+ Apply(Select(q, nme.getClass_), List())
+
+ if (settings.refinementMethodDispatch.value == "invoke-dynamic") {
+/* val guardCallSite: Tree = {
+ val cachedClass = addStaticVariableToClass("cachedClass", definitions.ClassClass.tpe, EmptyTree)
+ val tmpVar = currentOwner.newVariable(ad.pos, unit.fresh.newName(ad.pos, "x")).setInfo(definitions.AnyRefClass.tpe)
+ atPos(ad.pos)(Block(List(
+ ValDef(tmpVar, transform(qual))),
+ If(Apply(Select(gen.mkAttributedRef(cachedClass), nme.EQ), List(getClass(Ident(tmpVar)))),
+ Block(List(Assign(gen.mkAttributedRef(cachedClass), getClass(Ident(tmpVar)))),
+ copy.ApplyDynamic(ad, Ident(tmpVar), transformTrees(params))),
+ EmptyTree)))
+ }
+ //println(guardCallSite)
+*/
+ localTyper.typed(copy.ApplyDynamic(ad, transform(qual), transformTrees(params)))
+ } else {
+
/* ### BODY OF THE TRANSFORMATION -> remember we're in case ad@ApplyDynamic(qual, params) ### */
/* This creates the tree that does the reflective call (see general comment
@@ -659,7 +678,7 @@ abstract class CleanUp extends Transform {
/* We return the dynamic call tree, after making sure no other
* clean-up transformation are to be applied on it. */
transform(t)
-
+ }
/* ### END OF DYNAMIC APPLY TRANSFORM ### */
/* Some cleanup transformations add members to templates (classes, traits, etc).
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b14f6724e2..dec6d58b45 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3373,9 +3373,10 @@ trait Typers { self: Analyzer =>
typedApply(fun, args)
case ApplyDynamic(qual, args) =>
+ val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic")
val qual1 = typed(qual, AnyRefClass.tpe)
- val args1 = List.mapConserve(args)(arg => typed(arg, AnyRefClass.tpe))
- copy.ApplyDynamic(tree, qual1, args1) setType AnyRefClass.tpe
+ val args1 = List.mapConserve(args)(arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg))
+ copy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType)
case Super(qual, mix) =>
typedSuper(qual, mix)
diff --git a/src/library/scala/runtime/DynamicDispatch.java b/src/library/scala/runtime/DynamicDispatch.java
new file mode 100644
index 0000000000..2868298211
--- /dev/null
+++ b/src/library/scala/runtime/DynamicDispatch.java
@@ -0,0 +1,42 @@
+package scala.runtime;
+
+import java.dyn.CallSite;
+import java.dyn.MethodHandle;
+
+/**
+ * This class resolves calls through refinement types. The
+ * bootstrap method is called when an invokedynamic is found
+ * by the Java VM.
+ *
+ * Note: Requires Java 7 with invoke dynamic support (see JSR 292)
+ *
+ * @author Iulian Dragos
+ * @see JSR292
+ */
+public class DynamicDispatch {
+
+ /**
+ * Resolve an invoke dynamic in Scala code. invokedynamic calls appear
+ * when a method defined by a refinement type is called. It is resolved
+ * by looking up a method with the same name and types in the receiver
+ * object. It is guaranteed by the type checker that such a method
+ * exists.
+ *
+ * The current implementation is not correct, a call site being
+ * always bootstrapped to a method handle. A bound call site should be
+ * guarded by a test on the receiver type. Such code should either
+ * be generated by the compiler, or by this bootstrap method using
+ * one of the code combinators provided in java.dyn.*.
+ *
+ * ATM, they are not yet available in the JVM.
+ */
+ public static bootstrapInvokeDynamic(CallSite cs, Object... args) {
+ println(cs);
+
+ MethodHandle mh = MethodHandles.findVirtual(cs.callerClass(),
+ cs.name(),
+ cs.type());
+ cs.setTarget(mh);
+ return mh(args)
+ }
+}