]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-207
authorchibash <chiba@javassist.org>
Sun, 11 Aug 2013 12:52:08 +0000 (21:52 +0900)
committerchibash <chiba@javassist.org>
Sun, 11 Aug 2013 12:52:08 +0000 (21:52 +0900)
Readme.html
src/main/javassist/bytecode/stackmap/BasicBlock.java
src/main/javassist/bytecode/stackmap/MapMaker.java
src/main/javassist/bytecode/stackmap/Tracer.java
src/test/Test.java [new file with mode: 0644]
src/test/javassist/JvstTest4.java
src/test/javassist/bytecode/StackMapTest.java
src/test/test4/JIRA207.java [new file with mode: 0644]

index 9820e64bd82e23011f6f2939efff46e309eb5664..05386252ecf93aaeb18c9ce5778dcabac24543b5 100644 (file)
@@ -283,7 +283,7 @@ see javassist.Dump.
 
 <p>-version 3.19
 <ul>
-<li>JIRA JASSIST-206.
+<li>JIRA JASSIST-158, 206.
 </ul>
 </p>
 
index 6213e22a64b2b627e9be31e387205d826fb1866d..43367307b00304be39cf19101425cedb28d75086 100644 (file)
@@ -97,6 +97,10 @@ public class BasicBlock {
         sbuf.append("}");
     }
 
+    /**
+     * A Mark indicates the position of a branch instruction
+     * or a branch target.
+     */
     static class Mark implements Comparable {
         int position;
         BasicBlock block;
@@ -349,10 +353,11 @@ public class BasicBlock {
                     }
                     else {
                         // the previous mark already has exits.
-                        int prevPos = prev.position;
-                        if (prevPos + prev.length < m.position) {
-                            prev = makeBlock(prevPos + prev.length);
-                            prev.length = m.position - prevPos;
+                        if (prev.position + prev.length < m.position) {
+                            // dead code is found.
+                            prev = makeBlock(prev.position + prev.length);
+                            blocks.add(prev);
+                            prev.length = m.position - prev.position;
                             // the incoming flow from dead code is not counted
                             // bb.incoming++;
                             prev.exit = makeArray(bb);
index 16d3f2945f54789f7c983ab420e7f909e48a7583..b1aa7008e172fe5bab5c042896f0670a3544c47d 100644 (file)
@@ -307,34 +307,63 @@ public class MapMaker extends Tracer {
     // Phase 1.5
 
     /*
-     * Javac may generate an exception handler that catches only an exception
+     * Javac may generate an exception handler that catches only the exception
      * thrown within the handler itself.  It is dead code.
+     * See javassist.JvstTest4.testJIRA195().
      */
 
     private void findDeadCatchers(byte[] code, TypedBlock[] blocks) throws BadBytecode {
         int len = blocks.length;
         for (int i = 0; i < len; i++) {
             TypedBlock block = blocks[i];
-            if (block.localsTypes == null) { // if block is dead code
+            if (!block.alreadySet()) {
+                fixDeadcode(code, block);
                 BasicBlock.Catch handler = block.toCatch;
-                while (handler != null)
-                    if (handler.body == block) {
-                        BasicBlock.Catch handler2
-                            = new BasicBlock.Catch(block, handler.typeIndex, null);
-                        traceException(code, handler2);
-                        break;
+                if (handler != null) {
+                    TypedBlock tb = (TypedBlock)handler.body;
+                    if (!tb.alreadySet()) {
+                        // tb is a handler that catches only the exceptions
+                        // thrown from dead code.
+                        recordStackMap(tb, handler.typeIndex);
+                        fixDeadcode(code, tb);
+                        tb.incoming = 1;
                     }
-                    else
-                        handler = handler.next;
+                }
+                
             }
         }
     }
 
+    private void fixDeadcode(byte[] code, TypedBlock block) throws BadBytecode {
+        int pos = block.position;
+        int len = block.length - 3;
+        if (len < 0) {
+            // if the dead-code length is shorter than 3 bytes.
+            if (len == -1)
+                code[pos] = Bytecode.NOP;
+
+            code[pos + block.length - 1] = (byte)Bytecode.ATHROW;
+            block.incoming = 1;
+            recordStackMap(block, 0);
+            return;
+        }
+
+        // if block.incomping > 0, all the incoming edges are from
+        // other dead code blocks.  So set block.incoming to 0.
+        block.incoming = 0;
+
+        for (int k = 0; k < len; k++) 
+            code[pos + k] = Bytecode.NOP;
+
+        code[pos + len] = (byte)Bytecode.GOTO;
+        ByteArray.write16bit(-len, code, pos + len + 1);
+    }
+
     // Phase 2
 
     /*
      * This method first finds strongly connected components (SCCs)
-     * on a graph made by TypeData by Tarjan's algorithm.
+     * in a TypeData graph by Tarjan's algorithm.
      * SCCs are TypeData nodes sharing the same type.
      * Since SCCs are found in the topologically sorted order,
      * their types are also fixed when they are found. 
@@ -345,9 +374,7 @@ public class MapMaker extends Tracer {
         int index = 0;
         for (int i = 0; i < len; i++) {
             TypedBlock block = blocks[i];
-            if (block.localsTypes == null)  // if block is dead code
-                fixDeadcode(code, block);
-            else {
+            if (block.alreadySet()) {   // if block is not dead code
                 int n = block.localsTypes.length;
                 for (int j = 0; j < n; j++)
                     index = block.localsTypes[j].dfs(preOrder, index, classPool);
@@ -359,20 +386,6 @@ public class MapMaker extends Tracer {
         }
     }
 
-    private void fixDeadcode(byte[] code, TypedBlock block) throws BadBytecode {
-        int pos = block.position;
-        int len = block.length - 3;
-        if (len < 0)
-            throw new BadBytecode("dead code detected at " + pos
-                                  + ".  No stackmap table generated.");
-
-        for (int k = 0; k < len; k++) 
-            code[pos + k] = Bytecode.NOP;
-
-        code[pos + len] = (byte)Bytecode.GOTO;
-        ByteArray.write16bit(-len, code, pos + len + 1);
-    }
-
     // Phase 3
 
     public StackMapTable toStackMap(TypedBlock[] blocks) {
index e5216165f582e72c68c6c8b47a28dcfdea1c9dd2..4111d58930fc4f735c3435bb10207c7bd723285e 100644 (file)
@@ -81,7 +81,7 @@ public abstract class Tracer implements TypeTag {
                     return doOpcode148_201(pos, code, op);
         }
         catch (ArrayIndexOutOfBoundsException e) {
-            throw new BadBytecode("inconsistent stack height " + e.getMessage());
+            throw new BadBytecode("inconsistent stack height " + e.getMessage(), e);
         }
     }
 
diff --git a/src/test/Test.java b/src/test/Test.java
new file mode 100644 (file)
index 0000000..51591cf
--- /dev/null
@@ -0,0 +1,16 @@
+import javassist.*;
+
+public class Test {
+    public static void main(String[] args) throws Exception {
+        ClassPool cp = ClassPool.getDefault();
+        // ClassPool cp = new ClassPool();
+        cp.insertClassPath("./target/test-classes");
+        CtClass cc = cp.get("test4.JIRA207");
+        // cc.getClassFile().setMajorVersion(javassist.bytecode.ClassFile.JAVA_4);
+        CtMethod cm = cc.getDeclaredMethod("foo");
+        cm.insertBefore("throw new Exception();");
+        CtMethod cm2 = cc.getDeclaredMethod("run2");
+        cm2.insertBefore("throw new Exception();");
+        cc.writeFile();
+    }
+}
index b3b04c29471915efefdeddc3f3a4e5248b06606b..85ee4b0fecad506a5841c793babd98353cbefcac 100644 (file)
@@ -903,4 +903,20 @@ public class JvstTest4 extends JvstTestRoot {
         Object obj = make(cc.getName());
         assertEquals(15, invoke(obj, "run"));
     }
+
+    public void testJIRA207() throws Exception {
+        CtClass cc = sloader.get("test4.JIRA207");
+        CtMethod cm = cc.getDeclaredMethod("foo");
+        cm.insertBefore("throw new Exception();");
+
+        CtMethod cm2 = cc.getDeclaredMethod("run2");
+        cm2.insertBefore("throw new Exception();");
+        cc.writeFile();
+        Object obj = make(cc.getName());
+        try {
+            invoke(obj, "run2");
+            fail("run2");
+        }
+        catch (Exception e) {}
+    }
 }
index 4fadc890927aabcb2988bcc8b8e57888f71f9f58..fc54c5923e9124ff24ab2f72f6dfed5a176c2ccc 100644 (file)
@@ -680,18 +680,16 @@ public class StackMapTest extends TestCase {
 
     public void testJIRA175b() throws Exception {
         CtClass cc = loader.get("javassist.bytecode.StackMapTest$C6");
-        try {
-            cc.getDeclaredMethod("setter").instrument(new javassist.expr.ExprEditor() {
-                public void edit(javassist.expr.FieldAccess f) throws javassist.CannotCompileException {
-                    if (!f.where().getMethodInfo().isMethod())
-                        return;
+        cc.getDeclaredMethod("setter").instrument(new javassist.expr.ExprEditor() {
+            public void edit(javassist.expr.FieldAccess f) throws javassist.CannotCompileException {
+                if (!f.where().getMethodInfo().isMethod())
+                    return;
 
-                    f.replace("{ $_ = $proceed($$); return $_;}");
-                }
-            });
-            fail("deadcode detection");
-        }
-        catch (javassist.CannotCompileException e) {}
+                // this will make a 1-byte dead code.
+                f.replace("{ $_ = $proceed($$); return $_;}");
+            }
+        });
+        cc.writeFile();
     }
 
     public static class C6 {
diff --git a/src/test/test4/JIRA207.java b/src/test/test4/JIRA207.java
new file mode 100644 (file)
index 0000000..c0e6752
--- /dev/null
@@ -0,0 +1,51 @@
+package test4;
+
+public class JIRA207 {
+    public int run() {
+        int i = 3;
+        return foo(i);
+    }
+
+    public int foo(int i) {
+        int k = i + 3;
+        if (k > 0)
+            return k * k;
+        else
+            return k;
+    }
+
+    public int run2() {
+        int i = 0;
+        int p = i;
+        int q = p;
+        int r = q;
+        for (int k = 1; k < 3; ++k)
+            p += k;
+
+        for (int k = 3; k > 0; --k)
+            try {
+                foo(k);
+                p++;
+            }
+            finally {
+                p++;
+            }
+
+        try {
+            foo(p);
+        }
+        catch (RuntimeException e) {
+            if (p > 0)
+                throw e;
+        }
+
+        switch (p) {
+        case 1:
+            p = 100;
+            break;
+        default :
+            ++p;
+        }
+        return p + r;
+    }
+}