# 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]
# Monday, 31 March 2003
Sockets
I completed most of the Socket code and fixed a few bugs. Mauve results (with current Classpath CVS code): 172 of 7707 tests failed.

I updated to BlogX rev 20 and this means that the RSS will now contain xhtml:body (for the new entries). Chris says: "So, if you favorite aggregator isn't showing the full text of my blog, send them a mail and get them to support <xhtml:body>!"

I've updated the source and binaries snapshots
Monday, 31 March 2003 17:06:44 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Wednesday, 19 March 2003
System.arraycopy

At first sight, it might seem that System.arraycopy is not a very interesting method, but once you dig into it, it turns out to be an interesting case study.

.NET has a very similar method Array.Copy and one of its overloads has the exact same signature as its Java cousin, but throws slightly different exceptions and there is a tiny difference in behavior. So an initial naïve implementation of System.arraycopy would look as follows:

public static void arraycopy(object src, int srcStart,
       object dest, int destStart, int length) {
    try {
        Array.Copy(src, srcStart, dest, destStart, length);
    } catch(ArgumentNullException) {
        throw new NullReferenceException();
    } catch(ArgumentException) {
        throw new ArrayIndexOutOfBoundsException();
    } catch(ArrayTypeMismatchException) {
        throw new ArrayStoreException();
    } catch(InvalidCastException) {
        throw new ArrayStoreException();
    }
}

This works fairly well, but it has two problems. The first problem is that it is too powerful. Array.Copy allows widening conversions for primitive types. This means, for example, that it is possible to copy a byte array to an int array. Java doesn’t allow this. The second problem is more subtle, Javadocs for System.arraycopy say:

“Otherwise, if any actual component of the source array from position srcPos through srcPos1 cannot be converted to the component type of the destination array by assignment conversion, an ArrayStoreException is thrown. In this case, let k be the smallest nonnegative integer less than length such that src[srcPosk] cannot be converted to the component type of the destination array; when the exception is thrown, source array components from positions srcPos through srcPosk-1 will already have been copied to destination array positions destPos through destPosk-1 and no other positions of the destination array will have been modified.”

In other words, if an ArrayStoreException is thrown, all elements prior to the one that failed are copied. In contrast to this, the .NET documentation for Array.Copy says:

“If this method throws an exception while copying, the state of destinationArray is undefined.”

So to be strictly correct, we cannot rely on Array.Copy to implement copying of reference arrays that might throw an exception during copying. Here is a better implementation of System.arraycopy:

public static void arraycopy(object src, int srcStart,
       object dest, int destStart, int length) {
    // fast path if source and destination are same
    if(src != dest) {
        Type type_src = src.GetType();
        Type type_dst = dest.GetType();
        // fast path if arrays are of identical type
        
if(type_src != type_dst) {
            if(len < 0) {
                throw newArrayIndexOutOfBoundsException();
            }
            try {
                Object[] src1 = (Object[])src;
                Object[] dst1 = (Object[])dest;
                for(; len > 0; len--) {
                    dst1[destStart++] = src1[srcStart++];
                }
            } catch(InvalidCastException) {
                throw JavaException.ArrayStoreException();
            }
        }
    }
    try {
        Array.Copy((Array)src, srcStart,
                   (Array)dest, destStart, length);
    } catch(ArgumentNullException) {
        throw new NullReferenceException();
    } catch(ArgumentException) {
        throw new ArrayIndexOutOfBoundsException();
    } catch(InvalidCastException) {
        throw new ArrayStoreException();
    }
}

I think this is a correct implementation of System.arraycopy. It’s still not perfect though, because it turns out to be really slow. Here is a small benchmark:

class arraycopy {
    public static void main(String[] args){
        test(10, 10000000);
        test(100, 1000000);
        test(1000, 100000);
    }

    private static void test(int size, int count) {
        int[] a = new int[size];
        int[] b = new int[size];
        long start = System.currentTimeMillis();
        for(int i = 0; i < count; i++) {
            System.arraycopy(a, 0, b, 0, a.length);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

Here are the results for the JDK 1.1 Symantec JIT, JRE 1.4.1 HotSpot Client VM and IKVM running on .NET 1.0:

Symantec

JRE 1.4.1

IKVM

10

1012

2343

12127

100

340

531

1402

1000

120

310

340

It’s obvious that for small arrays, the overhead is really large. The reason this is so much slower than the Java version is probably because of the cost of the call to GetType combined with the extra checking going on inside Array.Copy. If Sun had only provided overloaded versions of System.arraycopy for each type of primitive array, we wouldn’t need to do so much type checking! It turns out that even without these overloads we can still get the same result (in many cases), because the verifier often knows the types of the arguments. In compiles.cs I added some code to the invokestatic handler to check for invocations of System.arraycopy and if the array arguments are known to be primitive arrays, the call gets redirected to a more efficient arraycopy implementation.

Here is where the call to System.arraycopy in the above benchmark gets redirected to:

public static void arraycopy_primitive_4(Array src,
       int srcStart, Array dest, int destStart, int len) {

    try {

        checked {

            Buffer.BlockCopy(src, srcStart << 2,
                       dest, destStart << 2, len << 2);

            return;

        }

    } catch(ArgumentNullException) {

        throw new NullReferenceException();

    } catch(OverflowException) {

        throw new ArrayIndexOutOfBoundsException();

    } catch(ArgumentException) {

        throw new ArrayIndexOutOfBoundsException();

    }

}

No more calls to GetType and no more casts to Array are required. In addition, since we know that the arrays are both of the same primitive type, we can use the more efficient Buffer.BlockCopy instead of Array.Copy.

Here are the performance results for the new implementation:

Symantec

JRE 1.4.1

IKVM

10

1012

2343

1713

100

340

531

381

1000

120

310

230

Obviously a worthwhile improvement. For completeness, here are the performance results for doing the arraycopy with a simple for loop (i.e. in a modified version of the benchmark that doesn't call System.arraycopy , but instead has simple simple method that copies the array using a for loop):

for(; len > 0; len--)
    src[srcStart++] = dest[destStart++];

Symantec

JRE 1.4.1

IKVM

10

1853

2724

1522

100

1542

2444

1162

1000

1532

2363

1131

Wednesday, 19 March 2003 18:00:14 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 17 March 2003
Cobol

On the ikvm-developers list, Brian Sullivan reported that he had partial success with running a Cobol application (compiled with PERCobol to a Java jar) under ikvm.

The exception was caused by some missing org.xml.sax.* classes.

In unrelated news, I checked in several changes and made new source and binaries snapshots.

Monday, 17 March 2003 15:20:43 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 13 March 2003
Welcome on the other side

Like many before me, I finally grew tired of Radio and so I've migrated to BlogX by Chris Anderson. All I need now is an rss aggregator, preferably ASP.NET based.

Thursday, 13 March 2003 14:28:06 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 03 March 2003
Hello Mono (2)
C:\>mono --noinline --share-code c:\ikvm\bin\ikvm.exe hello
** Warning **: cannot find C:\cygwin\home\lalo\go-mono\install\
etc\mono\machine.config
Trying to load app config file...
Hello World

The latest ikvm binaries together with Mono 0.21 now run Hello World!

Many thanks to everyone at Ximian, the Mono contributors and especially Zoltan Varga!

The --noinline and --share-code options are needed to work around a bug in the current Mono JIT that cause it to call the class constructors to eagerly.

I've updated the source and binaries snapshots.

Monday, 03 March 2003 11:57:22 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]