summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <rubybugs@bernsteinbear.com>2025-11-19 12:58:24 -0800
committerGitHub <noreply@github.com>2025-11-19 15:58:24 -0500
commit4a1af72a13d41dcc38af7d69ea1f44856265d43f (patch)
tree38846de07c6ca3fd1399ddca16859c55de797226
parent28908a95c4d303e3cf12f03b0b475a48778435a7 (diff)
ZJIT: Count all calls to C functions from generated code (#15240)
lobsters: ``` Top-20 calls to C functions from JIT code (79.9% of total 97,004,883): rb_vm_opt_send_without_block: 19,874,212 (20.5%) rb_vm_setinstancevariable: 9,774,841 (10.1%) rb_ivar_get: 9,358,866 ( 9.6%) rb_hash_aref: 6,828,948 ( 7.0%) rb_vm_send: 6,441,551 ( 6.6%) rb_vm_env_write: 5,375,989 ( 5.5%) rb_vm_invokesuper: 3,037,836 ( 3.1%) Module#===: 2,562,446 ( 2.6%) rb_ary_entry: 2,354,546 ( 2.4%) Kernel#is_a?: 1,424,092 ( 1.5%) rb_vm_opt_getconstant_path: 1,344,923 ( 1.4%) Thread.current: 1,300,822 ( 1.3%) rb_zjit_defined_ivar: 1,222,613 ( 1.3%) rb_vm_invokeblock: 1,184,555 ( 1.2%) Hash#[]=: 1,061,969 ( 1.1%) rb_ary_push: 1,024,987 ( 1.1%) rb_ary_new_capa: 904,003 ( 0.9%) rb_str_buf_append: 833,782 ( 0.9%) rb_class_allocate_instance: 822,626 ( 0.8%) Hash#fetch: 755,913 ( 0.8%) ``` railsbench: ``` Top-20 calls to C functions from JIT code (74.8% of total 189,170,268): rb_vm_opt_send_without_block: 29,870,307 (15.8%) rb_vm_setinstancevariable: 17,631,199 ( 9.3%) rb_hash_aref: 16,928,890 ( 8.9%) rb_ivar_get: 14,441,240 ( 7.6%) rb_vm_env_write: 11,571,001 ( 6.1%) rb_vm_send: 11,153,457 ( 5.9%) rb_vm_invokesuper: 7,568,267 ( 4.0%) Module#===: 6,065,923 ( 3.2%) Hash#[]=: 2,842,990 ( 1.5%) rb_ary_entry: 2,766,125 ( 1.5%) rb_ary_push: 2,722,079 ( 1.4%) rb_vm_invokeblock: 2,594,398 ( 1.4%) Thread.current: 2,560,129 ( 1.4%) rb_str_getbyte: 1,965,627 ( 1.0%) Kernel#is_a?: 1,961,815 ( 1.0%) rb_vm_opt_getconstant_path: 1,863,678 ( 1.0%) rb_hash_new_with_size: 1,796,456 ( 0.9%) rb_class_allocate_instance: 1,785,043 ( 0.9%) String#empty?: 1,713,414 ( 0.9%) rb_ary_new_capa: 1,678,834 ( 0.9%) ``` shipit: ``` Top-20 calls to C functions from JIT code (83.4% of total 182,402,821): rb_vm_opt_send_without_block: 45,753,484 (25.1%) rb_ivar_get: 21,020,650 (11.5%) rb_vm_setinstancevariable: 17,528,603 ( 9.6%) rb_hash_aref: 11,892,856 ( 6.5%) rb_vm_send: 11,723,471 ( 6.4%) rb_vm_env_write: 10,434,452 ( 5.7%) Module#===: 4,225,048 ( 2.3%) rb_vm_invokesuper: 3,705,906 ( 2.0%) Thread.current: 3,337,603 ( 1.8%) rb_ary_entry: 3,114,378 ( 1.7%) Hash#[]=: 2,509,912 ( 1.4%) Array#empty?: 2,282,994 ( 1.3%) rb_vm_invokeblock: 2,210,511 ( 1.2%) Hash#fetch: 2,017,960 ( 1.1%) _bi20: 1,975,147 ( 1.1%) rb_zjit_defined_ivar: 1,897,127 ( 1.0%) rb_vm_opt_getconstant_path: 1,813,294 ( 1.0%) rb_ary_new_capa: 1,615,406 ( 0.9%) Kernel#is_a?: 1,567,854 ( 0.9%) rb_class_allocate_instance: 1,560,035 ( 0.9%) ``` Thanks to @eregon for the idea. Co-authored-by: Jacob Denbeaux <jacob.denbeaux@shopify.com> Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
-rw-r--r--zjit.rb1
-rw-r--r--zjit/src/backend/lir.rs12
-rw-r--r--zjit/src/codegen.rs68
-rw-r--r--zjit/src/cruby.rs12
-rw-r--r--zjit/src/hir.rs11
-rw-r--r--zjit/src/hir/opt_tests.rs82
-rw-r--r--zjit/src/state.rs9
-rw-r--r--zjit/src/stats.rs7
8 files changed, 127 insertions, 75 deletions
diff --git a/zjit.rb b/zjit.rb
index bb6d4d3cdc..fc306c19a4 100644
--- a/zjit.rb
+++ b/zjit.rb
@@ -174,6 +174,7 @@ class << RubyVM::ZJIT
# Show counters independent from exit_* or dynamic_send_*
print_counters_with_prefix(prefix: 'not_inlined_cfuncs_', prompt: 'not inlined C methods', buf:, stats:, limit: 20)
+ print_counters_with_prefix(prefix: 'ccall_', prompt: 'calls to C functions from JIT code', buf:, stats:, limit: 20)
# Don't show not_annotated_cfuncs right now because it mostly duplicates not_inlined_cfuncs
# print_counters_with_prefix(prefix: 'not_annotated_cfuncs_', prompt: 'not annotated C methods', buf:, stats:, limit: 20)
diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs
index cb8382a43c..3c9bf72023 100644
--- a/zjit/src/backend/lir.rs
+++ b/zjit/src/backend/lir.rs
@@ -2065,6 +2065,17 @@ impl Assembler {
out
}
+ pub fn count_call_to(&mut self, fn_name: &str) {
+ // We emit ccalls while initializing the JIT. Unfortunately, we skip those because
+ // otherwise we have no counter pointers to read.
+ if crate::state::ZJITState::has_instance() && get_option!(stats) {
+ let ccall_counter_pointers = crate::state::ZJITState::get_ccall_counter_pointers();
+ let counter_ptr = ccall_counter_pointers.entry(fn_name.to_string()).or_insert_with(|| Box::new(0));
+ let counter_ptr: &mut u64 = counter_ptr.as_mut();
+ self.incr_counter(Opnd::const_ptr(counter_ptr), 1.into());
+ }
+ }
+
pub fn cmp(&mut self, left: Opnd, right: Opnd) {
self.push_insn(Insn::Cmp { left, right });
}
@@ -2389,6 +2400,7 @@ pub(crate) use asm_comment;
macro_rules! asm_ccall {
[$asm: ident, $fn_name:ident, $($args:expr),* ] => {{
$crate::backend::lir::asm_comment!($asm, concat!("call ", stringify!($fn_name)));
+ $asm.count_call_to(stringify!($fn_name));
$asm.ccall($fn_name as *const u8, vec![$($args),*])
}};
}
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index 8fc66791a6..18266b4693 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -419,14 +419,14 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
&Insn::GuardLess { left, right, state } => gen_guard_less(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
&Insn::GuardGreaterEq { left, right, state } => gen_guard_greater_eq(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
Insn::PatchPoint { invariant, state } => no_output!(gen_patch_point(jit, asm, invariant, &function.frame_state(*state))),
- Insn::CCall { cfunc, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfunc, opnds!(args)),
+ Insn::CCall { cfunc, args, name, return_type: _, elidable: _ } => gen_ccall(asm, *cfunc, *name, opnds!(args)),
// Give up CCallWithFrame for 7+ args since asm.ccall() doesn't support it.
Insn::CCallWithFrame { cd, state, args, .. } if args.len() > C_ARG_OPNDS.len() =>
gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), SendFallbackReason::CCallWithFrameTooManyArgs),
- Insn::CCallWithFrame { cfunc, args, cme, state, blockiseq, .. } =>
- gen_ccall_with_frame(jit, asm, *cfunc, opnds!(args), *cme, *blockiseq, &function.frame_state(*state)),
- Insn::CCallVariadic { cfunc, recv, args, name: _, cme, state, return_type: _, elidable: _ } => {
- gen_ccall_variadic(jit, asm, *cfunc, opnd!(recv), opnds!(args), *cme, &function.frame_state(*state))
+ Insn::CCallWithFrame { cfunc, name, args, cme, state, blockiseq, .. } =>
+ gen_ccall_with_frame(jit, asm, *cfunc, *name, opnds!(args), *cme, *blockiseq, &function.frame_state(*state)),
+ Insn::CCallVariadic { cfunc, recv, args, name, cme, state, return_type: _, elidable: _ } => {
+ gen_ccall_variadic(jit, asm, *cfunc, *name, opnd!(recv), opnds!(args), *cme, &function.frame_state(*state))
}
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))),
@@ -697,6 +697,7 @@ fn gen_invokebuiltin(jit: &JITState, asm: &mut Assembler, state: &FrameState, bf
let mut cargs = vec![EC];
cargs.extend(args);
+ asm.count_call_to(unsafe { std::ffi::CStr::from_ptr(bf.name).to_str().unwrap() });
asm.ccall(bf.func_ptr as *const u8, cargs)
}
@@ -754,6 +755,7 @@ fn gen_ccall_with_frame(
jit: &mut JITState,
asm: &mut Assembler,
cfunc: *const u8,
+ name: ID,
args: Vec<Opnd>,
cme: *const rb_callable_method_entry_t,
blockiseq: Option<IseqPtr>,
@@ -801,6 +803,7 @@ fn gen_ccall_with_frame(
asm.mov(CFP, new_cfp);
asm.store(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP), CFP);
+ asm.count_call_to(&name.contents_lossy());
let result = asm.ccall(cfunc, args);
asm_comment!(asm, "pop C frame");
@@ -817,7 +820,8 @@ fn gen_ccall_with_frame(
/// Lowering for [`Insn::CCall`]. This is a low-level raw call that doesn't know
/// anything about the callee, so handling for e.g. GC safety is dealt with elsewhere.
-fn gen_ccall(asm: &mut Assembler, cfunc: *const u8, args: Vec<Opnd>) -> lir::Opnd {
+fn gen_ccall(asm: &mut Assembler, cfunc: *const u8, name: ID, args: Vec<Opnd>) -> lir::Opnd {
+ asm.count_call_to(&name.contents_lossy());
asm.ccall(cfunc, args)
}
@@ -827,6 +831,7 @@ fn gen_ccall_variadic(
jit: &mut JITState,
asm: &mut Assembler,
cfunc: *const u8,
+ name: ID,
recv: Opnd,
args: Vec<Opnd>,
cme: *const rb_callable_method_entry_t,
@@ -859,6 +864,7 @@ fn gen_ccall_variadic(
asm.store(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP), CFP);
let argv_ptr = gen_push_opnds(asm, &args);
+ asm.count_call_to(&name.contents_lossy());
let result = asm.ccall(cfunc, vec![args.len().into(), argv_ptr, recv]);
gen_pop_opnds(asm, &args);
@@ -1169,9 +1175,10 @@ fn gen_send(
unsafe extern "C" {
fn rb_vm_send(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
- asm.ccall(
- rb_vm_send as *const u8,
- vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
+ asm_ccall!(
+ asm,
+ rb_vm_send,
+ EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@@ -1192,9 +1199,10 @@ fn gen_send_forward(
unsafe extern "C" {
fn rb_vm_sendforward(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
- asm.ccall(
- rb_vm_sendforward as *const u8,
- vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
+ asm_ccall!(
+ asm,
+ rb_vm_sendforward,
+ EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@@ -1213,9 +1221,10 @@ fn gen_send_without_block(
unsafe extern "C" {
fn rb_vm_opt_send_without_block(ec: EcPtr, cfp: CfpPtr, cd: VALUE) -> VALUE;
}
- asm.ccall(
- rb_vm_opt_send_without_block as *const u8,
- vec![EC, CFP, Opnd::const_ptr(cd)],
+ asm_ccall!(
+ asm,
+ rb_vm_opt_send_without_block,
+ EC, CFP, Opnd::const_ptr(cd)
)
}
@@ -1331,9 +1340,10 @@ fn gen_invokeblock(
unsafe extern "C" {
fn rb_vm_invokeblock(ec: EcPtr, cfp: CfpPtr, cd: VALUE) -> VALUE;
}
- asm.ccall(
- rb_vm_invokeblock as *const u8,
- vec![EC, CFP, Opnd::const_ptr(cd)],
+ asm_ccall!(
+ asm,
+ rb_vm_invokeblock,
+ EC, CFP, Opnd::const_ptr(cd)
)
}
@@ -1353,9 +1363,10 @@ fn gen_invokesuper(
unsafe extern "C" {
fn rb_vm_invokesuper(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
- asm.ccall(
- rb_vm_invokesuper as *const u8,
- vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
+ asm_ccall!(
+ asm,
+ rb_vm_invokesuper,
+ EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@@ -1436,9 +1447,10 @@ fn gen_array_include(
unsafe extern "C" {
fn rb_vm_opt_newarray_include_p(ec: EcPtr, num: c_long, elts: *const VALUE, target: VALUE) -> VALUE;
}
- asm.ccall(
- rb_vm_opt_newarray_include_p as *const u8,
- vec![EC, num.into(), elements_ptr, target],
+ asm_ccall!(
+ asm,
+ rb_vm_opt_newarray_include_p,
+ EC, num.into(), elements_ptr, target
)
}
@@ -1454,9 +1466,10 @@ fn gen_dup_array_include(
unsafe extern "C" {
fn rb_vm_opt_duparray_include_p(ec: EcPtr, ary: VALUE, target: VALUE) -> VALUE;
}
- asm.ccall(
- rb_vm_opt_duparray_include_p as *const u8,
- vec![EC, ary.into(), target],
+ asm_ccall!(
+ asm,
+ rb_vm_opt_duparray_include_p,
+ EC, ary.into(), target
)
}
@@ -1527,6 +1540,7 @@ fn gen_object_alloc_class(asm: &mut Assembler, class: VALUE, state: &FrameState)
let alloc_func = unsafe { rb_zjit_class_get_alloc_func(class) };
assert!(alloc_func.is_some(), "class {} passed to ObjectAllocClass must have an allocator", get_class_name(class));
asm_comment!(asm, "call allocator for class {}", get_class_name(class));
+ asm.count_call_to(&format!("{}::allocator", get_class_name(class)));
asm.ccall(alloc_func.unwrap() as *const u8, vec![class.into()])
}
}
diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs
index db47385bc8..61c25a4092 100644
--- a/zjit/src/cruby.rs
+++ b/zjit/src/cruby.rs
@@ -775,11 +775,17 @@ pub fn rust_str_to_ruby(str: &str) -> VALUE {
unsafe { rb_utf8_str_new(str.as_ptr() as *const _, str.len() as i64) }
}
-/// Produce a Ruby symbol from a Rust string slice
-pub fn rust_str_to_sym(str: &str) -> VALUE {
+/// Produce a Ruby ID from a Rust string slice
+pub fn rust_str_to_id(str: &str) -> ID {
let c_str = CString::new(str).unwrap();
let c_ptr: *const c_char = c_str.as_ptr();
- unsafe { rb_id2sym(rb_intern(c_ptr)) }
+ unsafe { rb_intern(c_ptr) }
+}
+
+/// Produce a Ruby symbol from a Rust string slice
+pub fn rust_str_to_sym(str: &str) -> VALUE {
+ let id = rust_str_to_id(str);
+ unsafe { rb_id2sym(id) }
}
/// Produce an owned Rust String from a C char pointer
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 58638f30f0..982400db50 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -2889,12 +2889,13 @@ impl Function {
let mut cfunc_args = vec![recv];
cfunc_args.append(&mut args);
+ let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let ccall = fun.push_insn(block, Insn::CCallWithFrame {
cd,
cfunc,
args: cfunc_args,
cme,
- name: method_id,
+ name,
state,
return_type: types::BasicObject,
elidable: false,
@@ -3018,6 +3019,7 @@ impl Function {
// No inlining; emit a call
let cfunc = unsafe { get_mct_func(cfunc) }.cast();
+ let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let mut cfunc_args = vec![recv];
cfunc_args.append(&mut args);
let return_type = props.return_type;
@@ -3025,7 +3027,7 @@ impl Function {
// Filter for a leaf and GC free function
if props.leaf && props.no_gc {
fun.push_insn(block, Insn::IncrCounter(Counter::inline_cfunc_optimized_send_count));
- let ccall = fun.push_insn(block, Insn::CCall { cfunc, args: cfunc_args, name: method_id, return_type, elidable });
+ let ccall = fun.push_insn(block, Insn::CCall { cfunc, args: cfunc_args, name, return_type, elidable });
fun.make_equal_to(send_insn_id, ccall);
} else {
if get_option!(stats) {
@@ -3036,7 +3038,7 @@ impl Function {
cfunc,
args: cfunc_args,
cme,
- name: method_id,
+ name,
state,
return_type,
elidable,
@@ -3099,12 +3101,13 @@ impl Function {
}
let return_type = props.return_type;
let elidable = props.elidable;
+ let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let ccall = fun.push_insn(block, Insn::CCallVariadic {
cfunc,
recv,
args,
cme,
- name: method_id,
+ name,
state,
return_type,
elidable,
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index fadb6ced5f..19f0e91b47 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -560,7 +560,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(CustomEq@0x1000, !=@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(CustomEq@0x1000)
v28:HeapObject[class_exact:CustomEq] = GuardType v9, HeapObject[class_exact:CustomEq]
- v29:BoolExact = CCallWithFrame !=@0x1038, v28, v9
+ v29:BoolExact = CCallWithFrame BasicObject#!=@0x1038, v28, v9
v20:NilClass = Const Value(nil)
CheckInterrupts
Return v20
@@ -784,7 +784,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, fun_new_map@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v24:ArraySubclass[class_exact:C] = GuardType v13, ArraySubclass[class_exact:C]
- v25:BasicObject = CCallWithFrame fun_new_map@0x1038, v24, block=0x1040
+ v25:BasicObject = CCallWithFrame C#fun_new_map@0x1038, v24, block=0x1040
v16:BasicObject = GetLocal l0, EP@3
CheckInterrupts
Return v25
@@ -1043,7 +1043,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Object@0x1008, puts@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Object@0x1008)
v22:HeapObject[class_exact*:Object@VALUE(0x1008)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1008)]
- v23:BasicObject = CCallVariadic puts@0x1040, v22, v12
+ v23:BasicObject = CCallVariadic Kernel#puts@0x1040, v22, v12
CheckInterrupts
Return v23
");
@@ -2241,7 +2241,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Module@0x1010, name@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(Module@0x1010)
IncrCounter inline_cfunc_optimized_send_count
- v34:StringExact|NilClass = CCall name@0x1048, v29
+ v34:StringExact|NilClass = CCall Module#name@0x1048, v29
PatchPoint NoEPEscape(test)
v22:Fixnum[1] = Const Value(1)
CheckInterrupts
@@ -2273,7 +2273,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v29:Fixnum = CCall length@0x1038, v13
+ v29:Fixnum = CCall Array#length@0x1038, v13
v20:Fixnum[5] = Const Value(5)
CheckInterrupts
Return v20
@@ -2417,7 +2417,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v29:Fixnum = CCall size@0x1038, v13
+ v29:Fixnum = CCall Array#size@0x1038, v13
v20:Fixnum[5] = Const Value(5)
CheckInterrupts
Return v20
@@ -3150,7 +3150,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1008, new@0x1010, cme:0x1018)
PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Class@0x1040)
- v57:BasicObject = CCallVariadic new@0x1048, v46, v16
+ v57:BasicObject = CCallVariadic Array.new@0x1048, v46, v16
CheckInterrupts
Return v57
");
@@ -3181,7 +3181,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Set@0x1008, initialize@0x1040, cme:0x1048)
PatchPoint NoSingletonClass(Set@0x1008)
v49:SetExact = GuardType v18, SetExact
- v50:BasicObject = CCallVariadic initialize@0x1070, v49
+ v50:BasicObject = CCallVariadic Set#initialize@0x1070, v49
CheckInterrupts
CheckInterrupts
Return v18
@@ -3211,7 +3211,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1008, new@0x1010, cme:0x1018)
PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Class@0x1040)
- v54:BasicObject = CCallVariadic new@0x1048, v43
+ v54:BasicObject = CCallVariadic String.new@0x1048, v43
CheckInterrupts
Return v54
");
@@ -3243,7 +3243,7 @@ mod hir_opt_tests {
v50:RegexpExact = ObjectAllocClass Regexp:VALUE(0x1008)
PatchPoint MethodRedefined(Regexp@0x1008, initialize@0x1048, cme:0x1050)
PatchPoint NoSingletonClass(Regexp@0x1008)
- v54:BasicObject = CCallVariadic initialize@0x1078, v50, v17
+ v54:BasicObject = CCallVariadic Regexp#initialize@0x1078, v50, v17
CheckInterrupts
CheckInterrupts
Return v50
@@ -3271,7 +3271,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v30:Fixnum = CCall length@0x1038, v18
+ v30:Fixnum = CCall Array#length@0x1038, v18
CheckInterrupts
Return v30
");
@@ -3298,7 +3298,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v30:Fixnum = CCall size@0x1038, v18
+ v30:Fixnum = CCall Array#size@0x1038, v18
CheckInterrupts
Return v30
");
@@ -3458,7 +3458,7 @@ mod hir_opt_tests {
v10:HashExact = NewHash
PatchPoint MethodRedefined(Hash@0x1000, dup@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Hash@0x1000)
- v22:BasicObject = CCallWithFrame dup@0x1038, v10
+ v22:BasicObject = CCallWithFrame Kernel#dup@0x1038, v10
v14:BasicObject = SendWithoutBlock v22, :freeze
CheckInterrupts
Return v14
@@ -3551,7 +3551,7 @@ mod hir_opt_tests {
v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, dup@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
- v22:BasicObject = CCallWithFrame dup@0x1038, v10
+ v22:BasicObject = CCallWithFrame Kernel#dup@0x1038, v10
v14:BasicObject = SendWithoutBlock v22, :freeze
CheckInterrupts
Return v14
@@ -3645,7 +3645,7 @@ mod hir_opt_tests {
v11:StringExact = StringCopy v10
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
- v23:BasicObject = CCallWithFrame dup@0x1040, v11
+ v23:BasicObject = CCallWithFrame String#dup@0x1040, v11
v15:BasicObject = SendWithoutBlock v23, :freeze
CheckInterrupts
Return v15
@@ -3740,7 +3740,7 @@ mod hir_opt_tests {
v11:StringExact = StringCopy v10
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
- v23:BasicObject = CCallWithFrame dup@0x1040, v11
+ v23:BasicObject = CCallWithFrame String#dup@0x1040, v11
v15:BasicObject = SendWithoutBlock v23, :-@
CheckInterrupts
Return v15
@@ -3882,7 +3882,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1008, to_s@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
v31:ArrayExact = GuardType v9, ArrayExact
- v32:BasicObject = CCallWithFrame to_s@0x1040, v31
+ v32:BasicObject = CCallWithFrame Array#to_s@0x1040, v31
v19:String = AnyToString v9, str: v32
v21:StringExact = StringConcat v13, v19
CheckInterrupts
@@ -4745,7 +4745,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
- v25:BoolExact = CCall empty?@0x1038, v23
+ v25:BoolExact = CCall Array#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@@ -4773,7 +4773,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Hash@0x1000)
v23:HashExact = GuardType v9, HashExact
IncrCounter inline_cfunc_optimized_send_count
- v25:BoolExact = CCall empty?@0x1038, v23
+ v25:BoolExact = CCall Hash#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@@ -5036,7 +5036,7 @@ mod hir_opt_tests {
v11:ArrayExact = ArrayDup v10
PatchPoint MethodRedefined(Array@0x1008, map@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
- v21:BasicObject = CCallWithFrame map@0x1040, v11, block=0x1048
+ v21:BasicObject = CCallWithFrame Array#map@0x1040, v11, block=0x1048
CheckInterrupts
Return v21
");
@@ -5484,7 +5484,7 @@ mod hir_opt_tests {
v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, reverse@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
- v20:ArrayExact = CCallWithFrame reverse@0x1038, v10
+ v20:ArrayExact = CCallWithFrame Array#reverse@0x1038, v10
CheckInterrupts
Return v20
");
@@ -5537,7 +5537,7 @@ mod hir_opt_tests {
v13:StringExact = StringCopy v12
PatchPoint MethodRedefined(Array@0x1008, join@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
- v23:StringExact = CCallVariadic join@0x1040, v10, v13
+ v23:StringExact = CCallVariadic Array#join@0x1040, v10, v13
CheckInterrupts
Return v23
");
@@ -5859,7 +5859,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Class@0x1010, current@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(Class@0x1010)
IncrCounter inline_cfunc_optimized_send_count
- v25:BasicObject = CCall current@0x1048, v20
+ v25:BasicObject = CCall Thread.current@0x1048, v20
CheckInterrupts
Return v25
");
@@ -5889,7 +5889,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, []=@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v31:ArrayExact = GuardType v9, ArrayExact
- v32:BasicObject = CCallVariadic []=@0x1038, v31, v16, v18
+ v32:BasicObject = CCallVariadic Array#[]=@0x1038, v31, v16, v18
CheckInterrupts
Return v18
");
@@ -5980,7 +5980,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, push@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v28:ArrayExact = GuardType v9, ArrayExact
- v29:BasicObject = CCallVariadic push@0x1038, v28, v14, v16, v18
+ v29:BasicObject = CCallVariadic Array#push@0x1038, v28, v14, v16, v18
CheckInterrupts
Return v29
");
@@ -6008,7 +6008,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall length@0x1038, v23
+ v25:Fixnum = CCall Array#length@0x1038, v23
CheckInterrupts
Return v25
");
@@ -6036,7 +6036,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall size@0x1038, v23
+ v25:Fixnum = CCall Array#size@0x1038, v23
CheckInterrupts
Return v25
");
@@ -6064,7 +6064,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1008, =~@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
v25:StringExact = GuardType v9, StringExact
- v26:BasicObject = CCallWithFrame =~@0x1040, v25, v14
+ v26:BasicObject = CCallWithFrame String#=~@0x1040, v25, v14
CheckInterrupts
Return v26
");
@@ -6235,7 +6235,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1000, setbyte@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v30:StringExact = GuardType v13, StringExact
- v31:BasicObject = CCallWithFrame setbyte@0x1038, v30, v14, v15
+ v31:BasicObject = CCallWithFrame String#setbyte@0x1038, v30, v14, v15
CheckInterrupts
Return v31
");
@@ -6264,7 +6264,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
- v25:BoolExact = CCall empty?@0x1038, v23
+ v25:BoolExact = CCall String#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@@ -6348,7 +6348,7 @@ mod hir_opt_tests {
bb2(v8:BasicObject, v9:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, succ@0x1008, cme:0x1010)
v22:Integer = GuardType v9, Integer
- v23:BasicObject = CCallWithFrame succ@0x1038, v22
+ v23:BasicObject = CCallWithFrame Integer#succ@0x1038, v22
CheckInterrupts
Return v23
");
@@ -6405,7 +6405,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1000, <<@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v27:StringExact = GuardType v11, StringExact
- v28:BasicObject = CCallWithFrame <<@0x1038, v27, v12
+ v28:BasicObject = CCallWithFrame String#<<@0x1038, v27, v12
CheckInterrupts
Return v28
");
@@ -6465,7 +6465,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(MyString@0x1000, <<@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(MyString@0x1000)
v27:StringSubclass[class_exact:MyString] = GuardType v11, StringSubclass[class_exact:MyString]
- v28:BasicObject = CCallWithFrame <<@0x1038, v27, v12
+ v28:BasicObject = CCallWithFrame String#<<@0x1038, v27, v12
CheckInterrupts
Return v28
");
@@ -6622,7 +6622,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, ^@0x1008, cme:0x1010)
v25:Integer = GuardType v11, Integer
- v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
+ v26:BasicObject = CCallWithFrame Integer#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@@ -6645,7 +6645,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, ^@0x1008, cme:0x1010)
v25:Fixnum = GuardType v11, Fixnum
- v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
+ v26:BasicObject = CCallWithFrame Integer#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@@ -6668,7 +6668,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(TrueClass@0x1000, ^@0x1008, cme:0x1010)
v25:TrueClass = GuardType v11, TrueClass
- v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
+ v26:BasicObject = CCallWithFrame TrueClass#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@@ -6718,7 +6718,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Hash@0x1000)
v23:HashExact = GuardType v9, HashExact
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall size@0x1038, v23
+ v25:Fixnum = CCall Hash#size@0x1038, v23
CheckInterrupts
Return v25
");
@@ -7086,7 +7086,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1008, respond_to?@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(C@0x1008)
v24:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
- v25:BasicObject = CCallVariadic respond_to?@0x1040, v24, v14
+ v25:BasicObject = CCallVariadic Kernel#respond_to?@0x1040, v24, v14
CheckInterrupts
Return v25
");
@@ -7637,7 +7637,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall size@0x1038, v23
+ v25:Fixnum = CCall String#size@0x1038, v23
CheckInterrupts
Return v25
");
@@ -7756,7 +7756,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall length@0x1038, v23
+ v25:Fixnum = CCall String#length@0x1038, v23
CheckInterrupts
Return v25
");
@@ -7922,7 +7922,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Class@0x1038)
v30:ModuleSubclass[class_exact*:Class@VALUE(0x1038)] = GuardType v26, ModuleSubclass[class_exact*:Class@VALUE(0x1038)]
IncrCounter inline_cfunc_optimized_send_count
- v32:StringExact|NilClass = CCall name@0x1070, v30
+ v32:StringExact|NilClass = CCall Module#name@0x1070, v30
CheckInterrupts
Return v32
");
diff --git a/zjit/src/state.rs b/zjit/src/state.rs
index 06296eb8f2..fd59161812 100644
--- a/zjit/src/state.rs
+++ b/zjit/src/state.rs
@@ -59,6 +59,9 @@ pub struct ZJITState {
/// Counter pointers for un-annotated C functions
not_annotated_frame_cfunc_counter_pointers: HashMap<String, Box<u64>>,
+ /// Counter pointers for all calls to any kind of C function from JIT code
+ ccall_counter_pointers: HashMap<String, Box<u64>>,
+
/// Locations of side exists within generated code
exit_locations: Option<SideExitLocations>,
}
@@ -135,6 +138,7 @@ impl ZJITState {
exit_trampoline_with_counter: exit_trampoline,
full_frame_cfunc_counter_pointers: HashMap::new(),
not_annotated_frame_cfunc_counter_pointers: HashMap::new(),
+ ccall_counter_pointers: HashMap::new(),
exit_locations,
};
unsafe { ZJIT_STATE = Enabled(zjit_state); }
@@ -215,6 +219,11 @@ impl ZJITState {
&mut ZJITState::get_instance().not_annotated_frame_cfunc_counter_pointers
}
+ /// Get a mutable reference to ccall counter pointers
+ pub fn get_ccall_counter_pointers() -> &'static mut HashMap<String, Box<u64>> {
+ &mut ZJITState::get_instance().ccall_counter_pointers
+ }
+
/// Was --zjit-save-compiled-iseqs specified?
pub fn should_log_compiled_iseqs() -> bool {
get_option!(log_compiled_iseqs).is_some()
diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs
index b0ca28d258..df172997ce 100644
--- a/zjit/src/stats.rs
+++ b/zjit/src/stats.rs
@@ -689,6 +689,13 @@ pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE, target_key: VALUE) ->
set_stat_usize!(hash, &key_string, **counter);
}
+ // Set ccall counters
+ let ccall = ZJITState::get_ccall_counter_pointers();
+ for (signature, counter) in ccall.iter() {
+ let key_string = format!("ccall_{}", signature);
+ set_stat_usize!(hash, &key_string, **counter);
+ }
+
hash
}