diff --git a/jode/test/Flow.java b/jode/test/Flow.java new file mode 100644 index 0000000..dcff980 --- /dev/null +++ b/jode/test/Flow.java @@ -0,0 +1,200 @@ +package jode.test; + +public abstract class Flow { + int g; + int[] ain; + + void skip() { + for (int i=0; i<3; i++) { + if (g > 5) { + for (int j=0; j<5; j++) { + g++; + } + } + i--; + } + } + + /* This tests the while in a switch problem. + */ + public void switchWhileTest() { + int dir = g; + int x = 0; + int y = 0; + boolean done = false; + g = 5; + switch (dir) { + case 1: + while (!done) { + done = true; + if (g > 7) + g = g - 4; + x = g; + y = g; + if (x > 7) + x = x - 4; + for (int i=0; i<4; i++) { + for (int j=0; j<5; j++) { + if (ain[j] == x + i && ain[j] == y) + done = false; + } + } + } + for (int i=0; i<5; i++) { + ain[g] = x + i; + ain[g] = y; + g += 1; + } + break; + case 2: + while (!done) { + done = true; + x = g; + y = g; + if (y > 7) + y = y - 4; + for (int i=0; i<4; i++) { + for (int j=0; j<4; j++) { + if (ain[j] == x && ain[j] == y + i) + done = false; + } + } + } + for (int i = 0; i<4; i++) { + ain[g] = x; + ain[g] = y + i; + g += 1; + } + break; + case 3: // Same code as case 2 slightly optimized + big: + for (;;) { + x = g; + y = g; + if (y > 7) + y = y - 4; + for (int i=0; i<4; i++) { + for (int j=0; j<4; j++) { + if (ain[j] == x && ain[j] == y + i) + continue big; + } + } + break; + } + for (int i = 0; i<4; i++) { + ain[g] = x; + ain[g] = y + i; + g += 1; + } + break; + } + } + + /** + * This was an example where our flow analysis didn't find an + * elegant solution. The reason is, that we try to make + * while(true)-loops as small as possible (you can't see the real + * end of the loop, if it is breaked there like here). + * + * Look at the assembler code and you know why my Decompiler had + * problems with this. But the decompiler did produce compilable + * code which produces the same assembler code. + * + * The solution was, to make switches as big as possible, the whole + * analyze methods were overworked. + */ + void WhileTrueSwitch() { + int i = 1; + while (true) { + switch (i) { + case 0: + return; + case 1: + i = 5; + continue; + case 2: + i = 6; + continue; + case 3: + throw new RuntimeException(); + default: + i = 7; + return; + } + } + } + + abstract int test(); + + /** + * This tests shorts and empty ifs. Especially the no op ifs can + * be optimized to very unusual code. + */ + public void shortIf() { + while(g != 7) { + if (g == 5) + return; + else if (g != 4) + break; + else if (g == 2) + shortIf(); + else + return; + + if (g!= 7) + shortIf(); + else { + shortIf(); + return; + } + + if (g != 1) + break; + else if (g == 3) + shortIf(); + else + break; + + // javac optimizes this instruction to + // test(); + // jikes reproduces this statement as one would expect + if (g + 5 == test()) { + } + + // javac -O optimizes this to the following weired statements + // PUSH g; + // PUSH test(); + // POP2; + // This cannot be decompiled correctly, since the == is lost. + if (g == test()) + continue; + } + while(g == 3) { + // javac: + // PUSH test() == 4 || test() == 3 && test() == 2; + // POP; + if (test() == 4 || test() == 3 && test() == 2); + // javac -O: + // if (test() != 4 && test() == 3) { + // PUSH test()+test() - test(); + // PUSH g-4; + // POP2; + // } + if (test() == 4 || test() == 3 && test() == 2) + continue; + } + while (g==2) { + // javac: + // test(); + // test(); + // test(); + if ((long) (test() + test() - test()) == (long)(g-4)); + // javac -O: + // PUSH (long)(test() + test() - test()) <=> (long)(g-4) + // POP; + if ((long) (test() + test() - test()) == (long)(g-4)) + continue; + } + System.err.println("Hallo"); + } +} diff --git a/jode/test/LocalTypes.java b/jode/test/LocalTypes.java new file mode 100644 index 0000000..ae869f4 --- /dev/null +++ b/jode/test/LocalTypes.java @@ -0,0 +1,145 @@ +package jode.test; + +class A { +} + +interface I1 { +} + +interface I2 { +} + +interface I12 extends I1, I2 { +} + +class B extends A implements I1 { +} + +class C extends B implements I2, I12 { +} + +class D extends A implements I12 { +} + +class E extends A implements I2 { +} + +public class LocalTypes { + A a; + B b; + C c; + D d; + E e; + + I1 i1; + I2 i2; + I12 i12; + + boolean g_bo; + byte g_by; + short g_sh; + int g_in; + + int z; + int[]ain; + + public void arithTest() { + int a=1,b=2; + boolean x = true,y = false; + int c=0; + arithTest(); + if (x & y) { + c = 5; + arithTest(); + x &= y; + arithTest(); + x = x | y; + arithTest(); + x ^= y; + arithTest(); + x = x && y; + arithTest(); + b <<= a; + b <<= c; + } + a&=b; + } + + public void intTypeTest() { + boolean b = false; + boolean abo[] = null; + byte aby[] = null; + byte by; + int in; + short sh; + b = g_bo; + in = g_sh; + sh = (short)g_in; + by = (byte)sh; + sh = by; + in = by; + abo[0] = g_bo; + abo[1] = false; + abo[2] = true; + aby[0] = g_by; + aby[1] = 0; + aby[2] = 1; + } + + native void arrFunc(B[] b); + + /** + * This is an example where it is really hard to know, which type + * each local has. + */ + void DifficultType () { + B myB = c; + C myC = c; + I2 myI2 = c; + I12 myI12 = c; + boolean bool = true; + B[] aB = new C[3]; + arrFunc(new C[3]); + + while (bool) { + if (bool) { + i1 = myB; + i2 = myC; + i1 = aB[0]; + } else if (bool) { + i1 = myI12; + i2 = myI2; + } else { + i1 = myC; + i2 = myI12; + } + myB = b; + if (bool) + myI2 = i12; + else { + myI12 = d; + myI2 = e; + } + } + } + + /** + * This is an example where it is really hard to know, which type + * each local has. + */ + void DifficultArrayType () { + boolean bool = true; + B[] aB = new C[3]; + arrFunc(new C[3]); + C[][][][][] x = new C[4][3][4][][]; + int[][][][][] y = new int[1][2][][][]; + + while (bool) { + if (bool) { + i1 = aB[0]; + aB[0] = b; + } + } + } +} +