You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/09/30 14:27:09 UTC

[groovy] branch GROOVY_2_5_X updated: Tweak GROOVY-9126: Eliminate more unreachable bytecode

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new a2d07bc  Tweak GROOVY-9126: Eliminate more unreachable bytecode
a2d07bc is described below

commit a2d07bc9221c668c279845fa7087fa7c3c157ba3
Author: Daniel Sun <su...@apache.org>
AuthorDate: Wed Sep 30 22:26:54 2020 +0800

    Tweak GROOVY-9126: Eliminate more unreachable bytecode
---
 .../groovy/classgen/AsmClassGenerator.java         | 19 ++++++
 src/test/groovy/bugs/Groovy9126.groovy             | 70 +++++++++++++++++++++-
 2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index ed31b20..12bf2bf 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -505,6 +505,9 @@ public class AsmClassGenerator extends ClassGenerator {
         super.visitConstructorOrMethod(node, isConstructor);
 
         controller.getCompileStack().clear();
+
+        if (checkIfLastStatementIsReturnOrThrow(code)) return;
+
         if (node.isVoidMethod()) {
             mv.visitInsn(RETURN);
         } else {
@@ -523,6 +526,22 @@ public class AsmClassGenerator extends ClassGenerator {
         }
     }
 
+    private boolean checkIfLastStatementIsReturnOrThrow(Statement code) {
+        if (code instanceof BlockStatement) {
+            BlockStatement blockStatement = (BlockStatement) code;
+            List<Statement> statementList = blockStatement.getStatements();
+            int statementCnt = statementList.size();
+            if (statementCnt > 0) {
+                Statement lastStatement = statementList.get(statementCnt - 1);
+                if (lastStatement instanceof ReturnStatement || lastStatement instanceof ThrowStatement) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
     void visitAnnotationDefaultExpression(AnnotationVisitor av, ClassNode type, Expression exp) {
         if (exp instanceof ClosureExpression) {
             ClassNode closureClass = controller.getClosureWriter().getOrAddClosureClass((ClosureExpression) exp, ACC_PUBLIC);
diff --git a/src/test/groovy/bugs/Groovy9126.groovy b/src/test/groovy/bugs/Groovy9126.groovy
index 3df9633..d1dc2ba 100644
--- a/src/test/groovy/bugs/Groovy9126.groovy
+++ b/src/test/groovy/bugs/Groovy9126.groovy
@@ -22,8 +22,6 @@ import groovy.transform.CompileStatic
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
 import org.junit.Test
 
-import static groovy.test.GroovyAssert.assertScript
-
 @CompileStatic
 final class Groovy9126 extends AbstractBytecodeTestCase {
 
@@ -45,7 +43,73 @@ final class Groovy9126 extends AbstractBytecodeTestCase {
                  'IMUL',
                  'IRETURN',
                  'L1',
-                 'FRAME FULL [] [java/lang/Throwable]']
+                 'LOCALVARIABLE this Lscript; L0 L1 0']
+        )
+    }
+
+    @Test
+    void testUnreachableBytecode2() {
+        def bytecode = compile([method:'nonVoidMethod'],'''
+            @groovy.transform.CompileStatic
+            def nonVoidMethod() {
+                println 123
+                567
+            }
+        ''')
+
+        assert bytecode.hasStrictSequence(
+                ['public nonVoidMethod()Ljava/lang/Object;',
+                 'L0',
+                 'LINENUMBER 4 L0',
+                 'ALOAD 0',
+                 'CHECKCAST script',
+                 'BIPUSH 123',
+                 'INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;',
+                 'INVOKEVIRTUAL script.println (Ljava/lang/Object;)V',
+                 'ACONST_NULL',
+                 'POP',
+                 'L1',
+                 'LINENUMBER 5 L1',
+                 'SIPUSH 567',
+                 'INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;',
+                 'ARETURN',
+                 'L2',
+                 'LOCALVARIABLE this Lscript; L0 L2 0']
+        )
+    }
+
+    @Test
+    void testUnreachableBytecode3() {
+        def bytecode = compile([method:'nonVoidMethod'],'''
+            @groovy.transform.CompileStatic
+            def nonVoidMethod() {
+                println 123
+                throw new RuntimeException()
+            }
+        ''')
+
+        println bytecode
+
+        assert bytecode.hasStrictSequence(
+                ['public nonVoidMethod()Ljava/lang/Object;',
+                 'L0',
+                 'LINENUMBER 4 L0',
+                 'ALOAD 0',
+                 'CHECKCAST script',
+                 'BIPUSH 123',
+                 'INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;',
+                 'INVOKEVIRTUAL script.println (Ljava/lang/Object;)V',
+                 'ACONST_NULL',
+                 'POP',
+                 'L1',
+                 'LINENUMBER 5 L1',
+                 'NEW java/lang/RuntimeException',
+                 'DUP',
+                 'INVOKESPECIAL java/lang/RuntimeException.<init> ()V',
+                 'CHECKCAST java/lang/Throwable',
+                 'ATHROW',
+                 'L2',
+                 'LOCALVARIABLE this Lscript; L0 L2 0']
         )
     }
 }