Commit 05be09f
committed
ZJIT: Keep the profiled shape reachable through guards and dispatch arms
[zjit/min port note] Hand-ported slice of fcb775d ("Specialize `&block`
forwarding sends and keep profiled shapes"), af5bc8f ("Keep the profiled
shape inside polymorphic dispatch arms") and 7ce7db7 ("Don't re-speculate on
the receiver in a type-dispatch fallthrough"), which together are what makes
zjit/all's getivar_fallback_no_profile_missing_ic 338,599 where this branch's is
5,204,190.
`Type` records a class but not a shape, so once a receiver was guarded or
refined to a profiled type, later specializations of the same value could no
longer see its shape. Three leaks followed, all ending in a full `rb_ivar_get`
call for what should be a direct field load:
* Inlined callees. An ISEQ only starts profiling once the interpreter has
entered it, so a method reached only from JIT code has no profile of its
own; its `self` is the caller's guarded receiver, and the guard was the
last place the shape existed. `Function::guarded_profiled_types` now
remembers the profiled type behind each guard, and
`resolve_receiver_type` prefers it over the static class.
* Polymorphic dispatch arms. Each arm refined the receiver to a class and
dropped its profile entry outright. The arm now carries the profiled type
forward, both as the Snapshot's receiver entry and via
`record_profiled_type`.
* `opt_send_without_block`, the hottest send opcode, went through a
near-clone of `emit_polymorphic_send` (`gen_send_chain`) that did none of
this. Deleted, and the opcode routed through `emit_polymorphic_send` like
upstream does.
Adaptations: `recorded_profiled_type` keeps `union_find.borrow()` because min
still has the RefCell around the union-find. Upstream tags an arm's shape with
`ProfiledType::as_polymorphic_arm()` and has consumers branch on it rather than
guard it (`ShapeMiss`, from 98f1b7a and 2f92871, not ported here);
without that machinery an arm hands its shape over only when every bucket
profiled for that class agrees on it, so the shape is a real prediction and a
consumer may guard it with the same confidence as at a monomorphic site.
Rerouting `opt_send_without_block` also required 7ce7db7's fallthrough fix:
`copy_entries_except` now takes an optional replacement summary for the
receiver, and the fallthrough substitutes a megamorphic one. `gen_send_chain`
reused the original Snapshot, so dropping the entry without a replacement would
have turned its fallthrough into a `NoProfileSend` side exit instead of the
dynamic send it has to be. That also fixes the same latent re-speculation on
min's `YARVINSN_send` path, whose fallthrough already took a fresh Snapshot but
passed no summary.1 parent ab05167 commit 05be09f
3 files changed
Lines changed: 378 additions & 332 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
267 | 267 | | |
268 | 268 | | |
269 | 269 | | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
270 | 288 | | |
271 | 289 | | |
272 | 290 | | |
| |||
0 commit comments