summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-12-11 18:59:27 +0100
committerJason Zaugg <jzaugg@gmail.com>2012-12-12 07:19:54 +0100
commitf69b8468b76edc9f25a4cb97022a136be988b236 (patch)
tree11ee20533761c70f2b7bda9748e22ebda277acd2
parent79a43d78b27232be005755eb206fd9e4ce9a0625 (diff)
downloadscala-f69b8468b76edc9f25a4cb97022a136be988b236.tar.gz
scala-f69b8468b76edc9f25a4cb97022a136be988b236.tar.bz2
scala-f69b8468b76edc9f25a4cb97022a136be988b236.zip
SI-6288 Fix positioning of label jumps
ICode generation was assigning the position of the last label jump to all jumps to that particular label def. This problem is particularly annoying under the new pattern matcher: a breakpoint in the body of the final case will be triggered on the way out of the body of any other case. Thanks to @dragos for the expert guidance as we wended our way through GenICode to the troublesome code. Chalk up another bug for mutability. I believe that the ICode output should be stable enough to use a a .check file, if it proves otherwise we should make it so.
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala7
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala4
-rw-r--r--test/files/run/t6288b-jump-position.check80
-rw-r--r--test/files/run/t6288b-jump-position.scala22
4 files changed, 112 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 068836fe4f..d50d4cd125 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -320,7 +320,12 @@ trait BasicBlocks {
else
instrs.zipWithIndex collect {
case (oldInstr, i) if map contains oldInstr =>
- code.touched |= replaceInstruction(i, map(oldInstr))
+ // SI-6288 clone important here because `replaceInstruction` assigns
+ // a position to `newInstr`. Without this, a single instruction can
+ // be added twice, and the position last position assigned clobbers
+ // all previous positions in other usages.
+ val newInstr = map(oldInstr).clone()
+ code.touched |= replaceInstruction(i, newInstr)
}
////////////////////// Emit //////////////////////
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 8c18809ad6..483cb491a1 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -39,6 +39,10 @@ abstract class DirectTest extends App {
// new compiler
def newCompiler(args: String*): Global = {
val settings = newSettings((CommandLineParser tokenize ("-d \"" + testOutput.path + "\" " + extraSettings)) ++ args.toList)
+ newCompiler(settings)
+ }
+
+ def newCompiler(settings: Settings): Global = {
if (settings.Yrangepos.value) new Global(settings, reporter(settings)) with interactive.RangePositions
else new Global(settings, reporter(settings))
}
diff --git a/test/files/run/t6288b-jump-position.check b/test/files/run/t6288b-jump-position.check
new file mode 100644
index 0000000000..45ec31c308
--- /dev/null
+++ b/test/files/run/t6288b-jump-position.check
@@ -0,0 +1,80 @@
+object Case3 extends Object {
+ // fields:
+
+ // methods
+ def unapply(z: Object (REF(class Object))): Option {
+ locals: value z
+ startBlock: 1
+ blocks: [1]
+
+ 1:
+ 2 NEW REF(class Some)
+ 2 DUP(REF(class Some))
+ 2 CONSTANT(-1)
+ 2 BOX INT
+ 2 CALL_METHOD scala.Some.<init> (static-instance)
+ 2 RETURN(REF(class Option))
+
+ }
+ Exception handlers:
+
+ def main(args: Array[String] (ARRAY[REF(class String)])): Unit {
+ locals: value args, value x1, value x2, value x
+ startBlock: 1
+ blocks: [1,2,3,6,7]
+
+ 1:
+ 4 CONSTANT("")
+ 4 STORE_LOCAL(value x1)
+ 4 SCOPE_ENTER value x1
+ 4 JUMP 2
+
+ 2:
+ 5 LOAD_LOCAL(value x1)
+ 5 IS_INSTANCE REF(class String)
+ 5 CZJUMP (BOOL)NE ? 3 : 6
+
+ 3:
+ 5 LOAD_LOCAL(value x1)
+ 5 CHECK_CAST REF(class String)
+ 5 STORE_LOCAL(value x2)
+ 5 SCOPE_ENTER value x2
+ 6 LOAD_MODULE object Predef
+ 6 CONSTANT("case 0")
+ 6 CALL_METHOD scala.Predef.println (dynamic)
+ 6 LOAD_FIELD scala.runtime.BoxedUnit.UNIT
+ 6 STORE_LOCAL(value x)
+ 6 JUMP 7
+
+ 6:
+ 8 LOAD_MODULE object Predef
+ 8 CONSTANT("default")
+ 8 CALL_METHOD scala.Predef.println (dynamic)
+ 8 LOAD_FIELD scala.runtime.BoxedUnit.UNIT
+ 8 STORE_LOCAL(value x)
+ 8 JUMP 7
+
+ 7:
+ 10 LOAD_MODULE object Predef
+ 10 CONSTANT("done")
+ 10 CALL_METHOD scala.Predef.println (dynamic)
+ 10 RETURN(UNIT)
+
+ }
+ Exception handlers:
+
+ def <init>(): Case3.type {
+ locals:
+ startBlock: 1
+ blocks: [1]
+
+ 1:
+ 12 THIS(Case3)
+ 12 CALL_METHOD java.lang.Object.<init> (super())
+ 12 RETURN(UNIT)
+
+ }
+ Exception handlers:
+
+
+}
diff --git a/test/files/run/t6288b-jump-position.scala b/test/files/run/t6288b-jump-position.scala
new file mode 100644
index 0000000000..e22a1ab120
--- /dev/null
+++ b/test/files/run/t6288b-jump-position.scala
@@ -0,0 +1,22 @@
+import scala.tools.partest.IcodeTest
+
+object Test extends IcodeTest {
+ override def code =
+ """object Case3 { // 01
+ | def unapply(z: Any): Option[Int] = Some(-1) // 02
+ | def main(args: Array[String]) { // 03
+ | ("": Any) match { // 04
+ | case x : String => // 05 Read: <linenumber> JUMP <target basic block id>
+ | println("case 0") // 06 expecting "6 JUMP 7", was "8 JUMP 7"
+ | case _ => // 07
+ | println("default") // 08 expecting "8 JUMP 7"
+ | } // 09
+ | println("done") // 10
+ | }
+ |}""".stripMargin
+
+ override def show() {
+ val lines1 = collectIcode("")
+ println(lines1 mkString "\n")
+ }
+}