Skip to content

Commit 1fb0c5b

Browse files
committed
ZJIT: Fn stub: Move args to create appropriate unfilled optional param gap
1 parent 04774d3 commit 1fb0c5b

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

zjit/src/codegen.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@ fn gen_send_iseq_direct(
16301630
}
16311631

16321632
// Make a method call. The target address will be rewritten once compiled.
1633-
let iseq_call = IseqCall::new(iseq, num_optionals_passed);
1633+
let iseq_call = IseqCall::new(iseq, num_optionals_passed, args.len().try_into().expect("TODO: no panic here from downcast from usize"));
16341634
let dummy_ptr = cb.get_write_ptr().raw_ptr(cb);
16351635
jit.iseq_calls.push(iseq_call.clone());
16361636
let ret = asm.ccall_with_iseq_call(dummy_ptr, c_args, &iseq_call);
@@ -2872,22 +2872,40 @@ c_callable! {
28722872
// function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC.
28732873
let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const IseqCall) };
28742874
let iseq = iseq_call.iseq.get();
2875+
let argc = iseq_call.argc;
2876+
let num_opts_filled = iseq_call.jit_entry_idx;
28752877
let entry_insn_idxs = crate::hir::jit_entry_insns(iseq);
28762878
let pc = unsafe { rb_iseq_pc_at_idx(iseq, entry_insn_idxs[iseq_call.jit_entry_idx.to_usize()]) };
28772879
unsafe { rb_set_cfp_pc(cfp, pc) };
28782880

28792881
// Successful JIT-to-JIT calls fill nils to non-parameter locals in generated code.
28802882
// If we side-exit from function_stub_hit (before JIT code runs), we need to set them here.
2881-
fn prepare_for_exit(iseq: IseqPtr, cfp: CfpPtr, sp: *mut VALUE, compile_error: &CompileError) {
2883+
fn prepare_for_exit(iseq: IseqPtr, cfp: CfpPtr, sp: *mut VALUE, argc: u32, num_opts_filled: u32, compile_error: &CompileError) {
28822884
unsafe {
28832885
// Set SP which gen_push_frame() doesn't set
28842886
rb_set_cfp_sp(cfp, sp);
28852887

2886-
// Fill nils to uninitialized (non-argument) locals
2888+
// Fill nils to uninitialized (non-parameter) locals
28872889
let local_size = get_iseq_body_local_table_size(iseq).to_usize();
2888-
let num_params = iseq.params().size.to_usize();
2890+
let params = iseq.params();
2891+
let num_params = params.size.to_usize();
28892892
let base = sp.offset(-local_size_and_idx_to_bp_offset(local_size, num_params) as isize);
2893+
// TODO one slice for everything
28902894
slice::from_raw_parts_mut(base, local_size - num_params).fill(Qnil);
2895+
2896+
let opt_num: usize = params.opt_num.try_into().expect("ISEQ opt_num should be non-negative");
2897+
let num_opts_unfilled = opt_num - num_opts_filled.to_usize();
2898+
if num_opts_unfilled > 0 {
2899+
let lead_num: usize = params.lead_num.try_into().expect("should be non-negative");
2900+
let after_opts = lead_num + opt_num;
2901+
2902+
// TODO rename
2903+
let base = sp.offset(-local_size_and_idx_to_bp_offset(local_size, 0) as isize);
2904+
let params = slice::from_raw_parts_mut(base, num_params);
2905+
params.copy_within(num_opts_filled.to_usize()..argc.to_usize(), after_opts);
2906+
2907+
(&mut params[num_opts_filled.to_usize()..after_opts]).fill(Qnil);
2908+
}
28912909
}
28922910

28932911
// Increment a compile error counter for --zjit-stats
@@ -2911,7 +2929,7 @@ c_callable! {
29112929
// We'll use this Rc again, so increment the ref count decremented by from_raw.
29122930
unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); }
29132931

2914-
prepare_for_exit(iseq, cfp, sp, compile_error);
2932+
prepare_for_exit(iseq, cfp, sp, argc, num_opts_filled, compile_error);
29152933
return ZJITState::get_exit_trampoline_with_counter().raw_ptr(cb);
29162934
}
29172935

@@ -2926,7 +2944,7 @@ c_callable! {
29262944
// We'll use this Rc again, so increment the ref count decremented by from_raw.
29272945
unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); }
29282946

2929-
prepare_for_exit(iseq, cfp, sp, &compile_error);
2947+
prepare_for_exit(iseq, cfp, sp, argc, num_opts_filled, &compile_error);
29302948
ZJITState::get_exit_trampoline_with_counter()
29312949
});
29322950
cb.mark_all_executable();
@@ -3253,6 +3271,9 @@ pub struct IseqCall {
32533271
/// Index that corresponds to [crate::hir::jit_entry_insns]
32543272
jit_entry_idx: u32,
32553273

3274+
/// Argument count passing to the HIR function
3275+
argc: u32,
3276+
32563277
/// Position where the call instruction starts
32573278
start_addr: Cell<Option<CodePtr>>,
32583279

@@ -3264,12 +3285,13 @@ pub type IseqCallRef = Rc<IseqCall>;
32643285

32653286
impl IseqCall {
32663287
/// Allocate a new IseqCall
3267-
fn new(iseq: IseqPtr, jit_entry_idx: u32) -> IseqCallRef {
3288+
fn new(iseq: IseqPtr, jit_entry_idx: u32, argc: u32) -> IseqCallRef {
32683289
let iseq_call = IseqCall {
32693290
iseq: Cell::new(iseq),
32703291
start_addr: Cell::new(None),
32713292
end_addr: Cell::new(None),
32723293
jit_entry_idx,
3294+
argc,
32733295
};
32743296
Rc::new(iseq_call)
32753297
}

zjit/src/hir/opt_tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14765,4 +14765,24 @@ mod hir_opt_tests {
1476514765
Return v13
1476614766
");
1476714767
}
14768+
14769+
#[test]
14770+
fn test_exit_from_function_stub_for_opt_keyword_callee() {
14771+
set_call_threshold(2);
14772+
let result = eval("
14773+
def target(a = nil, b: nil)
14774+
::RubyVM::ZJIT.induce_compile_failure!
14775+
b
14776+
end
14777+
14778+
def entry = target(b: -1)
14779+
14780+
entry
14781+
entry
14782+
");
14783+
// TODO assert failure for target
14784+
// TODO it's not entering into jit code. is rb_zjit_enabled_p=false in harness?
14785+
//assert_snapshot!(hir_string("entry"), @"");
14786+
assert_eq!(VALUE::fixnum_from_isize(-1), result);
14787+
}
1476814788
}

0 commit comments

Comments
 (0)