Commit 82ac816
committed
ZJIT: Branch on the ivar shape for attr_accessor sends in polymorphic arms
[zjit/min port note] Hand-ported af5bc8f, 98f1b7a and 2f92871, adapted
to min's ivar dispatch, plus afe2f67 ("Branch on the ivar shape in an
attr_reader's final version").
The previous commit handed a dispatch arm its shape only when every bucket
profiled for the class agreed on it, because a consumer would *guard* that
shape and side-exit on a miss. Upstream instead marks such a type
(`ProfiledType::as_polymorphic_arm`) and has consumers branch on it: a receiver
of the right class but another shape takes the generic C helper instead of
side-exiting out of a version that never promised the shape. With that, an arm
can hand over every shape its class was profiled with, which is what actually
moves getivar_fallback_no_profile_missing_ic.
* `Flags::IS_POLYMORPHIC_ARM` marks a type synthesized for an arm rather than
observed at that program point.
* `emit_polymorphic_send` hands each arm every bucket for its class, not just
the one that named the arm. A sibling has to carry at least
1/`ARM_SHAPE_MIN_SHARE` of the class's samples to earn an arm: the arms live
in the caller and share its inline budget, so specializing a shape almost
nobody has can push a hot callee out of the budget and cost more in dynamic
sends than it saves in ivar reads.
* The `VM_METHOD_TYPE_IVAR` and `VM_METHOD_TYPE_ATTRSET` send paths route a
polymorphic-arm profile through `dispatch_getivar`/`dispatch_setivar`
instead of a shape guard, over every shape the arm carries
(`profiled_shape_variants`). attr_writer's shape transition is not itself
speculative: the destination shape is a function of the source shape and the
ivar, and the branch has already established the source shape.
* attr_reader's final version (`no_side_exits`) previously emitted an
unconditional `rb_ivar_get`; it now branches the same way
`getinstancevariable` already did.
Adaptations: min's `dispatch_ivar` already ends every shape chain in a branch to
a generic fallback rather than a side exit, so upstream's three-valued
`ShapeMiss` collapses onto min's existing `covers_profile` flag (false asks for
the branchy form) plus a new `reprofile_on_miss` flag. The latter is upstream's
`CallFallbackWithoutReprofile`: sampling an arm's fallback miss would earn the
ISEQ a re-profile and throw away the type profile the arms were built from.
`try_emit_optimized_setivar` is deleted, as upstream does, now that the
attr_writer path drives `prepare_optimized_setivar` directly.1 parent 1ee1ff0 commit 82ac816
4 files changed
Lines changed: 223 additions & 46 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
281 | 292 | | |
282 | | - | |
283 | 293 | | |
284 | | - | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
285 | 298 | | |
286 | 299 | | |
287 | 300 | | |
| |||
0 commit comments