Point where code installed by C1 and C2 is loaded?
Julian Waters
tanksherman27 at gmail.com
Thu Oct 13 13:03:13 UTC 2022
Hi Vladimir, thanks for the reply!
Looking at set_code it seems to me like the redirection is done in
mh->_from_compiled_entry = code->verified_entry_point();
while
mh->_from_interpreted_entry = mh->get_i2c_entry();
is done to make execution jump to compiled code if it was running in the
interpreter prior, did i get that right? Seems a little strange to me that
_code is also stored in the Method if it's not actually used in execution,
but I guess it's probably used for other reasons. Given the comments
accompanying _from_compiled_entry and _from_interpreted_entry:
// Entry point for calling from compiled code, to compiled code if it exists
// or else the interpreter.
// Cache of _code ? _adapter->i2c_entry() : _i2i_entry
// Cache of: _code ? _code->entry_point() : _adapter->c2i_entry()
If i understand this correctly, if _code != NULL, _from_interpreted_entry
would be _adapter->i2c_entry(), which is(?) a CodeBlob containing assembly
to transfer control to the associated nmethod, and vice versa for
_from_compiled_entry? I am somewhat curious about where these are actually
loaded during frame creation, and how the runtime would know whether what
it just received were the contents of an nmethod that could be executed
immediately, or a method running in the interpreter that needs to be
decoded, dispatched, etc.
I appreciate the response explaining method invocation!
best regards,
Julian
On Thu, Oct 13, 2022 at 1:13 AM Vladimir Ivanov <
vladimir.x.ivanov at oracle.com> wrote:
> At runtime, every method is invoked either through
> Method::_from_compiled_entry or Method::_from_interpreted_entry
> (depending on where the call is performed from).
>
> As part of nmethod installation (ciEnv::register_method()), entry points
> of the relevant method (the root of the compilation) are updated (by
> Method::set_code()) and Method::_from_compiled_entry starts to point to
> the entry point of the freshly installed nmethod.
>
> (Also, there is a special case of OSR compilation, but I don't cover it
> here.)
>
> src/hotspot/share/oops/method.hpp [1]:
>
> class Method : public Metadata {
> ...
> // Entry point for calling from compiled code, to compiled code if it
> exists
> // or else the interpreter.
> volatile address _from_compiled_entry; // Cache of: _code ?
> _code->entry_point() : _adapter->c2i_entry()
> // The entry point for calling both from and to compiled code is
> // "_code->entry_point()". Because of tiered compilation and de-opt,
> this
> // field can come and go. It can transition from NULL to not-null at
> any
> // time (whenever a compile completes). It can transition from
> not-null to
> // NULL only at safepoints (because of a de-opt).
> CompiledMethod* volatile _code; // Points to
> the corresponding piece of native code
> volatile address _from_interpreted_entry; // Cache of _code
> ? _adapter->i2c_entry() : _i2i_entry
>
> Hp
>
> Best regards,
> Vladimir Ivanov
>
> [1]
>
> https://github.com/openjdk/jdk/blob/master/src/hotspot/share/oops/method.hpp#L109-L118
>
> On 10/12/22 08:18, Julian Waters wrote:
> > Hi all,
> >
> > I apologise if this is a silly question, but where exactly is code
> > installed by C1 and C2 loaded and executed by the runtime? I've tried
> > looking through the entirety of hotspot, but haven't found anything that
> > seems to be related. All I can surmise is that the compiler interface
> > ultimately creates an nmethod that allocates itself on the CodeCache
> > using a CodeBuffer containing C1 or C2 emitted instructions, and then
> > Method::set_code sets the method's _code to reference that entry in the
> > cache (or method->method_holder()->add_osr_nmethod(nm); is called in
> > other circumstances, I don't quite understand what the difference is but
> > I assume the end result is probably the same). Given my rudimentary
> > understanding of hotspot's execution pipeline I'd assume that when a new
> > frame (frame.hpp) is created, the frame's code blob would be set to
> > reference the nmethod in the method that was called, or otherwise
> > somehow jump back to the interpreter if that method hasn't been compiled
> > yet. But there doesn't seem to be any point where method->code() is
> > called to load the instructions emitted by either C1 or C2 into a frame,
> > so where does that happen?
> >
> > I guess this is probably more a question of how hotspot runs loaded
> > programs in general, which seems to me at a glance like it's chaining
> > assembly in CodeBlobs together and jumping to the next blob/codelet (in
> > the next frame?) when it's finished, but I can't really figure out where
> > those codelets are set for each frame, or how it chooses between one
> > compiled by C1 or C2, and the handwritten assembly codelets that make up
> > the interpreter (or for that matter how it even finds the correct
> > interpreter codelet).
> >
> > I appreciate any help with this query, sorry if this isn't the correct
> > list to post this question to, but it seemed like the most appropriate.
> >
> > best regards,
> > Julian
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/hotspot-compiler-dev/attachments/20221013/b5b0e32c/attachment.htm>
More information about the hotspot-compiler-dev
mailing list