From f9dbade4dbc3a888f927983c164b83ef5d500af9 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 23 Sep 2015 13:53:35 +0200 Subject: Move addLambdaDeserialize into the BTypes assembly This allows accessing the method from the inliner, which doesn't have access to the Global instance. --- .../scala/tools/nsc/backend/jvm/BCodeHelpers.scala | 54 -------------------- .../tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../scala/tools/nsc/backend/jvm/CoreBTypes.scala | 14 +++--- .../nsc/backend/jvm/analysis/BackendUtils.scala | 57 +++++++++++++++++++++- 4 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 0f381a4325..bc3bdfc6ba 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -683,60 +683,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { new java.lang.Long(id) ).visitEnd() } - - /** - * Add: - * private static java.util.Map $deserializeLambdaCache$ = null - * private static Object $deserializeLambda$(SerializedLambda l) { - * var cache = $deserializeLambdaCache$ - * if (cache eq null) { - * cache = new java.util.HashMap() - * $deserializeLambdaCache$ = cache - * } - * return scala.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l); - * } - */ - def addLambdaDeserialize(clazz: Symbol, jclass: asm.ClassVisitor): Unit = { - val cw = jclass - import scala.tools.asm.Opcodes._ - - // Need to force creation of BTypes for these as `getCommonSuperClass` is called on - // automatically computing the max stack size (`visitMaxs`) during method writing. - javaUtilHashMapReference - javaUtilMapReference - - cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC + ACC_FINAL + ACC_STATIC) - - { - val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambdaCache$", "Ljava/util/Map;", null, null) - fv.visitEnd() - } - - { - val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", "(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", null, null) - mv.visitCode() - // javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol. - mv.visitFieldInsn(GETSTATIC, clazz.javaBinaryName.toString, "$deserializeLambdaCache$", "Ljava/util/Map;") - mv.visitVarInsn(ASTORE, 1) - mv.visitVarInsn(ALOAD, 1) - val l0 = new asm.Label() - mv.visitJumpInsn(IFNONNULL, l0) - mv.visitTypeInsn(NEW, "java/util/HashMap") - mv.visitInsn(DUP) - mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false) - mv.visitVarInsn(ASTORE, 1) - mv.visitVarInsn(ALOAD, 1) - mv.visitFieldInsn(PUTSTATIC, clazz.javaBinaryName.toString, "$deserializeLambdaCache$", "Ljava/util/Map;") - mv.visitLabel(l0) - mv.visitFieldInsn(GETSTATIC, "scala/runtime/LambdaDeserializer$", "MODULE$", "Lscala/runtime/LambdaDeserializer$;") - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false) - mv.visitVarInsn(ALOAD, 1) - mv.visitVarInsn(ALOAD, 0) - mv.visitMethodInsn(INVOKEVIRTUAL, "scala/runtime/LambdaDeserializer$", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false) - mv.visitInsn(ARETURN) - mv.visitEnd() - } - } } // end of trait BCClassGen /* functionality for building plain and mirror classes */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index 9875ade113..8d8ffe31d2 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -130,7 +130,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { && indyLambdaHosts.contains(claszSymbol)) if (shouldAddLambdaDeserialize) - addLambdaDeserialize(claszSymbol, cnode) + backendUtils.addLambdaDeserialize(cnode) addInnerClassesASM(cnode, innerClassBufferASM.toList) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala index 00ca096e59..48e43c74f4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala @@ -206,12 +206,14 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] { def boxedClasses: Set[ClassBType] - def RT_NOTHING : ClassBType - def RT_NULL : ClassBType - - def ObjectReference : ClassBType - def jlCloneableReference : ClassBType - def jioSerializableReference : ClassBType + def RT_NOTHING: ClassBType + def RT_NULL : ClassBType + + def ObjectReference : ClassBType + def jlCloneableReference : ClassBType + def jioSerializableReference: ClassBType + def javaUtilHashMapReference: ClassBType + def javaUtilMapReference : ClassBType } /** 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 f4badd8383..4e0d7a4c44 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -2,7 +2,8 @@ package scala.tools.nsc package backend.jvm package analysis -import scala.tools.asm.tree.{AbstractInsnNode, MethodNode} +import scala.tools.asm.Label +import scala.tools.asm.tree.{ClassNode, AbstractInsnNode, MethodNode} import scala.tools.asm.tree.analysis.{Frame, BasicInterpreter, Analyzer, Value} import scala.tools.nsc.backend.jvm.BTypes._ import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ @@ -47,4 +48,58 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { } class ProdConsAnalyzer(val methodNode: MethodNode, classInternalName: InternalName) extends AsmAnalyzer(methodNode, classInternalName, new Analyzer(new InitialProducerSourceInterpreter)) with ProdConsAnalyzerImpl + + /** + * Add: + * private static java.util.Map $deserializeLambdaCache$ = null + * private static Object $deserializeLambda$(SerializedLambda l) { + * var cache = $deserializeLambdaCache$ + * if (cache eq null) { + * cache = new java.util.HashMap() + * $deserializeLambdaCache$ = cache + * } + * return scala.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l); + * } + */ + def addLambdaDeserialize(classNode: ClassNode): Unit = { + val cw = classNode + import scala.tools.asm.Opcodes._ + + // Need to force creation of BTypes for these as `getCommonSuperClass` is called on + // automatically computing the max stack size (`visitMaxs`) during method writing. + btypes.coreBTypes.javaUtilHashMapReference + btypes.coreBTypes.javaUtilMapReference + + cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC + ACC_FINAL + ACC_STATIC) + + { + val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambdaCache$", "Ljava/util/Map;", null, null) + fv.visitEnd() + } + + { + val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", "(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", null, null) + mv.visitCode() + // javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol. + mv.visitFieldInsn(GETSTATIC, classNode.name, "$deserializeLambdaCache$", "Ljava/util/Map;") + mv.visitVarInsn(ASTORE, 1) + mv.visitVarInsn(ALOAD, 1) + val l0 = new Label() + mv.visitJumpInsn(IFNONNULL, l0) + mv.visitTypeInsn(NEW, "java/util/HashMap") + mv.visitInsn(DUP) + mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false) + mv.visitVarInsn(ASTORE, 1) + mv.visitVarInsn(ALOAD, 1) + mv.visitFieldInsn(PUTSTATIC, classNode.name, "$deserializeLambdaCache$", "Ljava/util/Map;") + mv.visitLabel(l0) + mv.visitFieldInsn(GETSTATIC, "scala/runtime/LambdaDeserializer$", "MODULE$", "Lscala/runtime/LambdaDeserializer$;") + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false) + mv.visitVarInsn(ALOAD, 1) + mv.visitVarInsn(ALOAD, 0) + mv.visitMethodInsn(INVOKEVIRTUAL, "scala/runtime/LambdaDeserializer$", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false) + mv.visitInsn(ARETURN) + mv.visitEnd() + } + } } -- cgit v1.2.3