half-baked ideas on specializing MethodHandle-combining expressions
Garcia Gutierrez Miguel Alfredo
miguelalfredo.garcia at epfl.ch
Tue Aug 6 04:32:49 PDT 2013
There's quite a spoonful of material to review before attempting to optimize MH expressions, you know, things like:
- when are MH invocations lowered into Macro nodes,
- the lowering into LambdaForm that the ever-so-helpful JDK8 performs
- interplay of MH lowering with nominal types, ways to avoid unintended class loading (and the ensuing initialization)
- I'm sure I'm forgetting some more
And that's only the MH part of the story, leaving aside for the moment Callsites (resulting from invokedynamic) and their substitutions.
Assuming one has digested all of the above (you may safely assume I'm not yet there) a next step could be tackling questions like:
(a) let's say we have a MH-combining expression that captures other MHs that it uses as "ingredients" to realize its "recipe" (aka algorithm). For example:
MethodHandle repeatInt = ... // a MH that, when invoked, takes an int as input, returns a List with zero or more copies of the argument
MethodHandle flatMapByRepeating = flatMapMH.bindTo(repeatInt);
List<int> listWithRunsOfSameElem = flatMapWithRepetitions.invoke(List(1, 2, 3));
The piece of functionality denoted by "flatMapWithRepetitions" could be specialized to repeatInt (which has been captured, ie is finally-bound for the lifetime of the immutable object denoted by "flatMapWithRepetitions")
Let's say we take "specialized to repeatInt" to mean "inlining the concrete target of repeatInt", as we'd like to avoid allocations of the intermediate lists (one per input element). Yea, that's "generalized stream fusion" [1] for the Haskellers in the audience.
Actually the question seems not whether it could be specialized (given enough attention by the JIT compiler) but rather whether:
(b) the code-cache management tradeoffs: how many specialized variants of (possibly only slightly different) MH-combining expressions are we willing to live with?
(c) what hints to follow to determine which MH-combining expression should be specialized (and code-cached)?
There are many syntactically-different ways to capture a MH. Besides bindTo as in the example above, final arguments, final instance fields, final static fields; are all examples.
(d) also related to code-cache management is the question how often the (by now specialized) "MH-combining MH" gets invoked, invocations that are bracketed by the lifetime of the "MH-combining MH" (lifetime in the sense of heap-reachability).
The strategy sketched above has an "embedded runtime-compiler" flavor to it (as opposed to profile-guided, one callsite at a time, inlining). The strategy instead calls for performing at once all the inlinings implied by captured-MHs in a MH-combining expression as a whole, before the first invocation of the combined MH. Granted, in the example this doesn't make a big difference (just one "ingredient" MH).
That's the half-baked idea, thrown to the world for discussion. Comments are welcome! (I hope it also qualifies as summer-time reading)
[1] Exploiting vector instructions with generalized stream fusion,
Geoff Mainland, Simon Peyton Jones, Simon Marlow, Roman Leshchinskiy.
ICFP 2013
http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/haskell-beats-C.pdf
Miguel
http://magarciaepfl.github.io/scala/
--
Miguel Garcia
Swiss Federal Institute of Technology
EPFL - IC - LAMP1 - INR 328 - Station 14
CH-1015 Lausanne - Switzerland
http://lamp.epfl.ch/~magarcia/
More information about the graal-dev
mailing list