Initial round of jit inliner refactoring
In the jit, a particular inline decision is the aggregate result of checks
in many different parts of the code. The primary goal of this refactoring
is to establity a single object instance that will accumulate the necessary
information, and to ensure there are a small number of places in the code
where the final outcome is known.
That object is the `JitInlineResult`. I've updated it so it is no longer
copyable or assignable. Instead each root instance is passed down stack
by reference to helper methods that update the instance as the inline decision
making process evolves. Methods on the JitInlineResult can be used to advance
the state of what's known. The allowable state transitions are limited and the
code verifies that (when appropriate) a decision was actually made.
There are 4 such root instances:
* the main check done in the inlining pass.
* the candidate identification pass done in the importer.
* a pre-jit viability scan also done in the importer.
* another pre-jit viability scan done in the importer.
(These latter two identify un-inlinable methods at pre-jit time, so
subsequent jit invocations don't expend any cycles considering them).
I've updated various APIs to try and avoid introducing aliased copies or
projections of the inline result, for instance passing it via argument to
a helper that already has access to it via a member variable, or returning
a bool result from one of the various 'canInline' methods. More work is possible
here -- for example the compiler instance probably doesn't need an inline
result member of its own, since whenever it is inlining it has an inline
instance that has an inline result. I've added a few asserts in places to ensure
that if there is more than one plausible path to the result that they all refer
to the same object.
I've also started streamlining a bit of the goto-heavy case analysis in favor
of early returns, which I find more readable. The reporting obligation
is now held by the JitInlineResult destructor. Future work may go further in this
direction, and make the JitInlineResult responsible for never attribute flagging,
logging and dump messages, and perhaps even responsibility for undoing some of
the speculative state modification done when preparing for inlining (eg cleaning up
the locals in `fgMorphCallInlineHelper`).
At this stage the various candidate and failure reasons are still strings.
I added some new strings for in-progress checks so the dumps now show the
"success reason" for an inline. This is an area that will undergo
further refinement. Success reasons and failures and failure reasons
are still not captured in the inline tree; that too is forthcoming.
This change has minor codegen diffs. In cases where the callee has pinned locals
and returns a bool, we'll now identify the callee as a "never" candidate and so
some calls to it will never get the anticipatory wrapping that inline candidates
get. While this wrapping is undone later when inlining fails, it leaves a type
conversion behind and that conversion impacts the generated code slightly: I see
`test eax, eax` to query the return value rather than `test al, al`.
While I was striving for a no-diff change I think taking this one change is
reasonable: it's preferable to identify never candidates rather than repeatedly try
inlining them and fail each time.