Question on HotSpot JIT and invokeinterface

John Rose John.Rose at Sun.COM
Thu Feb 26 11:32:34 PST 2009


On Feb 24, 2009, at 11:58 PM, Pekka Enberg wrote:

> There's a nice description of how HotSpot implements JIT'ed  
> invokeinterface
> at HotSpot Internals wiki:
>
>  http://wikis.sun.com/display/HotSpotInternals/InterfaceCalls

Please add your discoveries to it!  Part of the benefit of the wiki is  
that people can share their "learning curves", so we don't all have to  
rediscover the same things.

> Unfortunately there are no pointers to the actual code.

It's easy enough to make pointers, at least at the file level:
   http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/cpu/x86/vm/vtableStubs_x86_32.cpp

(Too bad URLs can't end with tags-like search terms, as **.cpp#/ 
create_itable_stub.)

> I recently started
> looking at how the interface resolution stubs are generated and  
> spent quite
> a lot of time figuring out what was going on!

Yes, it takes a lot of time.  The wiki is there to help the second  
person in line. :-)

> I think I got it mostly right but thought I thought I'd get a second
> opinion. Maybe this is something that could be added to the wiki as  
> well?

It looks good.  Please feel free to add it, in some useful form, to  
the wiki.

> ---
>
> [Assuming 32-bit x86 here.]
>
> I think it's the VtableStubs::create_itable_stub() function in
> src/cpu/x86/vm/vtableStubs_x86_32.cpp. Tracing trough the the  
> callers in
> reverse order, we have:
>
>  VtableStubs::create_itable_stub()
>    VtableStubs::create_stub()
>      CompiledIC::set_to_megamorphic()
>        SharedRuntime::handle_ic_miss_helper()
>          SharedRuntime::handle_wrong_method_ic_miss()

The megamorphic state is the final catch-all state for a CompiledIC  
(compiled inline cache).  The header file that documents the (highly  
interesting!) state transitions is:
   http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/vm/code/compiledIC.hpp

States before megamorphic are clean (fresh from compiler) and  
monomorphic (common case).  An inline cache miss transitions the call  
site to megamorphic.

> and in src/cpu/x86/vm/sharedRuntime_x86_32.cpp we have
>
>  SharedRuntime::generate_stubs()
>
> that generates a resolve blob that points to
> SharedRuntime::handle_wrong_method_ic_miss():
>
>  _ic_miss_blob = generate_resolve_blob(
>    CAST_FROM_FN_PTR(
>      address, SharedRuntime::handle_wrong_method_ic_miss),  
> "ic_miss_stub");
>
> Now the IC miss stub is called if we can't find a method in the  
> inline cache.
> The instruction sequence of _ic_miss_blob is returned by:
>
>  static address SharedRuntime::get_ic_miss_stub() {
>    assert(_ic_miss_blob!= NULL, "oops");
>    return _ic_miss_blob->instructions_begin();
>  }
>
> Looking at a reverse call-graph:
>
>  SharedRuntime::get_ic_miss_stub()
>    SharedRuntime::generate_i2c2i_adapters()
>      AdapterHandlerLibrary::get_create_adapter_index()
>        AdapterHandlerLibrary::get_adapter()
>          methodOopDesc::make_adapters()
>
> we can see how a method oop adapter has a pointer to the IC miss stub.

The rest of this is wonderful too, but belongs on a new page or pages,  
such as CallsIntoJava and/or CallTransitions.

> To
> complete the explanation, lets look at how HotSpot loads a Java  
> class and jumps
> into the main() method:
>
>  src/os/linux/launcher/java.c::main()
>    src/os/linux/launcher/java.c::CallStaticVoidMethod()
>      src/share/vm/prims/jni.cpp::jni_invoke_static()
>        src/share/vm/runtime/javaCalls.cpp::JavaCalls::call()
>          src/share/vm/runtime/javaCalls.cpp::JavaCalls::call_helper()
>
> Now JavaCalls::call_helper() does:
>
>  src/share/vm/runtime/stubRoutines.hpp::StubRoutines::call_stub()
>
> which returns a function pointer to a stub and calls that. The call  
> stub in
> turn delegates to is something called the entry point which is
> obtained in JavaCalls::call_helper() as follows:
>
>  address entry_point = method->from_interpreted_entry();
>
> Now when a method is compiled into native code, the
>
>  src/share/vm/ci/ciEnv.cpp:ciEnv::register_method()
>
> function calls
>
>  src/share/vm/oops/methodOop.cpp::methodOopDesc::set_code()
>
> which sets up _from_interpreted_entry like this:
>
>    mh->_from_interpreted_entry = mh->get_i2c_entry();
>
> where get_i2_c_entry() looks like this:
>
>  address methodOopDesc::get_i2c_entry() {
>    assert(_adapter != NULL, "must have");
>    return _adapter->get_i2c_entry();
>  }
>
> The _adapter of type class AdapterHandlerEntry which are created in
>
>  src/cpu/x86/vm/ 
> sharedRuntime_x86_32.cpp::SharedRuntime::generate_i2c2i_adapters()
>
> which we know already to jump to a stub returned by
> SharedRuntime::get_ic_miss_stub() if a method cannot be found in the
> inline cache.
>
> ---
>
> That's it! Comments and corrections are most appreciated!

Please post!

Best wishes,
-- John

> Regards,
>
>                        Pekka
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-dev/attachments/20090226/24dc5a0e/attachment.html 


More information about the hotspot-dev mailing list