Community
Participate
Working Groups
Eclipse compiles the following code: public class X<T> { T counter; public static void main(String[] args) { X<Integer> x = new X<Integer>(); x.counter = 0; System.out.println(Integer.toString(x.counter++)); } } but it creates a VerifyError at runtime: Exception in thread "main" java.lang.VerifyError: (class: X, method: main signature: ([Ljava/lang/String;)V) Incompatible object argument for function call This fails as well using jdk6, but passes using jdk7b25.
Problem comes from the generic checkcast to Integer being inserted a bit too late in the bytecode. So it comes after the field value got dup'ed on the stack (@24). Hence only the top of the stack gets cast in Integer (@25). The dup value below is not cast, and when unboxed it is not proven to be an Integer any longer. // Method descriptor #16 ([Ljava/lang/String;)V // Stack: 5, Locals: 2 public static void main(String[] arg0); 0 new X [1] 3 dup 4 invokespecial X() [17] 7 astore_1 8 aload_1 9 iconst_0 10 invokestatic Integer.valueOf(int) : Integer [18] 13 putfield X.counter : Object [24] 16 getstatic System.out : PrintStream [26] 19 aload_1 20 dup 21 getfield X.counter : Object [24] 24 dup_x1 25 checkcast Integer [19] 28 invokevirtual Integer.intValue() : int [32] 31 iconst_1 32 iadd 33 invokestatic Integer.valueOf(int) : Integer [18] 36 putfield X.counter : Object [24] 39 invokevirtual Integer.intValue() : int [32] 42 invokestatic Integer.toString(int) : String [36] 45 invokevirtual PrintStream.println(String) : void [40] 48 return
Ideally, we should produce: public static void main(String[] args); 0 new X [1] 3 dup 4 invokespecial X() [22] 7 astore_1 [x] 8 aload_1 [x] 9 iconst_0 10 invokestatic Integer.valueOf(int) : Integer [23] 13 putfield X.counter : Object [29] 16 getstatic System.out : PrintStream [31] 19 aload_1 [x] 20 dup 21 getfield X.counter : Object [29] 24 checkcast Integer [24] 27 invokevirtual Integer.intValue() : int [37] 30 dup_x1 31 iconst_1 32 iadd 33 invokestatic Integer.valueOf(int) : Integer [23] 36 putfield X.counter : Object [29] 39 invokestatic Integer.toString(int) : String [41] 42 invokevirtual PrintStream.println(String) : void [45] 45 return
Note that problem also arise in other type of references, e.g. public class X<T> { T counter; public static void main(String[] args) { bar(new X<Integer>()); new Y().foo(); new Y().baz(); } static void bar(X<Integer> x) { x.counter = 0; System.out.print(Integer.toString(x.counter++)); } } class Y extends X<Integer> { Y() { this.counter = 0; } void foo() { System.out.print(Integer.toString(counter++)); } void baz() { System.out.println(Integer.toString(this.counter++)); } } should print "000"
Added AutoboxingTest#test154-155
Induced changes are likely too big for inclusion in 3.4RC3. Also given other Java6 compilers do fail it as well, this is not super critical.
Created attachment 101778 [details] Proposed patch patch is combined with cleanup suggest in bug 231861#c17
Btw javac7 produces a longer/unoptimal sequence: // Method descriptor #21 ([Ljava/lang/String;)V // Stack: 4, Locals: 5 public static void main(String[] arg0); 0 new X [2] 3 dup 4 invokespecial X() [3] 7 astore_1 8 aload_1 9 iconst_0 10 invokestatic Integer.valueOf(int) : Integer [4] 13 putfield X.counter : Object [5] 16 getstatic System.out : PrintStream [6] 19 aload_1 20 astore_2 21 aload_2 22 getfield X.counter : Object [5] 25 checkcast Integer [7] 28 astore_3 29 aload_2 30 aload_2 31 getfield X.counter : Object [5] 34 checkcast Integer [7] 37 invokevirtual Integer.intValue() : int [8] 40 iconst_1 41 iadd 42 invokestatic Integer.valueOf(int) : Integer [4] 45 dup_x1 46 putfield X.counter : Object [5] 49 astore 4 51 aload_3 52 invokevirtual Integer.intValue() : int [8] 55 invokestatic Integer.toString(int) : String [9] 58 invokevirtual PrintStream.println(String) : void [10] 61 return
Added AutoboxingTest#test156-158
Comment on attachment 101778 [details] Proposed patch The proposed patch does not quite work. More work is needed.
Created attachment 106131 [details] Better patch for 3.4.x
Simpler solution now produces: // Method descriptor #21 ([Ljava/lang/String;)V // Stack: 5, Locals: 2 public static void main(String[] args); 0 new X [1] 3 dup 4 invokespecial X() [22] 7 astore_1 [x] 8 aload_1 [x] 9 iconst_0 10 invokestatic Integer.valueOf(int) : Integer [23] 13 putfield X.counter : Object [29] 16 getstatic System.out : PrintStream [31] 19 aload_1 [x] 20 dup 21 getfield X.counter : Object [29] 24 checkcast Integer [24] 27 dup_x1 28 invokevirtual Integer.intValue() : int [37] 31 iconst_1 32 iadd 33 invokestatic Integer.valueOf(int) : Integer [23] 36 putfield X.counter : Object [29] 39 invokevirtual Integer.intValue() : int [37] 42 invokestatic Integer.toString(int) : String [41] 45 invokevirtual PrintStream.println(String) : void [45] 48 return
Also added AutoboxingTest#test160-164 Released for 3.3.x maintenance branch.
Released for 3.4.1 Released for 3.5M1 Fixed
Verified for 3.5M1 using I20080805-1307
Verified for 3.4.1 using build M20080827-2000.