Open Atry opened 6 years ago
As @sjrd pointed out, if the parameter is an explicit function, then no reflective call generated. This behavior is more efficient than the behavior of by-name parameter.
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_152).
Type in expressions for evaluation. Or try :help.
scala> class Test {
| def byName(b: () => Int): Int = b()
| def testByNameFunction = {
| val namedFunction: ((() => Int) => Int) { def apply(i: () => Int): Int } = byName _
| namedFunction(i = () => 1)
| }
| }
defined class Test
scala> :javap Test
Size 2542 bytes
MD5 checksum a29ad0d28926030d11a2d43b2eece24b
Compiled from "<console>"
public class $line3.$read$$iw$$iw$Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 $line3/$read$$iw$$iw$Test
#2 = Class #1 // $line3/$read$$iw$$iw$Test
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <console>
#6 = Utf8 $line3/$read$$iw$
#7 = Class #6 // $line3/$read$$iw$
#8 = Utf8 $line3/$read
#9 = Class #8 // $line3/$read
#10 = Utf8 $iw$
#11 = Utf8 $line3/$read$$iw$$iw$
#12 = Class #11 // $line3/$read$$iw$$iw$
#13 = Utf8 Test
#14 = Utf8 java/lang/invoke/MethodHandles$Lookup
#15 = Class #14 // java/lang/invoke/MethodHandles$Lookup
#16 = Utf8 java/lang/invoke/MethodHandles
#17 = Class #16 // java/lang/invoke/MethodHandles
#18 = Utf8 Lookup
#19 = Utf8 byName
#20 = Utf8 (Lscala/Function0;)I
#21 = Utf8 b
#22 = Utf8 scala/Function0
#23 = Class #22 // scala/Function0
#24 = Utf8 apply$mcI$sp
#25 = Utf8 ()I
#26 = NameAndType #24:#25 // apply$mcI$sp:()I
#27 = InterfaceMethodref #23.#26 // scala/Function0.apply$mcI$sp:()I
#28 = Utf8 this
#29 = Utf8 L$line3/$read$$iw$$iw$Test;
#30 = Utf8 Lscala/Function0;
#31 = Utf8 testByNameFunction
#32 = Utf8 java/lang/invoke/LambdaMetafactory
#33 = Class #32 // java/lang/invoke/LambdaMetafactory
#34 = Utf8 altMetafactory
#35 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#36 = NameAndType #34:#35 // altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#37 = Methodref #33.#36 // java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#38 = MethodHandle #6:#37 // invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#39 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
#40 = MethodType #39 // (Ljava/lang/Object;)Ljava/lang/Object;
#41 = Utf8 $anonfun$testByNameFunction$1$adapted
#42 = Utf8 (L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#43 = NameAndType #41:#42 // $anonfun$testByNameFunction$1$adapted:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#44 = Methodref #2.#43 // $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$1$adapted:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#45 = MethodHandle #6:#44 // invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$1$adapted:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#46 = Utf8 (Lscala/Function0;)Ljava/lang/Object;
#47 = MethodType #46 // (Lscala/Function0;)Ljava/lang/Object;
#48 = Integer 7
#49 = Integer 1
#50 = Utf8 scala/Serializable
#51 = Class #50 // scala/Serializable
#52 = Utf8 apply
#53 = Utf8 (L$line3/$read$$iw$$iw$Test;)Lscala/Function1;
#54 = NameAndType #52:#53 // apply:(L$line3/$read$$iw$$iw$Test;)Lscala/Function1;
#55 = InvokeDynamic #0:#54 // #0:apply:(L$line3/$read$$iw$$iw$Test;)Lscala/Function1;
#56 = MethodType #25 // ()I
#57 = Utf8 $anonfun$testByNameFunction$2
#58 = NameAndType #57:#25 // $anonfun$testByNameFunction$2:()I
#59 = Methodref #2.#58 // $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$2:()I
#60 = MethodHandle #6:#59 // invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$2:()I
#61 = Integer 3
#62 = Utf8 ()Lscala/runtime/java8/JFunction0$mcI$sp;
#63 = NameAndType #24:#62 // apply$mcI$sp:()Lscala/runtime/java8/JFunction0$mcI$sp;
#64 = InvokeDynamic #1:#63 // #1:apply$mcI$sp:()Lscala/runtime/java8/JFunction0$mcI$sp;
#65 = Utf8 scala/Function1
#66 = Class #65 // scala/Function1
#67 = NameAndType #52:#39 // apply:(Ljava/lang/Object;)Ljava/lang/Object;
#68 = InterfaceMethodref #66.#67 // scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
#69 = Utf8 scala/runtime/BoxesRunTime
#70 = Class #69 // scala/runtime/BoxesRunTime
#71 = Utf8 unboxToInt
#72 = Utf8 (Ljava/lang/Object;)I
#73 = NameAndType #71:#72 // unboxToInt:(Ljava/lang/Object;)I
#74 = Methodref #70.#73 // scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
#75 = Utf8 namedFunction
#76 = Utf8 Lscala/Function1;
#77 = Utf8 $anonfun$testByNameFunction$1
#78 = Utf8 (L$line3/$read$$iw$$iw$Test;Lscala/Function0;)I
#79 = Utf8 $this
#80 = NameAndType #19:#20 // byName:(Lscala/Function0;)I
#81 = Methodref #2.#80 // $line3/$read$$iw$$iw$Test.byName:(Lscala/Function0;)I
#82 = Utf8 <init>
#83 = Utf8 ()V
#84 = NameAndType #82:#83 // "<init>":()V
#85 = Methodref #4.#84 // java/lang/Object."<init>":()V
#86 = NameAndType #77:#78 // $anonfun$testByNameFunction$1:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)I
#87 = Methodref #2.#86 // $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$1:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)I
#88 = Utf8 boxToInteger
#89 = Utf8 (I)Ljava/lang/Integer;
#90 = NameAndType #88:#89 // boxToInteger:(I)Ljava/lang/Integer;
#91 = Methodref #70.#90 // scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
#92 = Utf8 $deserializeLambda$
#93 = Utf8 (Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
#94 = Utf8 scala/runtime/LambdaDeserialize
#95 = Class #94 // scala/runtime/LambdaDeserialize
#96 = Utf8 bootstrap
#97 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
#98 = NameAndType #96:#97 // bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
#99 = Methodref #95.#98 // scala/runtime/LambdaDeserialize.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
#100 = MethodHandle #6:#99 // invokestatic scala/runtime/LambdaDeserialize.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
#101 = Utf8 lambdaDeserialize
#102 = NameAndType #101:#93 // lambdaDeserialize:(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
#103 = InvokeDynamic #2:#102 // #2:lambdaDeserialize:(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
#104 = Utf8 Code
#105 = Utf8 LocalVariableTable
#106 = Utf8 LineNumberTable
#107 = Utf8 Signature
#108 = Utf8 (Lscala/Function0<Ljava/lang/Object;>;)I
#109 = Utf8 MethodParameters
#110 = Utf8 BootstrapMethods
#111 = Utf8 SourceFile
#112 = Utf8 InnerClasses
#113 = Utf8 ScalaInlineInfo
#114 = Utf8 Scala
{
public int byName(scala.Function0<java.lang.Object>);
descriptor: (Lscala/Function0;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_1
1: invokeinterface #27, 1 // InterfaceMethod scala/Function0.apply$mcI$sp:()I
6: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this L$line3/$read$$iw$$iw$Test;
0 7 1 b Lscala/Function0;
LineNumberTable:
line 12: 0
Signature: #108 // (Lscala/Function0<Ljava/lang/Object;>;)I
MethodParameters:
Name Flags
b final
public int testByNameFunction();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: invokedynamic #55, 0 // InvokeDynamic #0:apply:(L$line3/$read$$iw$$iw$Test;)Lscala/Function1;
6: astore_1
7: aload_1
8: invokedynamic #64, 0 // InvokeDynamic #1:apply$mcI$sp:()Lscala/runtime/java8/JFunction0$mcI$sp;
13: invokeinterface #68, 2 // InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
18: invokestatic #74 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
21: ireturn
LocalVariableTable:
Start Length Slot Name Signature
6 15 1 namedFunction Lscala/Function1;
0 22 0 this L$line3/$read$$iw$$iw$Test;
LineNumberTable:
line 14: 0
line 15: 7
public static final int $anonfun$testByNameFunction$1($line3.$read$$iw$$iw$Test, scala.Function0);
descriptor: (L$line3/$read$$iw$$iw$Test;Lscala/Function0;)I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokevirtual #81 // Method byName:(Lscala/Function0;)I
5: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 $this L$line3/$read$$iw$$iw$Test;
0 6 1 b Lscala/Function0;
LineNumberTable:
line 14: 0
MethodParameters:
Name Flags
$this final synthetic
b final
public static final int $anonfun$testByNameFunction$2();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: iconst_1
1: ireturn
LineNumberTable:
line 15: 0
public $line3.$read$$iw$$iw$Test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #85 // Method java/lang/Object."<init>":()V
4: return
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this L$line3/$read$$iw$$iw$Test;
LineNumberTable:
line 19: 0
line 11: 4
public static final java.lang.Object $anonfun$testByNameFunction$1$adapted($line3.$read$$iw$$iw$Test, scala.Function0);
descriptor: (L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokestatic #87 // Method $anonfun$testByNameFunction$1:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)I
5: invokestatic #91 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
8: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 $this L$line3/$read$$iw$$iw$Test;
0 9 1 b Lscala/Function0;
LineNumberTable:
line 14: 0
MethodParameters:
Name Flags
$this final
b final
}
BootstrapMethods:
0: #38 invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#40 (Ljava/lang/Object;)Ljava/lang/Object;
#45 invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$1$adapted:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#47 (Lscala/Function0;)Ljava/lang/Object;
#48 7
#49 1
#51 scala/Serializable
#49 1
#47 (Lscala/Function0;)Ljava/lang/Object;
1: #38 invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#56 ()I
#60 invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$2:()I
#56 ()I
#61 3
#49 1
#51 scala/Serializable
2: #100 invokestatic scala/runtime/LambdaDeserialize.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
Method arguments:
#45 invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$1$adapted:(L$line3/$read$$iw$$iw$Test;Lscala/Function0;)Ljava/lang/Object;
#60 invokestatic $line3/$read$$iw$$iw$Test.$anonfun$testByNameFunction$2:()I
SourceFile: "<console>"
InnerClasses:
public static #10= #7 of #9; //$iw$=class $line3/$read$$iw$ of class $line3/$read
public static #10= #12 of #7; //$iw$=class $line3/$read$$iw$$iw$ of class $line3/$read$$iw$
public static #13= #2 of #12; //Test=class $line3/$read$$iw$$iw$Test of class $line3/$read$$iw$$iw$
public static final #18= #15 of #17; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
Error: unknown attribute
ScalaInlineInfo: length = 0x22
01 00 00 06 00 29 00 2A 01 00 4D 00 4E 01 00 39
00 19 01 00 52 00 53 00 00 13 00 14 00 00 1F 00
19 00
Error: unknown attribute
Scala: length = 0x0
The accidental reflective call is the root cause of #10334 and https://github.com/scala-js/scala-js/issues/3232.
According to @gzm0's example, if namedFunction
is an AnyRef
, then the reflective call warning is shown, as expected:
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_152).
Type in expressions for evaluation. Or try :help.
scala> class Test {
| def byName(b: => Int): Int = b
| def testByNameFunction = {
| val namedFunction: AnyRef { def apply(i: => Int): Int } = byName _
| namedFunction(i = 1)
| }
| }
<console>:15: warning: reflective access of structural type member method apply should be enabled
by making the implicit value scala.language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scaladoc for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.
namedFunction(i = 1)
^
defined class Test
Note that
namedFunction(i = 1)
is a reflective call, i.e. there is aninvokevirtual
to thejava/lang/reflect/Method.invoke
, while no reflective call warning is shown.@sjrd said in https://github.com/scala-js/scala-js/issues/3232: