Skip to content

Commit 7688b05

Browse files
authored
ZJIT: Optimize VM_METHOD_TYPE_ALIAS (ruby#15018)
Just loop until you find a non-alias.
1 parent ab01fcc commit 7688b05

File tree

2 files changed

+103
-4
lines changed

2 files changed

+103
-4
lines changed

zjit/src/hir.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,7 +2276,11 @@ impl Function {
22762276
// Load an overloaded cme if applicable. See vm_search_cc().
22772277
// It allows you to use a faster ISEQ if possible.
22782278
cme = unsafe { rb_check_overloaded_cme(cme, ci) };
2279-
let def_type = unsafe { get_cme_def_type(cme) };
2279+
let mut def_type = unsafe { get_cme_def_type(cme) };
2280+
while def_type == VM_METHOD_TYPE_ALIAS {
2281+
cme = unsafe { rb_aliased_callable_method_entry(cme) };
2282+
def_type = unsafe { get_cme_def_type(cme) };
2283+
}
22802284
if def_type == VM_METHOD_TYPE_ISEQ {
22812285
// TODO(max): Allow non-iseq; cache cme
22822286
// Only specialize positional-positional calls
@@ -2453,7 +2457,11 @@ impl Function {
24532457
// Load an overloaded cme if applicable. See vm_search_cc().
24542458
// It allows you to use a faster ISEQ if possible.
24552459
cme = unsafe { rb_check_overloaded_cme(cme, ci) };
2456-
let def_type = unsafe { get_cme_def_type(cme) };
2460+
let mut def_type = unsafe { get_cme_def_type(cme) };
2461+
while def_type == VM_METHOD_TYPE_ALIAS {
2462+
cme = unsafe { rb_aliased_callable_method_entry(cme) };
2463+
def_type = unsafe { get_cme_def_type(cme) };
2464+
}
24572465
self.set_dynamic_send_reason(insn_id, SendNotOptimizedMethodType(MethodType::from(def_type)));
24582466
self.push_insn_id(block, insn_id); continue;
24592467
}
@@ -2810,13 +2818,17 @@ impl Function {
28102818
};
28112819

28122820
// Do method lookup
2813-
let method: *const rb_callable_method_entry_struct = unsafe { rb_callable_method_entry(recv_class, method_id) };
2821+
let mut method: *const rb_callable_method_entry_struct = unsafe { rb_callable_method_entry(recv_class, method_id) };
28142822
if method.is_null() {
28152823
return Err(());
28162824
}
28172825

28182826
// Filter for C methods
2819-
let def_type = unsafe { get_cme_def_type(method) };
2827+
let mut def_type = unsafe { get_cme_def_type(method) };
2828+
while def_type == VM_METHOD_TYPE_ALIAS {
2829+
method = unsafe { rb_aliased_callable_method_entry(method) };
2830+
def_type = unsafe { get_cme_def_type(method) };
2831+
}
28202832
if def_type != VM_METHOD_TYPE_CFUNC {
28212833
return Err(());
28222834
}

zjit/src/hir/opt_tests.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,93 @@ mod hir_opt_tests {
638638
");
639639
}
640640

641+
#[test]
642+
fn test_optimize_send_without_block_to_aliased_iseq() {
643+
eval("
644+
def foo = 1
645+
alias bar foo
646+
alias baz bar
647+
def test = baz
648+
test; test
649+
");
650+
assert_snapshot!(hir_string("test"), @r"
651+
fn test@<compiled>:5:
652+
bb0():
653+
EntryPoint interpreter
654+
v1:BasicObject = LoadSelf
655+
Jump bb2(v1)
656+
bb1(v4:BasicObject):
657+
EntryPoint JIT(0)
658+
Jump bb2(v4)
659+
bb2(v6:BasicObject):
660+
PatchPoint MethodRedefined(Object@0x1000, baz@0x1008, cme:0x1010)
661+
PatchPoint NoSingletonClass(Object@0x1000)
662+
v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
663+
IncrCounter inline_iseq_optimized_send_count
664+
v22:Fixnum[1] = Const Value(1)
665+
CheckInterrupts
666+
Return v22
667+
");
668+
}
669+
670+
#[test]
671+
fn test_optimize_send_without_block_to_aliased_cfunc() {
672+
eval("
673+
alias bar itself
674+
alias baz bar
675+
def test = baz
676+
test; test
677+
");
678+
assert_snapshot!(hir_string("test"), @r"
679+
fn test@<compiled>:4:
680+
bb0():
681+
EntryPoint interpreter
682+
v1:BasicObject = LoadSelf
683+
Jump bb2(v1)
684+
bb1(v4:BasicObject):
685+
EntryPoint JIT(0)
686+
Jump bb2(v4)
687+
bb2(v6:BasicObject):
688+
PatchPoint MethodRedefined(Object@0x1000, baz@0x1008, cme:0x1010)
689+
PatchPoint NoSingletonClass(Object@0x1000)
690+
v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
691+
IncrCounter inline_cfunc_optimized_send_count
692+
CheckInterrupts
693+
Return v20
694+
");
695+
}
696+
697+
#[test]
698+
fn test_optimize_send_to_aliased_cfunc() {
699+
eval("
700+
class C < Array
701+
alias fun_new_map map
702+
end
703+
def test(o) = o.fun_new_map {|e| e }
704+
test C.new; test C.new
705+
");
706+
assert_snapshot!(hir_string("test"), @r"
707+
fn test@<compiled>:5:
708+
bb0():
709+
EntryPoint interpreter
710+
v1:BasicObject = LoadSelf
711+
v2:BasicObject = GetLocal l0, SP@4
712+
Jump bb2(v1, v2)
713+
bb1(v5:BasicObject, v6:BasicObject):
714+
EntryPoint JIT(0)
715+
Jump bb2(v5, v6)
716+
bb2(v8:BasicObject, v9:BasicObject):
717+
v13:BasicObject = GetLocal l0, EP@3
718+
PatchPoint MethodRedefined(C@0x1000, fun_new_map@0x1008, cme:0x1010)
719+
PatchPoint NoSingletonClass(C@0x1000)
720+
v25:ArraySubclass[class_exact:C] = GuardType v13, ArraySubclass[class_exact:C]
721+
v26:BasicObject = CCallWithFrame fun_new_map@0x1038, v25, block=0x1040
722+
v16:BasicObject = GetLocal l0, EP@3
723+
CheckInterrupts
724+
Return v26
725+
");
726+
}
727+
641728
#[test]
642729
fn test_optimize_nonexistent_top_level_call() {
643730
eval("

0 commit comments

Comments
 (0)