# Tuesday, 16 May 2006
Using foreach to enumerate Java collections in C# 3.0
A long standing feature request for IKVM has been to make Java collections implement System.IEnumerable and I've always resisted doing that for various reasons.

I while ago -- while discussing this with Stuart Ballard -- I realised that with the proposed C# 3.0 language extensions, in particular "extension methods" it should be possible to make Java collections foreach-able with little effort:

namespace java.util
{
  public static class CollectionExtensionMethods
  {
    public static IEnumerator GetEnumerator(this java.util.Collection col)
    {
       return new CollectionEnumerator(col);
    }
  }
}

For those who don't know how extension methods work, basically the above code (note the this keyword before the argument type) adds a method to java.util.Collection that feels like an instance method.

Given the way foreach works, I had expected that it too would recognize this GetEnumerator method and therefore work on all Java collections, but alas that is not the case.
If you want to see this changed before C# 3.0 is released, please vote. Alternatively, if you're Miguel and on the ECMA C# committee, it should be obvious what to do ;-)

Tuesday, 16 May 2006 15:03:28 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
IKVM 0.28 rc1

A new release candidate based on GNU Classpath 0.91. I did some perf work and a fair bit of restructuring in the way class loaders work, to better support ikvmc and ikvmstub on assemblies loaded in the ReflectionOnly context (on .NET 2.0). The perf work resulted in a significantly improved startup time for Eclipse (IKVM 0.26: 1 minute 23 seconds, IKVM 0.28: 55 seconds).

Updated japi results are available here. The comparison is against JDK 1.5 now and ignores the generics metadata.

Changes:

  • Integrated GNU Classpath 0.91 plus one patch.
  • Added explicit null check for return value of GetEntryAssembly() in VMSystemProperties.
  • Implemented socket timeout by using Socket.Poll() instead of setting the timeout on the underlying socket (because .NET 2.0 considers the socket broken after a Read timed out).
  • Removed classLoader field from TypeWrapper and made GetClassLoader() abstract (to enable subclasses to use a more efficient way to store the class loader).
  • Moved creation of java.lang.Class object from TypeWrapper constructor (because it would trigger a call to GetClassLoader before that was ready to return meaningful data and also because it wasn't semantically correct to expose the TypeWrapper instance before it was fully constructed).
  • Added ikvm.lang.Internal annotation to mark types and members as internal to the assembly (supported by ikvmc only, not in dynamic mode.) Note that ikvm.lang.Internal should only be applied to public types and members. Note also that to reflection these internal types and members will appears as package private.
  • Removed map.xml hacks to work around cross package accessibility issues (now done by marking the appropriate types/members public and annotating them with @ikvm.lang.Internal).
  • Added map.xml implementation of Class.newInstance (to support @ikvm.lang.Internal).
  • Changed ClassFile to pack major version and flags together to reduce the size of the object.
  • Changed ClassFile.FieldOrMethod to pack flags together.
  • Simplified (and made more consistent) member access checking in reflection.
  • Added -privatepackage option to ikvmc (to mark all classes in a package tree as internal).
  • Fixed object model remapping to add methods inherited from Object to Throwable.
  • Fixed some edge cases in method override resolution.
  • Added optimization to compiler to devirtualize method calls on this reference when it is safe to do so.
  • Added volatile opcode prefix to remapper.
  • Added support for specifying .NET types in catch block to remapper.
  • Made 1.5 support part of the standard build.
  • Restructed ikvmc.exe and IKVM.Runtime.dll.
  • Centralized caching of ByteCodeHelper MethodInfos in ByteCodeHelperMethods.
  • Fixed Thread.join() bug that caused join to spin for large timeouts.
  • Added optimization to not emit linenumbertable for methods that cannot throw exceptions.
  • Much improved annotation support.
  • Fixed ikvmc to only generate corresponding .NET attributes for annotations that have RetentionPolicy.RUNTIME.
  • Fixed ikvmc to add AttributeUsageAttribute to annotation attributes (based on the Target annotation).
  • Optimized verifier a little by making InstructionState use copy-on-write strategy.
  • Changed string comparisons to ReferenceEquals when possible (identifiers are interned, so this is usually possible).
  • Improved VMStackWalker.getCalling[Class|ClassLoader] performance by removing the unnecessary check for HideFromJava/HideFromReflection attributes.
  • Almost completely removed usage of custom attributes for dynamically compiled code (because defining custom attributes is slow).
  • Fixed race condition when two threads define the same class name in two different class loaders at the same time.
  • Fixed possible deadlock while finishing dynamically loaded types.
  • Fixed bug in Class.getModifiers() for statically compiled anonymous inner classes.
  • Moved loading .NET types by their assembly qualified names from the class loader to Class.forName.
  • Fixed class loader not to load Java classes, by their .NET array, pointer or reference name.
  • Moved hack to return system class loader for .NET and statically compiled types from [Compiled|DotNet]TypeWrapper to Class.getClassLoader.

Files are available here: ikvm-0.28.0.0.zip (sources + binaries), ikvmbin-0.28.0.0.zip (binaries), ikvmbin-generics-0.28.0.0.zip (binaries built from generics branch)

Tuesday, 16 May 2006 11:06:10 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 06 April 2006
@ikvm.lang.Internal

Hopefully someday Java will support more than the current simplistic scheme where classes are either public or non-public. In the meantime, I've added support to ikvmc for marking classes (and members) as internal (i.e. private to the assembly they live in). By marking a public class with the @ikvm.lang.Internal annotation ikvmc (and IKVM.Runtime.dll) will only allow access to the class by other code also living in the same assembly. I've also added a switch to ikvmc for making an entire package tree internal (the switch is named -privatepackage:<prefix>).

In addition, I've now enabled 1.5 support in the mainline version. Many of the 1.5 APIs that previously were only available on the GNU Classpath generics branch have been ported to the trunk, so it is starting to make more sense to enable 1.5 support in the VM by default.

The code is in cvs, although SourceForge has been having some problems, so it might not yet be available thru anoncvs. Development snapshot binaries are available here.

Thursday, 06 April 2006 14:42:05 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Thursday, 30 March 2006
A Micro Optimization

Yesterday I thought of a potential micro optimization for the generated CIL code. Since I'm now tracking method invocations on the this reference, it is possible to devirtualize calls to final methods or methods that are provably not overridden. I didn't expect too much from this optimization, because I assumed that the .NET JIT is capable of doing the same optimization and so the only effective difference would be the removal of the explict null check of the this reference.

After implementing the optimization I wrote a micro benchmark:

final class perf {
  public static void main(String[] args) {
    perf p = new perf();
    p.runTest();
  }
  private void runTest() {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000000; i++) {
      equals(null);
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Here are the results:

  Time (ms)
IKVM 0.26 10806
IKVM 0.27 1883
JDK 1.1 4597
JDK 1.5 Client VM 12068
JDK 1.5 Server VM 0


Somewhat to my surprise neither JDK 1.5 Client VM nor the .NET Framework JIT realised that the virtual method invocation could be devirtualized. Unsurprisingly, HotSpot Server VM was able to deduce that the loop didn't actually do anything at all and optimize it away entirely.

I also threw in JDK 1.1, because as usual in microbenchmarks it outperforms HotSpot Client VM.

Note that the use of the equals method in the benchmark is not very significant, it's just a placeholder for a simple method that can easily be inlined. This optimization is most significant for simple property getters that can be inlined.

The code for this optimization is not yet in cvs.

Oops

On a more embarrassing note, doing this optimization also revealed a hole in the object model remapping. Throwable doesn't properly inherit all the Object methods. The code that gets generated works correctly (in most cases), but it is not verifiable. Here's an example of something that is currently broken:

public class test extends Throwable {
  public static void main(String[] args) throws Exception {
    test c = new test() {
      protected Object clone() {
        return "OK";
      }
    };
    System.out.println(c.clone());
  }
}

Running this on IKVM throws a CloneNotSupportedException instead of printing OK.

Thursday, 30 March 2006 11:08:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Friday, 24 March 2006
Rotor 2.0 released

Microsoft released Rotor 2.0. Rotor is the Shared Source implementation of the CLI (and shares a large part of the code with the .NET Framework 2.0).

Congratulations and thanks to the Rotor team!

Friday, 24 March 2006 16:07:55 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 23 March 2006
IKVM 0.26 Released

I finally got around to releasing the 0.26 bits (identical to rc2). Get them here.

Thursday, 23 March 2006 13:34:00 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Saturday, 11 March 2006
IKVM 0.26 rc2

A new release candidate. It turns out I was a little over enthusiastic in restructuring the class loading to move dynamic class loading into a subclass (which I did to make it easier to build a version of IKVM.Runtime.dll that doesn't support dynamic class loading, to run on the Compact Framework). java.lang.reflect.Proxy support requires that you can dynamically load classes in the bootstrap class loader, so I added back support for that (in a hacky way by delegating to a bogus instance of DynamicClassLoader). This bug was reported by Chris Keller who was also kind enough to fix two socket bugs.

Changes:

  • Restored the ability to dynamically load a class in the bootstrap class loader.
  • Changed PlainSocketImpl to throw java.net.SocketTimeoutException instead of java.io.InterruptedIOException when a timeout expires.
  • Changed PlainSocketImpl.read() to return zero instead of throwing an exception when a non-blocking socket read would block.

Files are available here: ikvm-0.26.0.1.zip (sources + binaries), ikvmbin-0.26.0.1.zip (binaries), ikvmbin-generics-0.26.0.1.zip (binaries built from generics branch)

Saturday, 11 March 2006 19:48:06 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, 08 March 2006
IKVM 0.26 rc1

A new release candidate based on GNU Classpath 0.90 (the successor to 0.20). IKVM.GNU.Classpath.dll grew by more than a megabyte. A big part of this is due to the new crypto implementation that was merged into GNU Classpath. This a great improvement!

Updated japi results are available here.

  • Integrated GNU Classpath 0.90
  • Updated classpath.security with new security providers
  • Added "Windows Vista" as a possible value of os.name system property
  • Included VMObjectInputStream.currentClassLoader() fix from Classpath version
  • Fixed Float.toString() bug (1E8 would be converted to "1E+08.0" instead of "1.0E8")
  • Made some VMThread members package accessible to avoid accessor methods
  • Added copyright banners to executables (when run without command line arguments or with the -version option)
  • Added "-showversion" option to ikvm.exe
  • Fixed ikvmstub to use IKVM.Runtime.Util.GetClassFromTypeHandle() instead of IKVM.Runtime.Util.GetFriendlyClassFromType(), because that would cause problems on remapped types in mscorlib.
  • Fixed support for dynamically instantiating a class that was not loadable at method compilation time.
  • Added support for running interface static initializer when accessing a final field.
  • Moved most .NET resource reading code from IKVM.GNU.Classpath to IKVM.Runtime, to make it easier to use new resource and compression APIs on Whidbey.
  • Introduced ikvm.io.InputStreamWrapper (wraps a java.io.InputStream around a System.IO.Stream).
  • Removed undocumented -manifestResources ikvmc option. When compiled for Whidbey, resources are now always stored as manifest resources.
  • When compiled for Whidbey, resources are now compressed using DeflateStream instead of custom compression.
  • Changed SoftReference never to be cleared, since there is no reliable way to detect low memory and clearing them too eagerly breaks Eclipse.
  • Fixed ikvmstub to also export implemented interfaces that are non-public.
  • Split off dynamic class loading support from ClassLoaderWrapper.cs into new DynamicClassLoader.cs.
  • Moved static compiler support from vm.cs to new file CompilerClassLoader.cs.
  • Fixed CompiledTypeWrapper and DotNetTypeWrapper to finish base class and interfaces in their Finish method.

Files are available here: ikvm-0.26.0.0.zip (sources + binaries), ikvmbin-0.26.0.0.zip (binaries), ikvmbin-generics-0.26.0.0.zip (binaries built from generics branch)

Wednesday, 08 March 2006 11:14:37 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Saturday, 11 February 2006
Eclipse Again

Nat commented on the previous entry:

I just tried to run ikvm against eclipse 3.1.2. It failed with the following message:

!ENTRY initial@reference:file:plugins/org.eclipse.core.runtime_3.1.2.jar/ 0 0 2006-02-02 11:49:09.218
!MESSAGE FrameworkEvent.ERROR
!STACK 0
org.eclipse.core.runtime.InvalidRegistryObjectException: Invalid registry object
...

This turns out to be caused by a SoftReference that is being cleared too eagerly. Since .NET has no soft references and there is no way to determine if the managed heap is running low, I used a hack to always promote objects referenced by a soft reference to generation 2 and from there on treat them as weak references, which effectively means they will be collected the next time a full GC is run and there are no more strong references to the object. Strictly speaking clearing them before running out of memory is not incorrect, because the Java doc for SoftReference says:

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared.

However, Eclipse depends on soft references not being cleared (at least during a particular window while it is starting up). I realised that always promoting the object to generation 2 is not correct either (because you may run out of memory before the object gets there). So considering the complexity and possible performance implications of the current hacks, I decided to simply never clear SoftReferences.

In conclusion, the .NET Framework needs something like soft reference support and until that happens, it won't be possible to implement SoftReference correctly and efficiently.

Update: Nat points out in the comments that there is a workaround:

As a workaround, you can start up eclipse with the following command line

eclipse -vm c:\tools\ikvm-0.24.0.1\bin\ikvm.exe -vmargs -Declipse.noRegistryFlushing=true

Saturday, 11 February 2006 13:52:02 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Monday, 30 January 2006
IKVM 0.24 Released

I released 0.24.0.1 to SourceForge. João Saraiva reported that ikvmstub doesn't work correctly for mscorlib, but I've decided not to fix that for this version and instead make the correct mscorlib.jars available for download: .NET 1.1 and .NET 2.0

Monday, 30 January 2006 09:12:31 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]