I always thought that something wrong was happening with Try-Catch translation because the CodeAPITestBytecode.class
was always inconsistent, now looking at the bytecode, there are various nop
which isn't generated when the class is compiled with Javac.
Analyzing the bytecode, the problem looks to be with finally
translation, the Inlined finally
generated by CodeAPI does not generate extra try-catch nodes, but the Javac does.
Java:
try {
if (msg != null) {
System.out.println(msg);
}
Object ref = System.out;
throw new IllegalStateException("Error");
} catch (IllegalStateException | IllegalArgumentException thr) {
System.out.println("Rethrow from var 'thr'!");
thr.printStackTrace();
} catch (ClassNotFoundException | IOException tlr) {
System.out.println("Rethrow from var 'tlr'!");
tlr.printStackTrace();
} finally {
System.out.println("Finally!");
}
CodeAPI:
public static println(java.lang.Object arg0) { //(Ljava/lang/Object;)V
<localVar:index=2 , name=ref , desc=Ljava/lang/Object;, sig=null, start=L1, end=L2>
<localVar:index=2 , name=thr , desc=Ljava/lang/Throwable;, sig=null, start=L3, end=L4>
<localVar:index=2 , name=tlr , desc=Ljava/lang/Throwable;, sig=null, start=L3, end=L5>
<localVar:index=1 , name=test , desc=Lcom/github/jonathanxd/codeapi/test/asm/CodeAPITestBytecode;, sig=null, start=L6, end=L7>
<localVar:index=0 , name=msg , desc=Ljava/lang/Object;, sig=null, start=L8, end=L7>
TryCatch: L9 to L10 handled by L3: java/lang/IllegalArgumentException
TryCatch: L9 to L10 handled by L3: java/lang/IllegalStateException
TryCatch: L9 to L10 handled by L11: java/io/IOException
TryCatch: L9 to L10 handled by L11: java/lang/ClassNotFoundException
L8 {
new com/github/jonathanxd/codeapi/test/asm/CodeAPITestBytecode
dup
invokespecial com/github/jonathanxd/codeapi/test/asm/CodeAPITestBytecode <init>(()V);
}
L6 {
astore1
getstatic java/lang/System.out:java.io.PrintStream
aload1
getfield com/github/jonathanxd/codeapi/test/asm/CodeAPITestBytecode.b:java.lang.String
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L9 {
aload0
ifnull L12
getstatic java/lang/System.out:java.io.PrintStream
aload0
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L12 {
getstatic java/lang/System.out:java.io.PrintStream
}
L1 {
astore2
new java/lang/IllegalStateException
dup
ldc "Error" (java.lang.String)
invokespecial java/lang/IllegalStateException <init>((Ljava/lang/String;)V);
athrow
}
L10 {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
athrow
}
L2 {
nop
nop
athrow
}
L3 {
astore2
getstatic java/lang/System.out:java.io.PrintStream
ldc "Rethrow from var 'thr'!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
aload2
invokevirtual java/lang/Throwable printStackTrace(()V);
getstatic java/lang/System.out:java.io.PrintStream
ldc "Finally!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L4 {
goto L13
}
L11 {
astore2
getstatic java/lang/System.out:java.io.PrintStream
ldc "Rethrow from var 'tlr'!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
aload2
invokevirtual java/lang/Throwable printStackTrace(()V);
getstatic java/lang/System.out:java.io.PrintStream
ldc "Finally!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L5 {
goto L13
}
L13 {
return
}
L7 {
}
}
!access: ACC_PUBLIC, ACC_STATIC (9)
!parameter[name: msg, access: (0)]
public static void println(java.lang.Object) {
desc: (Ljava/lang/Object;)V
maxStack: 3, maxLocals: 3
Label_0:
new com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode
dup
invokespecial com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode.<init>()void (ownerIsInterface: false)
Label_1:
astore 1
getstatic java.lang.System.out (type: java.io.PrintStream)
aload 1
getfield com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode.b (type: java.lang.String)
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_2:
aload 0
ifnull Label_3
getstatic java.lang.System.out (type: java.io.PrintStream)
aload 0
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_3:
FRAME[type: F_APPEND, locals: 1, local: {com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode}, stacks: 0, stack: {}]
getstatic java.lang.System.out (type: java.io.PrintStream)
Label_4:
astore 2
new java.lang.IllegalStateException
dup
ldc "Error" // type: java.lang.String
invokespecial java.lang.IllegalStateException.<init>(java.lang.String)void (ownerIsInterface: false)
athrow
Label_5:
FRAME[type: F_FULL, locals: 0, local: {}, stacks: 1, stack: {java.lang.Throwable}]
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
athrow
Label_6:
FRAME[type: F_SAME1, locals: 0, local: {}, stacks: 1, stack: {java.lang.Throwable}]
nop
nop
athrow
Label_7:
FRAME[type: F_FULL, locals: 2, local: {java.lang.Object, com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode}, stacks: 1, stack: {java.lang.RuntimeException}]
astore 2
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Rethrow from var 'thr'!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
aload 2
invokevirtual java.lang.Throwable.printStackTrace()void (ownerIsInterface: false)
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Finally!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_8:
goto Label_11
Label_9:
FRAME[type: F_SAME1, locals: 0, local: {}, stacks: 1, stack: {java.lang.Exception}]
astore 2
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Rethrow from var 'tlr'!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
aload 2
invokevirtual java.lang.Throwable.printStackTrace()void (ownerIsInterface: false)
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Finally!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_10:
goto Label_11
Label_11:
FRAME[type: F_APPEND, locals: 1, local: {java.lang.Exception}, stacks: 0, stack: {}]
return
Label_12:
TryCatchBlocks {
start: Label_2, end: Label_5, handler: Label_7, exception: java.lang.IllegalArgumentException
start: Label_2, end: Label_5, handler: Label_7, exception: java.lang.IllegalStateException
start: Label_2, end: Label_5, handler: Label_9, exception: java.io.IOException
start: Label_2, end: Label_5, handler: Label_9, exception: java.lang.ClassNotFoundException
}
LocalVariables {
index: 2, name: ref, start: Label_4, end: Label_6, type: java.lang.Object, signature: null
index: 2, name: thr, start: Label_7, end: Label_8, type: java.lang.Throwable, signature: null
index: 2, name: tlr, start: Label_7, end: Label_10, type: java.lang.Throwable, signature: null
index: 1, name: test, start: Label_1, end: Label_12, type: com.github.jonathanxd.codeapi.test.asm.CodeAPITestBytecode, signature: null
index: 0, name: msg, start: Label_0, end: Label_12, type: java.lang.Object, signature: null
}
}
public static println(java.lang.Object arg0) { //(Ljava/lang/Object;)V
<localVar:index=1 , name=ref , desc=Ljava/io/PrintStream;, sig=null, start=L1, end=L2>
<localVar:index=2 , name=f , desc=Ljava/io/File;, sig=null, start=L3, end=L2>
<localVar:index=1 , name=thr , desc=Ljava/lang/RuntimeException;, sig=null, start=L4, end=L5>
<localVar:index=1 , name=tlr , desc=Ljava/lang/Exception;, sig=null, start=L6, end=L7>
<localVar:index=0 , name=msg , desc=Ljava/lang/Object;, sig=null, start=L8, end=L9>
TryCatch: L8 to L2 handled by L2: java/lang/IllegalArgumentException
TryCatch: L8 to L2 handled by L2: java/lang/IllegalStateException
TryCatch: L8 to L2 handled by L10: java/io/IOException
TryCatch: L8 to L2 handled by L10: java/lang/ClassNotFoundException
TryCatch: L8 to L5 handled by L11: Type is null.
TryCatch: L10 to L7 handled by L11: Type is null.
L8 {
aload0
ifnull L12
}
L13 {
getstatic java/lang/System.out:java.io.PrintStream
aload0
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L12 {
getstatic java/lang/System.out:java.io.PrintStream
astore1
}
L1 {
new java/io/File
dup
ldc "s" (java.lang.String)
invokespecial java/io/File <init>((Ljava/lang/String;)V);
astore2
}
L3 {
aload2
invokevirtual java/io/File getCanonicalPath(()Ljava/lang/String;);
pop
}
L14 {
ldc "java.io.File" (java.lang.String)
invokestatic java/lang/Class forName((Ljava/lang/String;)Ljava/lang/Class;);
pop
}
L15 {
new java/lang/IllegalStateException
dup
ldc "Error" (java.lang.String)
invokespecial java/lang/IllegalStateException <init>((Ljava/lang/String;)V);
athrow
}
L2 {
astore1
}
L4 {
getstatic java/lang/System.out:java.io.PrintStream
ldc "Rethrow from var 'thr'!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L16 {
aload1
invokevirtual java/lang/RuntimeException printStackTrace(()V);
}
L5 {
getstatic java/lang/System.out:java.io.PrintStream
ldc "Finally!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L17 {
goto L18
}
L10 {
astore1
}
L6 {
getstatic java/lang/System.out:java.io.PrintStream
ldc "Rethrow from var 'tlr'!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L19 {
aload1
invokevirtual java/lang/Exception printStackTrace(()V);
}
L7 {
getstatic java/lang/System.out:java.io.PrintStream
ldc "Finally!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
}
L20 {
goto L18
}
L11 {
astore3
getstatic java/lang/System.out:java.io.PrintStream
ldc "Finally!" (java.lang.String)
invokevirtual java/io/PrintStream println((Ljava/lang/Object;)V);
aload3
athrow
}
L18 {
return
}
L9 {
}
}
- BytecodeDisassembler version:
!access: ACC_PUBLIC, ACC_STATIC (9)
public static void println(java.lang.Object) {
desc: (Ljava/lang/Object;)V
maxStack: 3, maxLocals: 4
Label_0:
LINE 7 -> Label_0
aload 0
ifnull Label_2
Label_1:
LINE 8 -> Label_1
getstatic java.lang.System.out (type: java.io.PrintStream)
aload 0
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_2:
LINE 10 -> Label_2
FRAME[type: F_SAME, locals: 0, local: {}, stacks: 0, stack: {}]
getstatic java.lang.System.out (type: java.io.PrintStream)
astore 1
Label_3:
LINE 11 -> Label_3
new java.io.File
dup
ldc "s" // type: java.lang.String
invokespecial java.io.File.<init>(java.lang.String)void (ownerIsInterface: false)
astore 2
Label_4:
LINE 12 -> Label_4
aload 2
invokevirtual java.io.File.getCanonicalPath()java.lang.String (ownerIsInterface: false)
pop
Label_5:
LINE 13 -> Label_5
ldc "java.io.File" // type: java.lang.String
invokestatic java.lang.Class.forName(java.lang.String)java.lang.Class (ownerIsInterface: false)
pop
Label_6:
LINE 14 -> Label_6
new java.lang.IllegalStateException
dup
ldc "Error" // type: java.lang.String
invokespecial java.lang.IllegalStateException.<init>(java.lang.String)void (ownerIsInterface: false)
athrow
Label_7:
LINE 15 -> Label_7
FRAME[type: F_SAME1, locals: 0, local: {}, stacks: 1, stack: {Reference[java.lang.RuntimeException]}]
astore 1
Label_8:
LINE 16 -> Label_8
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Rethrow from var 'thr'!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_9:
LINE 17 -> Label_9
aload 1
invokevirtual java.lang.RuntimeException.printStackTrace()void (ownerIsInterface: false)
Label_10:
LINE 22 -> Label_10
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Finally!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_11:
LINE 23 -> Label_11
goto Label_18
Label_12:
LINE 18 -> Label_12
FRAME[type: F_SAME1, locals: 0, local: {}, stacks: 1, stack: {Reference[java.lang.Exception]}]
astore 1
Label_13:
LINE 19 -> Label_13
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Rethrow from var 'tlr'!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_14:
LINE 20 -> Label_14
aload 1
invokevirtual java.lang.Exception.printStackTrace()void (ownerIsInterface: false)
Label_15:
LINE 22 -> Label_15
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Finally!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
Label_16:
LINE 23 -> Label_16
goto Label_18
Label_17:
LINE 22 -> Label_17
FRAME[type: F_SAME1, locals: 0, local: {}, stacks: 1, stack: {Reference[java.lang.Throwable]}]
astore 3
getstatic java.lang.System.out (type: java.io.PrintStream)
ldc "Finally!" // type: java.lang.String
invokevirtual java.io.PrintStream.println(java.lang.Object)void (ownerIsInterface: false)
aload 3
athrow
Label_18:
LINE 24 -> Label_18
FRAME[type: F_SAME, locals: 0, local: {}, stacks: 0, stack: {}]
return
Label_19:
TryCatchBlocks {
start: Label_0, end: Label_7, handler: Label_7, exception: java.lang.IllegalArgumentException
start: Label_0, end: Label_7, handler: Label_7, exception: java.lang.IllegalStateException
start: Label_0, end: Label_7, handler: Label_12, exception: java.io.IOException
start: Label_0, end: Label_7, handler: Label_12, exception: java.lang.ClassNotFoundException
start: Label_0, end: Label_10, handler: Label_17, exception: null
start: Label_12, end: Label_15, handler: Label_17, exception: null
}
LocalVariables {
index: 1, name: ref, start: Label_3, end: Label_7, type: java.io.PrintStream, signature: null
index: 2, name: f, start: Label_4, end: Label_7, type: java.io.File, signature: null
index: 1, name: thr, start: Label_8, end: Label_10, type: java.lang.RuntimeException, signature: null
index: 1, name: tlr, start: Label_13, end: Label_15, type: java.lang.Exception, signature: null
index: 0, name: msg, start: Label_0, end: Label_19, type: java.lang.Object, signature: null
}
}
The CodeAPI version looks weird.