MethodHandles.constant not inlining?

Charles Oliver Nutter headius at headius.com
Tue Jun 7 16:05:58 PDT 2011


FWIW, another nice example for "self[0] += 1", which does some
complicated call-site juggling. Eventually it will probably be a
single invokedynamic, but for now this shows how much lighter the
indy-based cache logic is. Remember that all the calls in the "before"
version are also traversing fields or array references to get at the
values that are bound directly into the call site in the "after"
version.

https://gist.github.com/9ed479bf8a720a34060b

- Charlie

On Tue, Jun 7, 2011 at 5:38 PM, Charles Oliver Nutter
<headius at headius.com> wrote:
> I'm adding more invokedynamic-based cache logic for lazily-initialized
> Ruby literals. Rather than construct all literals on script load, we
> have been initializing them lazily as they are first encountered. In
> stock JRuby, this involves pinging a per-script array and constructing
> and inserting the literal object into that array if it does not
> already exist. Subsequent hits just get the array-stored value.
>
> With invokedynamic, I am binding the literals directly into the call
> site, either using a ConstantCallSite or using a MutableCallSite
> rebound on first call to a MethodHandles.constant value.
>
> This is working great, and for example a literal regexp goes from this bytecode:
>
>   ALOAD 0
>    ALOAD 1
>    ALOAD 0
>    INVOKEVIRTUAL ruby/__dash_e__.getByteList0 ()Lorg/jruby/util/ByteList;
>    LDC 512
>    INVOKEVIRTUAL ruby/__dash_e__.getRegexp0
> (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/util/ByteList;I)Lorg/jruby/RubyRegexp;
>    ARETURN
>
> To this bytecode:
>
>    ALOAD 1
>    INVOKEDYNAMIC getRegexp
> (Lorg/jruby/runtime/ThreadContext;)Lorg/jruby/RubyRegexp;
> [org/jruby/runtime/invokedynamic/InvokeDynamicSupport.getRegexpBootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/invoke/CallSite;
> (6), "foo", "ASCII-8BIT", 512]
>    ARETURN
>
> And of course after the first call, there's no overhead other than
> traversing the MutableCallSite and a dropArguments handle. Quite
> slick, and especially interesting since it improves inlining budgeting
> and bytecode size substantially (since it cuts out the extra
> args/calls and the test + load from that per-script array).
>
> So I figured I'd check assembly output, and I was surprised to see a
> callq right where I expect to see the literal. Are
> MethodHandle.constant handles not inlined right now?
>
> Here's the assembly that results in the relevant location from a
> script like "def foo; 1; end; 100_000.times { foo }":
>
> https://gist.github.com/1013347
>
> Some logic at the beginning and end is the invokedynamic of "foo"
> inlined properly, but right smack in the middle is a callq where I
> would expect to see the literal bound.
>
> In this case, the bootstrap produces a MutableCallSite pointing at a
> first-time initFixnum method. That method rebinds the call site with a
> MethodHandles.constant containing the lazily-initialized RubyFixnum
> object. The whole chain after the first call ends up looking like
> this:
>
> MutableCallSite => dropArgments => constant
>
> I'm surprised to see a callq here at all. Thoughts on why?
>
> - Charlie
>


More information about the mlvm-dev mailing list