From eaf5835d6a0e914edfdbb6ad1a8af2660e87a08c Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Thu, 23 Feb 2017 14:52:10 -0800 Subject: JIT: defer setting outgoing args size until after optimization (#9683) For fixed out args ABIs, the jit currently computes the size of the out arg area during morph, as it encounters calls that must pass arguments via the stack. Subsequently, the optimizer may delete calls, either because they are pure and the results are unused, or because they are conditional and the guarding predicates are resolved by the optimizer in such a way that the call is no longer reachable. In particular if all the calls seen by morph are subsequently removed by the optimizer, the jit may generate a stack frame that it never uses and doesn't need. If only some calls are removed then the stack frame may end up larger than necessary. One motivating example is the inlining of a shared generic method that ignores its generic context parameter. The caller typically must invoke a pure helper to determine the proper argument to pass. Post inline the call's result is unused, and the helper call is deleted by the optimizer. This change defers the outgoing arg size computation until fgSimpleLowering, which runs after optimization. The code in morph now simply records the needed size for each call in the associated fgArgInfo. As before, the outgoing arg size computation ignores fast tail calls, since they can use the caller-supplied scratch area for memory arguments. The jit may introduce helper calls after optimization which could seemingly invalidate the out args area size. The presumption here is that these calls are carefully designed not to use the caller-supplied scratch area. The current code makes the same assumption. This change introduces some unanticipated diffs. Optcse estimates the frame size to decide how aggressive it should be about cses of local variable references. This size estimate included the out args area, which appears to be something of an oversight; there are no cse opportunities in this area and the offsets of the other local variables are not impacted by the size of this area. With this change the out args area size is seen as zero during optimization and so the cse strategy for a method may be different. --- src/jit/utils.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/jit/utils.h') diff --git a/src/jit/utils.h b/src/jit/utils.h index dbd5fd5a1f..b41cf84a1e 100644 --- a/src/jit/utils.h +++ b/src/jit/utils.h @@ -381,6 +381,15 @@ public: return m_value; } + // Mark the value as read only; explicitly change the variable to the "read" phase. + void MarkAsReadOnly() const + { +#ifdef DEBUG + assert(m_initialized); + (const_cast(this))->m_writePhase = false; +#endif // DEBUG + } + // Functions/operators to write the value. Must be in the write phase. PhasedVar& operator=(const T& value) -- cgit v1.2.3