4
public class Config {
    public static Ref<Config> s = new Ref<Config>(new Config());
    static class Ref<T> {
        public T r;
        public Ref(T r) {
            this.r = r;
        }
    }
    public int INTERVAL = 4000;

    public Config()
    {
    }

    public static void main(String[] args) {
        System.err.println(Config.s.r.INTERVAL);
    }
}

Running this cause to java.lang.VerifyError

Exception in thread "main" java.lang.VerifyError: (class: Config, method: main signature: ([Ljava/lang/String;)V) Incompatible type for getting or setting field

If i run this:

System.err.println(Config.s.r);

Than no exception is thrown and in debug i can see the value of 'Config.s.r.INTERVAL'

When i run with -verbose:class i can see that Ref class is not loaded in the first example. In the second example the Ref class is loaded.

This is the only class in the project compiled and run with java6. The problem is not in the jvm or 3rd party.

i guess that the problem is combine in the same line static variable initialization and instance variable.

running like this - work:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

Ps. The code is much complicated and it separated to 2 classes in dev env. I just limit it to short example

Jdk - Java SE 6 [1.6.0_65-b14-462] OS - Mac

Avihai Marchiano
  • 3,837
  • 3
  • 38
  • 55

2 Answers2

1

I guess its a bug. Any way workaround is to split to 2 lines , like this:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

the diff between the assembly (the diff is in only in the main function ): The working one , break 2 lines:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #22; //Field s:LRef;
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   6:   checkcast   #1; //class Config
   9:   astore_1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   13:  aload_1
   14:  getfield    #27; //Field INTERVAL:I
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

The broken one - all in one line:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   3:   getstatic   #22; //Field s:LRef;
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   9:   getfield    #27; //Field INTERVAL:I
   12:  checkcast   #1; //class Config
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}

By the help of @Hot Licks identity that the problem is in the checkcast in the broken version which check the field (int) and not the class. Open bug to Oracle.

Avihai Marchiano
  • 3,837
  • 3
  • 38
  • 55
  • 1
    This suggests that it's a compiler error. Someone who's got more time that work might try doing `javap` on the two versions of the code and seeing how they differ. – Hot Licks Jan 28 '14 at 21:40
  • Wow! The broken one is attempting to do a `checkcast` on an `int`! The compiler is major effed up. If you're into that sort of thing, file it as a javac bug with Oracle. – Hot Licks Jan 29 '14 at 17:04
  • How do you see this ? isnt the checkcast is the same for both? its my first time i tried to read such a thing. – Avihai Marchiano Jan 29 '14 at 19:33
  • 1
    It's a stack architecture. The checkcast operates on the thing pushed onto the stack immediately before it. – Hot Licks Jan 29 '14 at 19:44
0

Translated:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field s -- place is stack location 1
   0:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using stack 1 as base -- place in stack location 1
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   // Peform checkcast on stack location 1 to assure it's a "Config" -- leave stack unchanged
   6:   checkcast   #1; //class Config
   // Store stack location 1 into local variable 1.  Pop stack.
   9:   astore_1
   // Fetch static field System.err -- place in stack location 1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch local variable 1 -- place in stack location 2
   13:  aload_1
   // Fetch instance field I using stack 2 as base -- place in stack location 2 
   14:  getfield    #27; //Field INTERVAL:I
   // Invoke println, using stack 1 as base, stack 2 as parm -- stack becomes empty
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

The broken one:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field System.err -- place is stack location 1
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch static field s -- place in stack location 2
   3:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using location 2 as base -- place in stack location 2
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   // --- Note that the checkcast should be here ---
   // Fetch instance field I using location 2 as base -- place in stack location 2
   9:   getfield    #27; //Field INTERVAL:I
   // Perform checkcast on location 2, to assure it's a "Config" (it isn't)
   12:  checkcast   #1; //class Config
   // Invoke println using location 1 as base, location 2 as parm.
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}
Hot Licks
  • 47,103
  • 17
  • 93
  • 151