不同的字节码生成问题
Different byte code generated issue
我正在尝试对布尔值进行模式匹配。我写了同样的方法,稍作修改,但它们的字节码生成有很大差异。
例如
scala> def compare(flag: Boolean) = {
| flag match{
| case true => println("true..")
| case false => println("false...")
| }}
compare: (flag: Boolean)Unit
scala> :javap -c compare
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
public static $line4.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line4/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compare(boolean);
Code:
0: iload_1
1: istore_3
2: iconst_1
3: iload_3
4: if_icmpne 22
7: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
10: ldc #27 // String true..
12: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
15: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
18: astore_2
19: goto 60
22: goto 25
25: iconst_0
26: iload_3
27: if_icmpne 45
30: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
33: ldc #39 // String false...
35: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
38: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
41: astore_2
42: goto 60
45: goto 48
48: new #41 // class scala/MatchError
51: dup
52: iload_3
53: invokestatic #47 // Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
56: invokespecial #49 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
59: athrow
60: return
public $line4.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #52 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #54 // Field MODULE$:L$line4/$read$$iw$$iw$;
8: return
}
当我使用 if 表达式做同样的事情时,有不同的字节码。
scala> def compareAgain(flag: Boolean) = {
| if(flag) println("true..")
| else println("false...")
| }
compareAgain: (flag: Boolean)Unit
scala> :javap -c compareAgain
Compiled from "<console>"
public class $line5.$read$$iw$$iw$ {
public static $line5.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line5/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compareAgain(boolean);
Code:
0: iload_1
1: ifeq 15
4: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: ldc #27 // String true..
9: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
12: goto 23
15: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
18: ldc #33 // String false...
20: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
23: return
public $line5.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #36 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #38 // Field MODULE$:L$line5/$read$$iw$$iw$;
8: return
}
有不同的字节码。
这在第一个字节码中意味着什么?
// Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
提前致谢。
匹配表达式就是表达式。他们评估一个值。在这种情况下,您没有使用该值,但编译器无论如何都包含了代码。由于 println 没有 return 任何有用的东西,它的计算结果为所谓的 unit type,大致相当于 Void.
匹配表达式的情况也不同于 if else 的情况,因为如果参数既不是 true 也不是 false,则会抛出一个新的 MatchError。当然,除非您使用自定义字节码创建一个具有意外值的布尔值,否则这种情况是无法实现的,但编译器并没有尝试对其进行优化。
这是针对旧模式匹配器和旧后端回答的 this question 的副本。请注意当时的生活是多么简单。
对于新的和改进的,您可以通过优化器选项获得您想要的代码。我不知道他们为什么让你跳过篮球。
$ scala -opt:copy-propagation
Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
scala> def f(b: Boolean) = b match { case true => println() ; case _ => println() }
f: (b: Boolean)Unit
scala> :javap -c f
Compiled from "<console>"
public class $line3.$read$$iw$$iw$ {
public static $line3.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line3/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void f(boolean);
Code:
0: iconst_1
1: iload_1
2: if_icmpne 14
5: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
8: invokevirtual #28 // Method scala/Predef$.println:()V
11: goto 26
14: goto 17
17: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
20: invokevirtual #28 // Method scala/Predef$.println:()V
23: goto 26
26: return
public $line3.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #31 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #33 // Field MODULE$:L$line3/$read$$iw$$iw$;
8: return
}
我正在尝试对布尔值进行模式匹配。我写了同样的方法,稍作修改,但它们的字节码生成有很大差异。
例如
scala> def compare(flag: Boolean) = {
| flag match{
| case true => println("true..")
| case false => println("false...")
| }}
compare: (flag: Boolean)Unit
scala> :javap -c compare
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
public static $line4.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line4/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compare(boolean);
Code:
0: iload_1
1: istore_3
2: iconst_1
3: iload_3
4: if_icmpne 22
7: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
10: ldc #27 // String true..
12: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
15: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
18: astore_2
19: goto 60
22: goto 25
25: iconst_0
26: iload_3
27: if_icmpne 45
30: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
33: ldc #39 // String false...
35: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
38: getstatic #37 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
41: astore_2
42: goto 60
45: goto 48
48: new #41 // class scala/MatchError
51: dup
52: iload_3
53: invokestatic #47 // Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
56: invokespecial #49 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
59: athrow
60: return
public $line4.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #52 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #54 // Field MODULE$:L$line4/$read$$iw$$iw$;
8: return
}
当我使用 if 表达式做同样的事情时,有不同的字节码。
scala> def compareAgain(flag: Boolean) = {
| if(flag) println("true..")
| else println("false...")
| }
compareAgain: (flag: Boolean)Unit
scala> :javap -c compareAgain
Compiled from "<console>"
public class $line5.$read$$iw$$iw$ {
public static $line5.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line5/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void compareAgain(boolean);
Code:
0: iload_1
1: ifeq 15
4: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: ldc #27 // String true..
9: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
12: goto 23
15: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
18: ldc #33 // String false...
20: invokevirtual #31 // Method scala/Predef$.println:(Ljava/lang/Object;)V
23: return
public $line5.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #36 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #38 // Field MODULE$:L$line5/$read$$iw$$iw$;
8: return
}
有不同的字节码。 这在第一个字节码中意味着什么?
// Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
提前致谢。
匹配表达式就是表达式。他们评估一个值。在这种情况下,您没有使用该值,但编译器无论如何都包含了代码。由于 println 没有 return 任何有用的东西,它的计算结果为所谓的 unit type,大致相当于 Void.
匹配表达式的情况也不同于 if else 的情况,因为如果参数既不是 true 也不是 false,则会抛出一个新的 MatchError。当然,除非您使用自定义字节码创建一个具有意外值的布尔值,否则这种情况是无法实现的,但编译器并没有尝试对其进行优化。
这是针对旧模式匹配器和旧后端回答的 this question 的副本。请注意当时的生活是多么简单。
对于新的和改进的,您可以通过优化器选项获得您想要的代码。我不知道他们为什么让你跳过篮球。
$ scala -opt:copy-propagation
Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
scala> def f(b: Boolean) = b match { case true => println() ; case _ => println() }
f: (b: Boolean)Unit
scala> :javap -c f
Compiled from "<console>"
public class $line3.$read$$iw$$iw$ {
public static $line3.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line3/$read$$iw$$iw$
3: invokespecial #17 // Method "<init>":()V
6: return
public void f(boolean);
Code:
0: iconst_1
1: iload_1
2: if_icmpne 14
5: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
8: invokevirtual #28 // Method scala/Predef$.println:()V
11: goto 26
14: goto 17
17: getstatic #25 // Field scala/Predef$.MODULE$:Lscala/Predef$;
20: invokevirtual #28 // Method scala/Predef$.println:()V
23: goto 26
26: return
public $line3.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #31 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #33 // Field MODULE$:L$line3/$read$$iw$$iw$;
8: return
}