Skip to content

Commit 6c2ecb2

Browse files
authored
ZJIT: Use TypeDistribution to track stats about the super CME (ruby#15928)
This is a follow up to ruby#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.
1 parent 436ec3a commit 6c2ecb2

File tree

1 file changed

+17
-26
lines changed

1 file changed

+17
-26
lines changed

zjit/src/profile.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,8 @@ fn profile_invokesuper(profiler: &mut Profiler, profile: &mut IseqProfile) {
159159
let cme = unsafe { rb_vm_frame_method_entry(profiler.cfp) };
160160
let cme_value = VALUE(cme as usize); // CME is a T_IMEMO, which is a VALUE
161161

162-
match profile.super_cme.get(&profiler.insn_idx) {
163-
None => {
164-
// If `None`, then this is our first time looking at `super` for this instruction.
165-
profile.super_cme.insert(profiler.insn_idx, Some(cme_value));
166-
},
167-
Some(Some(existing_cme)) => {
168-
// Check if the stored method entry is the same as the current one. If it isn't, then
169-
// mark the call site as polymorphic.
170-
if *existing_cme != cme_value {
171-
profile.super_cme.insert(profiler.insn_idx, None);
172-
}
173-
}
174-
Some(None) => {
175-
// We've visited this instruction and explicitly stored `None` to mark the call site
176-
// as polymorphic.
177-
}
178-
}
162+
profile.super_cme.entry(profiler.insn_idx)
163+
.or_insert_with(|| TypeDistribution::new()).observe(ProfiledType::object(cme_value));
179164

180165
unsafe { rb_gc_writebarrier(profiler.iseq.into(), cme_value) };
181166

@@ -359,7 +344,7 @@ pub struct IseqProfile {
359344
num_profiles: Vec<NumProfiles>,
360345

361346
/// Method entries for `super` calls (stored as VALUE to be GC-safe)
362-
super_cme: HashMap<usize, Option<VALUE>>
347+
super_cme: HashMap<usize, TypeDistribution>
363348
}
364349

365350
impl IseqProfile {
@@ -377,8 +362,14 @@ impl IseqProfile {
377362
}
378363

379364
pub fn get_super_method_entry(&self, insn_idx: usize) -> Option<*const rb_callable_method_entry_t> {
380-
self.super_cme.get(&insn_idx)
381-
.and_then(|opt| opt.map(|v| v.0 as *const rb_callable_method_entry_t))
365+
let Some(entry) = self.super_cme.get(&insn_idx) else { return None };
366+
let summary = TypeDistributionSummary::new(entry);
367+
368+
if summary.is_monomorphic() {
369+
Some(summary.bucket(0).class.0 as *const rb_callable_method_entry_t)
370+
} else {
371+
None
372+
}
382373
}
383374

384375
/// Run a given callback with every object in IseqProfile
@@ -392,9 +383,9 @@ impl IseqProfile {
392383
}
393384
}
394385

395-
for cme_value in self.super_cme.values() {
396-
if let Some(cme) = cme_value {
397-
callback(*cme);
386+
for super_cme_values in self.super_cme.values() {
387+
for profiled_type in super_cme_values.each_item() {
388+
callback(profiled_type.class)
398389
}
399390
}
400391
}
@@ -411,9 +402,9 @@ impl IseqProfile {
411402
}
412403

413404
// Update CME references if they move during compaction.
414-
for cme_value in self.super_cme.values_mut() {
415-
if let Some(cme) = cme_value {
416-
callback(cme);
405+
for super_cme_values in self.super_cme.values_mut() {
406+
for ref mut profiled_type in super_cme_values.each_item_mut() {
407+
callback(&mut profiled_type.class)
417408
}
418409
}
419410
}

0 commit comments

Comments
 (0)