I've sunk a lot of time in to debugging Xadds in the runtime that unintentionally underflow and cause the unsigned number to wrap, leading to some (often subtle) horrible thing happening later. This debugging effort means the runtime is now sprinkled with underflow checks in many places where it calls Xadd.
We should consider making Xadd itself do this check, or introducing another variant that does. One caveat is that we currently don't have a signed version of Xadd, so there are places where we use it on a *uint32, but cast that unsigned value to a signed value everywhere we use it. In this case we definitely don't want to panic on unsigned underflow, so we should introduce a signed Xadd for these that takes a *int32 and doesn't do this check (though it could panic on signed wrap-around).
Still, why would the throw prevent inlining when panics in general do not? (And does mid-stack inlining improve the situation at all?)
Both throw and explicit calls to panic do prevent inlining right now. It's only implicit panics (inserted by the compiler for things like bounds checks or triggered by signals) that don't inhibit inlining.
Mid-stack inlining will probably make this a non-concern. There's nothing special about throw/panic that inhibits inlining. The inliner just sees them as calls, so the caller is a non-leaf function.