For Ashlar, I represent my closures as MethodHandle instances. (I actually represent pretty much everything as MethodHandle instances at this point, but that's a conversation for another time.) Since I'm statically typed, there's some work I can do at compile time in certain cases (recognizing Pervasive#each calls and turning them into loops, for instance). But let's set that aside and focus on runtime optimizations.
Now, there's no way that I am aware of to go from a MethodHandle to a java.lang.reflect.Method instance and an array of arguments, which would then enable me to inline it at runtime. There are good reasons I can imagine for not allowing that, starting first and foremost with argument adapters (and pretty much all the mutations in the MethodHandles class), which means that the MethodHandle has semantics different from passing the given arguments to the given method. So, if we're going to inline based on the MethodHandle, we need some kind of wrapper which will tell us whether the MethodHandle is inlinable, and which will tell us the method and arguments if it is reversible. Note that the method and arguments need not correspond directly to the underlying implementation—in theory, we could generate some other code at runtime to represent adapters, etc. But for the initial implementation, I'm considering a MethodHandle inlinable if it corresponds directly to an API method, possibly with currying. That solves half the problem: I can now go from MethodHandle to a java.lang.reflect.Method, which allows me to inline it at runtime (at least in the common case). The other half the problem is the call site. I use a custom CallSite which exposes MethodHandle#invokeGeneric so that it can track arguments passed in. I'd use that to track MethodHandle arguments passed in, and if the same inlinable MethodHandle is hit often enough, it should generate the inlined code, and then update the MethodHandle to check for this common case (MethodHandles#guardWithTest comes in here). This is pretty much exactly the logic I would hope a JVM would eventually implement, and I'm presuming that the JVM already has (or will soon have) the ability to optimize the MethodHandle resulting from MethodHandles#guardWithTest calls. Now, this is a fair bit of infrastructure and additional obscuring of the user's code path, which is where the question comes in about whether or not it is worth it. There are also serious concurrency issues: how do we balance performance with shared state? For instance, consider the implied counter for MethodHandle arguments—do we really want the overhead of synchronization on *every* invocation of this method? Imagining a global lock on "fold" just makes me blanch. We could go "volatile" and force memory flushes in all those cases, but is that really better? What's the alternative? (Taking the overhead and the loss of opportunities to track it per-thread? Is that really better?) I'm hesitant to spend time implementing an optimization that isn't (developing my language is a hobby, not my job, so there's very limited time resources), but if the gain is huge, it's probably worth it. Of course, I'd really like to declare it's the JVM's problem and look forward longingly to the day when it's resolved there. ~~ Robert. On Sat, Apr 2, 2011 at 8:35 PM, Charles Oliver Nutter <[email protected]> wrote: > On Sat, Apr 2, 2011 at 7:34 PM, Charles Oliver Nutter > <[email protected]> wrote: >> I also want to make clear this affects all languages that pass >> functions or closure around, including Groovy, JRuby, Scala, Clojure, >> current Java with callbacks/anon classes, and upcoming Java 7 closure >> support. > > Sent this a bit quickly... > > This may actually be a case where JRuby has a better chance of > optimizing since we are already mixed-mode. It won't be very difficult > for us to specialize a body of code to the point of use, allowing that > body and a closure passed to it to inline. Assuming that's not > possible for other languages, has anyone thought of other ways to make > closures/callbacks optimize as well as normal inlined monomophic call > paths? > > - Charlie > > -- > You received this message because you are subscribed to the Google Groups > "JVM Languages" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/jvm-languages?hl=en. > > -- You received this message because you are subscribed to the Google Groups "JVM Languages" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/jvm-languages?hl=en.
