When an ISEQ is recompiled after a guard_shape_failure (policy.no_side_exits == true), optimize_getivar skips shape specialization on the assumption that iseq_to_hir already emitted polymorphic branches with a GetIvar fallback.
That's only true for sites whose profile is Polymorphic / SkewedPolymorphic. For monomorphic sites, polymorphic_summary returns None, and iseq_to_hir emits a bare Insn::GetIvar expecting optimize_getivar to specialize it. On the recompiled version that never happens, so every monomorphic getivar in the ISEQ degrades to a rb_vm_getinstancevariable C call with no inline shape fast path — even sites that never failed a guard.
Possible fix
Under no_side_exits, still specialize monomorphic sites, but emit the side-exit-free IsBitEqual + IfTrue + GetIvar fallback pattern instead of the usual GuardBitEquals.
This should fix a regression in Optcarrot introduced by ruby#16589.
When an ISEQ is recompiled after a
guard_shape_failure(policy.no_side_exits == true),optimize_getivarskips shape specialization on the assumption thatiseq_to_hiralready emitted polymorphic branches with aGetIvarfallback.That's only true for sites whose profile is
Polymorphic/SkewedPolymorphic. For monomorphic sites,polymorphic_summaryreturnsNone, andiseq_to_hiremits a bareInsn::GetIvarexpectingoptimize_getivarto specialize it. On the recompiled version that never happens, so every monomorphic getivar in the ISEQ degrades to arb_vm_getinstancevariableC call with no inline shape fast path — even sites that never failed a guard.Possible fix
Under
no_side_exits, still specialize monomorphic sites, but emit the side-exit-freeIsBitEqual+IfTrue+GetIvarfallback pattern instead of the usualGuardBitEquals.This should fix a regression in Optcarrot introduced by ruby#16589.