« August 2006 »
SunMonTueWedThuFriSat
     
2
3
6
7
9
10
11
13
15
16
17
20
23
24
28
29
30
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 1650

Powered by Roller Weblogger.
« Previous day (Aug 30, 2006) | Main | Next day (Sep 1, 2006) »
20060901 Friday September 01, 2006

invokespecialdynamic?

There are 4 JVM bytecodes to call methods:

  1. invokeinterface - used to call an interface method on an object
  2. invokestatic - used to call a static method of a class
  3. invokevirtual - used to call a overridable method
  4. invokespecial - used to call
    • constructors
    • private instance methods
    • super class methods (super.foo() calls in the source)
All these instructions require the specification of
  1. target class (or interface for invokeinterface) name
  2. the name of the method (or <init> for constructors)
  3. the signature of the method.

Please refer to the JVM specification for further details.

To facilitate the compilation of dynamically typed languages such as Groovy, JRuby, Jython to JVM bytecodes, a new bytecode called invokedynamic is being proposed (JSR-292). Note that the details of this JSR will be available only in future. Whatever I say below could be (or could become) completely wrong!

invokedynamic will (probably) not require the target class name and the method signature. invokedynamic will search the specified method on the target object based using just the name. The way to handle method overloading will have to be specified by JSR]. How to handle failure to find required method? - again this will also need to be specified by the JSR (For example, throw NoSuchMethodException or call a pre-defined doesNotUnderstand or handleMethodCall method).

Let us consider the case of Groovy. (JSR-241). Groovy supports a flexible method dispatching framework. Without going into details: if a method to be called is found in the class, then a special invokeMethod method is called. I wrote about that in an earlier post. Groovy would be able to make use of invokedynamic to speed-up it's Meta Object Protocol implementation.


class Person {
    public Object invokeMethod(String methodName, Object args) {
        System.out.println("calling " + methodName);
        return methodName.toUpperCase();
    }
};

Person b = new Person();
// This works. Calls "invokeMethod" because there is no "name" 
// method in Person class.
System.out.println(b.name());

Problem with calling super class methods

While Groovy's method dispatch is flexible for "clients" of classes, calling a super class method is not so flexible. For example, when super.foo() is called from a Groovy class, it is compiled much like Java - i.e., using invokespecial. So, method searched has to be found at "compile time". This means the following will not work.


class Person {
    public Object invokeMethod(String methodName, Object args) {
        System.out.println("calling " + methodName);
        return methodName.toUpperCase();
    }
};

class Employee extends Person {
    public String name() { 
        // This does *not* work! there is no "name" method in Person!
        // Ideally, one would expect super.name() to call Person.invokeMethod().    
        return "Employee " + super.name(); 
    }
}

We get the following "compile time" error:


org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
General error during class generation: No such method: name for class: Employee.

Node: org.codehaus.groovy.ast.expr.MethodCallExpression. At [11:40] t.groovy


1 error


A more flexible language like Smalltalk will allow the user to call super class methods even not found during compilation. If the method is not found in super class at runtime (or it's super class and so on), then doesNotUnderstand method will be called [or should I say, doesNotUnderstand message will be sent!]

But, because Groovy is limited by JVM can do, currently it uses either Java reflection or bytecode generation to implement it's meta object protocol. Java reflection does not allow us to call a overriden super class method on an object. java.lang.reflect.Method.invoke's javadoc says: If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime type of the target object will occur.

Similarly, the reflection speed-up classes generated by Groovy can not call super class methods. [I am not sure why Groovy folks do this reflection speed-up -- HotSpot JVM already speeds up reflective calls by bytecode generation internally!] The only way to call super class method is to generate invokespecial which can only be inside a subclass! (and not in an unrelated reflection "speed-up" class). This explains why Groovy has to translate super.foo() with invokespecial instruction. Groovy could probably do the following to compile super.foo():

  1. Look for "foo" in super class or it's super class and so on. If found, generate invokespecial
  2. if matching method is not found in super class(es), instead of throwing error, call the invokeMethod method.

But the problem here is that the above scheme "fixes" method dispatching during compilation. For example, if a super class introduced "foo" method after the compilation of subclass then that new method won't be called! (invokeMethod would be called. So, do we probably need invokespecialdynamic?

What would the invokespecialdynamic do?

invokespecialdynamic would be like invokespecial except that

  1. it won't accept the method signature (handle overloading in the same way as invokedynamic would do!)
  2. if the method of specified name is found at runtime, fallback step is taken (that could be same as invokedynamic -like throwing exception or calling a special method)

With invokespecialdynamic, Groovy would be able to flexibly implement super.foo() calls.



( Sep 01 2006, 08:26:44 PM IST ) Permalink Comments [6] del.icio.us | furl | simpy | slashdot | technorati | digg

Extra bytes at the end of a .class file?

I accidentally deleted my Jython installation. I attempted to reinstall Jython 2.1). Last time I had installed it with JDK 1.5.0_06. This time I attempted with JDK 6. I got the following error:


D:\downloads\Java\Jython>d:\jdk1.6.0\bin\java jython_21
Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file jython_21
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)

Looks like Jython folks are self-extracing using the installer (jython_21.class). The installer class has extra bytes at the end of the .class file (which persumably has the installation data in compressed form).

JVM spec second edition section 4.9.1 makes it clear - a .class files can not have extra bytes at the end. May be the .class is verified with JDK 6 - but not with JDK 1.5.0_06? In fact, when using this command


D:\jdk1.5.0_06\bin\java -Xverify:all jython_21

I got the same aforementioned error - so clearly, with bytecode verification 1.5.0_06 also throws the same error. I tried the following command line:

D:\jdk1.6.0\bin\java -Xverify:none jython_21

Guess what? I got the same error! So, it appears that JDK 6's does not allow extra bytes at the end of .class files even when not doing bytecode verification!



( Sep 01 2006, 09:50:10 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Copyright (C) 2005, A. Sundararajan's Weblog