On Wed, May 16, 2012 at 12:55 PM, Per Bothner <p...@bothner.com> wrote: > The attachment ProcUsingVirt.java sketches out the current implementation. > This uses virtual apply[01N] methods that are overridden by specific > Procedure subclasses. (Kawa actually has apply[01234N], but I've > simplified.)
Very similar to JRuby's implementation, in fact. We generate [0123N] with and without closure argument, generally one class per method, either a handle class pointing at a method in a larger class file, or the actual method body in its own small class. > (See also http://www.gnu.org/software/kawa/internals/procedures.html) > > The attachment ProcUsingMH.java is a sketch of an alternative implementation > where each apply[01N] method has a matching MethodHandle field. The > apply[01N] > method is now final and just invokes the corresponding MethodHandle. I don't think this would optimize like you're hoping. First off, assuming you're going to use many Procedure object instances with their own handles, that makes the invokeExact calls polymorphic. You're still dispatching through a generic stub every time, and Hotspot can't (currently) inline across it. > Calling an MethodHandle using invokeExact requires more indirection and > more checking than just doing an invokevirtual. Would Hotspot be able to > optimize this to roughly the same speed? Presumably it might be a little > bit slower on less-optimizing VMs. I'm pretty sure truly constant handles invoked will be inlined, and by truly constant I mean in the constant pool. I doubt final MH fields will optimize the same way, since for optimization purposes Hotspot doesn't (currently) care about final since it can still be tweaked via reflection. There was talk about adding ways to optimize final fields better at last year's JVMLS, but most of the experts agreed it would only really be applicable to non-inlined static finals. Of course things may have changed here, but I think you're still out of luck with this approach. > To avoid one-class-per-function, Kawa will compile a switch-table per > module, > as sketched by the ProcUsingVirt.Builtins2 class. (see the section named > "Closures" in the internals document linked to above.) This is where using > MethodHandles seems most winning, since we can do as shown in the > ProcUingMH.Builins class. Is this likely to have a performance impact? JRuby has had switch-based dispatchers at various times during its life. I believe Jython still uses this mechanism. The main problem with switches, in my experience, is that they very quickly get too big for Hotspot to optimize well. In our case we saw the effect in our interpreter and parser. The interpreter used to be a big switch based on the AST node type. When we moved the individual AST nodes' logic into the nodes themselves, and dispatched virtually rather than through the switch, performance increased many times. The parser also used to be a big switch, at first generated with all code inline (as parser generators are wont to do), then with some post-processing to move the bodies out to separate methods (which gave us a boost because the inlined switch often was to large for Hotspot to compile!), and then finally with the current logic where all bodies are in their own classes, and dispatch uses a table of instance of those classes. The last version, even with indirection through an array and virtual dispatch, has been by far the fastest. > What if the apply[01N] method is non-final? That might make > interoperability > easier. For example, it's desirable to support a '--target 6' flag, though > supporting both styles in the same runtime may reduce the advantages of > either. In JRuby, AOT-compiled methods directly implement the equivalent of your apply method, and in JIT mode the apply methods dispatch to our one-method-per-class. In invokedynamic mode, all dispatches (will eventually) be direct from call site to a chain of handles leading to the actual target method. Obviously nothing has even come close to the invokedynamic approach on performance. > Finally, it seems that if Kawa in the future makes use of invokedynamic, > having the MethodHandles in the Procedure would be an advantage. We do keep a method handle in each method object, but only so we can more easily retrieve it and bind it to the invokedynamic call site. I don't think your'e going to see the performance gain you're hoping for with the Procedure object that aggregates handles. You really need the invokedynamic call site for the whole thing to optimize together well. - Charlie _______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev