Open rakudrama opened 6 years ago
The work-around is not enough to ensure consistency. If a method, that is itself called once, is attempted inlined in an inlining stack where not all frames are called once, we register the method as being non-inlinable. Had we met this one call-site first we would have inlined it - though with the first work-around, not cached this decision.
For instance
foo() {}
bar() => foo();
baz() {
bar();
bar();
}
If we codegen bar
first we will inline foo
whereas if we codegen baz
first and inlined bar
we might have registered foo
as being non-inlinable.
The full(?) work-around is therefore to not mark foo
as non-inlinable because it is itself called once and the inlining decision of foo
therefore is potentially based on it being called once.
The 'isCalledOnce' inlining signal is unreliable. The main problem is that call sites in Kernel do not correspond one-to-one to call sites in the expanded generative constructor factories.
Consider:
There is one call site to
foo
. The factory constructors are essentially:In this expansion there are two call sites for
foo
. The context for each call site can be different. Below, when inlining A(), the total call stack hasfactory A
which is called twice, but when inlining B(),factory B
is called once, but in a loop:A decision to not inline
foo()
outside of a loop in a non-called-once stack (via A) conflicts with a decision to inlinefoo()
inside a loop (via B). A work-around is to not store update decisions for called-once methods.