# Saturday, 01 October 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.

Saturday, 01 October 2005 13:27:27 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Sunday, 11 September 2005
IKVM 0.20 Released

I released 0.20 to SourceForge.

Sunday, 11 September 2005 16:39:33 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 07 September 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)

Wednesday, 07 September 2005 09:46:47 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, 06 September 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.
Tuesday, 06 September 2005 15:22:39 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, 15 August 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.

Monday, 15 August 2005 19:09:27 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Saturday, 06 August 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.

Saturday, 06 August 2005 18:52:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 22 July 2005
0.18 Released

I released 0.18.0.0 to SourceForge.

Friday, 22 July 2005 08:56:55 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, 19 July 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).

Tuesday, 19 July 2005 11:06:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Monday, 18 July 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)

Monday, 18 July 2005 10:09:06 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 01 July 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)

Friday, 01 July 2005 12:47:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]