# Tuesday, 10 August 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.

Tuesday, 10 August 2004 16:03:46 (W. Europe Daylight Time, UTC+02:00)  #    Comments [6]
# Wednesday, 30 June 2004
Mono 1.0

Congratulations to the Mono team with the release of 1.0!

Wednesday, 30 June 2004 19:03:12 (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.

Wednesday, 30 June 2004 14:34:50 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Monday, 28 June 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.
Monday, 28 June 2004 14:07:22 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Friday, 25 June 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.

Friday, 25 June 2004 16:14:06 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Sunday, 20 June 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.

Sunday, 20 June 2004 11:04:29 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Monday, 14 June 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.

Monday, 14 June 2004 20:12:18 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 09 June 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.

Wednesday, 09 June 2004 16:33:52 (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.

Wednesday, 09 June 2004 12:13:50 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Monday, 07 June 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.

Monday, 07 June 2004 15:03:16 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]