Community
Participate
Working Groups
Hello, [Short summary: For a given method bytecode instruction(s) are generated which will never be executed, neither in a normal nor in an exceptionel control flow. ] For the following method: _________________________ public void ifTryCatchFinallyMethod(){ for (int i = 0 ; i < 100 ; i++){ try { if (i == 50){ i++; continue; } else { try{ foo(); // System.out.println("Within try..."); // 1 continue; } catch (Exception e){ foo(); // System.out.println("Within catch..."); // 2 } finally { foo(); // System.out.println("within inner finally: (round: "+i+")"); // 3 } } } finally { foo(); // System.out.println("within outer finally: (round: "+i+")"); // 4 } } } the compiler generates the following bytecode instructions: ___________________________________________________________ LINE 75: [START OF VARIABLE 0 (localvariableindex = 0)]: de.tud.bat.testclasses.ControlFlowsTestClass this 0: iconst_0 /* stack change = 1 */ 1: istore_1 /* stack change = -1 */ [START OF VARIABLE 1 (localvariableindex = 1)]: int i 2: goto /* stack change = 0 */ #90 LINE 78: TRY[2]{ 5: iload_1 /* stack change = 1 */ 6: bipush = 50 /* stack change = 1 */ 8: if_icmpne /* stack change = -2 */ #20 LINE 79: 11: iinc_1 /* stack change = 0 */ LINE 80: 14: jsr /* stack change = 1 */ #79 17: goto /* stack change = 0 */ #87 LINE 84: TRY[0]{ TRY[1]{ 20: aload_0 /* stack change = 1 */ 21: invokespecial <de.tud.bat.testclasses.ControlFlowsTestClass>.foo () : void /* stack change = -1 */ LINE 85: 24: jsr /* stack change = 1 */ #55 27: jsr /* stack change = 1 */ #79 30: goto /* stack change = 0 */ #87 LINE 86: }[0] CATCH [0](java.lang.Exception) 33: astore_2 /* stack change = -1 */ LINE 87: [START OF VARIABLE 2 (localvariableindex = 2)]: java.lang.Exception e 34: aload_0 /* stack change = 1 */ 35: invokespecial <de.tud.bat.testclasses.ControlFlowsTestClass>.foo () : void /* stack change = -1 */ [END OF VARIABLE 2] }[1] 38: goto /* stack change = 0 */ #49 LINE 88: CATCH [1] (any exception) 41: astore_4 /* stack change = -1 */ 43: jsr /* stack change = 1 */ #55 46: aload_4 /* stack change = 1 */ 48: athrow /* stack change = 0 */ 49: jsr /* stack change = 1 */ #55 52: goto /* stack change = 0 */ #73 55: astore_3 /* stack change = -1 */ LINE 89: 56: aload_0 /* stack change = 1 */ 57: invokespecial <de.tud.bat.testclasses.ControlFlowsTestClass>.foo () : void /* stack change = -1 */ LINE 83: 60: ret_3 /* stack change = 0 */ 62: goto /* stack change = 0 */ #73 LINE 92: }[2] CATCH [2] (any exception) 65: astore_6 /* stack change = -1 */ 67: jsr /* stack change = 1 */ #79 70: aload_6 /* stack change = 1 */ 72: athrow /* stack change = 0 */ 73: jsr /* stack change = 1 */ #79 76: goto /* stack change = 0 */ #87 79: astore_5 /* stack change = -1 */ LINE 93: 81: aload_0 /* stack change = 1 */ 82: invokespecial <de.tud.bat.testclasses.ControlFlowsTestClass>.foo () : void /* stack change = -1 */ LINE 77: 85: ret_5 /* stack change = 0 */ LINE 75: 87: iinc_1 /* stack change = 0 */ 90: iload_1 /* stack change = 1 */ 91: bipush = 100 /* stack change = 1 */ 93: if_icmplt /* stack change = -2 */ #5 LINE 97: [END OF VARIABLE 1] 96: return /* stack change = 0 */ The "goto 73" instruction with "offset 62" will never be reached. The instruction with offset 62 is no jump target and is not a handler instruction. Even though this is not a violation of the JVM Spec. this behaviour is nevertheless suspicious.
Using latest code, I get: public void ifTryCatchFinallyMethod(); /* Stack: 2, Locals: 7 */ Code attribute: 0 iconst_0 1 istore_1 2 goto 84 5 iload_1 6 bipush 50 8 if_icmpne 20 11 iinc 1 1 14 jsr 70 17 goto 81 20 aload_0 21 invokespecial #17 <Method A#foo() void> 24 jsr 49 27 jsr 70 30 goto 81 33 astore_2 34 aload_0 35 invokespecial #17 <Method A#foo() void> 38 goto 56 41 astore 4 43 jsr 49 46 aload 4 48 athrow 49 astore_3 50 aload_0 51 invokespecial #17 <Method A#foo() void> 54 ret 3 56 jsr 49 59 goto 78 62 astore 6 64 jsr 70 67 aload 6 69 athrow 70 astore 5 72 aload_0 73 invokespecial #17 <Method A#foo() void> 76 ret 5 78 jsr 70 81 iinc 1 1 84 iload_1 85 bipush 100 87 if_icmplt 5 90 return Exception Table: [pc: 20, pc: 33] -> 33 when : java.lang.Exception [pc: 20, pc: 27] -> 41 when : any [pc: 33, pc: 38] -> 41 when : any [pc: 56, pc: 59] -> 41 when : any [pc: 5, pc: 17] -> 62 when : any [pc: 20, pc: 30] -> 62 when : any [pc: 33, pc: 62] -> 62 when : any [pc: 78, pc: 81] -> 62 when : any I don't see what bytecodes are unreachable. Could you please comment on this output?
Hello, > public void ifTryCatchFinallyMethod(); [...] > I don't see what bytecodes are unreachable. Could you please comment > on this output? I'm sorry - I thought I was using the most current version of Eclipse but I wasn't. The most current version does not longer produce unreachable instructions for the IfTryCatchFinallyMethod. However, the Versions Eclipse 3.0M3 and the Nightly Build with Build id: 200310070010 (Okt. 7.) still produce unreachable instructions. For the following class: public class Test { Object anchorInstruction = new Object(); public String toString(){ StringBuffer stringBuffer = new StringBuffer(); Object instr = anchorInstruction; while (true){ stringBuffer.append(instr); if (instr != null) { if (!(instr instanceof Exception)) stringBuffer.append("\n"); } else break; } return stringBuffer.toString(); } } The following Bytecode Instructions are generated: public java.lang.String toString(); Code: Stack=2, Locals=3, Args_size=1 0: new #21; //class StringBuffer 3: dup 4: invokespecial #22; //Method java/lang/StringBuffer."<init>":()V 7: astore_1 8: aload_0 9: getfield #13; //Field anchorInstruction:Ljava/lang/Object; 12: astore_2 13: aload_1 14: aload_2 15: invokevirtual #26; //Method java/lang/StringBuffer.append: (Ljava/lang/Object;)Ljava/lang/StringBuffer; 18: pop 19: aload_2 20: ifnull 46 23: aload_2 24: instanceof #28; //class Exception 27: ifne 43 30: aload_1 31: ldc #30; //String \n 33: invokevirtual #33; //Method java/lang/StringBuffer.append: (Ljava/lang/String;)Ljava/lang/StringBuffer; 36: pop 37: goto 43 40: goto 46 43: goto 13 46: aload_1 47: invokevirtual #35; //Method java/lang/StringBuffer.toString:() Ljava/lang/String; 50: areturn The "goto 46" instruction with offset 40 is unreachable. Best regards, Michael
This is a known issue as a result of our branch chaining (inline branch to a branch). Other example (with jsr generation disabled): public class X { public static void main(String[] argv){ int var; a: do { try { if (argv != null) break a; } finally { var = 12; System.out.print("SUB-"); } } while (argv.length == 0); System.out.println(var); } } 0 aload_0 1 ifnull 35 4 bipush 12 6 istore_1 7 getstatic #21 <Field java.lang.System#out java.io.PrintStream> 10 ldc #23 <String "SUB-"> 12 invokevirtual #29 <Method java.io.PrintStream#print(java.lang.String arg) void> 15 goto 51 18 goto 35 21 astore_2 22 bipush 12 24 istore_1 25 getstatic #21 <Field java.lang.System#out java.io.PrintStream> 28 ldc #23 <String "SUB-"> 30 invokevirtual #29 <Method java.io.PrintStream#print(java.lang.String arg) void> 33 aload_2 34 athrow 35 bipush 12 37 istore_1 38 getstatic #21 <Field java.lang.System#out java.io.PrintStream> 41 ldc #23 <String "SUB-"> 43 invokevirtual #29 <Method java.io.PrintStream#print(java.lang.String arg) void> 46 aload_0 47 arraylength 48 ifeq 0 51 getstatic #21 <Field java.lang.System#out java.io.PrintStream> 54 iload_1 55 invokevirtual #33 <Method java.io.PrintStream#println(int arg) void> 58 return Our branch chaining instruction should be smart enough to realize that the goto instruction in 18 isn't reachable and should be optimized out (no fall through since previous instruction is a goto elsewhere). Need to be careful about possible subsequent backward branches to this location (but we can figure if a label got placed at same location or not). Note that these dead bytecode are non lethal, but should still be removed.
should investigate within 3.0 time frame
Not for 3.0
Removing milestone of deferred item.
reopening
Olivier - is this still an issue ? Especially in the light of stackmap tables.
Closing as WORKSFORME since there is no more deadbytecodes with 3.3RC4