From 9b334b2ea3f9eee0582447658dcf2ac244121644 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Sun, 14 Feb 2016 21:20:54 +0100 Subject: Avoid generating ACONST_NULL; POP; ACONST_NULL when loading null When loading a value of type scala.runtime.Null$ we need to add POP; ACONST_NULL, see comment in BCodeBodyBuilder.adapt. This is however not necessary if the null value is a simple ACONST_NULL. This patch eliminates that redundancy. --- .../tools/nsc/backend/jvm/opt/InlinerTest.scala | 1 - .../nsc/backend/jvm/opt/UnreachableCodeTest.scala | 48 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'test/junit') diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala index 942b62b32c..70f3060027 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -1507,7 +1507,6 @@ class InlinerTest extends ClearAfterClass { |} """.stripMargin val List(c) = compile(code) - val t = getSingleMethod(c, "t") // box-unbox will clean it up assertEquals(getSingleMethod(c, "t").instructions.summary, diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala index 86c8baa3c6..62ee09e9de 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala @@ -215,4 +215,52 @@ class UnreachableCodeTest extends ClearAfterClass { assertTrue(List(FrameEntry(F_FULL, List(INTEGER, DOUBLE, Label(3)), List("java/lang/Object", Label(4))), Label(3), Label(4)) === List(FrameEntry(F_FULL, List(INTEGER, DOUBLE, Label(1)), List("java/lang/Object", Label(3))), Label(1), Label(3))) } + + @Test + def loadNullNothingBytecode(): Unit = { + val code = + """class C { + | def nl: Null = null + | def nt: Nothing = throw new Error("") + | def cons(a: Any) = () + | + | def t1 = cons(null) + | def t2 = cons(nl) + | def t3 = cons(throw new Error("")) + | def t4 = cons(nt) + |} + """.stripMargin + val List(c) = compileClasses(noOptCompiler)(code) + + assertEquals(getSingleMethod(c, "nl").instructions.summary, List(ACONST_NULL, ARETURN)) + + assertEquals(getSingleMethod(c, "nt").instructions.summary, List( + NEW, DUP, LDC, "", ATHROW)) + + assertEquals(getSingleMethod(c, "t1").instructions.summary, List( + ALOAD, ACONST_NULL, "cons", RETURN)) + + // GenBCode introduces POP; ACONST_NULL after loading an expression of type scala.runtime.Null$, + // see comment in BCodeBodyBuilder.adapt + assertEquals(getSingleMethod(c, "t2").instructions.summary, List( + ALOAD, ALOAD, "nl", POP, ACONST_NULL, "cons", RETURN)) + + // the bytecode generated by GenBCode is ... ATHROW; INVOKEVIRTUAL C.cons; RETURN + // the ASM classfile writer creates a new basic block (creates a label) right after the ATHROW + // and replaces all instructions by NOP*; ATHROW, see comment in BCodeBodyBuilder.adapt + // NOTE: DCE is enabled by default and gets rid of the redundant code (tested below) + assertEquals(getSingleMethod(c, "t3").instructions.summary, List( + ALOAD, NEW, DUP, LDC, "", ATHROW, NOP, NOP, NOP, ATHROW)) + + // GenBCode introduces an ATHROW after the invocation of C.nt, see BCodeBodyBuilder.adapt + // NOTE: DCE is enabled by default and gets rid of the redundant code (tested below) + assertEquals(getSingleMethod(c, "t4").instructions.summary, List( + ALOAD, ALOAD, "nt", ATHROW, NOP, NOP, NOP, ATHROW)) + + val List(cDCE) = compileClasses(dceCompiler)(code) + assertEquals(getSingleMethod(cDCE, "t3").instructions.summary, List( + ALOAD, NEW, DUP, LDC, "", ATHROW)) + assertEquals(getSingleMethod(cDCE, "t4").instructions.summary, List( + ALOAD, ALOAD, "nt", ATHROW)) + } } -- cgit v1.2.3