Sunday, April 08, 2007

Invariant Dynamic Calls

Basically, dynamically typed languages, Groovy in this context, dispatch calls by firstly choosing appropriate methods, then invoking them. The choosing process is obviously expensive. Several techniques, such as method caching, are currently implemented in Groovy to speed things up. However, choosing methods through reflection won't allow JIT to optimise method bodies for callers. With caching, the shortest steps for Groovy are still:

calling an invokeX method -> looking up cache -> calling the cached chosen method,

and you can not further optimise the invocation beyond this point.

The only way to do this is to simply replace that call by the chosen method call.
It's basic and everyone on the groovy-dev list knows about this (I supposed). Anyway, there're a lot arguments in the list that we should preserve the "dynamicity" of Groovy. I agree with those arguments, so we should leave Groovy core as it is, but we can really do somethings at the application level, in production phase.

During unit testing, developers may find sets of "invariant dynamic calls" of their applications. I roughly define an invariant dynamic call as a call that has only one chosen method. Trivial examples for this kind of call in Grails framework are Domain class' .save() and .delete(). If we assume that our test suites cover the application enough, so we can basically conclude that each dynamic call identified by the test suites is an invariant dynamic call, if there is only one chosen method for it. Then, we just simply replace these calls with static signatures, in class files or even by on-the-fly transformation, to gain performance back.

My current technique to analyse calls at bytecode-level is, firstly scanning for ScriptBytecodeAdapter.invoke*, then reverse looking for LDC "methodName" and other arguments that will be stored onto the stack.

Beyond Java 6
I dont exactly know when INVOKEDYNAMIC will arrive, but with this instruction replacing invariant dynamic calls will be much easier by
1. changing INVOKEDYNAMIC to appropriate kind of invoke, say INVOKEVIRTUAL, INVOKESPACIAL, INVOKESTATIC or INVOKEINTERFACE.
2. changing type descriptors to the correct classes.

I haven't followed the spec of INVOKEDYNAMIC at the moment, it's time to have a quick read again.

No comments: