Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken bytecode with "-optimize", "-target:jvm-1.7" #8645

Closed
scabug opened this issue Jun 4, 2014 · 10 comments
Closed

Broken bytecode with "-optimize", "-target:jvm-1.7" #8645

scabug opened this issue Jun 4, 2014 · 10 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Jun 4, 2014

Compile this code with both keys "-optimise" and "-target:jvm-1.7":

case class RichString[T](string: String, rich: List[(Int, T)]) {
  def apply(index: Int): (Char, T) =
    (string(index), rich.takeWhile(_._1 <= index).last._2)
}
object Main {
  def main(args: Array[String]): Unit =
    println(RichString("qwe", List((1, 1))));
}

Then run it and you get this error message:

java.lang.VerifyError: Uninitialized object exists on backward branch 54
Exception Details:
  Location:
    RichString.apply(I)Lscala/Tuple2; @136: goto
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: bb00 2859 b200 2db2 0032 2ab6 0034 4e4d
    0000010: 2d1b b600 38b8 003e 2ab6 0040 bb00 4259
    0000020: 2a1b b700 463a 073a 04bb 0048 59b7 004b
    0000030: 3a09 1904 3a0a 190a b900 5101 009a 0020
    0000040: 190a b900 5701 00c0 0028 b600 5b19 07b4
    0000050: 005f a300 0704 a700 0403 9a00 1519 09b6
    0000060: 0062 b600 67c0 0028 b600 6ab7 006d b019
    0000070: 0919 0ab9 0057 0100 b600 7157 190a b900
    0000080: 7601 00c0 0064 3a0a a7ff ae            
  Stackmap Table:
    full_frame(@54,{Object[#2],Integer,Object[#47],Object[#121],Object[#100],Top,Top,Object[#66],Top,Object[#72],Object[#100]},{Uninitialized[#0],Uninitialized[#0],Object[#123]})
    full_frame(@89,{Object[#2],Integer,Object[#47],Object[#121],Object[#100],Top,Top,Object[#66],Top,Object[#72],Object[#100]},{Uninitialized[#0],Uninitialized[#0],Object[#123]})
    full_frame(@90,{Object[#2],Integer,Object[#47],Object[#121],Object[#100],Top,Top,Object[#66],Top,Object[#72],Object[#100]},{Uninitialized[#0],Uninitialized[#0],Object[#123],Integer})
    full_frame(@93,{Object[#2],Integer,Object[#47],Object[#121],Object[#100],Top,Top,Object[#66],Top,Object[#72],Object[#100]},{Uninitialized[#0],Uninitialized[#0],Object[#123]})
    full_frame(@111,{Object[#2],Integer,Object[#47],Object[#121],Object[#100],Top,Top,Object[#66],Top,Object[#72],Object[#100]},{Uninitialized[#0],Uninitialized[#0],Object[#123]})

        at Main$.main(Main.scala:8)
        at Main.main(Main.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:68)
        at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:99)
        at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:68)
        at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:99)
        at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
        at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
        at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
        at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:72)
        at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:94)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

Scala version is 2.11.1.
java -version is:
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (ArchLinux build 7.u55_2.4.7-1-x86_64)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)

@scabug
Copy link
Author

scabug commented Jun 4, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8645?orig=1
Reporter: Kurnevsky Evgeny (kurnevsky)
Affected Versions: 2.11.1
See #6720

@scabug
Copy link
Author

scabug commented Jun 5, 2014

@lrytz said (edited on Oct 16, 2014 6:44:53 AM UTC):
minimized (this one needs to be compiled without -optimise otherwise the bug is optimized away, but with -target:jvm-1.7)

class C {
  def apply(x: Boolean) = new Tuple2(null, {
    while (x) { }
    null
  })
}

object Main {
  def main(args: Array[String]): Unit = println(new C())
}

gives

  public scala.Tuple2<scala.runtime.Null$, scala.runtime.Null$> apply(boolean);
    Signature: (Z)Lscala/Tuple2;
    Code:
       0: new           #12                 // class scala/Tuple2
       3: dup           
       4: aconst_null   
       5: iload_1       
       6: ifne          5
       9: aconst_null   
      10: invokespecial #16                 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      13: areturn       

the ifne is not allowed, because it jumps to a previous location, and the stack at this location contains an uninitialized object (the Tuple2 reference has been created with new, but its constructor has not yet been invoked). See last paragraph in http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.2.4.

@scabug
Copy link
Author

scabug commented Jun 5, 2014

@scabug
Copy link
Author

scabug commented Jun 5, 2014

@lrytz said:
Miguel has a fix here, but it uses quite a bit of infrastructure: https://github.com/magarciaEPFL/scala/blob/24db961fb7f1ce982a1d4a750433fe5a2c84b142/src/compiler/scala/tools/nsc/backend/jvm/BCodeOptIntra.scala#L427

Main idea: transform (when there are back jumps)

new
dup
<load arg 1>
...
<load arg n>
invokespecial <init>

to

<load arg 1>
...
<load arg n>
store local x1
...
store local xn
new
dup
load local x1
...
load local xn
invokespecial <init>

@scabug
Copy link
Author

scabug commented Oct 14, 2014

@gourlaysama said:
BTW, the underlying VerifyError bug in the JDK has been fixed in JDK-8046233 (in jdk9, backported to the just-released 8u25).

@scabug
Copy link
Author

scabug commented Oct 16, 2014

@scabug scabug closed this as completed Oct 16, 2014
@scabug
Copy link
Author

scabug commented Oct 16, 2014

@retronym said:
Interesting, I didn't know that OpenJDK switched to JIRA.

https://wiki.openjdk.java.net/display/general/JBS+Overview

Issues mentioning "Scala" (which includes some big feature tickets like a REPL and specialization)

https://bugs.openjdk.java.net/issues/?jql=text%20~%20scala%20ORDER%20BY%20updated%20DESC

@scabug
Copy link
Author

scabug commented Oct 16, 2014

@paulp said:
Did all their $s become $$s when they imported the existing tickets?

@scabug
Copy link
Author

scabug commented Oct 16, 2014

@som-snytt said:
I use the repl all the time to try out Java API (as I find myself in Java purgatory). I hope you folks appreciate how huge the repl is to us who grew up replless. I guess my Java colleague still creates test classes in his preferred IDE just to evaluate an expr. I have recently thought it would be fun if the repl (our repl) had a java mode, in particular since one often wonders what a class API looks like to javac.

@scabug scabug added this to the 2.11.3 milestone Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants