Skip to content

Commit 9f24ba5

Browse files
nirvdrumXrXr
authored andcommitted
ZJIT: Specialize direct sends to methods with post-required positional parameters
1 parent 62e59f2 commit 9f24ba5

3 files changed

Lines changed: 44 additions & 17 deletions

File tree

zjit/src/codegen.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,12 +1671,14 @@ fn gen_send_iseq_direct(
16711671
// See vm_call_iseq_setup_normal_opt_start in vm_inshelper.c
16721672
let lead_num = params.lead_num as u32;
16731673
let opt_num = params.opt_num as u32;
1674+
let post_num = params.post_num as u32;
16741675
let keyword = params.keyword;
16751676
let kw_total_num = if keyword.is_null() { 0 } else { unsafe { (*keyword).num } } as u32;
1676-
assert!(args.len() as u32 <= lead_num + opt_num + kw_total_num);
1677+
assert!(args.len() as u32 <= lead_num + opt_num + post_num + kw_total_num);
16771678
// For computing optional positional entry point, only count positional args
1679+
// and exclude the always-present lead and post slots.
16781680
let positional_argc = args.len() as u32 - kw_total_num;
1679-
let num_optionals_passed = positional_argc.saturating_sub(lead_num);
1681+
let num_optionals_passed = positional_argc.saturating_sub(lead_num + post_num);
16801682
num_optionals_passed
16811683
} else {
16821684
0

zjit/src/hir.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,7 +2402,6 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
24022402

24032403
use Counter::*;
24042404
if 0 != params.flags.has_rest() { count_failure(complex_arg_pass_param_rest) }
2405-
if 0 != params.flags.has_post() { count_failure(complex_arg_pass_param_post) }
24062405
if 0 != params.flags.forwardable() { count_failure(complex_arg_pass_param_forwardable) }
24072406
if callee_has_block_param && caller_passes_block_arg
24082407
{ count_failure(complex_arg_pass_param_block) }
@@ -2423,9 +2422,9 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
24232422
return false;
24242423
}
24252424

2426-
// Because we exclude e.g. post parameters above, they are also excluded from the checks below.
24272425
let lead_num = params.lead_num;
24282426
let opt_num = params.opt_num;
2427+
let post_num = params.post_num;
24292428
let keyword = params.keyword;
24302429
let kw_req_num = if keyword.is_null() { 0 } else { unsafe { (*keyword).required_num } };
24312430
let kw_total_num = if keyword.is_null() { 0 } else { unsafe { (*keyword).num } };
@@ -2441,7 +2440,7 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
24412440

24422441
let positional_ok = c_int::try_from(caller_positional)
24432442
.as_ref()
2444-
.map(|argc| (lead_num..=lead_num + opt_num).contains(argc))
2443+
.map(|argc| (lead_num + post_num..=lead_num + opt_num + post_num).contains(argc))
24452444
.unwrap_or(false);
24462445
let keyword_ok = c_int::try_from(caller_kw_count)
24472446
.as_ref()

zjit/src/hir/opt_tests.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3762,12 +3762,12 @@ mod hir_opt_tests {
37623762
}
37633763

37643764
#[test]
3765-
fn dont_specialize_call_to_post_param_iseq() {
3766-
enable_zjit_stats();
3765+
fn specialize_call_to_post_param_iseq() {
37673766
eval("
37683767
def foo(opt=80, post) = post
37693768
def test = foo(10)
37703769
test
3770+
test
37713771
");
37723772
assert_snapshot!(hir_string("test"), @"
37733773
fn test@<compiled>:3:
@@ -3778,18 +3778,44 @@ mod hir_opt_tests {
37783778
bb2():
37793779
EntryPoint JIT(0)
37803780
v4:BasicObject = LoadArg :self@0
3781-
IncrCounterPtr
37823781
Jump bb3(v4)
3783-
bb3(v7:BasicObject):
3784-
IncrCounter zjit_insn_count
3785-
IncrCounter zjit_insn_count
3786-
v14:Fixnum[10] = Const Value(10)
3787-
IncrCounter zjit_insn_count
3788-
IncrCounter complex_arg_pass_param_post
3789-
v17:BasicObject = Send v7, :foo, v14 # SendFallbackReason: Complex argument passing
3790-
IncrCounter zjit_insn_count
3782+
bb3(v6:BasicObject):
3783+
v11:Fixnum[10] = Const Value(10)
3784+
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
3785+
v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
3786+
v21:BasicObject = SendDirect v20, 0x1038, :foo (0x1048), v11
37913787
CheckInterrupts
3792-
Return v17
3788+
Return v21
3789+
");
3790+
}
3791+
3792+
#[test]
3793+
fn specialize_call_to_iseq_with_optional_between_required_params() {
3794+
let result = eval("
3795+
def foo(lead, opt=80, post) = lead + opt + post
3796+
def test = foo(10, 20)
3797+
test
3798+
test
3799+
");
3800+
assert_eq!(VALUE::fixnum_from_usize(110), result);
3801+
assert_snapshot!(hir_string("test"), @"
3802+
fn test@<compiled>:3:
3803+
bb1():
3804+
EntryPoint interpreter
3805+
v1:BasicObject = LoadSelf
3806+
Jump bb3(v1)
3807+
bb2():
3808+
EntryPoint JIT(0)
3809+
v4:BasicObject = LoadArg :self@0
3810+
Jump bb3(v4)
3811+
bb3(v6:BasicObject):
3812+
v11:Fixnum[10] = Const Value(10)
3813+
v13:Fixnum[20] = Const Value(20)
3814+
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
3815+
v22:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
3816+
v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
3817+
CheckInterrupts
3818+
Return v23
37933819
");
37943820
}
37953821

0 commit comments

Comments
 (0)