# Saturday, 13 March 2004
« To Invert Or Not To Invert | Main | New Snapshot »
JDK 1.5 beta

Yesterday I looked at the JDK 1.5 beta that Sun released recently. There appears not to be a complete list of changes to the VM yet and the only things I found were a few new modifier bits (that haven't yet stabilized) and the fact that class literals are finally supported in the VM. This is important for IKVM.NET, because it makes class literals in statically compiled code work better and more efficient.

For a quick refresher of how class literals are currently compiled, let's look at how the following class is compiled:

class ClassLiteral
  public static void main(String[] args)

Compiling this with Jikes 1.19 and then disassembling it (I've left out the default constructor that the compiler generated):

class ClassLiteral extends java/lang/Object

static java/lang/Class class$java$lang$String
// Unknown attribute : Synthetic//

public static main([Ljava/lang/String;)V
// attrib length: 53
// max stacks: 3
// max locals: 1
// code length: 25
0 getstatic <Field java/lang/System java/io/PrintStream out>
3 getstatic <Field ClassLiteral java/lang/Class class$java$lang$String>
6 dup
7 ifnonnull 21
10 pop
11 ldc "[Ljava.lang.String;"
13 iconst_0
14 invokestatic <Method ClassLiteral class$(Ljava/lang/String;Z)Ljava/lang/Class;>
17 dup
18 putstatic <Field ClassLiteral java/lang/Class class$java$lang$String>
21 invokevirtual <Method java/io/PrintStream println(Ljava/lang/Object;)V>
24 return

static class$(Ljava/lang/String;Z)Ljava/lang/Class;
// Unknown attribute : Synthetic
// attrib length: 55
// max stacks: 3
// max locals: 4
// code length: 23
0 aload_0
1 invokestatic <Method java/lang/Class forName(Ljava/lang/String;)Ljava/lang
4 iload_1
5 ifne 11
8 invokevirtual <Method java/lang/Class getComponentType()Ljava/lang/Class;>

11 areturn
12 new java/lang/NoClassDefFoundError
15 dup_x1
16 invokespecial <Method java/lang/NoClassDefFoundError <init>()V>
19 invokevirtual <Method java/lang/Throwable initCause(Ljava/lang/Throwable;)
22 athrow
Exception table:
start_pc = 0
end_pc = 12
handler_pc = 12
catch_type = java/lang/ClassNotFoundException

The amount of code generated is pretty bizarre. Note that this isn't Jikes' fault, there just isn't a way to do it better. Now, here is what it looks like compiled with javac from the 1.5 beta (specifying the -target 1.5 option):

class ClassLiteral extends java/lang/Object

public static main([Ljava/lang/String;)V
// attrib length: 38
// max stacks: 2
// max locals: 1
// code length: 10
0 getstatic <Field java/lang/System java/io/PrintStream out>
3 ldc_w java/lang/String
6 invokevirtual <Method java/io/PrintStream println(Ljava/lang/Object;)V>
9 return

This looks a lot better! No new bytecode instruction was added, instead the ldc instruction was modified to allow referencing a CONSTANT_Class_info . When the VM encounters this it loads the class and pushes the class object on the stack. I added support for this to IKVM.NET (not in cvs yet) in about 15 minutes. When JDK 1.1 was released (the first version to support class literals in the source), I wondered why they didn't add VM support at the same time, but fortunately they finally got around to it.


If you looked closely at the Jikes generated code, you may have noticed that Jikes actually loads the string array class ("[Ljava.lang.String;") instead of java.lang.String. Why does it do this? It does this, because it correctly implements the JLS. The JLS says that class literals should not cause a class to be initialized. Doing a Class.forName() initializes the class, but when you initialize an array class you don't initialize the component type class. So this is a clever trick. Javac doesn't do this, so it (incorrectly) causes the class to be initialized.


Why does this change help statically compiled code in IKVM.NET? Performance is a bit better, but that's not the most important difference. The real benefit shows up when you statically compile code into multiple assemblies. If one assembly references a class in another assembly via a class literal, you'd better be sure that the referenced assembly is already loaded in the AppDomain, otherwise the IKVM.NET runtime is unable to find the class. In the new (JDK 1.5) way of references class literals, it is no longer opaque to ikvmc, so it can now compile the construct in such a way that the class literal causes the appropriate assembly to be loaded by the .NET runtime when it is executed.


Something that struck me a funny is the new StringBuilder class that JDK 1.5 includes. It's almost identical to StringBuffer, except that it is not thread safe. If you look at the Rotor source code, you can see that the .NET StringBuilder also started life as StringBuffer. Now if the next version of .NET includes a thread safe version of StringBuilder and name it StringBuffer, we've come full circle ;-)

Saturday, 13 March 2004 18:38:45 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]