@@ -3,7 +3,7 @@ package scala.issues
3
3
import org .junit .runner .RunWith
4
4
import org .junit .runners .JUnit4
5
5
import org .junit .Test
6
- import scala .tools .asm .Opcodes
6
+ import scala .tools .asm .Opcodes . _
7
7
import scala .tools .nsc .backend .jvm .AsmUtils
8
8
import scala .tools .nsc .backend .jvm .CodeGenTools ._
9
9
import org .junit .Assert ._
@@ -77,4 +77,129 @@ class BytecodeTests {
77
77
// a @Retention annotation are currently emitted as RUNTIME.
78
78
check(" B.class" , " AnnotB" )
79
79
}
80
+
81
+ @ Test
82
+ def t6288bJumpPosition (): Unit = {
83
+ val code =
84
+ """ object Case3 { // 01
85
+ | def unapply(z: Any): Option[Int] = Some(-1) // 02
86
+ | def main(args: Array[String]) { // 03
87
+ | ("": Any) match { // 04
88
+ | case x : String => // 05
89
+ | println("case 0") // 06 println and jump at 6
90
+ | case _ => // 07
91
+ | println("default") // 08 println and jump at 8
92
+ | } // 09
93
+ | println("done") // 10
94
+ | }
95
+ |}
96
+ """ .stripMargin
97
+ val List (mirror, module) = compileClasses(compiler)(code)
98
+
99
+ val unapplyLineNumbers = getSingleMethod(module, " unapply" ).instructions.filter(_.isInstanceOf [LineNumber ])
100
+ assert(unapplyLineNumbers == List (LineNumber (2 , Label (0 ))), unapplyLineNumbers)
101
+
102
+ val expected = List (
103
+ LineNumber (4 , Label (0 )),
104
+ LineNumber (5 , Label (5 )),
105
+ Jump (IFEQ , Label (20 )),
106
+
107
+ LineNumber (6 , Label (11 )),
108
+ Invoke (INVOKEVIRTUAL , " scala/Predef$" , " println" , " (Ljava/lang/Object;)V" , false ),
109
+ Jump (GOTO , Label (33 )),
110
+
111
+ LineNumber (5 , Label (20 )),
112
+ Jump (GOTO , Label (24 )),
113
+
114
+ LineNumber (8 , Label (24 )),
115
+ Invoke (INVOKEVIRTUAL , " scala/Predef$" , " println" , " (Ljava/lang/Object;)V" , false ),
116
+ Jump (GOTO , Label (33 )),
117
+
118
+ LineNumber (10 , Label (33 )),
119
+ Invoke (INVOKEVIRTUAL , " scala/Predef$" , " println" , " (Ljava/lang/Object;)V" , false )
120
+ )
121
+
122
+ val mainIns = getSingleMethod(module, " main" ).instructions filter {
123
+ case _ : LineNumber | _ : Invoke | _ : Jump => true
124
+ case _ => false
125
+ }
126
+ assertSameCode(mainIns, expected)
127
+ }
128
+
129
+ @ Test
130
+ def bytecodeForBranches (): Unit = {
131
+ val code =
132
+ """ class C {
133
+ | def t1(b: Boolean) = if (b) 1 else 2
134
+ | def t2(x: Int) = if (x == 393) 1 else 2
135
+ | def t3(a: Array[String], b: AnyRef) = a != b && b == a
136
+ | def t4(a: AnyRef) = a == null || null != a
137
+ | def t5(a: AnyRef) = (a eq null) || (null ne a)
138
+ | def t6(a: Int, b: Boolean) = if ((a == 10) && b || a != 1) 1 else 2
139
+ | def t7(a: AnyRef, b: AnyRef) = a == b
140
+ | def t8(a: AnyRef) = Nil == a || "" != a
141
+ |}
142
+ """ .stripMargin
143
+
144
+ val List (c) = compileClasses(compiler)(code)
145
+
146
+ // t1: no unnecessary GOTOs
147
+ assertSameCode(getSingleMethod(c, " t1" ).instructions.dropNonOp, List (
148
+ VarOp (ILOAD , 1 ), Jump (IFEQ , Label (6 )),
149
+ Op (ICONST_1 ), Jump (GOTO , Label (9 )),
150
+ Label (6 ), Op (ICONST_2 ),
151
+ Label (9 ), Op (IRETURN )))
152
+
153
+ // t2: no unnecessary GOTOs
154
+ assertSameCode(getSingleMethod(c, " t2" ).instructions.dropNonOp, List (
155
+ VarOp (ILOAD , 1 ), IntOp (SIPUSH , 393 ), Jump (IF_ICMPNE , Label (7 )),
156
+ Op (ICONST_1 ), Jump (GOTO , Label (10 )),
157
+ Label (7 ), Op (ICONST_2 ),
158
+ Label (10 ), Op (IRETURN )))
159
+
160
+ // t3: Array == is translated to reference equality, AnyRef == to null checks and equals
161
+ assertSameCode(getSingleMethod(c, " t3" ).instructions.dropNonOp, List (
162
+ // Array ==
163
+ VarOp (ALOAD , 1 ), VarOp (ALOAD , 2 ), Jump (IF_ACMPEQ , Label (23 )),
164
+ // AnyRef ==
165
+ VarOp (ALOAD , 2 ), VarOp (ALOAD , 1 ), VarOp (ASTORE , 3 ), Op (DUP ), Jump (IFNONNULL , Label (14 )),
166
+ Op (POP ), VarOp (ALOAD , 3 ), Jump (IFNULL , Label (19 )), Jump (GOTO , Label (23 )),
167
+ Label (14 ), VarOp (ALOAD , 3 ), Invoke (INVOKEVIRTUAL , " java/lang/Object" , " equals" , " (Ljava/lang/Object;)Z" , false ), Jump (IFEQ , Label (23 )),
168
+ Label (19 ), Op (ICONST_1 ), Jump (GOTO , Label (26 )),
169
+ Label (23 ), Op (ICONST_0 ),
170
+ Label (26 ), Op (IRETURN )))
171
+
172
+ val t4t5 = List (
173
+ VarOp (ALOAD , 1 ), Jump (IFNULL , Label (6 )),
174
+ VarOp (ALOAD , 1 ), Jump (IFNULL , Label (10 )),
175
+ Label (6 ), Op (ICONST_1 ), Jump (GOTO , Label (13 )),
176
+ Label (10 ), Op (ICONST_0 ),
177
+ Label (13 ), Op (IRETURN ))
178
+
179
+ // t4: one side is known null, so just a null check on the other
180
+ assertSameCode(getSingleMethod(c, " t4" ).instructions.dropNonOp, t4t5)
181
+
182
+ // t5: one side known null, so just a null check on the other
183
+ assertSameCode(getSingleMethod(c, " t5" ).instructions.dropNonOp, t4t5)
184
+
185
+ // t6: no unnecessary GOTOs
186
+ assertSameCode(getSingleMethod(c, " t6" ).instructions.dropNonOp, List (
187
+ VarOp (ILOAD , 1 ), IntOp (BIPUSH , 10 ), Jump (IF_ICMPNE , Label (7 )),
188
+ VarOp (ILOAD , 2 ), Jump (IFNE , Label (12 )),
189
+ Label (7 ), VarOp (ILOAD , 1 ), Op (ICONST_1 ), Jump (IF_ICMPEQ , Label (16 )),
190
+ Label (12 ), Op (ICONST_1 ), Jump (GOTO , Label (19 )),
191
+ Label (16 ), Op (ICONST_2 ),
192
+ Label (19 ), Op (IRETURN )))
193
+
194
+ // t7: universal equality
195
+ assertInvoke(getSingleMethod(c, " t7" ), " scala/runtime/BoxesRunTime" , " equals" )
196
+
197
+ // t8: no null checks invoking equals on modules and constants
198
+ assertSameCode(getSingleMethod(c, " t8" ).instructions.dropNonOp, List (
199
+ Field (GETSTATIC , " scala/collection/immutable/Nil$" , " MODULE$" , " Lscala/collection/immutable/Nil$;" ), VarOp (ALOAD , 1 ), Invoke (INVOKEVIRTUAL , " java/lang/Object" , " equals" , " (Ljava/lang/Object;)Z" , false ), Jump (IFNE , Label (10 )),
200
+ Ldc (LDC , " " ), VarOp (ALOAD , 1 ), Invoke (INVOKEVIRTUAL , " java/lang/Object" , " equals" , " (Ljava/lang/Object;)Z" , false ), Jump (IFNE , Label (14 )),
201
+ Label (10 ), Op (ICONST_1 ), Jump (GOTO , Label (17 )),
202
+ Label (14 ), Op (ICONST_0 ),
203
+ Label (17 ), Op (IRETURN )))
204
+ }
80
205
}
0 commit comments