Small static method marked not entrant, inlining reversed?

Charles Oliver Nutter headius at headius.com
Tue Sep 7 23:34:10 PDT 2010


I'll give that a shot, Tom, thanks. Should have thought of it myself.

On Wed, Sep 8, 2010 at 12:04 AM, Tom Rodriguez <tom.rodriguez at oracle.com> wrote:
> Did you run with -XX:+PrintInlining?  That will report why we didn't inline.
>
> tom
>
> On Sep 7, 2010, at 2:44 PM, Charles Oliver Nutter wrote:
>
>> I've been working on JRuby performance lately and ran into a peculiar situation.
>>
>> I have a static utility method in JRuby that checks whether a given
>> object's class is the same as the when the compiler optimized it. So
>> for a snippit of code like this:
>>
>> def foo
>>  bar
>> end
>>
>> def bar
>>  # whatever
>> end
>>
>> After running for some time, the "foo" call will be compiled, the
>> compiler will see that the "bar" call has a cached method handle, and
>> it will emit both a dynamic call and a static-typed call plus guard.
>> The static-typed call looks like this:
>>
>>    ALOAD 8
>>    LDC 446
>>    INVOKESTATIC
>> org/jruby/javasupport/util/RuntimeHelpers.isGenerationEqual
>> (Lorg/jruby/runtime/builtin/IRubyObject;I)Z
>>    IFNE L2
>>    ALOAD 8
>>    CHECKCAST org/jruby/RubyFixnum
>>    ALOAD 1
>>    LDC 1
>>    INVOKEVIRTUAL org/jruby/RubyFixnum.op_plus
>> (Lorg/jruby/runtime/ThreadContext;J)Lorg/jruby/runtime/builtin/IRubyObject;
>>
>> And the isGenerationEqual method looks like this:
>>
>>    public static boolean isGenerationEqual(IRubyObject object, int
>> generation) {
>>        return object.getMetaClass().getCacheToken() == generation;
>>    }
>>
>> While running benchmarks, I noticed a peculiar thing happening. For
>> "fib", the method JITs in JRuby very quickly and is soon after JITed
>> by Hotspot. But later compiles cause "fib" to get deoptimized and
>> marked not-entrant. Around the same time, isGenerationEqual gets
>> marked not entrant. Unfortunately, when fib re-optimizes, it does so
>> without inlining the isGenerationEqual call, and I can see that where
>> it was inlined before, it now actually does a CALL in assembly.
>>
>> Manually inlining the same bytecode everywhere isGenerationEqual would
>> be called does not seem to be subject to the same effect.
>>
>> Any thoughts? The only theory I have is that early in optimization
>> Hotspot sees that the target object type (IRubyObject object in the
>> method def) is the same, and so it optimizes based on that. Later, as
>> other compiled methods start to hit this code, the tyoe of "object"
>> changes. But the logic behind the scenes should be identical in every
>> case... IRubyObject.getMetaClass() only has one final implementation
>> on org.jruby.RubyBasicObject, and getCacheToken() has only one final
>> implementation on org.jruby.RubyModule, which simply returns an int
>> field.
>>
>> So I'm stumped why at least isGenerationEqual would not inline in all cases.
>>
>> - Charlie
>
>


More information about the hotspot-compiler-dev mailing list