# Monday, 10 May 2004
Generics Again

I have a hard time truly understanding the Java generics model. I understand the implementation and I think it's a hack and this is probably making it harder for me to see the design objectively.

After looking at the recent JDK 1.5 beta, there was one method that particularly puzzled me:

public T cast(Object obj)

In java.lang.Class. Why would you need a method to dynamically cast? If you understand how generics work under the covers, you know that T is actually java.lang.Object, so calling this cast method doesn't actually buy you anything (the compiler will insert a real cast after your call).

Before diving in, if your knowledge of how Java generics work under the covers is a bit rusty, I recommend reading the paper on GJ: Making the future safe for the past: Adding Genericity to the Java Programming Language. While I was re-reading it, a few things jumped out: "Adding generics to an existing language is almost routine.." In fact, it's so easy that today in 2004 we still don't have generics in Java, even though the design was already done in 1998. Another quote: "GJ comes with a cast-iron guarantee: no cast inserted by the compiler will ever fail. (Caveat: this guarantee is void if the compiler generates an 'unchecked' warning, which may occur if legacy and parametric code is mixed without benefit of retrofitting.)" Please note that the caveat applies when you use one of the principal features of GJ: "GJ contains a novel language feature, raw types, to capture the correspondence between generic and legacy types, and a retrofitting mechanism to allow generic types to be imposed on legacy code."

Another interesting paper (that is referenced in the GJ paper as NextGen), is Compatible Genericity with Run-time Types for the Java TM Programming Language.

Anyway, let's look at some code and try to figure out what the purpose of the new cast method is:

Class<String> c = String.class;;
String s = c.cast("foo");;

This is compiled as:

ldc_w java/lang/String
astore_1
aload_1
ldc "foo"
invokevirtual java/lang/Class cast(Ljava/lang/Object;)Ljava/lang/Object;
checkcast java/lang/String
astore_2

Note in particular the checkcast that I highlighted. This is inserted by the compiler and is key to how Java generics work. Presumably the Class.cast() method also checks that the passed in object is actually castable to the type, so effectively you get two casts for the price of one (or rather, you pay twice for the same cast).

Why would you want (or need) that? The answer became clear (?) to me when I was contrasting the Java generics with the .NET generics model.

Let's look at some more code (C# 2.0 this time):

T LameFactory<T>() where T : new()
{
  return new T();
}

This method generically constructs instances. It's not relevant to my point, but it is interesting to note that the C# compiler uses reflection under the covers to implement this. Most C# generics constructs are actually supported by the CLR, but instantation isn't. The compiler generates something like this:

T LameFactory<T>()
{
  // If T is a Value Type, we don't need
  // to use Activator.CreateInstance.
  if((object)T.default != null)
  {
    return T.default;
  }
  return (T)Activator.CreateInstance(typeof(T));
}

How would you do something similar in Java? Here's how:

T LameFactory(Class<T> factory)
{
  return factory.newInstance();
}

In essence, what you're doing here is the same as what the CLR is doing under the covers (passing an extra parameter with the type information, at least conceptually). Class.newInstance returns an appropriately typed reference, because Class is a generic type. Suppose it hadn't returned the appropriate type, but simply Object like in the good old days. You could have used Class.cast() to the the downcast instead! Admittedly this isn't the greatest example for explaining the existence of Class.cast(), but I do understand now that it provides real functionality that would have been impossible to (safely) get in any order way. Note that the obvious:

T LameFactory(Class factory)
{
  Object o = factory.newInstance();
  return (T)o;
}

Isn't the right answer. When compiling this, the compiler rightfully warns: Note: cast.java uses unchecked or unsafe operations. The cast is unsafe, because it dissolves at compile time. Note that this doesn't break type safety (in the VM/security sense), because the caller of LameFactory will have inserted its own cast to T, but it does (allow you to) break compile time type safety. If you value compile time type safety, it's a good idea to stay away from code that generates this warning.

Monday, 10 May 2004 12:07:15 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
# Friday, 07 May 2004
Assembly Names

To clean up the assembly names, I propose to change to the following names for the next snapshot:

Current Name New Name
awt.dll IKVM.AWT.WinForms.dll
classpath.dll IKVM.GNU.Classpath.dll
ik.vm.jni.dll IKVM.JNI.CLR-Win32.dll
ik.vm.net.dll IKVM.Runtime.dll
ikvm.exe ikvm.exe
ikvmc.exe ikvmc.exe
Mono.IKVM.JNI.dll IKVM.JNI.Mono.dll
netexp.exe ikvmstub.exe
OpenSystem.Java.dll (will be removed)


I'm removing OpenSystem.Java.dll for the time being, because interop with dotGNU hasn't really happened so far and at this point it's just pre-mature design for reuse. Hopefully, in the future when they continue their work on Java support we can work together to make the two systems interoperable.

Any comments on the assembly names?

[Update: Stuart makes a good point in the comments. I've changed the suggested new name of netexp to ikvmstub.exe]

Friday, 07 May 2004 15:52:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Wednesday, 05 May 2004
Mono Beta 1

The Mono Beta 1 was released today and I've prepared a new snapshot that works with this version to test interoperability.

What's new?

  • Fixed ik.vm.jni.build to create output directory.
  • Added Profiler.Count calls to ByteCodeHelper.cs for dynamic helper methods.
  • Fixed TypeWrapper.IsSamePackage to handle case where one type is array and other isn't.
  • Fixed bug introduced in last snapshot in bytecode compiler, that caused NullReferenceException if exception block starts on an unreachable instructions.
  • Added exception handling to VMRuntime.exec.
  • Added -Xwait option to ikvm, to keep the process hanging around (this is just a hack so I can look at the console window that contains the profiling statistics and trace messages after Eclipse has exited).
  • Fixed ikvmc to ignore Main-Class attribute when building a library.
  • Implemented JNI methods AllocObject and ReleasePrimitiveArrayCritical (on Windows JNI provider only).
  • Fixed resource loading from -Xbootclasspath.
  • Fixed a minor bug in remapped type handling.
  • Changed map.xml format to support future metadata annotations (thanks Stuart!).
  • Fixed handling of final fields in ikvmc.
  • Changed handling of shadow types (e.g. cli.System.Object now extends java.lang.Object and cli.System.String exists side by side with java.lang.String).
  • Fixed support for deserializing final fields.
  • Fixed java.lang.Class/VMClass to no longer require VMClass instances (Class now contains direct reference to TypeWrapper).
  • Added the managed part of the Mono JNI provider to CVS and the build script (and the snapshot).
  • Updated the SharpZipLib reference to the latest version.
  • Locked to GNU Classpath 0.09 and changed classpath build directory to ../../classpath-0.09
  • Fixed Thread.sleep() to support larger values than Integer.MAX_VALUE

Linux Lamer

Since I'm a Linux Lamer (tm), I'm documenting the steps here to get JNI to work with Mono (primarily for my own use).

  • cd /usr/local/src/classpath-0.09
  • ./configure --with-jikes --disable-gtk-peer
  • make
  • cp include/jni.h /usr/local/include/
  • cp include/jni_md.h /usr/local/include/
  • cd ../mono-0.91/ikvm-jni/
  • make && make install
  • cd ../jnitest
  • vi test.java
    class test {
      public static void main(String[] args) {
        System.loadLibrary("test");
        nativeMethod();
      }
      static native void nativeMethod();
    }
  • jikes -cp ../classpath-0.09:../classpath-0.09/vm/reference:../ikvm/classpath test.java
  • vi test.c
    #include <stdio.h>
    #include <jni.h>
    JNIEXPORT void JNICALL Java_test_nativeMethod(
    JNIEnv* env, jclass clazz) { printf("Hello from JNI\n"); }
  • gcc -shared test.c -o libtest.so
  • export LD_LIBRARY_PATH=.
  • ikvm test

New snapshots: just the binaries and source plus binaries.

The GNU Classpath release that this is based on can be downloaded from ftp://ftp.gnu.org/pub/gnu/classpath/classpath-0.09.tar.gz

Note that anon cvs for SourceForge is apparently still lagging behind, so at the moment I'm posting this, anon cvs does not yet contain the latest changes.

Wednesday, 05 May 2004 11:06:43 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Thursday, 15 April 2004
Progress

While it's been quiet on the blog and the mailing list, there has been quite a lot of progress behind the scenes.

  • The next Mono release will contain the C half of the IKVM JNI provider and the next IKVM snapshot will contain the C# half of the Mono JNI provider. This means that JNI will work out of the box on Mono (for the parts of JNI that are actually implemented). Thanks to Zoltan and Miguel for this.
  • I'm planning an IKVM 0.8 release to coincide with the Mono 1.0 release.
  • John Luke added IKVM support to MonoDevelop. Read about it here or see the screenshot here.
  • I successfully started up Eclipse 3.0 M8 for the first time yesterday. Thanks to Michael Koch for his work on GNU Classpath's java.nio implementation and all the other GNU Classpath hackers, of course.
  • In the comments, Jesus Garcia point me to SwingWT. An SWT based implementation of AWT and Swing by Robin Rawson-Tetley. Very cool stuff! It doesn't run on the latest snapshot due to a JNI bug, but I have it running and it's very cool to see the SwingSet demo running on IKVM.

I hope to do a new snapshot in the first week of May and after that to work towards the 0.8 release.

Thursday, 15 April 2004 10:06:15 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
# Monday, 29 March 2004
Backward Branch Constraints

The last snapshot was totally broken on Mono (*blush*). My apologies to the Mono users. I should test my snapshots on Mono before releasing them, but I'm lazy so this sometimes slips through the cracks.

The breakage was kind of interesting though. As I wrote last time, I rewrote the bytecode compiler to emit CIL in the same order as the Java bytecode. This caused invalid (per the ECMA spec) CIL to be generated in some cases. The interesting thing is that the code isn't really invalid, the only reason it is invalid is because the spec says so:

Partition III -- 1.7.5 Backward Branch Contraints

It must be possible, with a single forward-pass through the CIL instruction stream for any method, to infer the exact state of the evaluation stack at every instruction (where by “state” we mean the number and type of each item on the evaluation stack).

In particular, if that single-pass analysis arrives at an instruction, call it location X, that immediately follows an unconditional branch, and where X is not the target of an earlier branch instruction, then the state of the evaluation stack at X, clearly, cannot be derived from existing information. In this case, the CLI demands that the evaluation stack at X be empty.

(Note that the section numbering seems to change with each version, this is from the working draft of June 2003.)

Java bytecode has no such requirment, so my straight forward translation caused Java bytecode that is only reachable through a backward branch to be translated into invalid CIL.

The Microsoft verifier and JIT don't require this constraint to be met and they will happily verify and JIT code that violates this constraint. However, the Mono JIT relies on it and so it was unable to handle some of the CIL that IKVM generated.

I fixed the IKVM bytecode compiler to emit ECMA compliant code (at least for this particular issue, who knows what else is wrong). I also fixed exception mapping, which didn't work on Mono as it relied on a currently unimplemented feature (I think, I didn't really investigate).

I think that, realistically, the Mono JIT will also have to be "fixed" to support the broken code, as you can be sure that there will be compilers that emit broken code, because it works on the Microsoft runtime.

New snapshots: just the binaries and source plus binaries.

Monday, 29 March 2004 12:56:28 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 26 March 2004
Debugging Support

I finished and fixed the local variable analysis and made various improvements to the debugging experience (in Visual Studio .NET). In the process I discovered some quirks in jikes' debugging tables. It associates two line numbers with the same bytecode address when that bytecode address is also the start of an exception block. It also (I think incorrectly) starts a local variable scope before the store instruction that first initializes that local variable. Javac starts the local variable scope immediately after the first store to that local, this makes more sense to me, but also required a hack in the local variable debugging support to make sure that the IL variable scope starts at the right position (i.e. before the first store to that local variable).

To make local variable scopes work, I had to change the bytecode compiler to emit IL in the same order as the original Java bytecode. For some reason I originally wrote the compiler to do the same code flow analysis as the verifier and this resulted in a somewhat arbitrary order of the generated IL. I finally fixed that and I also removed the recursion from the compiler (it now uses an explicit stack to keep track of exception blocks).

Note that unreachable code is still not compiled (it can't be verified, so it can't be compiled), but there will be nop IL instructions for each unreachable bytecode instruction, so you can set breakpoints and move the instruction pointer there. This could be a bit confusing and I probably should fix it at some point (by not emitting the nops).

I also had to reintroduce the automatic downcasting of locals, because I realised that it is possible to write bytecode by hand that depends on this (Java source will never require it). In non-debug builds of classpath.dll this introduces 12 (unnecessary) downcasts, so that's not really worth optimising.

What's new?

  • When compiling with -debug option, dead store are not optimized out anymore.
  • When compiling with -debug option, local variables are merged based on LocalVariableTable information.
  • When compiling with -debug option, the first instruction of a method will always (except when compiling with -Xmethodtrace) have an associated line number now (to enable stepping into the method).
  • When compiling with -debug option, local variables are now scoped based on LocalVariableTable information. Different locals with the same name are now handled correctly in the debugger.
  • Made helper method MethodInfo caching more consistent.
  • Method arguments that are value types are now boxed on method entry and not on each individual load, this makes them behave consistent with local variables.
  • Reusing method argument local variable slots (with different types) is now fully supported. I've never seen a Java compiler do this, but it is legal.
  • lookupswitch/tableswitch branches into exception blocks are now handled correctly (exception block is split around branch target). This completes branch/exception block handling. I originally thought that this would never happen, but apparently it does.
  • Added a helper method to emit Ldc_I4 that always uses the optimal encoding.
  • Added a class loader check to the System.arraycopy optimization check, to make sure that we're in fact calling System.arraycopy on the bootstrap version of java.lang.System.
  • Many fixes to the local variable analysis.
  • Added -srcpath option to ikvmc. If specified, this prepends the specified path and the package name to the source file name in the debugging information. In most cases this will be the correct location for the source file and will allow the debugger to automatically load the correct source.
  • Added AWT peer for Window.

New snapshots: just the binaries and source plus binaries.

Friday, 26 March 2004 11:30:36 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Thursday, 25 March 2004
Q & A

In the comments on the previous entry, Stuart asks:

Given an instance of System.Type, how do I determine what the typename is in Java?

This is tricky and my (lame) answer is that you shouldn't have to. Do you have a specific scenario in mind? Having said that, in your comment you're on the right track, there is no one-to-one mapping between System.Type instances and java.lang.Class instances. What I think you're after is the fact that you'll never encounter cli.System.Object or cli.System.Exception as field types or in method signatures. The only way to get the class object for these types, is by calling getClass() on an instance or by calling Class.getSuperclass() on a subclass of them.

Note that the above behaviour isn't actually implemented yet. At the moment cli.System.Object and cli.System.Exception are simply helper classes with static methods and you'll never encounter them as field types, in method signatures or as instance types.

As to which one to use from Java, you're right when you say java.lang.* is the answer is most cases. The only times you want to use cli.System.Object or cli.System.Exception is when you subclass them from Java to make your Java class look more .NET like to .NET consumers.

What would be really nice would be if there were something in the IK.VM.NET.dll that would let me answer this question authoritatively with a simple call...

There is the NativeCode.java.lang.VMClass.getClassFromType() method that is used by the runtime internally (it's public, so you could call it), but I can't really guarantee that it'll stay around or behave consistently over time. At some point in the future there'll probably be a utility class in the ikvm.lang package that will contain conversion method to go from System.Type to java.lang.Class and vice versa (but it probably will require you to specify to context for the mapping).

Oh, one other thing that occurred to me would be a nice feature: if a class implemented in Java could put itself into the cli.* package and thereby make itself look to other Java code as if it were a .NET type, without actually putting it in a cli.* namespace in .NET. In other words, a Java class cli.Foo.Bar would be compiled as namespace Foo.Bar *without* the attribute that preserves its name in Java, so that Foo.Bar then gets translated back to cli.Foo.Bar when Java code sees it.

Sort of the inverse of the attribute for turning name mangling off on the .NET side.

Can you explain why and when you'd want to use this?

Mike asks:

Are there any tasks for a CS scrub like myself to work on with IKVM?

Here is a partial list of things that need to be done:

  • Implement the AWT peers
  • Implement the missing JNI methods
  • Build a framework to test the verifier / bytecode compiler
  • Write a Java implementation of String.valueOf(float) and String.valueOf(double)
  • Search the source for // TODO for things that seem doable (or write test cases that show the current code is broken)
  • Write documentation
  • Design a logo
  • Design a website

If you (or anyone) decides to work on something, please send e-mail to the ikvm-developers list, so we can coordinate.

Thursday, 25 March 2004 10:28:51 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Saturday, 20 March 2004
Documentation

Miguel posted a nice example of how to use Gtk# from Java using IKVM/Mono on his blog. In response Pablo posted a question to the Mono list and Jonathan Pryor replied with a nice explanation of how delegates are handled to the IKVM and Mono lists (quoted with permission, slightly edited):

From: Jonathan Pryor
Sent: Friday, March 19, 2004 02:35
To: Pablo Baena
Cc: Miguel de Icaza; mono-list@lists.ximian.com; ikvm-developers@lists.sourceforge.net
Subject: Re: [Mono-list] Java and C#

Below...

On Thu, 2004-03-18 at 16:07, Pablo Baena wrote:
> Miguel: I saw your blog about IKVM. One thing I haven't been able to 
> investigate is, how useful can be Gtk# with Java. Because, for example, I 
> couldn't find a clue on how to attach a Java 'listener' to a C# event, or any 
> way to use attributes in Java.

They really need to document this better...

However, grepping through the ikvm.zip file (from their website), we
see:

// file: classpath/java/lang/VMRuntime.java
cli.System.AppDomain.get_CurrentDomain().add_ProcessExit (
  new cli.System.EventHandler (
    new cli.System.EventHandler.Method () {
      public void Invoke (Object sender, cli.System.EventArgs e) {
        Runtime.getRuntime().runShutdownHooks();
      }
    }
  )
);

>From this (and prior knowledge), we can draw the following statements:

1. Properties are actually functions with `get_' and `set_' prefixed to
them. Thus C# property System.AppDomain.CurrentDomain is the static
Java function cli.System.AppDomain.get_CurrentDomain().

2. Events are actually functions with `add_' and `remove_' prefixed to
their name. Thus C# event System.AppDomain.ProcessExit is the static
Java function cli.System.AppDomain.add_ProcessExit().

3. There is no equivalent to C# delegates in Java, so these are
translated into a class + interface pair. The EventHandler class is the
standard C# type name (cli.System.EventHandler), which takes as an
argument an interface to invoke, named "cli." + C# delegate type name +
".Method", hence cli.System.EventHandler.Method. The EventHandler.Method
interface has a function Invoke() which must be implemented, and this
method will be invoked when the event is signaled.

I suspect that there is no way to add attributes in Java. Microsoft's
Visual J# permits the use of Attributes (IIRC), but it's through their
Visual J++ syntax -- through a specially formed JavaDoc comment. 
Something like (from memory):

/**
* @attribute-name (args...)
*/
public void myMethod () {/* ... */}

Of course, that's compiler specific, and no standard Java compiler will
support that. So when it comes to attributes, you're probably up the
creek.

- Jon

I replied saying that I believe that the attribute construct in JDK 1.5 can probably be used to expose .NET attributes to Java (and use them in Java code that is target to run on IKVM).

Saturday, 20 March 2004 14:51:08 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
A Less Broken Snapshot?
In Tuesday's snapshot, ikvmc was completely broken. Sorry about that. The CoreClasses cache introduced an incorrect dependency between Object, Throwable and String. This caused Throwable or String to be loaded while it was being loaded and that resulted in an exception: System.ArgumentException: Item has already been added. Key in dictionary: "java.lang.Throwable" Key being added: "java.lang.Throwable"

Hopefully this snapshot will be a little better quality, but don't hold your breath, because the main change in this version is the addition of local variable liveness analysis to the verifier. This required some tricky code and made it clear to me (again) that the verifier desperately needs to be rewritten.

The trigger for the local variable liveness analysis was to be able to emit debugging information for local variables, but it also has the nice side effect of allowing a little better code generation. Previously, if a local variable slot was shared between two different reference types, the .NET local would have the type of the common base type, even if the uses were in fact totally distinct. The compiler had to emit downcasts whenever it emitted a load from one of those locals. In classpath.dll there were 1288 such downcasts. With the new liveness information, it is now possible to split those Java locals in multiple .NET locals, so these downcasts are now gone. Another optimization, which doesn't seem all that exciting, is the elimination of dead stores to local variables. In itself this is a fairly pointless optimization, because the CLR/Mono JIT will probably do it anyway. However, there is one very important optimization that can be done because of dead store elimination, in exception handling. Whenever an exception handler discards the exception object and the IKVM bytecode compiler can detect this, it can skip the (expensive) stack trace capturing that is normally required. I had already hacked some support to recognize these exception handlers (in classpath.dll there were 313 optimized exception handlers), but now it works much better (there are now 444 optimized exception handlers).

What's new?

  • Decorated the various ByteCodeHelper methods with the [DebuggerStepThroughAttribute] attribute to make stepping through the source code in the debugger less disruptive.
  • Restored the signature decoding methods in ClassFile.cs that I removed in the previous version. I had failed to realise that they're different from the ones in ClassLoaderWrapper, because they deal with unloadable classes.
  • Fixed CoreClasses to decouple the different classes (accessing one no longer triggers loading the others).
  • Changed handling of package accessible final fields (they're no longer turned into a property).
  • Fixed System.setOut (copy & paste mistake, it tried to set "in").
  • The debugging information is now classified as Java/Text. Not sure if this affects anything, but it seemed like the right thing to do.
  • Fixed debugging line number information to make sure the firt CIL instruction has a corresponding line number. Previously, Visual Studio .NET refused to step into an ikvmc compiled method.
  • Optimized dead stores to local variables and use new dead store information to optimize exception handling.
  • Local variables are now properly typed and have their names attached in debugging information (when ikvmc with the -debug option is used). NOTE: if the same variable name is reused in a method, the debugging information for those variables is not yet emitted correctly.
  • Fixed mapping of System.IntPtr to gnu.classpath.RawData. The mapping is now private to classpath.dll.
  • Changed JVM.CriticalFailure to write to always write to stderr on Unix instead of try to display a message box.
  • Fixed race condition between returning from Thread.join and the thread being removed from the thread pool / marked as dead.
  • Fixed Thread.yield to not consume thread interrupted status. (Note that Thread.sleep(0) behaves as Thread.yield() and also does not consume the interrupted status).

New snapshots: just the binaries and source plus binaries.

Saturday, 20 March 2004 14:26:49 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Tuesday, 16 March 2004
New Snapshot

Last week I said I'd go through a stabilization phase, but I couldn't resist the urge to implement some more stuff and fix various things. So this snapshot is a fairly big change again, but no major architectural overhaul like the pervious one.

What's new?

  • Merged with current Classpath cvs.
  • Support for JDK 1.5 style class literals (only for class files with version 49 or greater).
  • Removed signature decoding from ClassFile.cs (I once thought that it should live there, instead of in ClassLoaderWrapper, but that turned out not to be a good idea).
  • Added CoreClasses.cs to cache a few of the frequently used TypeWrappers (Object, Class, String and Throwable).
  • Fixed volatile long/double handling to use the (new in .NET 1.1) Thread.VolatileRead/VolatileWrite methods.
  • Changed type used in ImplementsAttribute to the ghost wrapper for ghosts.
  • Changed method name mangling for interface implementation stubs (shorter name and now uses a slash to make sure it doesn't clash with any Java method names).
  • Added support for Finalize/finalize method overriding when mixing Java and non-Java classes in the class hierarchy. I don't like this solution very much. The code is ugly and complicated.
  • Added special support for finalize method for .NET types that extend Java types.
  • Fixed handling of synchronized static methods. Previously, .NET MethodImplOptions.Synchronized flag was simply set, but this was incorrect because that causes the method to synchronize on the .NET Type object, instead of the Java Class object.
  • Fixed handling of instance calls on value types.
  • Fixed System.currentTimeMillis implementation to use DateTime.UtcNow instead of Environment.TickCount, to prevent overflow.
  • Changed System.setErr/setIn/setOut to use TypeWrapper based reflection instead of .NET reflection.
  • Changed handling of resources to use .NET resources instead of global fields, this allows resources to work in multi-module assemblies.
  • Changed URL format for assembly embedded resources from opaque to parseable, to facilitate parsing them as a URI.
  • Added support for passing ghost references to methods in map.xml instructions.
  • Fixed a regression introduced in the previous snapshot, that caused exception mapping not to be invoked for catch(Throwable).
  • Limited fixes to get AWT working again (after Classpath AWT changes).
  • Declared String.equals and String.compareTo(Object) in map.xml to make reflection appearance identical to JDK.
  • Implemented JDK 1.4 String methods that rely on regular expressions (Classpath now has java.util.regex.* support, although not 100% compatible with the JDK).
  • Minor performance improvement in String.hashCode implementation. Oddly enough, by doing the length check in the for condition, instead of manually hoisting it out of the loop. Apparantly the CLR JIT recognizes this pattern and optimizes it better.
  • Fixed Thread.join to work with non-Java created threads as well.
  • Fixed removal of non-Java created threads from ThreadGroup.
  • Fixed ServerSocket.accept() timeout support.
  • Fixed ikvmc handling of -reference assemblies (to handle the Load vs LoadFrom context issues).
  • Various comment fixes.

New snapshots: just the binaries and source plus binaries.

Tuesday, 16 March 2004 17:50:55 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]