# Wednesday, 03 January 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
Wednesday, 03 January 2007 12:12:02 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 28 December 2006
IKVM 0.32 Released

I released 0.32 to SourceForge (same bits as rc1).

Thursday, 28 December 2006 16:57:44 (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.

Thursday, 28 December 2006 14:07:23 (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.

Thursday, 28 December 2006 09:20:20 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 11 December 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.

Monday, 11 December 2006 09:43:31 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Thursday, 07 December 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.

Thursday, 07 December 2006 07:45:59 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Tuesday, 05 December 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

Tuesday, 05 December 2006 08:57:09 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Tuesday, 28 November 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!

Tuesday, 28 November 2006 07:28:13 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Tuesday, 14 November 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.

Tuesday, 14 November 2006 07:44:12 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Wednesday, 11 October 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

Wednesday, 11 October 2006 07:35:48 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]