summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zjit.rb3
-rw-r--r--zjit/src/hir.rs31
-rw-r--r--zjit/src/stats.rs55
3 files changed, 62 insertions, 27 deletions
diff --git a/zjit.rb b/zjit.rb
index e3d9d4c728..eb47a70470 100644
--- a/zjit.rb
+++ b/zjit.rb
@@ -41,7 +41,8 @@ class << RubyVM::ZJIT
# Show non-exit counters
print_counters_with_prefix(prefix: 'dynamic_send_type_', prompt: 'dynamic send types', buf:, stats:, limit: 20)
- print_counters_with_prefix(prefix: 'send_fallback_', prompt: 'send fallback def_types', buf:, stats:, limit: 20)
+ print_counters_with_prefix(prefix: 'unspecialized_def_type_', prompt: 'send fallback unspecialized def_types', buf:, stats:, limit: 20)
+ print_counters_with_prefix(prefix: 'send_fallback_', prompt: 'dynamic send types', buf:, stats:, limit: 20)
# Show exit counters, ordered by the typical amount of exits for the prefix at the time
print_counters_with_prefix(prefix: 'unhandled_yarv_insn_', prompt: 'unhandled YARV insns', buf:, stats:, limit: 20)
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 6b1d22ac11..b3a57a7439 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1690,6 +1690,28 @@ impl Function {
None
}
+ /// Return whether a given HIR instruction as profiled by the interpreter is polymorphic or
+ /// whether it lacks a profile entirely.
+ ///
+ /// * `Some(true)` if polymorphic
+ /// * `Some(false)` if monomorphic
+ /// * `None` if no profiled information so far
+ fn is_polymorphic_at(&self, insn: InsnId, iseq_insn_idx: usize) -> Option<bool> {
+ let profiles = self.profiles.as_ref()?;
+ let entries = profiles.types.get(&iseq_insn_idx)?;
+ let insn = self.chase_insn(insn);
+ for (entry_insn, entry_type_summary) in entries {
+ if self.union_find.borrow().find_const(*entry_insn) == insn {
+ if !entry_type_summary.is_monomorphic() && !entry_type_summary.is_skewed_polymorphic() {
+ return Some(true);
+ } else {
+ return Some(false);
+ }
+ }
+ }
+ None
+ }
+
fn likely_is_fixnum(&self, val: InsnId, profiled_type: ProfiledType) -> bool {
self.is_a(val, types::Fixnum) || profiled_type.is_fixnum()
}
@@ -1840,6 +1862,15 @@ impl Function {
// If we know that self is reasonably monomorphic from profile information, guard and use it to fold the lookup at compile-time.
// TODO(max): Figure out how to handle top self?
let Some(recv_type) = self.profiled_type_of_at(recv, frame_state.insn_idx) else {
+ if get_option!(stats) {
+ match self.is_polymorphic_at(recv, frame_state.insn_idx) {
+ Some(true) => self.push_insn(block, Insn::IncrCounter(Counter::send_fallback_polymorphic)),
+ // If the class isn't known statically, then it should not also be monomorphic
+ Some(false) => panic!("Should not have monomorphic profile at this point in this branch"),
+ None => self.push_insn(block, Insn::IncrCounter(Counter::send_fallback_no_profiles)),
+
+ };
+ }
self.push_insn_id(block, insn_id); continue;
};
(recv_type.class(), Some(recv_type))
diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs
index 012b8be250..4f38e4a131 100644
--- a/zjit/src/stats.rs
+++ b/zjit/src/stats.rs
@@ -138,19 +138,22 @@ make_counters! {
dynamic_send_type_invokesuper,
// Method call def_type related to fallback to dynamic dispatch
- send_fallback_iseq,
- send_fallback_cfunc,
- send_fallback_attrset,
- send_fallback_ivar,
- send_fallback_bmethod,
- send_fallback_zsuper,
- send_fallback_alias,
- send_fallback_undef,
- send_fallback_not_implemented,
- send_fallback_optimized,
- send_fallback_missing,
- send_fallback_refined,
- send_fallback_null,
+ unspecialized_def_type_iseq,
+ unspecialized_def_type_cfunc,
+ unspecialized_def_type_attrset,
+ unspecialized_def_type_ivar,
+ unspecialized_def_type_bmethod,
+ unspecialized_def_type_zsuper,
+ unspecialized_def_type_alias,
+ unspecialized_def_type_undef,
+ unspecialized_def_type_not_implemented,
+ unspecialized_def_type_optimized,
+ unspecialized_def_type_missing,
+ unspecialized_def_type_refined,
+ unspecialized_def_type_null,
+
+ send_fallback_polymorphic,
+ send_fallback_no_profiles,
// Writes to the VM frame
vm_write_pc_count,
@@ -252,19 +255,19 @@ pub fn send_fallback_counter(def_type: crate::hir::MethodType) -> Counter {
use crate::stats::Counter::*;
match def_type {
- Iseq => send_fallback_iseq,
- Cfunc => send_fallback_cfunc,
- Attrset => send_fallback_attrset,
- Ivar => send_fallback_ivar,
- Bmethod => send_fallback_bmethod,
- Zsuper => send_fallback_zsuper,
- Alias => send_fallback_alias,
- Undefined => send_fallback_undef,
- NotImplemented => send_fallback_not_implemented,
- Optimized => send_fallback_optimized,
- Missing => send_fallback_missing,
- Refined => send_fallback_refined,
- Null => send_fallback_null,
+ Iseq => unspecialized_def_type_iseq,
+ Cfunc => unspecialized_def_type_cfunc,
+ Attrset => unspecialized_def_type_attrset,
+ Ivar => unspecialized_def_type_ivar,
+ Bmethod => unspecialized_def_type_bmethod,
+ Zsuper => unspecialized_def_type_zsuper,
+ Alias => unspecialized_def_type_alias,
+ Undefined => unspecialized_def_type_undef,
+ NotImplemented => unspecialized_def_type_not_implemented,
+ Optimized => unspecialized_def_type_optimized,
+ Missing => unspecialized_def_type_missing,
+ Refined => unspecialized_def_type_refined,
+ Null => unspecialized_def_type_null,
}
}