# Monday, 03 January 2005
Design Flaws

Happy New Year!

The common theme in today's snapshot is clearly design flaws. I have two of my own to discuss and two others. Note that this reflects only an small portion of all design flaws in my (and other) code, but these are the ones that are at least mildly interesting to read about (I hope).

Thread.interrupt()

When I originally designed the Thread.interrupt() support, it seemed like an obvious thing to map this onto the .NET support for interrupting threads. In retrospect I can see that this was a mistake (when something seems obvious it's tempting not to think about it anymore), but at the time it appeared to work fairly well. Only after a while I discovered that the monitorenter bytecode instruction (implemented by calling System.Threading.Monitor.Enter()) wasn't supposed to be interruptable in Java. I "solved" this by redirecting monitorenter to ByteCodeHelper.monitorenter() that repeatedly calls Monitor.Enter() (and catches any ThreadInterruptedExceptions) until it is successful. When I fixed this, I should have noticed a more fundamental problem with the Thread.interrupt() mapping approach, but I only realised the problem when I was working on the class loading deadlock bug a couple of weeks ago. Since java.lang.InterruptedException is a checked exception and can only occur in a couple of well defined places in the Java library, it simply wasn't a good fit to map it onto System.Threading.ThreadInterruptedException, which can occur any time a synchronized code block is entered (and this basically includes any .NET method).

Once I realised the problem, the fix was fairly easy. Java threads now maintain their own interrupt pending flag and whenever a Java thread enters one of the interruptable waits (Object.wait() or Thread.join()) it checks the flag and marks the thread as inside an interruptable wait. When another thread interrupts the waiting thread, it uses the .NET Thread.Interrupt() to interrupt the wait and the interrupted wait notices that the interrupt pending flag is set and catches the .NET System.Threading.ThreadInterruptedException and throws a java.lang.InterruptedException.

System.Reflection.Emit.MethodBuilder

I did some heap analysis on a started Eclipse process and discovered that a ridiculous amount of memory was being held by the various MethodBuilder instances that are kept alive by the IKVM type information data structures. This wasn't a matter of a couple of wasted bytes, but somewhere around 20MB of useless objects that were still being referenced. I attempted several different workarounds, but the simplest and safest one turned out to be using reflection to clear all of the unused private fields in MethodBuilder after a dynamic type is baked. This is obviously a nasty hack, but the resulting memory reduction is so significant that I felt it was worth it. I filed a bug with Microsoft, so hopefully it'll get fixed for Whidbey. Another reflection design flaw is that System.Reflection.Emit.OpCode is a value type that contains a whole bunch of instance fields, instead of a lightweight enum. This means that whenever you use an OpCode (which is often when you're generating code with ILGenerator) you are carrying around about 40 bytes, instead of an int sized value.

Hashtables

After getting rid of (most of) the MethodBuilder overhead, I turned my attention to my own code and noticed that a lot of memory was being used up by the hashtables that the TypeWrapper instances used for the fields and methods. Using hashtables for this turned out to be a design flaw, because most classes don't have that many types or fields that the memory overhead of a hashtable of worthwhile (I'm doing a simple linear search through an array now, and it doesn't affect performance at all). Besides this change I also made a whole bunch of other changes to reduce memory consumption, the result is that starting up Eclipse now takes less than half the heap space than it did in the previous snapshot.

C# and the CLS

The C# team uses the CLS as a (lame) excuse not to have to support accessing static fields in interfaces, so you cannot access Java interface fields in C#. To work around this, I've added code to create an inner class named __Fields to every interface that has static fields and that inner class contains duplicates of the interface fields, so that they can be accessed from C#.

Changes:

  • Sync'ed with GNU Classpath cvs (IKVM.GNU.Classpath now contains GNU JAXP XML processing library). You can now run Eclipse without having to add the xml stuff to the bootclasspath: eclipse -vm c:\ikvm\bin\ikvm.exe
  • Moved ObjectHelper.wait() to VMThread.objectWait().
  • Moved ObjectHelper.toStringSpecial() to map.xml.
  • Removed java/lang/ObjectHelper.java
  • Removed remapping of System.Threading.ThreadInterruptedException to java.lang.InterruptedException.
  • Added code to set "user.language" and "user.region" system properties based on .NET culture.
  • Fixed two shutdown hooks bugs that could cause the shutdown hooks not to run or run very slowly.
  • Fixed Process.waitFor() to be interruptable.
  • Fixed bug in VMThread.join() that could cause it not to return when a native thread detaches the thread.
  • Totally rewrote Thread.interrupt() handling and detached Java thread interruption from .NET thread interruption.
  • Removed the MethodDescriptor class.
  • Removed ByteCodeHelper.monitorenter().
  • Changed class file parser to intern all class, field, method names and signatures.
  • Added check for class names that are too long for .NET to handle.
  • Changed class loading locking so that no locks (outside of the lock on the ClassLoader) are held when Java code is called, to prevent potential deadlocks.
  • Changed SimpleCallMethodWrapper and SmartCallMethodWrapper not to have two OpCode fields but use smaller enum type instead.
  • Changed field resolving/linking to use the same strategy as methods.
  • Unified NonPrimitiveValueTypeFieldWrapper, GhostFieldWrapper and SimpleFieldWrapper.
  • Changed compilation of synchronized instance methods to use MethodImplAttribute(MethodImplOptions.Synchronized).
  • Changed TypeWrapper to use simple arrays to store fields and methods, instead of hashtables.
  • Integrated lazy member publishing into TypeWrapper and removed LazyTypeWrapper.
  • Added BakedTypeCleanupHack to workaround bug/design flaw in Reflection.Emit that causes too much memory to be retained (the workaround is to use reflection to clear some private fields of MethodBuilder, ConstructorBuilder and FieldBuilder).
  • Added workaround to make interface fields usable from C# (by duplicating them in an inner class named __Fields in the interface).
  • Changed bytecode compiler to use CIL switch opcode for tableswitch bytecode (this is a bit more space efficient).
  • Added conv_i1, conv_i2, conv_i4 and conv_i8 instruction support to remapper.

New snapshots: just the binaries and source plus binaries.

Monday, 03 January 2005 18:11:32 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, 22 December 2004
New Snapshot

More fixes and stabilization work. More to come...

Changes:

  • Merged with GNU Classpath cvs.
  • Fixed a relatively obscure bytecode compiler bug (that caused a "critical failure" because of an undefined label).
  • Fixed error handling for sockets to deal with closed sockets.
  • Implemented support for parsing relative ikvmres URLs and improved error handling.
  • Fixed ikvmres protocol handler to set port to -1 instead of 0 to enable better URL/URI roundtripping.
  • Fixed defineClass to throw NoClassDefFoundError instead of ClassNotFoundException (in some cases).
  • Fixed reflection to use a classes real accessibility instead of the access flags from the inner classes attribute.
  • Fixed ikvmc to always return errorcode when compilation fails.
  • Improved exception printing in ikvmstub.
  • Many fixes to class file format checking.
  • Fixed dynamic bytecode helper methods to throw NoClassDefFoundError instead of ClassNotFoundException.
  • Improved detection of class circularity.
  • Added workaround for .NET bug for classes that end with a period.
  • Implemented support for enums that use unsigned integral types as underlying type.
  • Fixed several constant field related bugs.
  • Fixed several .NET literal field related bugs.
  • Added workaround for .NET 1.1 verifier bug that made accessing the Value field of an enum unverifiable (for integral types smaller than Int32).
  • Fixed obscure bytecode compiler bug dealing with assigning uninitialized object references to local variables.
  • Implemented verifier checks to enforce calling the base class constructor before returning from a constructor.
  • Fixed obscure verifier bug that incorrectly disallowed having the unitialized this in a local or on the stack when doing a backward branch.
  • Fixed several verifier bugs when dealing with incorrect bytecode (would previously throw an IndexOutOfBoundsException instead of a VerifyError).
  • Added validation of the exception handling tables to the verifier and class file parser.
  • Implemented invokeinterface verification for bogus bytes following the instruction.
  • Moved java.lang.Class object <-> TypeWrapper mapping from hashtable to field in TypeWrapper.
  • Fixed class loading deadlocking bug.
  • Fixed JNI methods to handle RetargetedJavaExceptions.
  • Fixed Class.getProtectionDomain() for array types (not in Classpath cvs yet).
  • Fixed Class.getModifiers() for inner class array types.

New snapshots: just the binaries and source plus binaries.

Wednesday, 22 December 2004 09:40:49 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 13 December 2004
Calling Conventions & New Snapshot

Puneet Nayyar had some problems with JNI and was kind enough to send me that DLL that didn't work with IKVM. It turned out that the DLL exported a bunch of methods without the name decorations that __stdcall (the JNICALL calling convention on Windows) requires. Originally I thought that the DLL used the __cdecl calling convention (which uses undecorated names, at least on the Visual Studio .NET 2003 C++ compiler, despite what Raymond Chen says), but an examination of the code showed that it did in fact pop the arguments of the stack. So the fix was trivial, just look up JNI methods in their undecorated form as well.

It worries me a little that this allows __cdecl methods to be found too (which is what you get when you forget the JNICALL modifier), because they would (most likely) result in a crash when called. The Sun JDK seems to (accidentally?) support the __cdecl calling convention, maybe they restore the stack pointer from EBP in their thunk.

Other changes:

  • Merged with GNU Classpath cvs.
  • Fixed Class.forName() bugs when dealing with invalid array class names.
  • Fixed Array.newInstance() when used on an unfinished class.
  • Changed os.name and os.version system properties to be more compatible with Sun (on Windows).
  • Changed ikvmc to allow building empty assemblies (mainly useful for creating executable that start a main method in an already compiled assembly).
  • Fixed FileChannelImpl to use a smaller buffer (FileStream forces the use of a buffer, but we don't want any buffering at all).
  • Fixed FileChannelImpl.write(int) to flush and handle exceptions.
  • Fixed FileChannelImpl to handle (asynchronously) closed streams correctly.
  • Fixed some weak reference bugs.
  • Fixed ikvmc to use correct resource names on Mono (leading slash wasn't chopped off).
  • Fixed JNI method lookup to support unmangled names.
  • Cleaned up handling of VerifyError and log the error in the right place.
  • Changed compilation "exception" trace messages to Error category (from Warning).
  • Added compiler support for special casing VMSystem.arraycopy (which is now called directly by Classpath's StringBuffer implementation).

New snapshots: just the binaries and source plus binaries.

Monday, 13 December 2004 08:56:12 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 02 December 2004
New Runtime -> Library Interface & New Snapshot

The major new feature in this version is that I introduced a new interface (ikvm.internal.LibraryVMInterface) to replace all late-bound library operations in the runtime. In some cases this is a performance optimization, but I mainly did it to get better compile time checking.

In addition to that a number of small steps on the long road to 1.0:

  • Merged with GNU Classpath cvs.
  • Made the Field/Method/Constructor constructors package private. These objects are constructed from java.lang.VMClass but they live in java.lang.reflect, so they needed to be public, but I realised that since package private turns into assembly accessibility, I could use some map.xml glue to make factory methods in java.lang.VMClass that access the package private constructors in the java.lang.reflect package.
  • Fixed a whole bunch of DatagramSocket bugs.
  • Increased my Mauve test set enormously. I now run almost all Mauve tests. Current results: 238 of 3600422 tests failed.
  • Fixed FileChannelImpl.truncate to only truncate (not grow) the file.
  • Fixed several small java.io.File compatibility problems.
  • Fixed exception cleaning code to not skip package private methods.
  • Fixed a regression in ikvmc that caused it not to emit the names of method parameters.
  • Fixed regression that caused an exception when processing a constant boolean field.
  • Introduced ikvm.internal.LibraryVMInterface to replace all late binding from the runtime to the class library.
  • Added public API IKVM.Runtime.Util.MapException() to map exceptions from non-Java code.
  • Added ldobj instruction to remapper.cs.
  • Added a tools sub-project (currently only contains one simple app to generate an assembly reference for ilasm).
  • Implemented java.nio.channels.Channels.new[In|Out]putStream native methods.
  • Added stack trace cleaning to remove java.lang.LibraryVMInterfaceImpl methods.
  • Fixed some uncommon cross language Finalize method issues (e.g. when a Java class inherits from a C# class that inherits from Java class).
  • Optimized empty finalize methods. They are no longer registered as real Finalize methods.
  • Fixed reflection on .NET types to properly handle Java ghost interfaces.
  • Added a jvm sub-project to build JVM.DLL (Windows only).
  • Removed stub ikvm/classpath/gnu/java/net/protocol/ftp/Handler.java now that GNU Classpath has an ftp implementation.

New snapshots: just the binaries and source plus binaries.

Thursday, 02 December 2004 10:09:11 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Wednesday, 24 November 2004
Direct ByteBuffer, Inlining & New Snapshot

Michael Koch finished Classpath's implementation of DirectByteBufferImpl. Direct ByteBuffers allow Java code to access unmanaged memory. You can allocate them from Java using ByteBuffer.allocateDirect or from JNI using NewDirectByteBuffer. The default Classpath implementation uses native methods to implement accessing the buffer, but for IKVM I really didn't want to do it that way, because I like to use managed code whenever possible (for both maintainability and portability) and also because native method invocation is fairly slow. I therefore decided to reimplement gnu.classpath.RawData (the Classpath abstract native memory pointer) and java.nio.VMDirectByteBuffer.

At first RawData was a value type containing a single IntPtr field in an attempt to avoid an indirection when loading the pointer. This required that I replaced the implementation of DirectByteBufferImpl.get/put with some handwritten CIL instructions, because the compiled Java code resulted in unnecessarily boxing the RawData struct and that obviously killed performance. Since I was replacing the get and put methods anyway, I also inlined the index check and position update. After some experimentation I discovered that making RawData a value type didn't really help performance (the .NET JIT isn't very good at taking advantage of value type optimization opportunities) so I changed it into a reference type, this removed the need for special casing get and put, but when I removed the handcoded CIL performance went down significantly (approx. 50% slower). For some reason the JIT wasn't inlining the index check method, so I left the handcoded CIL in map.xml.

Here's a random microbenchmark:

import java.nio.*;
class DirectByteBuffer {
  public static void main(String[] args) {
    final int SIZE = 10 * 1024 * 1024;
    for(int j = 0; j < 2; j++) {
      ByteBuffer b = ByteBuffer.allocateDirect(SIZE);
      long start = System.currentTimeMillis();
      for(int i = 0; i < SIZE; i++)
        b.put(i, (byte)i);
      long sum = 0;
      for(int i = 0; i < SIZE; i++)
        sum += b.get(i) & 0xFF;
      long end = System.currentTimeMillis();
      System.out.println(end - start);
      System.out.println("sum = " + sum);
    }
  }
}

Results:

JRE 1.4.2 HotSpot Client VM Average
671 530 541 521 461 545
450 461 450 460 460 456
           
JRE 1.5 HotSpot Client VM  
401 461 411 481 480 447
410 360 441 410 411 406
           
JRE 1.5 HotSpot Server VM  
220 120 110 120 120 138
100 110 110 160 100 116
           
IKVM on .NET 1.1  
201 231 231 240 251 231
210 210 210 221 220 214
           
IKVM on Mono 1.0.2 (--optimize=all)  
430 391 400 401 390 402
401 390 401 390 401 397


Pretty good results. Most other operations perform similarly, except for compact, copy a large buffer takes about twice as long as on the JRE. The .NET class library really should have a memcpy or memmove method that is properly optimized. Note that there is CIL instruction cpblk to copy memory and I tried that as well, it is about 30% faster than my straightforward C# loop, but it doesn't handle overlapping regions and I didn't want to use an unverfiable instruction anyway (as that would cause IKVM.GNU.Classpath to fail verification and I use verification as simple smoke test during build to catch the most obvious regressions in the compiler).

I've also updated the Japi status results: IKVM vs JDK and JDK vs IKVM.

Other changes:

  • Resync'ed with GNU Classpath cvs.
  • Removed java/net/SocketInputStream.java and java/net/SocketOutputStream.java.
  • Moved contents of java/net/PlainSocketImpl.java to gnu/java/net/PlainSocketImpl.java.
  • Moved contents of java/net/PlainDatagramSocketImpl.java to gnu/java/net/PlainDatagramSocketImpl.java.
  • Added deprecated attribute to the three deprecated String methods.
  • Added deprecated attribute support to map.xml parser.
  • Added deprecated attribute support to ClassFileWriter.
  • Added deprecated attribute support to ikvmstub.
  • Added public API to query deprecatedness of fields, methods, constructors and classes.
  • Changed ikvmstub to emit serialVersionUID fields even if it is private, to make Japicompat status more accurate.
  • Added public API to query the constant value of a field.
  • Added ConstantValueAttribute to persist the constant value of constant instance fields (which are treated the same as static constant fields, by javac).
  • Added support to ikvmstub for constant instance fields.
  • Changed japi build file to generate both forward and backward compatibility reports.
  • Fixed runtime to support loading a pre-compiled Java class by referencing an ikvmstub generated stub class.
  • Fixed module names when generating -Xsave files.
  • Moved JNI method pointer field to proxy class when generating -Xsave files.
  • Replaced gnu.classpath.RawData with an IKVM specific version.
  • Added optimized special case implementation of several java.nio.DirectByteBufferImpl methods to map.xml.
  • Removed CharConversionException handlers from StringHelper (I fixed Classpath's character/string encoders/decoders to no longer throw exceptions).
  • ClassLoaderWrapper has a new method PublishLibraryImplementationHelperType to publish types that live in IKVM.Runtime.dll (this is used for the new gnu.classpath.RawData that lives in IKVM.Runtime.dll because it contains unverifiable code).
  • Improved line number table encoding (more space efficient and simpler code).
  • Implemented JNI methods NewDirectByteBuffer, GetDirectBufferAddress and GetDirectBufferCapacity.
  • Added new method AttributeHelper.SetEditorBrowsableNever to decorate methods with the EditorBrowsableAttribute (to prevent them from showing up in Intellisense).
  • Implemented support to override method implementations in map.xml (not implemented for constructors yet).
  • Renamed all of the IKVM introduced fields and methods to __<xxx>.
  • Added support for several new CIL instructions to remapper.cs.
  • Shadow types (e.g. the .NET java.lang.Object type) now hide all inherited methods and decorate them with EditorBrowsableAttribute(Never) so that they no longer show up in Intellisense.
  • I broke JNI.RegisterNatives in this snapshot (but it's fixed in cvs).

New snapshots: just the binaries and source plus binaries.

Wednesday, 24 November 2004 13:56:56 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Tuesday, 09 November 2004
New Snapshot

A new snapshot. Nothing new, except that FileDescriptor.sync now actually works on Linux.

Thanks to lupus for reporting that it didn't work before.

New snapshots: just the binaries and source plus binaries.

Tuesday, 09 November 2004 17:37:29 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
Comment Spam

Yesterday I disabled comments, because the comment spam was driving me nuts. I've now re-enabled them, but I've added a programming question that hopefully should be easy to answer for anyone wishing to comment, but too hard for the spammers to be worthwhile to figure out.

If you want to comment but don't know the answer to the question, feel free to e-mail me.

Sorry, for the inconvenience. :-(

Tuesday, 09 November 2004 15:02:36 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Monday, 08 November 2004
Running Derby on IKVM

At the Colorado Software Summit I attended a presentation on Derby by Dan Debrunner. Derby is the open source version of IBM's Cloudscape database engine. After seeing the presentation I decided to try to run it on IKVM. I tried some simple tests and they all went fine. At the moment Derby doesn't include a test suite yet (IBM is working on releasing their tests), so I didn't do any extensive testing.

Since Derby is a real transactional database engine it uses a transaction log and requires FileDescriptor.sync() to work corectly, so I decided to implement that. I hadn't previously implemented it, because it unfortunately requires platform specific code, so it only works on Windows and on Posix systems (when running on Mono).

I wrote a very simple test app in C# (and the Java equivalent) and did some performance tests (download source):

Operation Sun JDK 1.5 IKVM/.NET 1.1 IKVM/Mono 1.0.2
getConnection 1903 1472 2177
create table 450 634 624
prepareStatement1 344 514 978
1000x insert 1031 387 550
prepareStatement2 124 294 231
1000x select 1038 851 3682

(Times in milliseconds, based on average of three best runs out of four runs.)

All the usual disclaimers about benchmarks apply of course, but it's interesting to see that IKVM on .NET outperforms JDK 1.5 on the queries. Preparing the statements take longs, but that is expected, as IKVM has to convert the generated class files to CIL (and this part of IKVM is not very efficient).

Another interesting aside is that when I ran the test on JDK 1.4.1, the insert operation took about 40 seconds to run. This rather extreme performance bug was fixed in 1.4.2.

One thing that is important to note when running Derby on IKVM is that Derby compiles all queries to bytecode and IKVM doesn't support garbage collecting classes (due to .NET's inability to unload code), so unless your application uses a fixed set of prepared statements that fit in the Derby statement cache, you're going to leak memory.

I made a new snapshot that includes the new sync implementation:

  • Resync'ed with GNU Classpath cvs.
  • Implemented java.io.FileDescriptor.sync() and java.nio.channels.FileChannel.force().
  • Fixed java.io.File to treat file paths as case insensitive on Windows.
  • Made exception helper a little more robust against exceptions happening early in bootstrap.
  • Fixed japi build file to include all the public APIs.
  • Fixed ClassLoaderWrapper.getSystemClassLoader() to bypass ClassLoader.getSystemClassLoader() and access the underlying field directly, to prevent a security check.
  • Changed DotNetTypeWrapper to overrider GetClassLoader to lazily get the system class loader.
  • Fixed ikvmc generated main stub to return 1 if the program exited with an exception.
  • Implemented support for java.security.manager system property (the security manager can now be set from the command line using -Djava.security.manager=<class>).

New snapshots: just the binaries and source plus binaries.

Monday, 08 November 2004 11:51:13 (W. Europe Standard Time, UTC+01:00)  #    Comments [8]
# Thursday, 04 November 2004
Japitools & New Snapshot

I've integrated Stuart Ballard's Japitools in my build process to keep track of the API completion status and to test ikvmc and ikvmstub. To results of running it on the current ikvm development snapshot can be found here.

What's new in the snapshot:

  • Implemented AWT Toolkit.getFontList().
  • Regenerated mscorlib, System and System.Xml stub jars with new version of ikvmstub.
  • Resync'ed with GNU Classpath cvs.
  • Improved error handling in Socket classes (exceptions throw now match the JDK better).
  • Implemented urgent data and shutdown methods in PlainSocketImpl (thanks to Dmitry Gromov for this).
  • Fixed ikvm.exe and ikvmc.exe to support slashes in Main-Class entry in manifest.
  • Fixed ikvmstub.exe to emit throws clauses for constructors.
  • Fixed bug that caused internal error when compiling class that has a non-private final field of a type that cannot be loaded.
  • Fixed reflection on .NET types to mark non-virtual methods as final.
  • Fixed name clash detection algorithm to ignore constructors (because name clash prevention isn't yet implemented for constructors).
  • Fixed reflection on .NET types to ignore newslot methods that hide a virtual method in a base class.
  • Fixed reflection on .NET types to not emit a public for explicitly implemented interface methods if a base class already has a suitable method.
  • Removed HideFromJavaAttribute from remapped types.
  • Added HideFromJavaAttribute to nested helper type generated for remapped interfaces.

New snapshots: just the binaries and source plus binaries.

Thursday, 04 November 2004 14:13:12 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Tuesday, 19 October 2004
Stack Traces & Line Numbers

Today's snapshot contains a very helpful new feature: Line numbers in stack traces. Unfortunately you only get line numbers in statically compiled code on .NET 1.1, but on Whidbey you'll also get line numbers for dynamically compiled code. At the moment Mono doesn't support them at all :-(

Together with this I also fixed up the stack trace cleaning code to remove most of the IKVM and .NET implementation artifacts from the stack traces. If you don't want the sanitized stack traces, you can use -Dikvm.cleanstacktrace=0 to disable it. This can be helpful to understand what's going on under the covers, especially if there is a bug in the cleanup code ;-)

Here is an example of a cleaned stack trace with line numbers (when run on Whidbey):

public class test
{
  public static void main(String[] args)
  {
    try {
      Object o = new Object();
      ((cli.System.Object)o).ToString();
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      new java.util.Hashtable().put(null, null);
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      "".endsWith(null);
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      "".charAt(1);
    } catch(Throwable t) {
      t.printStackTrace();
    }
  }
}
C:\tmp>ikvm test
java.lang.ClassCastException
        at test.main (test.java:7)
java.lang.NullPointerException
        at java.util.Hashtable.hash (Hashtable.java:822)
        at java.util.Hashtable.put (Hashtable.java:432)
        at test.main (test.java:12)
java.lang.NullPointerException
        at cli.System.String.EndsWith (Unknown Source)
        at java.lang.String.endsWith (map.xml:335)
        at test.main (test.java:17)
java.lang.StringIndexOutOfBoundsException
        at java.lang.String.charAt (map.xml:266)
        at test.main (test.java:22)

What's new:

  • Merged with Classpath cvs.
  • Added stub to AWT toolkit for getClasspathTextLayoutPeer.
  • Added two new public APIs to the runtime:
    - IKVM.Runtime.Util.GetClassFromObject(). It returns the java.lang.Class object corresponding to the passed in object. It is now used by java.lang.Object.getClass().
    - IKVM.Runtime.Util.GetClassFromTypeHandle(). This is used by the compiler when it needs the class object (for synchronized static methods, for static JNI methods and for the new 1.5 ldc class literal).
  • Changed map.xml String.hashCode body to redirect.
  • Inlined String.charAt in map.xml.
  • Improved stack trace cleaning so that IKVM implementation artifacts are removed from exception stack traces.
  • Code compiled with ikvmc now produces stack traces with line numbers even if the -debug option isn't used. On Whidbey, dynamically converted code will also have line numbers in the stack traces.
  • Moved my system/extension class loader implementation into GNU Classpath.
  • Implemented stack walking for AccessController security checks.
  • Fixed -D option. I used a StringDictionary to store the key/value pairs, but that converts the keys to lowercase.
  • Added -nostacktraceinfo option to ikvmc, to disable generating the line number information table and source file attributes.
  • Made ikvmc a little more robust in dealing with bogus path arguments.
  • Changed TypeWrapper.IsAbstract and ClassFile.IsAbstract to return true for interfaces, even if the abstract bit isn't set.
  • Made class loading error tracer more robust.
  • Introduced a CountingILGenerator wrapper for ILGenerator that keeps track of the IL offset (required for the line number tables).
  • Added AttributeHelper methods to set the new SourceFileAttribute and LineNumberTableAttribute.
  • Removed TypeWrapper.PackageName (was only used in one place and it wasn't correct for array types).
  • De-virtualized TypeWrapper.EmitBox (custom boxing support was previously removed).
  • Reflection now reports a public default constructor on all ValueTypes (on the .NET the default constructor for value types is implicit).
  • Finally completed the inheritance inversion for java.lang.Object/cli.System.Object and java.lang.Throwable/cli.System.Exception. Casting and instanceof tests on cli.System.Object and cli.System.Exception will now work consistently with reflection (i.e. cli.System.Object is a subclass of java.lang.Object and cli.System.Exception is a subclass of java.lang.Throwable). Similar work still needs to be done for java.lang.Comparable/cli.System.IComparable and (a little different) java.lang.String/cli.System.String.
  • Introduced two new custom attributes SourceFileAttribute and LineNumberTableAttribute.
  • Added line number tracking to map.xml parsing.
  • Added blt, ldc_i4_1, add and mul opcodes to remapper.
  • Fixed bug in remapper that caused local variables and labels outside of exception blocks not to be visible inside exception blocks.
  • Fixed verifier to detect trying to instantiate an array type with the new bytecode.
  • Fixed verifier bug that caused NullReferenceException on methods that had dead code that contain local variable stores when compiling with the -debug option.
  • Fixed bug in remapped type code generator that caused remapping helper methods to show up in Java reflection (I forgot to emit the HideFromJavaAttribute).
  • Added error handling for unknown attributes to map.xml parser.

New snapshots: just the binaries and source plus binaries.

Tuesday, 19 October 2004 16:10:46 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]