# Thursday, 17 October 2002
No Title

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.

 

Thursday, 17 October 2002 17:44:55 (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]
# Monday, 14 October 2002
No Title

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.

Monday, 14 October 2002 10:48:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Friday, 27 September 2002
No Title

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.

Friday, 27 September 2002 17:57:38 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, 23 September 2002
No Title

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.

Monday, 23 September 2002 12:38:26 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 12 September 2002
No Title

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.

Thursday, 12 September 2002 12:05:55 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, 09 September 2002
No Title

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.

Monday, 09 September 2002 17:02:51 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 05 September 2002
No Title

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!

Thursday, 05 September 2002 18:43:29 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Tuesday, 03 September 2002
No Title

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.

Tuesday, 03 September 2002 19:19:30 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 30 August 2002
No Title

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

Friday, 30 August 2002 16:36:46 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 28 August 2002
No Title

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.

Wednesday, 28 August 2002 16:57:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]