runtime metaprogramming by composing MethodHandles

84 views
Skip to first unread message

Miguel Garcia

unread,
May 4, 2012, 4:51:51 AM5/4/12
to jvm-la...@googlegroups.com

I'm wondering what performance can be expected when composing many small MethodHandles, for example composing constant MHs at the granularity of "iadd" below:

  public class Instructions {
    public static int iadd(int a, int b) { return a + b; } // ie this is placeholder for the lonely instruction "iadd"
    . . .
  }

The experiment thus involves piecing together all those little MHs (not unlike AST building) thus making up the desired functionality (the motivation for this is picking bytecodes for primitive types on a per-type-instantiation basis, but that's another story).

Q1: Would the resulting MH be JITted down to native code without invocation overhead whatsover?

Q2: If not JITted (but after everything has been resolved) would the resulting MH perform in the worst case as the corresponding (statically emitted) bytecode?

Q1 and Q2: Never? Sometimes? Always? ("Sometimes" would be tricky because then the cost model becomes difficult to reason about).


Miguel
http://lampwww.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/


Rémi Forax

unread,
May 4, 2012, 5:58:50 AM5/4/12
to jvm-la...@googlegroups.com
On 05/04/2012 10:51 AM, Miguel Garcia wrote:
>
> I'm wondering what performance can be expected when composing many
> small MethodHandles, for example composing constant MHs at the
> granularity of "iadd" below:
>
> public class Instructions {
> public static int iadd(int a, int b) { return a + b; } // ie this
> is placeholder for the lonely instruction "iadd"
> . . .
> }
>
> The experiment thus involves piecing together all those little MHs
> (not unlike AST building) thus making up the desired functionality
> (the motivation for this is picking bytecodes for primitive types on a
> per-type-instantiation basis, but that's another story).

at runtime or not ?

>
> Q1: Would the resulting MH be JITted down to native code without
> invocation overhead whatsover?

I suppose you use foldArguments to link the pieces together.
The guarantee is that all codes involving method handles will disappear
but you have no guarantee that
methods iadd will be inlined, i.e it can be a method call, so you can
end up with
something like:
iadd(const(2), const(3))
with each call being a real method call.

With ForceInlining (new annotation added in jdk8 but Hotspot specific),
you can ask all instruction methods to be inlined, so in that case, the
generated assembler code
should be equivalent with the one generated from the equivalent bytecode.

You also have to simulate your own invokevirtual, invokeinterface
instructions
by using invokedynamic and your own inlining cache.

>
> Q2: If not JITted (but after everything has been resolved) would the
> resulting MH perform in the worst case as the corresponding
> (statically emitted) bytecode?

No.
You such guarantee exists even if it may be true with a peculiar VM
implementation.

>
> Q1 and Q2: Never? Sometimes? Always? ("Sometimes" would be tricky
> because then the cost model becomes difficult to reason about).

Q1 & Q2 => false

>
>
> Miguel
> http://lampwww.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/
> <http://lampwww.epfl.ch/%7Emagarcia/ScalaCompilerCornerReloaded/>


R�mi

Miguel Garcia

unread,
May 4, 2012, 7:31:04 AM5/4/12
to jvm-la...@googlegroups.com

Leaving performance considerations aside for a moment and turning to expressiveness of MH combination. Here's the make or break scenario I have in mind. Piecing together at runtime a new MH instance. Here's my homework:

Building blocks: static methods standing for bytecode instructions, for example:
  static int   addII(int   a, int   b) { return a + b; }
  static float addFF(float a, float b) { return a + b; }
(to be precise, the building blocks are constant MHs referring to the methods above)

Task: compile statically a method that return an MH that, once invoked, adds the three numeric arguments it finds on the stack (all of them ints, or all of them floats, in their primitive representation)

  // the mt argument represents either int or float
  public MethodHandle add3Factory(mt: MethodType) {
    . . .
  }

How to use the resulting MH is not the problem, ie the correct signature for the callsite is statically known, in the example either (III)I or (FFF)F

I'm looking at makeGuardWithTest() for inspiration, but some reassurance on whether there's hope would be helpful :)

Miguel
http://lampwww.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/
R�mi

Reply all
Reply to author
Forward
0 new messages