Decompilation Jascii Test
Program-Transformation.Org: The Program Transformation Wiki
jAscii Java Decompiler Simple Tests
NOTE: Jascii seems to have gone out of business at the end of 2003.
I tested jAscii 1.0.20 from
http://www.jascii.com.
Fibo
For source, see
DecompilerFiboTestSource. Decompiled source from jAscii:
//Decompiled by jAscii v1.0.20. Copyright 2001 D&C Software Solutions Inc.
//jAscii home page: http://www.jascii.com
//Decompiled from Fibo.class
//Original Source File Name: Fibo.java
import java.io.PrintStream;
class Fibo
{
Fibo()
{
}
private static int fib(int i)
{
if (i > 1)
{
return fib(i - 1) + fib(i - 2);
}
else
{
return i;
}
}
public static void main(String as[])
throws Exception
{
int i = 0;
try
{
i = Integer.parseInt(as[0]);
}
catch (Exception e)
{
System.out.println("Input error");
System.exit(1);
}
int j = fib(i);
System.out.println("fibonacci(" + i + ") = " + j);
}
}
As you can see, the decompilation is almost identical to the original source. The output compiled and ran perfectly with no changes required.
Casting
For source, see
DecompilerCastingTestSource. Here is the output from jAscii:
//Decompiled by jAscii v1.0.20. Copyright 2001 D&C Software Solutions Inc.
import java.io.PrintStream;
public class Casting
{
public Casting()
{
}
public static void main(String as[])
{
for (char ch = '\0'; ch < 128; ch = (char)(ch + 1))
System.out.println("ascii " + ch + " character " + ch);
}
}
As before, there is a cast missing. No modifications were needed to recompile it; when the cast was inserted, the program ran correctly.
Inner classes
For source, see
DecompilerInnerClassesTestSource. When decompiled with jAscii, the result is
//Decompiled by jAscii v1.0.20. Copyright 2001 D&C Software Solutions Inc.
import java.io.PrintStream;
public class Usa
{
public String name;
public class England
{
public String name;
public class Ireland
{
public String name;
public Ireland()
{
name = "Dublin";
}
public void print_names()
{
System.out.println(name);
}
}
public England()
{
name = "London";
}
}
public Usa()
{
name = "Detroit";
}
}
It reproduced the inner classes correctly, although the initialisations were moved to the constructors.
Deuces Wild
This is a 38K applet with two dimensional arrays of integers, some floating point code, and so on. It decompiled in about 8 seconds, with one error. In one
for
loop, a pair of braces was missing. The body of the loop had only one statement (a do while loop) and a declaration; perhaps the declaration was added after the loop was designated as not needing braces. When the braces were added, it recompiled and ran perfectly with no modifications. The arrays of strings are initialised fairly naturally, e.g.
String[] cardrank;
...
cardrank = { "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
"Ten", "Jack", "Queen", "King", "Ace" };
The initialisation was placed into the constructor method. It would have been nice to break the long strings onto several lines of less than 80 columns.
Sable Test Program
For source, see
DecompilerSableTestSource. Here is the result for function
f
(as produced by jAscii):
public static void f(short st)
{
Object object;
boolean flag;
if (st > 10)
{
Rectangle rectangle = new Rectangle(st, st);
flag = rectangle.isFat();
object = rectangle;
}
else
{
Circle circle = new Circle(st);
flag = circle.isFat();
object = circle;
}
if (!flag)
{
((Drawable)(object)).draw();
}
}
As you can see, it took the lazy option and declared the variable originally called
d
to be of type
Object
, and correctly cast the object as required. However, it neglected to cast 11 from int to short in the call to
f()
.
Optimised code
For source, see
DecompilerOptimisedTestSource. This was the result from jAscii for the method
f
:
public static void f(short st)
{
Object object;
if (st > 10)
{
Rectangle rectangle = new Rectangle;
rectangle.<init>(st, st);
st = rectangle.isFat();
object = rectangle;
}
else
{
object = new Circle;
((Circle)(object)).<init>(st);
st = ((Circle)(object)).isFat();
object = object;
}
if (st == 0)
{
((Drawable)(object)).draw();
}
}
As you can see, it is confused with the two constructors.
When the above problems were corrected (e.g.
Rectangle rectangle = new Rectangle(st, st)
, there
is still the problem of the boolean and the short sharing the same variable. When a boolean was declared, and another cast added (not shown above), the code finally compiled.
Simple control flow
For source, see
DecompilerControlFlowTestSource. jAscii produces:
public int foo(int i, int j)
{
RuntimeException e;
pop e
for (i = 10; i < j; i = j++ / i);
return j;
}
This result is strangely similar to that of SourceTec, and is completely wrong. For example,
i
should only be set to 10 if an exception occurs. Also obviously,
pop
is not valid Java.
Exceptions
For source, see
DecompilerExceptionTestSource. Here is jAscii's output:
public void foo()
{
System.out.println("a");
System.out.println("b");
System.out.println("c");
pop this
System.out.println("g");
System.out.println("d");
pop this
System.out.println("e");
System.out.println("f");
return;
}
jAscii has given up on the exception handling altogether. The output is obviously not correct, and will not compile.
Life
This version of Conway's Game of Life was compiled from Ada 95 source code. The applet is from
http://www.appletmagic.com/download/demo/LifeRect.html. With both classes that I tried to decompile (
LifeRect
and
LR_Colony
), jAscii complained that it was not able to complete its flow analysis, and emitted bytecodes (e.g.
pop
,
expression
) into the output (so it did not recompile). It did not bomb out during decompilation.
Conclusion
jAscii does not behave significantly better than some of the free decompilers. In fact, its behaviour is similar to that of the SourceTec decompiler, which is derived from the original Java decompiler, Mocha (except that jAscii handles Java 2 classfiles, and inner classes).
--
MikeVanEmmerik - 10 Feb 2003
CategoryDecompilation