summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala7
7 files changed, 41 insertions, 24 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index d5c4b5e201..6f9682f434 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -14,6 +14,7 @@ import scala.reflect.internal.Flags
import scala.tools.asm
import GenBCode._
import BackendReporting._
+import scala.collection.mutable
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.{MethodInsnNode, MethodNode}
import scala.tools.nsc.backend.jvm.BCodeHelpers.{InvokeStyle, TestOp}
@@ -1349,7 +1350,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val markers = if (addScalaSerializableMarker) classBTypeFromSymbol(definitions.SerializableClass).toASMType :: Nil else Nil
visitInvokeDynamicInsnLMF(bc.jmethod, sam.name.toString, invokedType, samMethodType, implMethodHandle, constrainedType, isSerializable, markers)
if (isSerializable)
- indyLambdaHosts += cnode.name
+ addIndyLambdaImplMethod(cnode.name, implMethodHandle :: Nil)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index 1bff8519ec..d4d532f4df 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -112,14 +112,6 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
gen(cd.impl)
- val shouldAddLambdaDeserialize = (
- settings.target.value == "jvm-1.8"
- && settings.Ydelambdafy.value == "method"
- && indyLambdaHosts.contains(cnode.name))
-
- if (shouldAddLambdaDeserialize)
- backendUtils.addLambdaDeserialize(cnode)
-
cnode.visitAttribute(thisBType.inlineInfoAttribute.get)
if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index 7b2686e7a9..0845e440d7 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -122,7 +122,16 @@ abstract class BTypes {
* inlining: when inlining an indyLambda instruction into a class, we need to make sure the class
* has the method.
*/
- val indyLambdaHosts: mutable.Set[InternalName] = recordPerRunCache(mutable.Set.empty)
+ val indyLambdaImplMethods: mutable.AnyRefMap[InternalName, mutable.LinkedHashSet[asm.Handle]] = recordPerRunCache(mutable.AnyRefMap())
+ def addIndyLambdaImplMethod(hostClass: InternalName, handle: Seq[asm.Handle]): Unit = {
+ indyLambdaImplMethods.getOrElseUpdate(hostClass, mutable.LinkedHashSet()) ++= handle
+ }
+ def getIndyLambdaImplMethods(hostClass: InternalName): List[asm.Handle] = {
+ indyLambdaImplMethods.getOrNull(hostClass) match {
+ case null => Nil
+ case xs => xs.toList.distinct
+ }
+ }
/**
* Obtain the BType for a type descriptor or internal name. For class descriptors, the ClassBType
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index c2010d2828..1dbb18722f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -283,7 +283,21 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
List(
coreBTypes.jliMethodHandlesLookupRef,
coreBTypes.StringRef,
- coreBTypes.jliMethodTypeRef
+ coreBTypes.jliMethodTypeRef,
+ ArrayBType(jliMethodHandleRef)
+ ),
+ coreBTypes.jliCallSiteRef
+ ).descriptor,
+ /* itf = */ coreBTypes.srLambdaDeserialize.isInterface.get)
+ lazy val lambdaDeserializeAddTargets =
+ new scala.tools.asm.Handle(scala.tools.asm.Opcodes.H_INVOKESTATIC,
+ coreBTypes.srLambdaDeserialize.internalName, "bootstrapAddTargets",
+ MethodBType(
+ List(
+ coreBTypes.jliMethodHandlesLookupRef,
+ coreBTypes.StringRef,
+ coreBTypes.jliMethodTypeRef,
+ ArrayBType(coreBTypes.jliMethodHandleRef)
),
coreBTypes.jliCallSiteRef
).descriptor,
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index 584b11d4ed..0a54767f76 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -266,6 +266,9 @@ abstract class GenBCode extends BCodeSyncAndTry {
try {
localOptimizations(item.plain)
setInnerClasses(item.plain)
+ val lambdaImplMethods = getIndyLambdaImplMethods(item.plain.name)
+ if (lambdaImplMethods.nonEmpty)
+ backendUtils.addLambdaDeserialize(item.plain, lambdaImplMethods)
setInnerClasses(item.mirror)
setInnerClasses(item.bean)
addToQ3(item)
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 83615abc31..d85d85003d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -76,7 +76,7 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
* host a static field in the enclosing class. This allows us to add this method to interfaces
* that define lambdas in default methods.
*/
- def addLambdaDeserialize(classNode: ClassNode): Unit = {
+ def addLambdaDeserialize(classNode: ClassNode, implMethods: List[Handle]): Unit = {
val cw = classNode
// Make sure to reference the ClassBTypes of all types that are used in the code generated
@@ -87,12 +87,13 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
val nilLookupDesc = MethodBType(Nil, jliMethodHandlesLookupRef).descriptor
val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectRef).descriptor
+ val addTargetMethodsObjDesc = MethodBType(ObjectRef :: Nil, UNIT).descriptor
{
val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null)
mv.visitCode()
mv.visitVarInsn(ALOAD, 0)
- mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle)
+ mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, implMethods: _*)
mv.visitInsn(ARETURN)
mv.visitEnd()
}
@@ -104,16 +105,16 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
* a boolean indicating if the instruction list contains an instantiation of a serializable SAM
* type.
*/
- def cloneInstructions(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], keepLineNumbers: Boolean): (InsnList, Map[AbstractInsnNode, AbstractInsnNode], Boolean) = {
+ def cloneInstructions(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], keepLineNumbers: Boolean): (InsnList, Map[AbstractInsnNode, AbstractInsnNode], List[Handle]) = {
val javaLabelMap = labelMap.asJava
val result = new InsnList
var map = Map.empty[AbstractInsnNode, AbstractInsnNode]
- var hasSerializableClosureInstantiation = false
+ var inlinedTargetHandles = mutable.ListBuffer[Handle]()
for (ins <- methodNode.instructions.iterator.asScala) {
- if (!hasSerializableClosureInstantiation) ins match {
+ ins match {
case callGraph.LambdaMetaFactoryCall(indy, _, _, _) => indy.bsmArgs match {
- case Array(_, _, _, flags: Integer, xs@_*) if (flags.intValue & LambdaMetafactory.FLAG_SERIALIZABLE) != 0 =>
- hasSerializableClosureInstantiation = true
+ case Array(_, targetHandle: Handle, _, flags: Integer, xs@_*) if (flags.intValue & LambdaMetafactory.FLAG_SERIALIZABLE) != 0 =>
+ inlinedTargetHandles += targetHandle
case _ =>
}
case _ =>
@@ -124,7 +125,7 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
map += ((ins, cloned))
}
}
- (result, map, hasSerializableClosureInstantiation)
+ (result, map, inlinedTargetHandles.toList)
}
def getBoxedUnit: FieldInsnNode = new FieldInsnNode(GETSTATIC, srBoxedUnitRef.internalName, "UNIT", srBoxedUnitRef.descriptor)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index 9c5a1a9f98..a7916f9c24 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -277,7 +277,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
}
case _ => false
}
- val (clonedInstructions, instructionMap, hasSerializableClosureInstantiation) = cloneInstructions(callee, labelsMap, keepLineNumbers = sameSourceFile)
+ val (clonedInstructions, instructionMap, targetHandles) = cloneInstructions(callee, labelsMap, keepLineNumbers = sameSourceFile)
// local vars in the callee are shifted by the number of locals at the callsite
val localVarShift = callsiteMethod.maxLocals
@@ -405,10 +405,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
callsiteMethod.maxStack = math.max(callsiteMethod.maxStack, math.max(stackHeightAtNullCheck, maxStackOfInlinedCode))
- if (hasSerializableClosureInstantiation && !indyLambdaHosts(callsiteClass.internalName)) {
- indyLambdaHosts += callsiteClass.internalName
- addLambdaDeserialize(byteCodeRepository.classNode(callsiteClass.internalName).get)
- }
+ addIndyLambdaImplMethod(callsiteClass.internalName, targetHandles)
callGraph.addIfMissing(callee, calleeDeclarationClass)