Prevent JIT bodies from strictly outliving methods inlined into them #7673
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is largely in preparation for constant references, but it should also have benefits for code motion. For more detail, see the Motivation section of the doc comment for
RetainedMethodSet
.Much of this commit is
OMR::RetainedMethodSet
, which describes a set of methods that will remain loaded under certain assumptions. This is a base class that is meant to be subclassed in any downstream project that allows methods to be dynamically unloaded.During inlining, each
TR_CallSite
andTR_CallTarget
will now have an associatedRetainedMethodSet
. Often, all methods named at call sites and all selected call targets can be established to outlive their callers, and transitively the outermost method. In this case, nothing of note happens.However, sometimes a call site is refined based on a known object, and the refined method is not already known to outlive its caller. In this case, a nested
RetainedMethodSet
is created to represent the refined method (in addition to the surrounding inline context). Any further nested call sites and call targets can therefore take this refined method for granted. If the call site is actually inlined, then we record a "keepalive" for the refined method. The idea of a keepalive is that the JIT compiler should create an additional reference to prevent that method from being unloaded as long as the JIT body is still valid. In this commit, no such reference is created because we do not yet have a mechanism to do so. They will be implemented later as extra constant references. In the meantime, the JIT will simply assume that anything covered by a keepalive will remain loaded on its own. This assumption isn't great, but it's essentially the same as our existing pervasive assumption that known object indices will remain accurate.Similarly, sometimes a call target is selected based on profiling or a single implementer, and the target method is not already known to outlive the base method named at the call site. In this case, a nested
RetainedMethodSet
is created to represent the target method (in addition to the surrounding inline context). Any further nested call sites and call targets can therefore take this target method for granted. If the call target is actually inlined, then we record a "bond" for the target method. The idea of a bond is to limit the lifetime of the JIT body to prevent it from strictly outliving the inlined method. This should be accomplished in a downstream project by creating an unload assumption so that when the inlined method is unloaded, the JIT body will be invalidated (similarly to preexistence).If the
dontInlineUnloadableMethods
option is set, then instead of requesting bonds, inliner will refuse to inline targets that would required them. In this case, assertions check after optimization that no inlined method will be unexpectedly unloaded.