# Saturday, 15 February 2003
Mauve

Zoltan has been working on running the Mauve testsuite on IKVM.NET running on Mono  and I've been doing the same on MS .NET.

Current status on MS .NET: 298 of 7338 tests failed
Current status on Mono: 143 of 3996 tests failed

Thanks to Mark for getting me started with Mauve and thanks to Zoltan for his excellent work on getting ikvm running on Mono.

Saturday, 15 February 2003 19:10:50 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Wednesday, 12 February 2003
Getting Eclipse to run

In the comments of the previous item John asked for specific instructions to get Eclipse running.

  1. Download the most recent IKVM binaries (I just updated them).
  2. Download Eclipse. I use build M3.
  3. Unzip both zip files. Here I will assume that both are unzipped in the root of C:\ (the ikvm zip creates an ikvm directory and all the Eclipse files end up in an eclipse directory)
  4. Download eclipse.bat, save it in the eclipse directory.
  5. Open a Command Prompt window and cd into the eclipse directory and run eclipse.bat

This should do the trick. If you have any problems, please let me know.

 

Wednesday, 12 February 2003 18:19:47 (W. Europe Standard Time, UTC+01:00)  #    Comments [5]
Finally back

I came across a class file that was the equivalent of the following source:

class Test
{
    public static final int FOO = 1;

    static {
        FOO = 1;
    }
}

This isn't legal Java, but the class file equivalent is. The FOO field has a ConstValue attribute with the value 1 and then there is code in the static initializer to set the value again. The code in the static initializer isn't needed and the Java compilers I've seen so far don't emit it.

Anyway, IKVM handles assignments to (non-blank) final fields by just ignoring the assignment, but my code generator emitted a nop instruction, instead of a pop (because it should consume the value on the stack). Fixed.

GNU Classpath is about to release version 0.05, so I got their code from cvs and updated my native methods to work with the latest code (the only changes required were for Object[In][Out]putStream, because Mark cleaned those up to use less native code, a nice improvement!). There was still one remaining issue with compiling the classpath code with ikvmc, I had to comment out a line of code in java/nio/charset/Charset.java:

  public final ByteBuffer encode (String str)
  {
    return encode (CharBuffer.wrap (str));
  }

CharBuffer.wrap takes an CharSequence as its argument, but my java.lang.String doesn't implement CharSequence (yet). It occurred to me that since it is legal for any reference type to be passed where an interface is expected (see here) this code was legal as well (even if String doesn't implement CharSequence), so I added support to the compiler to insert casts when the arguments on the stack do not match with the expected method arguments (but only for interface references).

Finally, there is still one patch required to Classpath, because new File("c://") hangs:

RCS file: /cvsroot/classpath/classpath/java/io/File.java,v
retrieving revision 1.21
diff -r1.21 File.java
334,335c334
< if (!PlatformHelper.isRootDirectory(path))
< while (PlatformHelper.endWithSeparator(path))
---
> while (!PlatformHelper.isRootDirectory(path) &&
> PlatformHelper.endWithSeparator(path))

You wouldn't expect this to be a common occurrence, but it turns out that this exact path is constructed by the code that computes the current directory, so if you use ikvm to run a Java application in the root directory of a drive it hangs (without this patch).

 

Wednesday, 12 February 2003 13:46:52 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Friday, 17 January 2003
Hello Mono

Zoltan Varga wrote on the ikvm-developers list:

   After lots of hacking, I managed to get IKVM to run HelloWorld under mono. This involved lots of changes/bugfixes to IKVM, the mono runtime and the class libs. I intend to submit a big patch to the mono mailing list shortly with the changes.

Great news!

Unrelated to the above, I checked in a bunch of changes and updated the source and binary snapshots. I'll be out of the country for two weeks, so there probably won't be much activity.

Friday, 17 January 2003 22:04:28 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Thursday, 16 January 2003
No Title

Ted Neward wrote:

All this really does, though, is help underscore how fundamentally broken the Java ClassLoader model really is. CLASSPATH is a gross hack and should be deprecated immediately (as in entirely absent from JDK 1.5 and up), and issues like verisoning and JAR-to-JAR dependencies resolved in a more sane and reasonable fashion. Anybody out there in bloggerland willing to go in with me on a new JSR? [The Mountain of Worthless Information]

I couldn't agree more. I've sent him an e-mail offering to help out with the JSR.

Thursday, 16 January 2003 13:09:15 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Saturday, 11 January 2003
custom modifiers and return type custom attributes

Suppose you have the following Managed C++ class:

__gc class Foo {
  void foo(int i) {}
 
void foo(long l) {}
};

How is this compiled? The problem, of course, is that int and long are both signed 32 bit integers. A type cannot have two methods with exactly the same signature. To solve this problem the CLR has custom modifiers (see Partion II Metadata.doc, section 7.1.1). ILDASM shows the above methods as follows:

[...] void  foo(int32 i) [...]
[...] void  foo(int32 modopt([Microsoft.VisualC]Microsoft.VisualC.IsLongModifier) l) [...]

The long parameter is annotated with the optional modifier Microsoft.VisualC.IsLongModifier. Modifiers are part of the signature, so it is legal to have signatures that differ only by modifier.

Now, suppose IKVM.NET is compiling the following Java class:

class Foo {
  Bar foo(Bar o) {}
  Baz foo(Baz o) {}
}

Also suppose that Bar and Baz are not yet available when the class is compiled. For the types that are not available, java.lang.Object is substituted, so now we again have two methods with the same signature. It would have been nice to use a custom modifier to resolve this, but this isn't possible for two reasons:

  1. custom modifiers are not supported by Reflection.Emit (in .NET 1.0 and 1.1)
  2. custom modifiers do not accept any arguments, only a type (it would be possible to generate a type for each modifier, but that would hardly be an elegant solution)

The solution is to use method name mangling. The next problem is that we need a place to store the name of the class that the arguments and return value actually are. The most obvious way to do this is custom attributes. Method arguments (parameters) can be annotated with custom attributes using MethodBuilder.DefineParameter(...). Parameters are indexed starting at one, this (and the ilasm syntax) suggests that zero refers to the return type, unfortunately DefineParameter throws an exception when it is called with zero. This bug also exists in both .NET 1.0 and 1.1. Again the work around is easy, just emit a method attribute and put the real return type class in there.

Saturday, 11 January 2003 12:02:32 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Sunday, 05 January 2003
Why Eclipse

Someone wondered why I chose to try to get Eclipse to run. Three simple reasons:

  • Mark Wielaard posted his success story on the GNU Classpath mailing list.
  • It's a complicated application and that really helps to find bugs.
  • It doesn't require AWT. It will be quite some time before AWT will be done (if ever), so for the time being console (or SWT) applications are all I can use.

Status update: I've been doing a lot of rewriting in the verifier/compiler. I now feel that I finally understand class loading (in particular, what happens when a class is not found). In the verifier and in the compiler, class names are now no longer used, instead references to the TypeWrapper class are used to identify types. This isn't just a performance optimization, but also a requirement because class names aren't necessarily unique (only within a class loader). Still no support for different classes with the same name though, it's getting closer though.

The reason I started this rewriting, is to enable dynamic binding when a class isn't found. The current compiler just inserts a throw NoClassDefFoundError when it encounters a type that couldn't be loaded (and if the verifier needed to load the type, the whole method will just be replaced with code that throws a VerifyError). This is not what the Sun JVM does, it actually retries to load the class everytime the method executes. To simulate this behavior I'm going to emit late bound code in the cases where a class isn't available when the type is compiled. After all this is done, I should be able to run Eclipse without the -Xbootclasspath workaround.

Sunday, 05 January 2003 16:01:01 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Tuesday, 31 December 2002
2 min 30 sec

I figured out a way to lazily create the stack traces (only for ClassNotFoundException, but the principle applies to some of the other exceptions as well) and this enables me to get the improved performance without losing stack trace information. With a precompiled xerces implementation, Eclipse startup is now 2.5 minutes.

Details of what I did:

Previously, whenever an exception object was instantiated, a call to Throwable.fillInStackTrace was inserted, but when the exception is thrown this isn't needed (when the exception isn't thrown, but printStackTrace is called on it, the call to fillInStackTrace is needed). So the compiler now checks if the instruction following the exception constructor invocation is an athrow and if it is, it will not add the call to fillInStackTrace.

The above in itself wouldn't really help performance, because whenever an exception is caught, the full stack trace is computed (if it wasn't done before), so I added code to the compiler to detect that the exception handler didn't actually use the exception object (easy for code compiled with javac 1.1, because the first instruction of the catch block is pop, harder for code compiled with javac 1.4 or jikes, because it stores the exception in a local variable, even if it isn't used). If the compiler detects that the catch block discards the exception object, it will not emit a call to MapException (which in turn calls fillInStackTrace).

Tuesday, 31 December 2002 13:12:46 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Monday, 30 December 2002
Eclipse Startup Perf

A large part of the startup time of Eclipse is caused by the overhead of producing stack traces for the about 25.000 ClassNotFoundExceptions that are thrown during startup (a really lame design of the Java class loader causes it to throw multiple ClassNotFoundExceptions for each class that is loaded). Java and .NET exception handling differ sufficiently that I have to do a lot of processing to build a stack trace for each exception that is thrown, and this is pretty expensive. As a test I decided to disable stack trace generation for ClassNotFoundExceptions and this reduces Eclipse startup time to 3 minutes! Note that this isn't entirely comparable to the 7 minute figure from Saturday, because various other things have also changed.

An alternative optimization that I investigated, was to add a hack the ClassLoader and URLClassLoader to reuse the exception object in URLClassLoader instead of throwing a new one, this also saved a significant amount of time. I'm wondering how others feel about this optimization? It consists of two changes: 1)ClassLoader.loadClass() calls ClassLoader.findClassFast(String name, ClassNotFoundException e) which calls ClassLoader.findClass(), 2) URLClassLoader overrides findClassFast and does a check to see if it has been subclassed, if not it calls findClassImpl and passes it the exception object it got from loadClass, if it has been subclassed it call URLClassLoader.findClass which calls findClassImpl with null as the exception object.

We're not there yet, but progress is being made :-)

Monday, 30 December 2002 18:00:08 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Saturday, 28 December 2002
No Title

Have you tried the java.util.zip.ZipFile speedup patch? http://gcc.gnu.org/ml/java/2002-12/msg00288.html It made a huge difference in startup time for gij. [Mark Wielaard]

Just did. Startup (with the CVS explorer and a Java source open) went from 7:18 to 7:03, so it does help, but not enough ;-)

Saturday, 28 December 2002 17:29:40 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]