Skip to content

Commit

Permalink
SI-6288 Fix positioning of label jumps
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
retronym committed Dec 12, 2012
1 parent 79a43d7 commit f69b846
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
Expand Up @@ -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 //////////////////////
Expand Down
4 changes: 4 additions & 0 deletions src/partest/scala/tools/partest/DirectTest.scala
Expand Up @@ -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))
}
Expand Down
80 changes: 80 additions & 0 deletions 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:


}
22 changes: 22 additions & 0 deletions 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")
}
}

0 comments on commit f69b846

Please sign in to comment.