diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-10-29 16:49:22 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-01-29 16:16:16 +1000 |
commit | df0d105f90816960b711c35a3289ff460295d1cc (patch) | |
tree | a478b92f5ae83d308a97f7f7ccd60c5e38b339ac /src/reflect/scala/reflect | |
parent | 8a761a313bfe3d79afefed1622b69a850636d732 (diff) | |
download | scala-df0d105f90816960b711c35a3289ff460295d1cc.tar.gz scala-df0d105f90816960b711c35a3289ff460295d1cc.tar.bz2 scala-df0d105f90816960b711c35a3289ff460295d1cc.zip |
Use invokedynamic for structural calls, symbol literals, lamba ser.
The previous encodings created static fields in the enclosing class
to host caches. However, this isn't an option once emit code in default
methods of interfaces, as Java interfaces don't allow private static
fields.
We could continue to emit fields, and make them public when added to
traits.
Or, as chosen in this commit, we can emulate a call-site specific
static field by using invokedynamic: when the call site is linked,
our bootstrap methid can perform one-time computation, and we can
capture the result in the CallSite.
To implement this, I've allowed encoding of arbitrary invokedynamic
calls in ApplyDynamic.
The encoding is:
ApplyDynamic(
NoSymbol.newTermSymbol(TermName("methodName")).setInfo(invokedType)
Literal(Constant(bootstrapMethodSymbol)) :: (
Literal(Constant(staticArg0)) :: Literal(Constant(staticArgN)) :: Nil
) :::
(dynArg0 :: dynArgN :: Nil)
)
So far, static args may be `MethodType`, numeric or string literals, or
method symbols, all of which can be converted to constant pool entries.
`MethodTypes` are transformed to the erased JVM type and are converted
to descriptors as String constants.
I've taken advantage of this for symbol literal caching and
for the structural call site cache.
I've also included a test case that shows how a macro could target this
(albeit using private APIs) to cache compiled regexes.
I haven't managed to use this for LambdaMetafactory yet, not sure
if the facility is general enough.
Diffstat (limited to 'src/reflect/scala/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 10 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/JavaUniverseForce.scala | 3 |
3 files changed, 15 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index ba6c363918..6b015df6b4 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -459,6 +459,16 @@ trait Definitions extends api.StandardDefinitions { lazy val MethodCacheClass = requiredClass[scala.runtime.MethodCache] def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_) def methodCache_add = getMemberMethod(MethodCacheClass, nme.add_) + lazy val StructuralCallSite = getClassIfDefined("scala.runtime.StructuralCallSite") + def StructuralCallSite_bootstrap = getMemberMethod(StructuralCallSite.linkedClassOfClass, sn.Bootstrap) + // Marker for invokedynamic runtime.StructuralCall.bootstrap + lazy val StructuralCallSite_dummy = NoSymbol.newMethodSymbol(nme.apply).setInfo(NullaryMethodType(StructuralCallSite.tpe)) + def StructuralCallSite_find = getMemberIfDefined(StructuralCallSite, nme.find_) + def StructuralCallSite_add = getMemberIfDefined(StructuralCallSite, nme.add_) + def StructuralCallSite_getParameterTypes = getMemberIfDefined(StructuralCallSite, nme.parameterTypes) + lazy val SymbolLiteral = getClassIfDefined("scala.runtime.SymbolLiteral") + def SymbolLiteral_bootstrap = getMemberIfDefined(SymbolLiteral.linkedClassOfClass, sn.Bootstrap) + def SymbolLiteral_dummy = NoSymbol.newMethodSymbol(nme.apply).setInfo(NullaryMethodType(SymbolModule.companionClass.tpe)) // XML lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope") diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 80ed597fb7..48e912d291 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -696,6 +696,7 @@ trait StdNames { val freshTermName: NameType = "freshTermName" val freshTypeName: NameType = "freshTypeName" val get: NameType = "get" + val parameterTypes: NameType = "parameterTypes" val hashCode_ : NameType = "hashCode" val hash_ : NameType = "hash" val head : NameType = "head" @@ -1170,6 +1171,7 @@ trait StdNames { final val InvokeExact: TermName = newTermName("invokeExact") final val AltMetafactory: TermName = newTermName("altMetafactory") + final val Bootstrap: TermName = newTermName("bootstrap") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index d6b611a3f4..ba85630dbc 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -282,6 +282,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.MethodClass definitions.EmptyMethodCacheClass definitions.MethodCacheClass + definitions.StructuralCallSite + definitions.StructuralCallSite_dummy + definitions.SymbolLiteral definitions.ScalaXmlTopScope definitions.ScalaXmlPackage definitions.ReflectPackage |