Summary
PERRY_INLINE_NEW=1 is worth a further −13.8% on pipeline (0.7924 of base, stacked on top of #7905), but the inline bump allocator never engages there by default. Cause: crates/perry-codegen/src/collectors/hot_callees.rs::record_callee records only Expr::FuncRef — i.e. direct calls.
pipeline's three stage closures are reached indirectly:
so they are never recorded as hot callees and never get the inline allocator, even though they are the hottest allocation sites in the program.
Why this wasn't just fixed in #7905
The measurement is easy; the admission rule is the hard part. #7871 priced the inline allocator at ~268 bytes of emitted code per new site and bounded its application deliberately. "Called indirectly from a loop" is not the same predicate as "called directly and hot", and widening admission without a size analysis risks paying that 268 bytes at every indirect call site in the program — a code-size and I-cache regression that would not show up on this corpus.
So this needs its own round: a size/benefit analysis for indirect callees, not a one-line predicate change.
Evidence
Acceptance
Notes and reproduce commands: gc-handoff/PIPELINE2-NOTES.md. Preserved arms: $HOME/pipeline2-arms/{base,fix}, corpora gc-handoff/m0810/{p2base,p2fix,p2inl}.
Summary
PERRY_INLINE_NEW=1is worth a further −13.8% onpipeline(0.7924 of base, stacked on top of #7905), but the inline bump allocator never engages there by default. Cause:crates/perry-codegen/src/collectors/hot_callees.rs::record_calleerecords onlyExpr::FuncRef— i.e. direct calls.pipeline's three stage closures are reached indirectly:so they are never recorded as hot callees and never get the inline allocator, even though they are the hottest allocation sites in the program.
Why this wasn't just fixed in #7905
The measurement is easy; the admission rule is the hard part. #7871 priced the inline allocator at ~268 bytes of emitted code per
newsite and bounded its application deliberately. "Called indirectly from a loop" is not the same predicate as "called directly and hot", and widening admission without a size analysis risks paying that 268 bytes at every indirect call site in the program — a code-size and I-cache regression that would not show up on this corpus.So this needs its own round: a size/benefit analysis for indirect callees, not a one-line predicate change.
Evidence
gc-handoff/MEASUREMENT-PROTOCOL.mdon why wall clock was unusable):pipelinefix+PERRY_INLINE_NEW=1= 0.7924 of base, vs 0.9192 for perf(codegen): serve.lengthon an untyped string receiver inline — pipeline −8.1%, shapes −10.2% #7905 alone..lengthon an untyped string receiver inline — pipeline −8.1%, shapes −10.2% #7905 the residual onpipelineis allocation, not dispatch — Generic class specialization is lost when a type argument is a type ALIAS — dispatch guard compiled against the template class, fast path permanently dead (53.8% ofpipeline) #7848/fix(hir): expand type aliases in the inferred type ofnew C<...>()so the generic specialization resolves (#7848) #7852 is confirmed fixed at this baseline (zerojs_method_direct_shape_guard, zerojs_native_call_method_by_id, all Registry sites direct$pshape), and Every dynamic method call pays 7 side-registry probes to exclude kinds the program never creates —is_registered_symbolalone takes a mutex + SipHash (6.5% ofpipeline) #7850'sgc_pointer_and_type_from_value/is_registered_symbolappear zero times in the profile.Acceptance
pipelineimproves materially toward node (currently 1.80x pre-perf(codegen): serve.lengthon an untyped string receiver inline — pipeline −8.1%, shapes −10.2% #7905).Notes and reproduce commands:
gc-handoff/PIPELINE2-NOTES.md. Preserved arms:$HOME/pipeline2-arms/{base,fix}, corporagc-handoff/m0810/{p2base,p2fix,p2inl}.