Skip to content

Commit 528100a

Browse files
committed
ZJIT: Fn stub: Move args to create appropriate unfilled optional param gap
1 parent a897e06 commit 528100a

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

zjit/src/codegen.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,7 @@ fn gen_send_iseq_direct(
16231623
}
16241624

16251625
// Make a method call. The target address will be rewritten once compiled.
1626-
let iseq_call = IseqCall::new(iseq, num_optionals_passed);
1626+
let iseq_call = IseqCall::new(iseq, num_optionals_passed, args.len().try_into().expect("TODO: no panic here from downcast from usize"));
16271627
let dummy_ptr = cb.get_write_ptr().raw_ptr(cb);
16281628
jit.iseq_calls.push(iseq_call.clone());
16291629
let ret = asm.ccall_with_iseq_call(dummy_ptr, c_args, &iseq_call);
@@ -2865,22 +2865,37 @@ c_callable! {
28652865
// function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC.
28662866
let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const IseqCall) };
28672867
let iseq = iseq_call.iseq.get();
2868+
let argc = iseq_call.argc;
2869+
let num_opts_filled = iseq_call.jit_entry_idx;
28682870
let entry_insn_idxs = crate::hir::jit_entry_insns(iseq);
28692871
let pc = unsafe { rb_iseq_pc_at_idx(iseq, entry_insn_idxs[iseq_call.jit_entry_idx.to_usize()]) };
28702872
unsafe { rb_set_cfp_pc(cfp, pc) };
28712873

28722874
// Successful JIT-to-JIT calls fill nils to non-parameter locals in generated code.
28732875
// If we side-exit from function_stub_hit (before JIT code runs), we need to set them here.
2874-
fn prepare_for_exit(iseq: IseqPtr, cfp: CfpPtr, sp: *mut VALUE, compile_error: &CompileError) {
2876+
fn prepare_for_exit(iseq: IseqPtr, cfp: CfpPtr, sp: *mut VALUE, argc: u32, num_opts_filled: u32, compile_error: &CompileError) {
28752877
unsafe {
28762878
// Set SP which gen_push_frame() doesn't set
28772879
rb_set_cfp_sp(cfp, sp);
28782880

2879-
// Fill nils to uninitialized (non-argument) locals
2881+
// Fill nils to uninitialized (non-parameter) locals
28802882
let local_size = get_iseq_body_local_table_size(iseq).to_usize();
2881-
let num_params = iseq.params().size.to_usize();
2883+
let params = iseq.params();
2884+
let num_params = params.size.to_usize();
28822885
let base = sp.offset(-local_size_and_idx_to_bp_offset(local_size, num_params) as isize);
2886+
// TODO one slice for everything
28832887
slice::from_raw_parts_mut(base, local_size - num_params).fill(Qnil);
2888+
2889+
let opt_num: usize = params.opt_num.try_into().expect("ISEQ opt_num should be non-negative");
2890+
let lead_num: usize = params.lead_num.try_into().expect("should be non-negative");
2891+
let after_opts = lead_num + opt_num;
2892+
2893+
// TODO rename
2894+
let base = sp.offset(-local_size_and_idx_to_bp_offset(local_size, 0) as isize);
2895+
let params = slice::from_raw_parts_mut(base, num_params);
2896+
params.copy_within(num_opts_filled.to_usize()..argc.to_usize(), after_opts);
2897+
2898+
(&mut params[num_opts_filled.to_usize()..after_opts]).fill(Qnil);
28842899
}
28852900

28862901
// Increment a compile error counter for --zjit-stats
@@ -2904,7 +2919,7 @@ c_callable! {
29042919
// We'll use this Rc again, so increment the ref count decremented by from_raw.
29052920
unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); }
29062921

2907-
prepare_for_exit(iseq, cfp, sp, compile_error);
2922+
prepare_for_exit(iseq, cfp, sp, argc, num_opts_filled, compile_error);
29082923
return ZJITState::get_exit_trampoline_with_counter().raw_ptr(cb);
29092924
}
29102925

@@ -2919,7 +2934,7 @@ c_callable! {
29192934
// We'll use this Rc again, so increment the ref count decremented by from_raw.
29202935
unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); }
29212936

2922-
prepare_for_exit(iseq, cfp, sp, &compile_error);
2937+
prepare_for_exit(iseq, cfp, sp, argc, num_opts_filled, &compile_error);
29232938
ZJITState::get_exit_trampoline_with_counter()
29242939
});
29252940
cb.mark_all_executable();
@@ -3246,6 +3261,9 @@ pub struct IseqCall {
32463261
/// Index that corresponds to [crate::hir::jit_entry_insns]
32473262
jit_entry_idx: u32,
32483263

3264+
/// Argument count passing to the HIR function
3265+
argc: u32,
3266+
32493267
/// Position where the call instruction starts
32503268
start_addr: Cell<Option<CodePtr>>,
32513269

@@ -3257,12 +3275,13 @@ pub type IseqCallRef = Rc<IseqCall>;
32573275

32583276
impl IseqCall {
32593277
/// Allocate a new IseqCall
3260-
fn new(iseq: IseqPtr, jit_entry_idx: u32) -> IseqCallRef {
3278+
fn new(iseq: IseqPtr, jit_entry_idx: u32, argc: u32) -> IseqCallRef {
32613279
let iseq_call = IseqCall {
32623280
iseq: Cell::new(iseq),
32633281
start_addr: Cell::new(None),
32643282
end_addr: Cell::new(None),
32653283
jit_entry_idx,
3284+
argc,
32663285
};
32673286
Rc::new(iseq_call)
32683287
}

zjit/src/hir/opt_tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14720,4 +14720,24 @@ mod hir_opt_tests {
1472014720
Return v13
1472114721
");
1472214722
}
14723+
14724+
#[test]
14725+
fn test_exit_from_function_stub_for_opt_keyword_callee() {
14726+
set_call_threshold(2);
14727+
let result = eval("
14728+
def target(a = nil, b: nil)
14729+
::RubyVM::ZJIT.induce_compile_failure!
14730+
b
14731+
end
14732+
14733+
def entry = target(b: -1)
14734+
14735+
entry
14736+
entry
14737+
");
14738+
// TODO assert failure for target
14739+
// TODO it's not entering into jit code. is rb_zjit_enabled_p=false in harness?
14740+
//assert_snapshot!(hir_string("entry"), @"");
14741+
assert_eq!(VALUE::fixnum_from_isize(-1), result);
14742+
}
1472314743
}

0 commit comments

Comments
 (0)