summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Menard <kevin@nirvdrum.com>2026-01-21 19:19:55 -0500
committerGitHub <noreply@github.com>2026-01-22 00:19:55 +0000
commit6c2ecb231a90eee2a6d2a50164e44a185b52dfe9 (patch)
treee8b53276d3672f6dc38ae159adc3142ddd066fa6
parent436ec3a9d68ae9282fbc79e9400382d93d05e800 (diff)
ZJIT: Use `TypeDistribution` to track stats about the `super` CME (#15928)
This is a follow up to #15816. Since I was only optimizing `invokesuper` for monomorphic cases, I could track that with a boolean value (actually, `Option` in this case). But, `TypeDistribution` is a better way to track this information and will put us on better footing if we end up handling polymorphic cases.
-rw-r--r--zjit/src/profile.rs43
1 files changed, 17 insertions, 26 deletions
diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs
index 7a584afd6f..c1feb75952 100644
--- a/zjit/src/profile.rs
+++ b/zjit/src/profile.rs
@@ -159,23 +159,8 @@ fn profile_invokesuper(profiler: &mut Profiler, profile: &mut IseqProfile) {
let cme = unsafe { rb_vm_frame_method_entry(profiler.cfp) };
let cme_value = VALUE(cme as usize); // CME is a T_IMEMO, which is a VALUE
- match profile.super_cme.get(&profiler.insn_idx) {
- None => {
- // If `None`, then this is our first time looking at `super` for this instruction.
- profile.super_cme.insert(profiler.insn_idx, Some(cme_value));
- },
- Some(Some(existing_cme)) => {
- // Check if the stored method entry is the same as the current one. If it isn't, then
- // mark the call site as polymorphic.
- if *existing_cme != cme_value {
- profile.super_cme.insert(profiler.insn_idx, None);
- }
- }
- Some(None) => {
- // We've visited this instruction and explicitly stored `None` to mark the call site
- // as polymorphic.
- }
- }
+ profile.super_cme.entry(profiler.insn_idx)
+ .or_insert_with(|| TypeDistribution::new()).observe(ProfiledType::object(cme_value));
unsafe { rb_gc_writebarrier(profiler.iseq.into(), cme_value) };
@@ -359,7 +344,7 @@ pub struct IseqProfile {
num_profiles: Vec<NumProfiles>,
/// Method entries for `super` calls (stored as VALUE to be GC-safe)
- super_cme: HashMap<usize, Option<VALUE>>
+ super_cme: HashMap<usize, TypeDistribution>
}
impl IseqProfile {
@@ -377,8 +362,14 @@ impl IseqProfile {
}
pub fn get_super_method_entry(&self, insn_idx: usize) -> Option<*const rb_callable_method_entry_t> {
- self.super_cme.get(&insn_idx)
- .and_then(|opt| opt.map(|v| v.0 as *const rb_callable_method_entry_t))
+ let Some(entry) = self.super_cme.get(&insn_idx) else { return None };
+ let summary = TypeDistributionSummary::new(entry);
+
+ if summary.is_monomorphic() {
+ Some(summary.bucket(0).class.0 as *const rb_callable_method_entry_t)
+ } else {
+ None
+ }
}
/// Run a given callback with every object in IseqProfile
@@ -392,9 +383,9 @@ impl IseqProfile {
}
}
- for cme_value in self.super_cme.values() {
- if let Some(cme) = cme_value {
- callback(*cme);
+ for super_cme_values in self.super_cme.values() {
+ for profiled_type in super_cme_values.each_item() {
+ callback(profiled_type.class)
}
}
}
@@ -411,9 +402,9 @@ impl IseqProfile {
}
// Update CME references if they move during compaction.
- for cme_value in self.super_cme.values_mut() {
- if let Some(cme) = cme_value {
- callback(cme);
+ for super_cme_values in self.super_cme.values_mut() {
+ for ref mut profiled_type in super_cme_values.each_item_mut() {
+ callback(&mut profiled_type.class)
}
}
}