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 2019/11/21 07:44:56 UTC

[groovy] branch master updated: GROOVY-9126: Unreachable line numbers after ARETURN in bytecode (#1095)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new ecb6c33  GROOVY-9126: Unreachable line numbers after ARETURN in bytecode (#1095)
ecb6c33 is described below

commit ecb6c331edf08a0b41ac3ff4b63aae99b85a4b76
Author: Daniel.Sun <su...@apache.org>
AuthorDate: Thu Nov 21 15:44:47 2019 +0800

    GROOVY-9126: Unreachable line numbers after ARETURN in bytecode (#1095)
---
 .../groovy/classgen/asm/StatementWriter.java       | 23 +++++++++-
 src/test/groovy/bugs/Groovy9126.groovy             | 51 ++++++++++++++++++++++
 2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
index 072d9ed..8459b89 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
@@ -20,6 +20,7 @@ package org.codehaus.groovy.classgen.asm;
 
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BooleanExpression;
@@ -88,13 +89,16 @@ public class StatementWriter {
         int mark = controller.getOperandStack().getStackLength();
         CompileStack compileStack = controller.getCompileStack();
         compileStack.pushVariableScope(block.getVariableScope());
-        for (Statement statement : block.getStatements()) {
+        List<Statement> statementList = block.getStatements();
+        for (Statement statement : statementList) {
             statement.visit(controller.getAcg());
         }
         compileStack.pop();
 
         // GROOVY-7647
-        if (block.getLastLineNumber() > 0) {
+        if (block.getLastLineNumber() > 0
+                && !methodOrConstructorsLastReturnStatementExists(block) // GROOVY-9126
+        ) {
             MethodVisitor mv = controller.getMethodVisitor();
             Label blockEnd = new Label();
             mv.visitLabel(blockEnd);
@@ -104,6 +108,21 @@ public class StatementWriter {
         controller.getOperandStack().popDownTo(mark);
     }
 
+    private boolean methodOrConstructorsLastReturnStatementExists(BlockStatement block) {
+        MethodNode methodNode = controller.getMethodNode();
+        if (null == methodNode) {
+            methodNode = controller.getConstructorNode();
+        }
+
+        if (null == methodNode || block != methodNode.getCode()) { // check if the block is method/constructor's code
+            return false;
+        }
+
+        List<Statement> statementList = block.getStatements();
+        final int size = statementList.size();
+        return size > 0 && statementList.get(size - 1) instanceof ReturnStatement;
+    }
+
     public void writeForStatement(ForStatement loop) {
         Parameter loopVar = loop.getVariable();
         if (loopVar == ForStatement.FOR_LOOP_DUMMY) {
diff --git a/src/test/groovy/bugs/Groovy9126.groovy b/src/test/groovy/bugs/Groovy9126.groovy
new file mode 100644
index 0000000..3df9633
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9126.groovy
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+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 {
+
+    @Test
+    void testUnreachableBytecode() {
+        def bytecode = compile([method:'nonVoidMethod'],'''
+            @groovy.transform.CompileStatic
+            int nonVoidMethod() {
+                1 * 1
+            }
+        ''')
+
+        assert bytecode.hasStrictSequence(
+                ['public nonVoidMethod()I',
+                 'L0',
+                 'LINENUMBER 4 L0',
+                 'ICONST_1',
+                 'ICONST_1',
+                 'IMUL',
+                 'IRETURN',
+                 'L1',
+                 'FRAME FULL [] [java/lang/Throwable]']
+        )
+    }
+}