From 055a373802a34ee09fc0ed20b2b25c3fa20507d4 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Thu, 2 Jul 2015 20:17:57 +0200 Subject: SI-9376 don't crash when inlining a closure body that throws. If the closure body method has return type Nothing$, add an `ATHROW` instruction after the callsite. This is required for computing stack map frames, as explained in a comment in BCodeBodyBuilder.adapt. Similar for closure bodies with return type Null$. --- .../nsc/backend/jvm/opt/ClosureOptimizerTest.scala | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala (limited to 'test') diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala new file mode 100644 index 0000000000..69eed1f75d --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala @@ -0,0 +1,74 @@ +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.collection.generic.Clearable +import scala.collection.mutable.ListBuffer +import scala.reflect.internal.util.BatchSourceFile +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import scala.tools.asm.tree._ +import scala.tools.asm.tree.analysis._ +import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.AsmAnalyzer +import scala.tools.nsc.io._ +import scala.tools.nsc.reporters.StoreReporter +import scala.tools.testing.AssertUtil._ + +import CodeGenTools._ +import scala.tools.partest.ASMConverters +import ASMConverters._ +import AsmUtils._ + +import BackendReporting._ + +import scala.collection.convert.decorateAsScala._ +import scala.tools.testing.ClearAfterClass + +object ClosureOptimizerTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings") + def clear(): Unit = { compiler = null } +} + +@RunWith(classOf[JUnit4]) +class ClosureOptimizerTest extends ClearAfterClass { + ClearAfterClass.stateToClear = ClosureOptimizerTest + + val compiler = ClosureOptimizerTest.compiler + + @Test + def nothingTypedClosureBody(): Unit = { + val code = + """abstract class C { + | def isEmpty: Boolean + | @inline final def getOrElse[T >: C](f: => T) = if (isEmpty) f else this + | def t = getOrElse(throw new Error("")) + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + val t = c.methods.asScala.toList.find(_.name == "t").get + val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$") + assert(bodyCall.getNext.getOpcode == ATHROW) + } + + @Test + def nullTypedClosureBody(): Unit = { + val code = + """abstract class C { + | def isEmpty: Boolean + | @inline final def getOrElse[T >: C](f: => T) = if (isEmpty) f else this + | def t = getOrElse(null) + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + val t = c.methods.asScala.toList.find(_.name == "t").get + val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$") + assert(bodyCall.getNext.getOpcode == POP) + assert(bodyCall.getNext.getNext.getOpcode == ACONST_NULL) + } +} -- cgit v1.2.3