Latest Posts »
Latest Comments »
Popular Posts »

When protected isn’t protected

Written by Jevgeni Kabanov on November 3, 2008 – 1:41 pm

For all those spec believers out there: what would you think if I told you that all of the JVM implementations consistently violate the spec for at least one particular instance?

Our story begins on a cold and lonely evening when I discover a bug in JavaRebel in conjunction with Xerces XMLEntityManager. The problem was with the following method:

JAVA:
  1. public String[] getRecognizedProperties() {
  2.   return (String[])(RPROPERTIES.clone());
  3. }

However when I looked at the class bytecode I saw a different picture:

JAVA:
  1. {
  2.   GETSTATIC XMLEntityManager.RPROPERTIES : String[]
  3.   INVOKEVIRTUAL Object.clone() : Object[]
  4.   CHECKCAST String[]
  5.   ARETURN
  6. }

For those of you who do not spend hours staring at the Java bytecode, it does the following:

  1. Retrieve the RPROPERTIES static field value (which is of type String[]) and put it on the top of the stack.
  2. Call Object.clone() using the top of the stack as target object (in our case the array). The target is popped off the stack and the result is placed on top of the stack instead of it.
  3. Cast the top of the stack to a String[]
  4. Return the top of the stack as method result.

Whooph. Now that is all fine except for one tiny thing. This is not legal. Object.clone() is a protected method and the JVM spec (see 2.7.4, INVOKEVIRTUAL) allows calls to protected method only if the following is true:

  1. The accessing class is a subclass of the target class or is the same class (check, XMLEntityManager is a subclass of Object, so’s everything else).
  2. The class of the target object (the actual runtime class of the object, not the target class we use in the signature) is either a subclass of the accessing class or is the same class.

The second check may sound crazy, but it restricts the calls to protected methods only to the classes inheriting from the target class, as you would expect. It can also only be enforced during runtime and is the cause of the IllegalAccessError you may see once in a while.

And obviously in our case String[] that is the actual type of the target object is in no way a subclass of the XMLEntityManager. This call should have cause an error in the JVM, but for some inexplicable reason it doesn’t. Further tests show that this is only limited (AFAIK) to the Object.clone() call, which is public as far as JVM cares.

A little googling turned up two JVM bugs that were discussing the same issue (bug 1, bug 2). Turns out the Sun javac compiler has been emitting wrong code at least until 1.4.2 and the JVMs have accommodated accordingly right until today.

Does this have any practical importance? Not for most of you, but if you handle Java bytecode in any way be prepared to handle this exception as well. To me it proves that there is more to Java than just the spec.


Tags: ,
Posted in Featured, creative | 8 Comments »

Return-Type-Based Method Overloading in Java

Written by Jevgeni Kabanov on August 1, 2008 – 2:56 pm

Return-Type-Based Method Overloading in Java — wow! Next you’ll discover that in Java bytecode you can throw/catch any object, not just Throwable subclasses and use that knowledge to implement more weird bytecode hacks! And BTW return-type overloading is used in Java 5 to implement bridge methods that allow overriding super methods with a different return type, so it’s not really so esoteric.


Tags: ,
Posted in meme | No Comments »

Typesafe ASM — problems solved?

Written by Jevgeni Kabanov on March 26, 2008 – 12:22 am

OK, I think I managed to solve both the primitive and the double slot problem introduced in the previous post. Basically I introduced another parametrized class — InvokeBuilder, which builds method invocations. The example now looks like this:

JAVA:
  1. ClassWriter cw = new ClassWriter(COMPUTE_MAXS);
  2.  
  3.   new ClassBuilder(cw, V1_4, ACC_PUBLIC, “HelloWorld”, “java/lang/Object”, null)   
  4.   .beginMethod(ACC_PUBLIC, “<init>”, void.class)
  5.   .loadVar0(Self.class)
  6.   .invoke().specVoid(Object.class, “<init>”)
  7.   .returnVoid()
  8.   .endMethod()
  9.  
  10.   .beginStaticMethod(ACC_PUBLIC | ACC_STATIC, “main”, void.class, String[].class)
  11.   .getStatic(System.class, “out”, PrintStream.class)
  12.   .loadVar0(String[].class)
  13.   .push(0)
  14.   .arrayLoad(String[].class, Integer.class, String.class)   
  15.   .invoke().param(String.class).virtVoid(PrintStream.class, “println”)
  16.   .returnVoid()
  17.   .endMethod();

Of course InvokeBuilder contains methods only for building invocation. The only inconvenience is that you have to specify parameters in reverse order to coincide with the way they are laid out on the stack. However it’s easy to add a bit of sugar for the most common cases.

Now all I have to do is overload the param() method for each primitive as well as make a paramTwoCell(), which consumes two stack slots (for long/double). Seems that only tedious work in implementing each and every instruction remains.

P.S. Thanks to Christian Vest Hansen for his input. It definitely helped me get this (last?) piece of the puzzle in place.


Tags: , , ,
Posted in creative | No Comments »

Typesafe DSLs in Java: Part 1 — Typesafe Bytecode

Written by Jevgeni Kabanov on March 24, 2008 – 12:25 am

Domain Specific Languages (DSLs) have been brought to Java under the name of Fluent Interface. However most of them utilize a lot of strings and untyped behavior to make the interface fluent enough. It turns out that using Java 5 and a bag of tricks we can have the compiler to check a lot more. In this post we'll check out how to write Java bytecode using ASM in a typesafe way.

Read more »


Tags: , , ,
Posted in Featured, creative | 6 Comments »

QCon London 2008: TerraCotta

Written by Jevgeni Kabanov on March 14, 2008 – 3:47 am

The best talk I’ve been to so far is TerraCotta’s introduction and patterns. Ari is a good speaker with passion, intensity and speed that I admire (though some others might find the talk a bit too informative).

I’ve heard about TerraCotta before, but this was the first time I got to know the details. The basic functionality that they claim is transparently clustering your objects, so that all changes on one JVM are visible in all the rest.

Turns out they instrument GETFIELD/PUTFIELD instructions and propagate updates among the servers. It is easy enough to do for the basic types and they have special support for strings and collections, but they also need to assign identities to objects so that updates to reference fields would change only the reference to an object with the same identity. For that they instrument constructors to associate identities with objects and reconstruct identical graphs on different JVMs. Of course, like JavaRebel, they also need to instrument reflection.

In addition to that they instrument MONITORENTER/MONITOREXIT instructions to acquire distributed locks instead of local ones. There are some quirks here that I’d be interested in finding out, e.g. how do they deal with locking the same monitor in the code not managed by TerraCotta. The likely answer is that they don’t :)

An interesting question to ask here is whether we could use STM. Basically TerraCotta needs to collect changes to the objects anyway, so to enable optimistic locking instead of pessimistic they’d have to add two things:

  • A way to revert changes done to objects. A pretty trivial thing to do.
  • A way to unwind the stack if the commit does not succeed. This is not easy, but can be done with an approach like Geert Bevin used to implement continuations.

There is also a question of what to do when the critical block does global side-effects. IMHO you can just delegate this to the user, so that he has to explicitly enable optimistic locking at a particular spot.

In fact when I think about it, this approach would make some sense even without distributivity. For highly concurrent code such optimistic concurrency would create a great performance win (as indicated by Azul). Of course you have to trade it off with the instrumentation costs, but for some applications the performance win might be tremendous.

When I asked Ari about optimistic locking he indicated that they have some experimental support in the works, but there are still some problems to overcome.


Tags: , , ,
Posted in report | No Comments »