# Monday, 28 April 2003
DotGNU & New Snapshot

Saturday I joined the DotGNU IRC meeting to discuss their Java support. We decided to make sure that our efforts will be interoperable.
They are working on a Java source to IL compiler and this complements IKVM's byte code to IL compiler nicely. We'll be working together to create a standard format for remapping Java classes to .NET classes and define custom attributes to express Java semantics that don't map directly onto the .NET standard attributes.

I made new source and binaries snapshots available. Not many changes:

  • invokespecial byte code now checks for null references before calling the method. I intend to write an item on invokespecial in the future, because it is quite an interesting instruction with a bit of a history.
  • Improved method overriding handling for methods that are less accessible than the method they override. Java allows this, but .NET doesn't. It is handled by giving the overriding method the same (or better) accessibility as the overriden method.
    IMHO this is a design flaw in the CLR, because it makes it a breaking change to widen the access of a virtual method in a new version of a type.
  • Improved ikvmc's handling of -recurse and added wildcard support to file arguments.
Monday, 28 April 2003 10:54:39 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Friday, 25 April 2003
Feedback
Stuart posted a nice comment:

Well, I now am a legitimate happy IKVM user.

I just found myself in a situation where I wanted to be able to call nrdo code (nrdo is a Java tool for database access, http://nrdo.sab39.org/) from a web application, that also had to read its input files from a windows machine. The individual parts of that aren't a problem: nrdo is reasonably well librarified so it's perfectly possible to call it from a web application, and it's perfectly possible to run Java code on windows (indeed, that's how our normal development is done).

But we don't have any windows machines running any Java application servers, and spawning a Java process from inside ASP.NET didn't appeal very much :)

It's funny how I've been following IKVM for a while but it still took ages before the obvious solution hit me. I compiled a nrdo.dll (okay, this took me longer than I thought because the -recurse option to ikvmc didn't do what I thought it would and neither did path\*.class), created an ASP.NET web application in Visual Studio, added references to classpath.dll, nrdo.dll and ik.vm.net.dll, and started typing.

It was a seriously schizophrenic experience (but in a good way!). I don't normally use an IDE for Java coding so it was the first time I'd ever seen intellisense for my nrdo libraries. And you can get seriously confused as to which language you're using when you write C# code that looks like this:

using java.util;

for (Iterator i = myList.iterator(); i.hasNext(); ) {
MyThing foo = (MyThing) i.next();
foo.something();
}

But it worked, and it took me about an hour to solve what I'd expected to be a pretty complex problem. The schizophrenic aspect is just an artefact of IKVM being really, *really* good at its job!

Thanks! Patches to make ikvmc more intuitive are always welcome of course ;-)

Friday, 25 April 2003 08:53:56 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Monday, 14 April 2003
Snapshot

I checked in my value type changes, along with a bunch of other changes and made new snapshots.

Here are the highlights:

  • (limited) support for using value types
  • support for calling methods with ByRef arguments
  • better support in map.xml for redirecting to Java classes
  • moved parts of StringHelper & ObjectHelper from C# to Java
  • updated to be compatible with current Classpath cvs

Source and binaries snapshots are in the usual locations.

Monday, 14 April 2003 12:32:48 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Friday, 11 April 2003
More value type feedback

Stuart Ballard commented on yesterday's entry:

I definitely think these changes should be included.

As I understand it, without them it is impossible to use C# structs, enums and other value types in Java code at all, and also impossible to call methods which require ref or out parameters.

This is correct (except that enums were already usable from Java, they are visible as classes containing public static final int fields and arguments are just int arguments).

To me this scenario is very disappointing - the dream of IKVM, for me, was to see Java as a first-class .NET language while still remaining "true java". Eliminating support for value types and reference arguments clashes with the first of these goals; requiring a hacked compiler violates the second.

I'd even go so far as to ask whether it would be possible to actually *write* a "struct" in java, along the lines of the following:

public class JavaStruct extends system.ValueType {
int structMember;
}

Presumably it would be possible for ikvm to detect classes that inherit from ValueType and compile them as structs rather than classes...

I briefly considered it, but dismissed it at the time because I didn't need it. You've convinced me to take another look at this.

To summarize, not only do I think this is cool functionality (even if the implementation *is* a little bit of a hack) I think it's extremely important functionality and I'd like to see further fine-tuning of the "hack" and further enhancements to the functionality, rather than leaving it out entirely.

The reason I didn't comment earlier, though, is that I don't really have any right to comment, as I don't actually use IKVM at all (although I may in the future to save my co-developers from downloading the JRE to run a single java program). I'm only commenting now to provide at least some positive feedback on the idea of checking it in, so that you don't throw it out on the basis that nobody thinks it's valuable (although of course I fully respect your right to throw it out for any other reason).

Thanks for commenting, I really appreciate it! I will go ahead and polish up the changes and check them in.

Friday, 11 April 2003 13:16:11 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 10 April 2003
More on value types

David Jeske commented on the previous entry

Can ValueType local variables be treated as ValueTypes instead of pointers to ValueTypes? If this were the case, then av[1] could be the pointer to the interior of the valuetype array, and av[1].foo = 42; would work correctly. This would also make the IL for using local ValueType variables most similar to how it would turn out if it had been C#.

The boxing/unboxing would only occur when coercing/converting from a local variable of a ValueType to a ReferenceType (i.e. Object foo = v; )

Remember that I'm working with a standard Java compiler. All the value type support is in the byte code to CIL compiler, because of this I wanted to stay as close to the Java semantics as possible, to prevent problems caused by Java compiler differences (there really isn't any guarantee that local variables in the source end up as local variables in the byte code). Also, the current design a lot easier to implement ;-)

Having said that, treating locals as value types still wouldn't allow av[1].foo = 42; to work. This would require the aaload instruction to return a pointer to the array element, in itself this isn't hard but the introduction of pointers would complicate the type system greatly.

Ultimately, the reason I added this (limited) value type support, is to enable me to write more "native" Java methods in Java. I haven't checked in these changes and I'm still not sure that doing so would be a good idea. Without Java compiler support it will always be a hack.

Thursday, 10 April 2003 12:26:21 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Saturday, 05 April 2003
Value Types & Reference Arguments

I've added experimental support for using value types and reference arguments in Java. The challenge is to do this without having to build a new Java compiler.

Here is a value type I constructed in C# for testing purposes:

public struct ValType {

  public int foo;

 

  public ValType(int f) {

    foo = f;

  }

 

  public override string ToString() {

    return "ValType:" + foo;

  }

 

  public static void Increment(ref ValType v) {

    v.foo++;

  }

}  

Here is a Java example that uses value types and calls a method with a reference argument:

import system.DateTime;

 

class ValTest {

  static DateTime dt;

 

  public static void main(String[] args) {

    ValType v = new ValType(0);

    v.foo = 42;

    System.out.println(v);

 

    ValType[] av = new ValType[1];

    av[0] = v;

    ValType.Increment(av);

    System.out.println(av[0]);

 

    dt = DateTime.get_Now();

    DateTime d = new DateTime(0);

    d = AddDay(d);

    System.out.println(d);

    System.out.println(dt);

  }

 

  private static DateTime AddDay(DateTime dt) {

    return dt.AddDays(1);

  }

}

How is this code compiled? Whenever a value type is loaded from a field or array, instantiated or returned from a method it is boxed. Local variables are references to boxed instances of the value type. When a boxed value type instance is assigned to a field, stored in an array or passed to a method, it is unboxed. Referenced method arguments are exported by NetExp as arrays.

Let's look at a few examples:

    ValType v = new ValType(0);

Is compiled as:

ldc.i4.0

newobj     instance void ValType::.ctor(int32)

box        ValType

stloc.0

The local variable v is of type object and contains a reference to the boxed value.

    v.foo = 42;

Assigning a field in the boxed value:

ldloc.0

ldc.i4.s   42

stloc.1

unbox      ValType

ldloc.1

stfld      int32 ValType::foo

After loading the reference to the boxed value, the constant (42) gets stored in a temporary local and then reference gets unboxed, this leaves a managed pointer to the interior of the boxed value on the stack and the stfld instruction uses this pointer to set the field.

    av[0] = v;

Setting an array element:

ldloc.2

ldc.i4.0

ldloc.0

stloc.3

ldelema    ValType

ldloc.3

unbox      ValType

ldobj      ValType

stobj      ValType

The address of element 0 of the array is loaded, v is unboxed and copied into the array.

    ValType.Increment(av);

Calling a method with a reference argument:

ldloc.2

stloc.s    V_4

ldloc.s    V_4

ldc.i4.0

ldelema    ValType

call void ValType::Increment(valuetype ValType&)

The Java code passes an array and the byte code to CIL compiler takes the address of the first element of the array and passes that to the method. BTW, if the array is of length zero, ldelema throws a System.IndexOutOfRangeException.

Pros and Cons of this Approach

The advantage of enabling value type of reference arguments are that it is easier to leverage .NET framework code from within Java code (targetted at IKVM.NET) and it enables me to write more glue code in Java.

The downside is the non-intuitive behavior. Compare these two lines:

    v.foo = 42;

    av[0].foo = 42;

The first line does what you'd expect, it assigns 42 to the field foo of the boxed value type. However, the second line has no effect, because it results in a boxed copy being loaded from the array, that boxed copy's field foo is assigned the value 42, but it is not copied back into the array. This also applies to fields, only local variables contain boxed value types and can be manipulated safely.

Finally, a small problem with arrays of value types is that the Java compiler will happily compile:

    Object[] array = new ValueType[1];

Obviously this isn't legal.

I'd like to get feedback from people who either like or dislike this new functionality. Of course, any ideas for alternative approaches would be most welcome too.

Saturday, 05 April 2003 16:03:00 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]