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