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>!"

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:

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:

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:

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):

While fixing bugs in ikvm to get more Mauve tests working (BTW, current results: 224 of 7584 tests failed), I ran across a small but interesting difference between Java and C# (and the underlying bytecodes) in converting floating point numbers to integers.

It turns out that the CIL instruction conv.i4 returns an undefined value when the float value lies outside of the range representable by an 32 bit integer, unlike the JVM's f2i instruction which is defined to return either Integer.MIN_VALUE or Integer.MAX_VALUE in that case.

If you want your .NET code to run consistently, use the conv.ovf.i4 instruction that checks for overflow. In C# this can be done by using a checked block:

Now, instead of returning an undefined value, the cast throws a System.OverflowException.

The JVM designers felt it was very important not to have any undefined or implementation defined behavior. One of the lessons learned from C and C++ is that whenever there is undefined or implementation defined behavior, code will be written that depends on the behavior of a particular platform/compiler. The JVM designers wanted to removed this source of portability problems.

However, they payed a price in performance for this. A well known example is the case of floating point performance (on x86), which was later "fixed" by relaxing the floating point specification and introducing strictfp. As Morpheus would say: "Welcome to the real world!" (Don Box claims everything in computing can be understood by watching The Matrix enough times).

I came across a class file that was the equivalent of the following source:

class Test{public static final int FOO = 1;

static { FOO = 1; }}

This isn't legal Java, but the class file equivalent is. The FOO field has a ConstValue attribute with the value 1 and then there is code in the static initializer to set the value again. The code in the static initializer isn't needed and the Java compilers I've seen so far don't emit it.

Anyway, IKVM handles assignments to (non-blank) final fields by just ignoring the assignment, but my code generator emitted a nop instruction, instead of a pop (because it should consume the value on the stack). Fixed.

GNU Classpath is about to release version 0.05, so I got their code from cvs and updated my native methods to work with the latest code (the only changes required were for Object[In][Out]putStream, because Mark cleaned those up to use less native code, a nice improvement!). There was still one remaining issue with compiling the classpath code with ikvmc, I had to comment out a line of code in java/nio/charset/Charset.java:

CharBuffer.wrap takes an CharSequence as its argument, but my java.lang.String doesn't implement CharSequence (yet). It occurred to me that since it is legal for any reference type to be passed where an interface is expected (see here) this code was legal as well (even if String doesn't implement CharSequence), so I added support to the compiler to insert casts when the arguments on the stack do not match with the expected method arguments (but only for interface references).

Finally, there is still one patch required to Classpath, because new File("c://") hangs:

You wouldn't expect this to be a common occurrence, but it turns out that this exact path is constructed by the code that computes the current directory, so if you use ikvm to run a Java application in the root directory of a drive it hangs (without this patch).

After lots of hacking, I managed to get IKVM to run HelloWorld under mono. This involved lots of changes/bugfixes to IKVM, the mono runtime and the class libs. I intend to submit a big patch to the mono mailing list shortly with the changes.

Great news!

Unrelated to the above, I checked in a bunch of changes and updated the source and binary snapshots. I'll be out of the country for two weeks, so there probably won't be much activity.