diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-07-04 16:45:01 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-07-04 16:47:26 +0200 |
commit | e5886361006f1b315af13f6aa98cf54a2f7ebe0b (patch) | |
tree | 6e1b7056e4c6c6c827f4c2afb7559aeefeb98578 /src/compiler/scala/tools/nsc/backend/jvm | |
parent | 6612ba010b0e70c53550d1e47141c8dc89a55f23 (diff) | |
download | scala-e5886361006f1b315af13f6aa98cf54a2f7ebe0b.tar.gz scala-e5886361006f1b315af13f6aa98cf54a2f7ebe0b.tar.bz2 scala-e5886361006f1b315af13f6aa98cf54a2f7ebe0b.zip |
SI-9515 closure elimination also for non-Scala-Function SAM types
Also logged in as SD-162
The optimizer had conservative checks in place to perform closure
elimination only for Scala Function types. We can eliminate IndyLambda
instructions for any functional interface. LambdaMetaFactory only
constructs lambda objects for interface types, which don't have any
side-effects on construction - they don't have a constructor.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm')
4 files changed, 5 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala index 1feca56923..d65380aa1f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala @@ -217,26 +217,6 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) { nonOverloadedConstructors(tupleClassSymbols) } - // enumeration of specialized classes is temporary, while we still use the java-defined JFunctionN. - // once we switch to ordinary FunctionN, we can use specializedSubclasses just like for tuples. - private def specializedJFunctionSymbols(base: String): Seq[Symbol] = { - def primitives = Seq("B", "S", "I", "J", "C", "F", "D", "Z", "V") - def ijfd = Iterator("I", "J", "F", "D") - def ijfdzv = Iterator("I", "J", "F", "D", "Z", "V") - def ijd = Iterator("I", "J", "D") - val classNames = { - primitives.map(base + "0$mc" + _ + "$sp") // Function0 - } ++ { - // return type specializations appear first in the name string (alphabetical sorting) - for (r <- ijfdzv; a <- ijfd) yield base + "1$mc" + r + a + "$sp" // Function1 - } ++ { - for (r <- ijfdzv; a <- ijd; b <- ijd) yield base + "2$mc" + r + a + b + "$sp" // Function2 - } - classNames map getRequiredClass - } - - lazy val functionRefs: Set[InternalName] = (FunctionClass.seq ++ specializedJFunctionSymbols("scala.runtime.java8.JFunction")).map(classBTypeFromSymbol(_).internalName).toSet - lazy val typeOfArrayOp: Map[Int, BType] = { import scalaPrimitives._ Map( @@ -342,8 +322,6 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] { def srRefConstructors : Map[InternalName, MethodNameAndType] def tupleClassConstructors : Map[InternalName, MethodNameAndType] - def functionRefs: Set[InternalName] - def lambdaMetaFactoryBootstrapHandle : asm.Handle def lambdaDeserializeBootstrapHandle : asm.Handle } @@ -410,8 +388,6 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: def srRefConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefConstructors def tupleClassConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.tupleClassConstructors - def functionRefs: Set[InternalName] = _coreBTypes.functionRefs - def srSymbolLiteral : ClassBType = _coreBTypes.srSymbolLiteral def srStructuralCallSite : ClassBType = _coreBTypes.srStructuralCallSite def srLambdaDeserialize : ClassBType = _coreBTypes.srLambdaDeserialize diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala index 539435a326..83615abc31 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -131,7 +131,6 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { private val anonfunAdaptedName = """.*\$anonfun\$.*\$\d+\$adapted""".r def hasAdaptedImplMethod(closureInit: ClosureInstantiation): Boolean = { - isBuiltinFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) && anonfunAdaptedName.pattern.matcher(closureInit.lambdaMetaFactoryCall.implMethod.getName).matches } @@ -256,8 +255,6 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { } } - def isBuiltinFunctionType(internalName: InternalName): Boolean = functionRefs(internalName) - /** * Visit the class node and collect all referenced nested classes. */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala index d6942d9ff9..5248183337 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala @@ -430,7 +430,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) { def unapply(insn: AbstractInsnNode): Option[(InvokeDynamicInsnNode, Type, Handle, Type)] = insn match { case indy: InvokeDynamicInsnNode if indy.bsm == metafactoryHandle || indy.bsm == altMetafactoryHandle => indy.bsmArgs match { - case Array(samMethodType: Type, implMethod: Handle, instantiatedMethodType: Type, xs@_*) => // xs binding because IntelliJ gets confused about _@_* + case Array(samMethodType: Type, implMethod: Handle, instantiatedMethodType: Type, _@_*) => // LambdaMetaFactory performs a number of automatic adaptations when invoking the lambda // implementation method (casting, boxing, unboxing, and primitive widening, see Javadoc). // diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala index 4163d62df7..b05669ce89 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala @@ -295,18 +295,12 @@ class CopyProp[BT <: BTypes](val btypes: BT) { } /** - * Eliminate the closure value produced by `indy`. If the SAM type is known to construct - * without side-effects (e.g. scala/FunctionN), the `indy` and its inputs - * are eliminated, otherwise a POP is inserted. + * Eliminate LMF `indy` and its inputs. */ def handleClosureInst(indy: InvokeDynamicInsnNode): Unit = { - if (isBuiltinFunctionType(Type.getReturnType(indy.desc).getInternalName)) { - toRemove += indy - callGraph.removeClosureInstantiation(indy, method) - handleInputs(indy, Type.getArgumentTypes(indy.desc).length) - } else { - toInsertAfter(indy) = getPop(1) - } + toRemove += indy + callGraph.removeClosureInstantiation(indy, method) + handleInputs(indy, Type.getArgumentTypes(indy.desc).length) } def runQueue(): Unit = while (queue.nonEmpty) { |