Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def stats_string
print_counters_with_prefix(prefix: 'dynamic_send_type_', prompt: 'dynamic send 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)
print_counters_with_prefix(prefix: 'not_optimized_cfuncs_', prompt: 'unoptimized sends to C functions', 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)
Expand Down
186 changes: 61 additions & 125 deletions zjit/src/codegen.rs

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion zjit/src/cruby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,10 @@ pub fn iseq_opcode_at_idx(iseq: IseqPtr, insn_idx: u32) -> u32 {
unsafe { rb_iseq_opcode_at_pc(iseq, pc) as u32 }
}

/// Return true if the ISEQ always uses a frame with escaped EP.
/// Return true if a given ISEQ is known to escape EP to the heap on entry.
///
/// As of vm_push_frame(), EP is always equal to BP. However, after pushing
/// a frame, some ISEQ setups call vm_bind_update_env(), which redirects EP.
pub fn iseq_escapes_ep(iseq: IseqPtr) -> bool {
match unsafe { get_iseq_body_type(iseq) } {
// The EP of the <main> frame points to TOPLEVEL_BINDING
Expand All @@ -305,6 +308,17 @@ pub fn iseq_escapes_ep(iseq: IseqPtr) -> bool {
}
}

/// Index of the local variable that has a rest parameter if any
pub fn iseq_rest_param_idx(iseq: IseqPtr) -> Option<i32> {
if !iseq.is_null() && unsafe { get_iseq_flags_has_rest(iseq) } {
let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) };
let lead_num = unsafe { get_iseq_body_param_lead_num(iseq) };
Some(opt_num + lead_num)
} else {
None
}
}

/// Iterate over all existing ISEQs
pub fn for_each_iseq<F: FnMut(IseqPtr)>(mut callback: F) {
unsafe extern "C" fn callback_wrapper(iseq: IseqPtr, data: *mut c_void) {
Expand Down
10 changes: 4 additions & 6 deletions zjit/src/gc.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! This module is responsible for marking/moving objects on GC.

use std::cell::RefCell;
use std::rc::Rc;
use std::{ffi::c_void, ops::Range};
use crate::codegen::IseqCall;
use crate::codegen::IseqCallRef;
use crate::stats::CompileError;
use crate::{cruby::*, profile::IseqProfile, state::ZJITState, stats::with_time_stat, virtualmem::CodePtr};
use crate::stats::Counter::gc_time_ns;
Expand All @@ -21,7 +19,7 @@ pub struct IseqPayload {
pub gc_offsets: Vec<CodePtr>,

/// JIT-to-JIT calls in the ISEQ. The IseqPayload's ISEQ is the caller of it.
pub iseq_calls: Vec<Rc<RefCell<IseqCall>>>,
pub iseq_calls: Vec<IseqCallRef>,
}

impl IseqPayload {
Expand Down Expand Up @@ -191,10 +189,10 @@ fn iseq_update_references(payload: &mut IseqPayload) {

// Move ISEQ references in IseqCall
for iseq_call in payload.iseq_calls.iter_mut() {
let old_iseq = iseq_call.borrow().iseq;
let old_iseq = iseq_call.iseq.get();
let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr;
if old_iseq != new_iseq {
iseq_call.borrow_mut().iseq = new_iseq;
iseq_call.iseq.set(new_iseq);
}
}

Expand Down
1,152 changes: 824 additions & 328 deletions zjit/src/hir.rs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions zjit/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::asm::CodeBlock;
use crate::options::get_option;
use crate::stats::{Counters, ExitCounters};
use crate::virtualmem::CodePtr;
use std::collections::HashMap;

#[allow(non_upper_case_globals)]
#[unsafe(no_mangle)]
Expand Down Expand Up @@ -46,6 +47,9 @@ pub struct ZJITState {

/// Trampoline to call function_stub_hit
function_stub_hit_trampoline: CodePtr,

/// Counter pointers for unoptimized C functions
unoptimized_cfunc_counter_pointers: HashMap<String, Box<u64>>,
}

/// Private singleton instance of the codegen globals
Expand Down Expand Up @@ -80,6 +84,7 @@ impl ZJITState {
exit_trampoline,
function_stub_hit_trampoline,
exit_trampoline_with_counter: exit_trampoline,
unoptimized_cfunc_counter_pointers: HashMap::new(),
};
unsafe { ZJIT_STATE = Some(zjit_state); }

Expand Down Expand Up @@ -138,6 +143,11 @@ impl ZJITState {
&mut ZJITState::get_instance().exit_counters
}

/// Get a mutable reference to unoptimized cfunc counter pointers
pub fn get_unoptimized_cfunc_counter_pointers() -> &'static mut HashMap<String, Box<u64>> {
&mut ZJITState::get_instance().unoptimized_cfunc_counter_pointers
}

/// Was --zjit-save-compiled-iseqs specified?
pub fn should_log_compiled_iseqs() -> bool {
get_option!(log_compiled_iseqs).is_some()
Expand Down
7 changes: 7 additions & 0 deletions zjit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,13 @@ pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE, target_key: VALUE) ->
set_stat_f64!(hash, "ratio_in_zjit", 100.0 * zjit_insn_count as f64 / total_insn_count as f64);
}

// Set unoptimized cfunc counters
let unoptimized_cfuncs = ZJITState::get_unoptimized_cfunc_counter_pointers();
for (signature, counter) in unoptimized_cfuncs.iter() {
let key_string = format!("not_optimized_cfuncs_{}", signature);
set_stat_usize!(hash, &key_string, **counter);
}

hash
}

Expand Down