summaryrefslogtreecommitdiff
path: root/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
blob: cb01f3d1645efd0b2c39c54ccab57810a2662791 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package scala.tools.nsc
package backend.jvm
package opt

import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.Test
import scala.tools.asm.Opcodes._
import org.junit.Assert._

import CodeGenTools._
import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass

object EmptyExceptionHandlersTest extends ClearAfterClass.Clearable {
  var noOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none")
  var dceCompiler   = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code")
  def clear(): Unit = {
    noOptCompiler = null
    dceCompiler = null
  }
}

@RunWith(classOf[JUnit4])
class EmptyExceptionHandlersTest extends ClearAfterClass {
  ClearAfterClass.stateToClear = EmptyExceptionHandlersTest

  val noOptCompiler = EmptyExceptionHandlersTest.noOptCompiler
  val dceCompiler   = EmptyExceptionHandlersTest.dceCompiler

  val exceptionDescriptor = "java/lang/Exception"

  @Test
  def eliminateEmpty(): Unit = {
    val handlers = List(ExceptionHandler(Label(1), Label(2), Label(2), Some(exceptionDescriptor)))
    val asmMethod = genMethod(handlers = handlers)(
      Label(1),
      Label(2),
      Op(RETURN)
    )
    assertTrue(convertMethod(asmMethod).handlers.length == 1)
    LocalOptImpls.removeEmptyExceptionHandlers(asmMethod)
    assertTrue(convertMethod(asmMethod).handlers.isEmpty)
  }

  @Test
  def eliminateHandlersGuardingNops(): Unit = {
    val handlers = List(ExceptionHandler(Label(1), Label(2), Label(2), Some(exceptionDescriptor)))
    val asmMethod = genMethod(handlers = handlers)(
      Label(1),          // nops only
      Jump(GOTO, Label(3)),
      Label(3),
      Jump(GOTO, Label(4)),

      Label(2),          // handler
      Op(ACONST_NULL),
      Op(ATHROW),

      Label(4),          // return
      Op(RETURN)
    )
    assertTrue(convertMethod(asmMethod).handlers.length == 1)
    LocalOptImpls.removeEmptyExceptionHandlers(asmMethod)
    assertTrue(convertMethod(asmMethod).handlers.isEmpty)
  }

  @Test
  def eliminateUnreachableHandler(): Unit = {
    val code = "def f: Unit = try { } catch { case _: Exception => println(0) }; println(1)"

    assertTrue(singleMethod(noOptCompiler)(code).handlers.length == 1)
    val optMethod = singleMethod(dceCompiler)(code)
    assertTrue(optMethod.handlers.isEmpty)

    val code2 =
      """def f: Unit = {
        |  println(0)
        |  return
        |  try { throw new Exception("") } // removed by dce, so handler will be removed as well
        |  catch { case _: Exception => println(1) }
        |  println(2)
        |}""".stripMargin

    assertTrue(singleMethod(dceCompiler)(code2).handlers.isEmpty)
  }

  @Test
  def keepAliveHandlers(): Unit = {
    val code =
      """def f: Int = {
        |  println(0)
        |  try { 1 }
        |  catch { case _: Exception => 2 }
        |}""".stripMargin

    assertTrue(singleMethod(dceCompiler)(code).handlers.length == 1)
  }
}