# Thursday, 24 July 2003
GridBagLayout and more AWT

I did some work on the GNU Classpath GridBagLayout and it is now almost done (a large part was already done by Michael Koch). Obviously, writing the GridBagLayout code requires a good understanding of how it works. I never bothered to really understand the GridBagLayout, but I did use it quite frequently, a couple of years ago. I remember it was mostly a process of trial and error. After taking the time to figure out how it works, I must say that I actually really like it. It has a somewhat bad reputation in the Java community, but I think it's quite nice.

I can't leave it on that positive note, of course ;-) I have to criticize it as well. Sun has this really nasty habit of renaming virtual methods (adding aliases). This is not a good idea, to put it mildly. In JDK 1.4 they introduced: getLayoutInfo, adjustForGravity, getMinSize and arrangeGrid. These methods offer no new functionality, they are "replacements" for GetLayoutInfo, AdjustForGravity, GetMinSize and ArrangeGrid. So just because someone didn't abide by the method naming rules, some idiot now decides to enormously complicate the class.

You might think, what's the big deal? The problem is that when you're overriding a virtual method that has two names, you don't know which one you should override. Overriding both usually doesn't work either because you usually want to call the super class implementation one of which in turn usually calls the other version of the method, thus resulting in infinite recursion.

Anyway, I made new snapshots. Source and binaries.

What's new?

  • More AWT support, still nowhere near usable. But see these screenshots for some non-trivial stuff that is (partially) working.
  • Statically compiled classes are now annotated with a custom attribute for each interface they implement. This enables the Class.getInterfaces() to work correctly for statically compiled classes.
  • Fixed a bug in Method.getModifiers() for constructors in statically compiled classes, that caused them to appear final.
Thursday, 24 July 2003 17:38:07 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Monday, 21 July 2003
Abstract Windowing Toolkit

Originally I had titled this item "Afwul Windowing Toolkit", but then I decided to look up the dictionary definition of abstract. It's one of those words, like its close relative virtual, that we (programmers) like to use a lot using our own private (to our group) definition, but what else does it mean?

Here are some definitions courtesy of yourDictionary.com

ab·stract
adj.

  1. Considered apart from concrete existence: an abstract concept.
  2. Not applied or practical; theoretical. See Synonyms at theoretical.
  3. Difficult to understand; abstruse: abstract philosophical problems.
  4. Thought of or stated without reference to a specific instance: abstract words like truth and justice.
  5. Impersonal, as in attitude or views.
  6. Having an intellectual and affective artistic content that depends solely on intrinsic form rather than on narrative content or pictorial representation: abstract painting and sculpture.

I always thought that the abstract in AWT referred to meaning 4, which is closest to our programmer definition, but maybe the joke's on us and did the original designers (and I use the term loosely) of AWT have meanings 2, 3 and 6 in mind ;-)

As you probably guessed from the above, I did a little work on AWT support. Here are two trivial test apps that I got working:


AwtTest.java. Getting FontMetrics, Graphics and Frame insets working. 

 
FlowLayoutTest.java. Button, TextField, Label, Panel, FlowLayout and BorderLayout. Also helped me figure out how ambient properties (don't) work.

Please note that only a very small percentage of AWT is implemented at the moment, so don't expect any useful applications to actually work.

What else is new?

  • ikvmc now uses local variable name debugging information (if available) to name method arguments.
  • Updated to work with current GNU Classpath CVS.
  • Added SO_TIMEOUT and SO_REUSEADDR support to PlainDatagramSocketImpl.

BTW, the included classpath.dll contains a few Classpath AWT patches that haven't been committed to Classpath CVS yet.

Updated the binaries and source snapshots.

Monday, 21 July 2003 14:13:45 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 10 July 2003
Benchmarks, strictfp and other floating point stuff

Mark Wielaard did some benchmarks of some of the free JVMs available.

I noted on the Classpath mailing list that the IKVM floating point performance is probably overstated, because IKVM doesn't implement FP correctly. It uses the .NET framework FP instructions and methods and those in turn are implemented using the x86 FP instructions.

The original JVM specification was very strict in specifying floating point operations. Basically, it mapped 100% onto the Sparc floating point model and this caused spec compliant FP code to be slow on Intel. I don't think any of the early VMs correctly implemented the spec so this wasn't really a problem. I don't know why early the VM implementers didn't implement the spec, maybe they felt the performance cost was too high or maybe they just didn't find it an interesting issue (the "problem" is that the Intel FP results are actually too accurate).

In JDK 1.2 Sun introduced the strictfp keyword and corresponding JVM method and class access flag. Interestingly, they loosened the default FP requirements and specified the original FP behavior for methods (or classes) marked with the strictfp keyword.

IKVM doesn't implement strictfp at the moment, but this isn't the whole story. For trigonometric* functions (e.g. Math.sin()) IKVM uses the equivalent .NET Math functions and those are (probably) implemented using the x86 FP instructions and these are not compliant with the JVM specification and I think that in this case the Intel instructions are not more accurate than required, but actually less accurate. So this is a real problem that should be fixed at some point in the future.

*This probably also applies to other Math functions, like Math.exp, Math.log, Math.sqrt, etc.

Thursday, 10 July 2003 11:08:38 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 19 June 2003
One Year Ago Today

It's been exactly one year since I started blogging about the development of IKVM.NET. I actually started development about a month earlier on the 22nd of May.

To celebrate this, I've created a time-line of significant (or interesting) events that happened in the past year.

2002-05-22

Started development on a project called "bytecode". I started by porting my Java class file reader from Java to C#.

2002-06-19

Started my IK<<VM.NET Radio weblog about "The Development of a Java VM for .NET"

2002-06-27

"Hello, World!" runs for the very first time. Replaced the << in the name with a dot, because Radio doesn't escape the title properly.

2002-08-07

First version of netexp is released. Java code can now directly use .NET types.

2002-08-12

The static compiles makes its appearance. For the first time the binary snapshot contains a statically compiled classpath.dll.

2002-09-03

Very basic AWT support is introduced.

2002-09-09

Class loader support makes its first appearance.

2002-10-25

James runs!

2002-11-01

Zoltan Varga starts to work on getting IKVM to run on Mono.

2002-12-19

Created the IKVM.NET SourceForge project. Dropped the first dot from the name.

2002-12-28

Eclipse starts up!

2003-01-17

Zoltan Varga gets IKVM to run HelloWorld on Mono.

2003-03-13

Moved blog from Radio to BlogX.

2003-04-05

Added support for using value types from Java.

2003-05-10

Zoltan Varga gets IKVM to run Eclipse on Mono.

2003-06-19

The IKVM.NET blog celebrates its first birthday.

Thanks to everyone who contributed to IKVM.NET in the past year. It's been great fun and I hope the coming year will be as productive as this past year has been.

Thursday, 19 June 2003 11:22:49 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
# Monday, 02 June 2003
Invokespecial

One of the more interesting bytecode instructions is invokespecial. During Java's early days this instruction was called invokenonvirtual, but in JDK 1.0.2 it was renamed to invokespecial to indicate it has some very special semantics.

Invokespecial is used in three ways, to call instance initializers (constructors),  to call base class methods non-virtually and to call private methods. It's worth mentioning that, unlike the CLR call instruction, invokespecial cannot be used to call arbitrary methods, it can only call methods in the current class or in a base class of of the current class (and then only on references of the type of the current class, or subclasses of it). The JVM's invokevirtual is very similar to the CLR's callvirt instruction. In addition to invokespecial and invokevirtual, the JVM also has invokestatic and invokeinterface to invoke static methods and interface methods, respectively. The CLR has no special instructions for that, it uses the call and callvirt instructions to call static and interface methods.

Prior to JDK 1.1, invokespecial called the exact method specified in the instruction. In JDK 1.1 this behavior was changed, because it caused versioning problems. Here is an example of what could go wrong:

Component A - version 1

public class GrandParent {
  protected void myMethod() {
    // ...
  }
}
public class Parent extends GrandParent {
}

Component B

public class Child extends Parent {
  protected void myMethod() {
    // ...
    super.myMethod();
  }
}

The compiler would compile the super.myMethod() call in Child to invokespecial GrandParent.myMethod(). Now suppose a new version of Component A is released:

Component A - version 2

public class GrandParent {
  protected void myMethod() {
    // ...
  }
}
public class Parent extends GrandParent {
  protected void myMethod() {
    // ...
    super.myMethod();
  }
}

When Component B is used (without recompiling) with this new version of Component A, the super.myMethod call in Child will still go directly to GrandParent.myMethod and this is probably not what the author of Component A had intended.

To fix this, invokespecial was changed to search the class hierarchy if the called class is a base class of the caller (from the caller's base class on up), but only if the caller's class has the ACC_SUPER bit set in the class' access_flags mask. All Java compilers since JDK 1.1 always set the ACC_SUPER flag. It's interesting to note that the current Sun JRE 1.4.1 still honors a cleared ACC_SUPER flag.

Why doesn't the CLR have an equivalent of the ACC_SUPER flag? The reason is that it isn't needed. When, for example, the C# compiler compiles a base method call, it emits a call instruction to the immediate base class of the caller, even if that class isn't the one that implements the called method[1]. When the JIT is resolving the call it searches up the class hierarchy to find the actual method.

Comparison JVM and CLR call instructions

JVM

CLR

Notes

invokespecial

call

invokespecial checks the object reference for null, call doesn't.

invokevirtual

callvirt

invokeinterface

callvirt

Like in other places where the JVM consumes interface references, the object reference doesn't have to statically implement the called interface type.

invokestatic

call

One final issue relevant to IKVM here is that invokespecial requires the object reference to be checked for null, the CLR call instruction doesn't do this (for this reason the C# compiler uses callvirt when calling non-virtual methods, except when explicitly calling a base class method of course, it always makes sure the object reference isn't null). The IKVM compiler has to insert an explicit check for null references when it is compiling invokespecial. It took me a while to come up with an efficient way of doing this. Javac faces a similar issue when it compiles the explicit instantation of an inner class:

public class Foo {
  public class Inner {}
  static void method() {
    // next line throws a NullPointerException
    ((Foo)null).new Inner();
  }
}

Why does this throw a NullPointerException? The answer may be surprising, but it is because Javac inserts a call to ((Foo)null).getClass() to make it throw a NullPointerException if the outer this is null. If it didn't do this, you'd run into a NullPointerException later on when one of Inner's methods tried to use the outer this and this would be a very surprising and hard to find bug. However, I didn't want to use this trick because it isn't particularly efficient. What I came up with is the following trick:

ldvirtftn instance string System.Object::ToString()
pop

The JIT compiles this to:

mov   eax,dword ptr [ecx]
mov   eax,dword ptr [eax+28h]

If the reference in question is null, the first instruction causes an x86 trap that the CLR translates into a NullReferenceException. The second instruction is overhead and hopefully a future version of the JIT will stop emitting it, but it isn't very expensive anyway.

Note to self: Consider adding an optimization to the IKVM compiler to detect Javac's null reference check:

invokevirtual java/lang/Object.getClass()
pop

and replace it with the more efficient ldvirtftn based check above. This could actually be an important optimization, because getClass() on IKVM is pretty expensive.

[1] When the base classes are in the same module, the C# actually emits a call to the class the defines the method, instead of to the direct base class. This is an optimization, because it saves the JIT from having to search for the method in the class hierarchy. When all classes are in the same module, there obviously aren't any versioning issues, since the module is always built as one unit.

Monday, 02 June 2003 17:56:11 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 30 May 2003
Update

After a long hiatus, finally another update. Many changes, mostly clean up. I moved some of the custom attributes to a new assembly OpenSystem.Java.dll. Hopefully this will be useful for the dotGNU Java compiler.

I made new source and binaries snapshots available, these are based on the current GNU Classpath cvs code + one patch.

Friday, 30 May 2003 14:17:50 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
Redmond
Like Ingo, I'll be in Redmond on the 25th and 26th of June. Anyone else?
Friday, 30 May 2003 08:51:15 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Saturday, 10 May 2003
Eclipse on Mono

Zoltan Varga just posted the following to the ikvm-developers list:

Hi,

I got Eclipse running under IKVM under Mono. A screenshot, Makefiles etc. can be found here:

http://www.nexus.hu/vargaz/

The port uses a JNI provider written in C which works with mono. Eclipse startup up+shuts down in about 1 minute on an 1Ghz PC, while consuming about 90MB of memory. It works with Mono 0.24 and current mono CVS.

I made some modifications to IKVM which are in the attached patch.

Could they be applied to the official version?

The modifications are:

- ikvm.build: fix case of directory names

- ClassLoaderWrapper.cs: Create Assemblies with Run flag, so the

runtime can apply some memory saving optimizations.

- TypeWrapper.cs: Cache field lookups

- classpath.cs: Make shared library loading work under UNIX

There is one other issue: Mono does not yet support the

GetLoadedModules() method, so this has to be commmented out in classpath.cs and in Handler.java.

BTW: The IBM RVM project includes a nice JNI testsuite:

http://www-124.ibm.com/developerworks/oss/jikesrvm/

The Mauve test status of mono:

191 of 7294 tests failed

Would it be possible to post the Mauve test results of IKVM somewhere (with -verbose) so I can compare it to the Mono version?

have fun

Zoltan

Wow! This is great news.

Saturday, 10 May 2003 13:33:40 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 09 May 2003
Class.forName()

Stuart asks:

Can IKVMC handle Class.forName if the target class is in an assembly that isn't directly referenced by the assembly making the call?

Yes, but then you have to specify the assembly qualified name of the class. For example:

Class.forName("System.Windows.Forms.Form, " +
    "System.Windows.Forms, " +
    "Version=1.0.3300.0, " +
    "Culture=neutral, " +
    "PublicKeyToken=b77a5c561934e089");

Another alternative, when the class hasn't been compiled to an assembly, is to instantiate a class loader and use that to load the class:

URL[] classpath = new URL[1];
classpath[0] = new URL("...");
ClassLoader loader = new URLClassLoader(classpath);
Class clazz = loader.loadClass("...");

Currently, when ikvm.exe isn't used to start your application you don't have an application class loader that loads classes from the directories specified in the CLASSPATH environment variable.

Friday, 09 May 2003 11:16:56 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Monday, 28 April 2003
DotGNU & New Snapshot

Saturday I joined the DotGNU IRC meeting to discuss their Java support. We decided to make sure that our efforts will be interoperable.
They are working on a Java source to IL compiler and this complements IKVM's byte code to IL compiler nicely. We'll be working together to create a standard format for remapping Java classes to .NET classes and define custom attributes to express Java semantics that don't map directly onto the .NET standard attributes.

I made new source and binaries snapshots available. Not many changes:

  • invokespecial byte code now checks for null references before calling the method. I intend to write an item on invokespecial in the future, because it is quite an interesting instruction with a bit of a history.
  • Improved method overriding handling for methods that are less accessible than the method they override. Java allows this, but .NET doesn't. It is handled by giving the overriding method the same (or better) accessibility as the overriden method.
    IMHO this is a design flaw in the CLR, because it makes it a breaking change to widen the access of a virtual method in a new version of a type.
  • Improved ikvmc's handling of -recurse and added wildcard support to file arguments.
Monday, 28 April 2003 10:54:39 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]