Skip to content

Commit 2678d34

Browse files
committed
SI-9403 fix ICodeReader for negative BIPUSH / SIPUSH values
The byte value of a BIPUSH instruction and the (byte1 << 8) | byte2 value of a SIPUSH instruction are signed, see [1] and [2]. Similar for the increment value of IINC [3]. [1] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.bipush [2] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.sipush [3] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iinc
1 parent 0e9525a commit 2678d34

File tree

5 files changed

+41
-3
lines changed

5 files changed

+41
-3
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ abstract class ClassfileParser {
8484
protected final def u2(): Int = in.nextChar.toInt
8585
protected final def u4(): Int = in.nextInt
8686

87+
protected final def s1(): Int = in.nextByte.toInt // sign-extend the byte to int
88+
protected final def s2(): Int = (in.nextByte.toInt << 8) | u1 // sign-extend and shift the first byte, or with the unsigned second byte
89+
8790
private def readInnerClassFlags() = readClassFlags()
8891
private def readClassFlags() = JavaAccFlags classFlags u2
8992
private def readMethodFlags() = JavaAccFlags methodFlags u2

src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,8 @@ abstract class ICodeReader extends ClassfileParser {
326326
case JVM.dconst_0 => code emit CONSTANT(Constant(0.0))
327327
case JVM.dconst_1 => code emit CONSTANT(Constant(1.0))
328328

329-
case JVM.bipush => code.emit(CONSTANT(Constant(u1))); size += 1
330-
case JVM.sipush => code.emit(CONSTANT(Constant(u2))); size += 2
329+
case JVM.bipush => code.emit(CONSTANT(Constant(s1))); size += 1
330+
case JVM.sipush => code.emit(CONSTANT(Constant(s2))); size += 2
331331
case JVM.ldc => code.emit(CONSTANT(pool.getConstant(u1))); size += 1
332332
case JVM.ldc_w => code.emit(CONSTANT(pool.getConstant(u2))); size += 2
333333
case JVM.ldc2_w => code.emit(CONSTANT(pool.getConstant(u2))); size += 2
@@ -466,7 +466,7 @@ abstract class ICodeReader extends ClassfileParser {
466466
size += 2
467467
val local = code.getLocal(u1, INT)
468468
code.emit(LOAD_LOCAL(local))
469-
code.emit(CONSTANT(Constant(u1)))
469+
code.emit(CONSTANT(Constant(s1)))
470470
code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))
471471
code.emit(STORE_LOCAL(local))
472472

test/files/run/t9403.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Ybackend:GenASM -optimize

test/files/run/t9403/C_1.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package p
2+
class C {
3+
@inline final def f(x: Int): Long = 10L / (if (x < 0) -2 else 2)
4+
@inline final def g(x: Int): Long = 3000L / (if (x < 0) -300 else 300)
5+
}

test/files/run/t9403/Test_2.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import p.C
2+
import scala.tools.asm.Opcodes
3+
import scala.tools.partest.BytecodeTest
4+
import scala.tools.partest.ASMConverters._
5+
6+
7+
object Test extends BytecodeTest {
8+
def foo(c: C, x: Int) = c.f(x)
9+
def goo(c: C, x: Int) = c.g(x)
10+
11+
def has(i: Instruction, c: String, m: String) = {
12+
val cls = loadClassNode(c)
13+
val mth = convertMethod(getMethod(cls, m))
14+
assert(mth.instructions.contains(i))
15+
}
16+
17+
def show(): Unit = {
18+
assert(foo(new C, -2) == -5L)
19+
assert(goo(new C, -2) == -10L)
20+
21+
val bipush2 = IntOp(Opcodes.BIPUSH, -2)
22+
has(bipush2, "p.C", "f")
23+
has(bipush2, "Test$", "foo")
24+
25+
val sipush300 = IntOp(Opcodes.SIPUSH, -300)
26+
has(sipush300, "p.C", "g")
27+
has(sipush300, "Test$", "goo")
28+
}
29+
}

0 commit comments

Comments
 (0)