Skip to content

Commit 76d9b59

Browse files
committed
change: split ArgcParamMismatch checks for positional and keyword args
1 parent d5fc9b5 commit 76d9b59

File tree

1 file changed

+17
-20
lines changed

1 file changed

+17
-20
lines changed

zjit/src/hir.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,31 +1898,37 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
18981898
return false;
18991899
}
19001900

1901-
// Because we exclude e.g. post parameters above, they are also excluded from the sum below.
1901+
// Because we exclude e.g. post parameters above, they are also excluded from the checks below.
19021902
let lead_num = params.lead_num;
19031903
let opt_num = params.opt_num;
19041904
let keyword = params.keyword;
19051905
let kw_req_num = if keyword.is_null() { 0 } else { unsafe { (*keyword).required_num } };
19061906
let kw_total_num = if keyword.is_null() { 0 } else { unsafe { (*keyword).num } };
1907-
// Minimum args: all required positional + all required keywords
1908-
let min_argc = lead_num + kw_req_num;
1909-
// Maximum args: all positional (required + optional) + all keywords (required + optional)
1910-
let max_argc = lead_num + opt_num + kw_total_num;
1907+
let kwarg = unsafe { rb_vm_ci_kwarg(ci) };
1908+
let caller_kw_count = if kwarg.is_null() { 0 } else { (unsafe { get_cikw_keyword_len(kwarg) }) as usize };
1909+
let caller_positional = match args.len().checked_sub(caller_kw_count) {
1910+
Some(count) => count,
1911+
None => {
1912+
function.set_dynamic_send_reason(send_insn, ArgcParamMismatch);
1913+
return false;
1914+
}
1915+
};
19111916

1912-
can_send = c_int::try_from(args.len())
1917+
let positional_ok = c_int::try_from(caller_positional)
19131918
.as_ref()
1914-
.map(|argc| (min_argc..=max_argc).contains(argc))
1919+
.map(|argc| (lead_num..=lead_num + opt_num).contains(argc))
19151920
.unwrap_or(false);
1916-
if !can_send {
1921+
let keyword_ok = c_int::try_from(caller_kw_count)
1922+
.as_ref()
1923+
.map(|argc| (kw_req_num..=kw_total_num).contains(argc))
1924+
.unwrap_or(false);
1925+
if !positional_ok || !keyword_ok {
19171926
function.set_dynamic_send_reason(send_insn, ArgcParamMismatch);
19181927
return false
19191928
}
19201929

19211930
// asm.ccall() doesn't support 6+ args. Compute the final argc after keyword setup:
19221931
// final_argc = caller's positional args + callee's total keywords (all kw slots are filled).
1923-
let kwarg = unsafe { rb_vm_ci_kwarg(ci) };
1924-
let caller_kw_count = if kwarg.is_null() { 0 } else { (unsafe { get_cikw_keyword_len(kwarg) }) as usize };
1925-
let caller_positional = args.len() - caller_kw_count;
19261932
// Right now, the JIT entrypoint accepts the block as an param
19271933
// We may remove it, remove the block_arg addition to match
19281934
// See: https://github.com/ruby/ruby/pull/15911#discussion_r2710544982
@@ -1933,15 +1939,6 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
19331939
return false;
19341940
}
19351941

1936-
// Caller passing a hash as a positional arg but callee expects keyword-only args will
1937-
// raise ArgumentError at runtime. Fall back to VM dispatch to handle this correctly.
1938-
if kwarg.is_null() && !keyword.is_null() {
1939-
if lead_num == 0 && opt_num == 0 && caller_positional > 0 {
1940-
function.set_dynamic_send_reason(send_insn, ArgcParamMismatch);
1941-
return false;
1942-
}
1943-
}
1944-
19451942
can_send
19461943
}
19471944

0 commit comments

Comments
 (0)