@@ -12,7 +12,7 @@ package jvm
12
12
import scala .annotation .switch
13
13
14
14
import scala .tools .asm
15
- import scala .tools .asm .Label
15
+ import scala .tools .asm .{ Handle , Label , Opcodes }
16
16
import scala .tools .nsc .backend .jvm .BCodeHelpers .InvokeStyle
17
17
18
18
/*
@@ -27,6 +27,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
27
27
import int ._
28
28
import bTypes ._
29
29
import coreBTypes ._
30
+ import BCodeBodyBuilder ._
30
31
31
32
/*
32
33
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
@@ -1448,8 +1449,13 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1448
1449
def genLoadTry (tree : Try ): BType
1449
1450
1450
1451
def genInvokeDynamicLambda (ctor : Symbol , lambdaTarget : Symbol , environmentSize : Int , functionalInterface : Symbol ): BType = {
1452
+ import java .lang .invoke .LambdaMetafactory .FLAG_SERIALIZABLE
1453
+
1451
1454
debuglog(s " Using invokedynamic rather than `new ${ctor.owner}` " )
1452
1455
val generatedType = classBTypeFromSymbol(functionalInterface)
1456
+ // Lambdas should be serializable if they implement a SAM that extends Serializable or if they
1457
+ // implement a scala.Function* class.
1458
+ val isSerializable = functionalInterface.isSerializable || functionalInterface.isFunctionClass
1453
1459
val isInterface = lambdaTarget.owner.isEmittedInterface
1454
1460
val invokeStyle =
1455
1461
if (lambdaTarget.isStaticMember) asm.Opcodes .H_INVOKESTATIC
@@ -1481,18 +1487,45 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1481
1487
val mt = asmMethodType(abstractMethod)
1482
1488
mt.toASMType
1483
1489
}
1484
- bc.jmethod.visitInvokeDynamicInsn(methodName, desc, lambdaMetaFactoryBootstrapHandle,
1485
- // boostrap args
1486
- applyN, targetHandle, constrainedType
1487
- )
1490
+ val bsmArgs0 = Seq (applyN, targetHandle, constrainedType)
1491
+ val bsmArgs =
1492
+ if (isSerializable)
1493
+ bsmArgs0 +: Int .box(FLAG_SERIALIZABLE )
1494
+ else
1495
+ bsmArgs0
1496
+
1497
+ val metafactory =
1498
+ if (isSerializable)
1499
+ lambdaMetaFactoryAltMetafactoryHandle // altMetafactory needed to be able to pass the SERIALIZABLE flag
1500
+ else
1501
+ lambdaMetaFactoryMetafactoryHandle
1502
+
1503
+ bc.jmethod.visitInvokeDynamicInsn(methodName, desc, metafactory, bootstrapArgs : _* )
1488
1504
1489
1505
generatedType
1490
1506
}
1491
1507
}
1492
- val lambdaMetaFactoryBootstrapHandle =
1493
- new asm.Handle (asm.Opcodes .H_INVOKESTATIC ,
1494
- int.LambdaMetaFactory .javaBinaryName, int.MetafactoryName ,
1495
- " (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" ,
1496
- /* itf = */ int.LambdaMetaFactory .isEmittedInterface)
1508
+ }
1497
1509
1510
+ object BCodeBodyBuilder {
1511
+ val lambdaMetaFactoryMetafactoryHandle = new Handle (
1512
+ Opcodes .H_INVOKESTATIC ,
1513
+ " java/lang/invoke/LambdaMetafactory" ,
1514
+ " metafactory" ,
1515
+ " (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" ,
1516
+ /* itf = */ false )
1517
+
1518
+ val lambdaMetaFactoryAltMetafactoryHandle = new Handle (
1519
+ Opcodes .H_INVOKESTATIC ,
1520
+ " java/lang/invoke/LambdaMetafactory" ,
1521
+ " altMetafactory" ,
1522
+ " (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" ,
1523
+ /* itf = */ false )
1524
+
1525
+ val lambdaDeserializeBootstrapHandle = new Handle (
1526
+ Opcodes .H_INVOKESTATIC ,
1527
+ " scala/runtime/LambdaDeserialize" ,
1528
+ " bootstrap" ,
1529
+ " (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;" ,
1530
+ /* itf = */ false )
1498
1531
}
0 commit comments