Question on HotSpot JIT and invokeinterface

Tom Rodriguez Thomas.Rodriguez at Sun.COM
Thu Feb 26 11:55:09 PST 2009


If you want a full sketch of the process then you're missing one  
important piece which is the behaviour of the inline cache itself.  If  
an interface call site only ever has one receiver type then we'll  
never use the itable stub at all.  The itable stub is only used once  
the inline cache misses which means there is more 1 receiver type  
involved.

I think the order that you lay things out is slightly confusing.  It  
feels like it starts in the middle.  A description that followed the  
processing from an unresolved inline cache to a single receiver and  
then onto a second receiver would be quite nice.  The invokevirtual  
path parallels invokeinterface so you could include that without much  
trouble.  If that seems like more than you want to bite off I'd just  
suggest structuring your description in the order of what happens  
during the process and describe where each part comes from when you  
get to it.  You also describe the call graphs as reversed and they  
don't seem reversed to me.  They seem like the natural order you'd  
describe them in so I'd just leave out the word revered.  Also mixing  
in the description of how main gets invoked seems odd since it's not  
an interface.

Anyway, it looks like a good start at a description.

tom

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

> Hi all,
>
> I have a question regarding HotSpot JIT and invokeinterface.
>
> There's a nice description of how HotSpot implements JIT'ed  
> invokeinterface
> at HotSpot Internals wiki:
>
>  http://wikis.sun.com/display/HotSpotInternals/InterfaceCalls
>
> Unfortunately there are no pointers to the actual code. 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!
>
> 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?
>
> ---
>
> [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()
>
> 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. 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!
>
> Regards,
>
>                        Pekka
>




More information about the hotspot-dev mailing list