@@ -2,7 +2,8 @@ package scala.tools.nsc
22package backend .jvm
33package analysis
44
5- import scala .tools .asm .tree .{AbstractInsnNode , MethodNode }
5+ import scala .tools .asm .Label
6+ import scala .tools .asm .tree .{ClassNode , AbstractInsnNode , MethodNode }
67import scala .tools .asm .tree .analysis .{Frame , BasicInterpreter , Analyzer , Value }
78import scala .tools .nsc .backend .jvm .BTypes ._
89import scala .tools .nsc .backend .jvm .opt .BytecodeUtils ._
@@ -47,4 +48,58 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
4748 }
4849
4950 class ProdConsAnalyzer (val methodNode : MethodNode , classInternalName : InternalName ) extends AsmAnalyzer (methodNode, classInternalName, new Analyzer (new InitialProducerSourceInterpreter )) with ProdConsAnalyzerImpl
51+
52+ /**
53+ * Add:
54+ * private static java.util.Map $deserializeLambdaCache$ = null
55+ * private static Object $deserializeLambda$(SerializedLambda l) {
56+ * var cache = $deserializeLambdaCache$
57+ * if (cache eq null) {
58+ * cache = new java.util.HashMap()
59+ * $deserializeLambdaCache$ = cache
60+ * }
61+ * return scala.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l);
62+ * }
63+ */
64+ def addLambdaDeserialize (classNode : ClassNode ): Unit = {
65+ val cw = classNode
66+ import scala .tools .asm .Opcodes ._
67+
68+ // Need to force creation of BTypes for these as `getCommonSuperClass` is called on
69+ // automatically computing the max stack size (`visitMaxs`) during method writing.
70+ btypes.coreBTypes.javaUtilHashMapReference
71+ btypes.coreBTypes.javaUtilMapReference
72+
73+ cw.visitInnerClass(" java/lang/invoke/MethodHandles$Lookup" , " java/lang/invoke/MethodHandles" , " Lookup" , ACC_PUBLIC + ACC_FINAL + ACC_STATIC )
74+
75+ {
76+ val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC , " $deserializeLambdaCache$" , " Ljava/util/Map;" , null , null )
77+ fv.visitEnd()
78+ }
79+
80+ {
81+ val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC , " $deserializeLambda$" , " (Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;" , null , null )
82+ mv.visitCode()
83+ // javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol.
84+ mv.visitFieldInsn(GETSTATIC , classNode.name, " $deserializeLambdaCache$" , " Ljava/util/Map;" )
85+ mv.visitVarInsn(ASTORE , 1 )
86+ mv.visitVarInsn(ALOAD , 1 )
87+ val l0 = new Label ()
88+ mv.visitJumpInsn(IFNONNULL , l0)
89+ mv.visitTypeInsn(NEW , " java/util/HashMap" )
90+ mv.visitInsn(DUP )
91+ mv.visitMethodInsn(INVOKESPECIAL , " java/util/HashMap" , " <init>" , " ()V" , false )
92+ mv.visitVarInsn(ASTORE , 1 )
93+ mv.visitVarInsn(ALOAD , 1 )
94+ mv.visitFieldInsn(PUTSTATIC , classNode.name, " $deserializeLambdaCache$" , " Ljava/util/Map;" )
95+ mv.visitLabel(l0)
96+ mv.visitFieldInsn(GETSTATIC , " scala/runtime/LambdaDeserializer$" , " MODULE$" , " Lscala/runtime/LambdaDeserializer$;" )
97+ mv.visitMethodInsn(INVOKESTATIC , " java/lang/invoke/MethodHandles" , " lookup" , " ()Ljava/lang/invoke/MethodHandles$Lookup;" , false )
98+ mv.visitVarInsn(ALOAD , 1 )
99+ mv.visitVarInsn(ALOAD , 0 )
100+ mv.visitMethodInsn(INVOKEVIRTUAL , " scala/runtime/LambdaDeserializer$" , " deserializeLambda" , " (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;" , false )
101+ mv.visitInsn(ARETURN )
102+ mv.visitEnd()
103+ }
104+ }
50105}
0 commit comments