redline-smalltalk/redline-smalltalk — pull request #175 by headius (2013-02-27 19:03:02+00:00)
Title: Start invokedynamic support and move to ASM 4.1

This pull request does the following:

Update to ASM 4.1
----------------------------

This required some rework of how ClassBytecodeWriter handled the "tracing" path. In ASM 4+, ClassWriter's methods are all final, so extending it does not work. I went with something similar to JRuby, where the actual ClassWriter and the ClassVisitor used for compilation are separate. TracingClassVisitor replaces TracingClassWriter and simply delegates to the ClassVisitor it is given (the ClassWriter, in this case).

Dispatch "perform" path via invokedynamic
-------------------------------------------------------------------------------

When running on a Java 1.7+ VM, invokedynamic will be used for the "perform" call path (i.e. not for superPerform). Currently, call sites will be bount to an "apply" target with the previously-seen method and class cached. The guard checks that the incoming object's class is the same as last time and that the global PrimObjectClass.CLASS_MODIFICATIONS token is the same object. When PrimObjectClass variables are updated, CLASS_MODIFICATIONS is assigned to a new Object, allowing for a simple identity check in the guard. This could be improved with a SwitchPoint, but doing that in a way compatible with non-indy JDKs is more involved.

Invokedynamic TO DOs
-----------------------------------

* superPerform needs to be bound via indy
* Directly binding to invoke is necessary to get inlining across the call boundary (apply is a megamorphic path). This will require the bound handle to construct PrimContext from incoming arguments each time. See performance TO DOs below.
* Better type modification guard based on SwitchPoint

Performance TO DOs
-------------------------------

Along with the above indy TO DOs, the following are likely necessary to get the best possible performance.

* Avoid creating PrimContext every time if possible. Future escape analysis in the JVM will help reduce this cost, but until then it's very expensive to create a large object for every call. I believe the call path could be modified to pass through all the elements of PrimContext rather than constructing it, at least in the invokedynamic path.
* Improve invalidation of call sites due to modification by localizing the invalidation down-hierarchy, as in JRuby. If all classes know their subclasses (weakly) they could cascade invalidation down-hierarchy, allowing type modification guards to apply to a specific type. This would reduce the cost of runtime method definition invalidating all call sites in the system, as in this PR.

In general, best performance will come by binding call sites directly to the target code and not constructing any transient objects along any call path.