Skip to content

Commit 0ce1665

Browse files
committed
Enable ZJIT jit hooks for with_jit builtins
1 parent c541438 commit 0ce1665

File tree

7 files changed

+112
-10
lines changed

7 files changed

+112
-10
lines changed

jit_hook.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ class Module
22
# Internal helper for built-in initializations to define methods only when JIT is enabled.
33
# This method is removed in jit_undef.rb.
44
private def with_jit(&block) # :nodoc:
5-
# ZJIT currently doesn't compile Array#each properly, so it's disabled for now.
6-
if defined?(RubyVM::ZJIT) && false # TODO: remove `&& false` (Shopify/ruby#667)
5+
if defined?(RubyVM::ZJIT)
76
RubyVM::ZJIT.send(:add_jit_hook, block)
8-
elsif defined?(RubyVM::YJIT)
7+
end
8+
if defined?(RubyVM::YJIT)
99
RubyVM::YJIT.send(:add_jit_hook, block)
1010
end
1111
end

zjit/bindgen/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ fn main() {
167167
.allowlist_var("rb_cClass")
168168
.allowlist_var("rb_cRegexp")
169169
.allowlist_var("rb_cISeq")
170+
.allowlist_var("rb_cRubyVM")
171+
.allowlist_function("rb_const_get")
170172

171173
.allowlist_type("ruby_fl_type")
172174
.allowlist_type("ruby_fl_ushift")

zjit/src/cruby.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,12 @@ pub mod test_utils {
11331133
crate::cruby::ids::init(); // for ID! usages in tests
11341134
}
11351135

1136+
// Call ZJIT hooks to install Ruby implementations of builtins like Array#each
1137+
unsafe {
1138+
let zjit = rb_const_get(rb_cRubyVM, rust_str_to_id("ZJIT"));
1139+
rb_funcallv(zjit, rust_str_to_id("call_jit_hooks"), 0, std::ptr::null());
1140+
}
1141+
11361142
// Set up globals for convenience
11371143
let zjit_entry = ZJITState::init();
11381144

zjit/src/cruby_bindings.inc.rs

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir/opt_tests.rs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -823,11 +823,11 @@ mod hir_opt_tests {
823823
bb2(v8:BasicObject, v9:BasicObject):
824824
PatchPoint NoSingletonClass(C@0x1000)
825825
PatchPoint MethodRedefined(C@0x1000, fun_new_map@0x1008, cme:0x1010)
826-
v23:ArraySubclass[class_exact:C] = GuardType v9, ArraySubclass[class_exact:C]
827-
v24:BasicObject = CCallWithFrame v23, :C#fun_new_map@0x1038, block=0x1040
826+
v22:ArraySubclass[class_exact:C] = GuardType v9, ArraySubclass[class_exact:C]
827+
v23:BasicObject = SendDirect v22, 0x1038, :fun_new_map (0x1048)
828828
v15:BasicObject = GetLocal :o, l0, EP@3
829829
CheckInterrupts
830-
Return v24
830+
Return v23
831831
");
832832
}
833833

@@ -6490,9 +6490,9 @@ mod hir_opt_tests {
64906490
v11:ArrayExact = ArrayDup v10
64916491
PatchPoint NoSingletonClass(Array@0x1008)
64926492
PatchPoint MethodRedefined(Array@0x1008, map@0x1010, cme:0x1018)
6493-
v21:BasicObject = CCallWithFrame v11, :Array#map@0x1040, block=0x1048
6493+
v20:BasicObject = SendDirect v11, 0x1040, :map (0x1050)
64946494
CheckInterrupts
6495-
Return v21
6495+
Return v20
64966496
");
64976497
}
64986498

@@ -11887,4 +11887,44 @@ mod hir_opt_tests {
1188711887
Return v31
1188811888
");
1188911889
}
11890+
11891+
#[test]
11892+
fn test_array_each() {
11893+
eval("[1, 2, 3].each { |x| x }");
11894+
assert_snapshot!(hir_string_proc("Array.instance_method(:each)"), @r"
11895+
fn each@<internal:array>:
11896+
bb0():
11897+
EntryPoint interpreter
11898+
v1:BasicObject = LoadSelf
11899+
v2:NilClass = Const Value(nil)
11900+
Jump bb2(v1, v2)
11901+
bb1(v5:BasicObject):
11902+
EntryPoint JIT(0)
11903+
v6:NilClass = Const Value(nil)
11904+
Jump bb2(v5, v6)
11905+
bb2(v8:BasicObject, v9:NilClass):
11906+
v13:NilClass = Const Value(nil)
11907+
v15:TrueClass|NilClass = Defined yield, v13
11908+
v17:CBool = Test v15
11909+
IfFalse v17, bb3(v8, v9)
11910+
v35:Fixnum[0] = Const Value(0)
11911+
Jump bb7(v8, v35)
11912+
bb3(v23:BasicObject, v24:NilClass):
11913+
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
11914+
CheckInterrupts
11915+
Return v28
11916+
bb7(v48:BasicObject, v49:BasicObject):
11917+
v52:BasicObject = InvokeBuiltin ary_at_end, v48, v49
11918+
v54:CBool = Test v52
11919+
IfFalse v54, bb6(v48, v49)
11920+
CheckInterrupts
11921+
Return v48
11922+
bb6(v67:BasicObject, v68:BasicObject):
11923+
v72:BasicObject = InvokeBuiltin ary_at, v67, v68
11924+
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
11925+
v78:BasicObject = InvokeBuiltin fixnum_inc, v67, v68
11926+
PatchPoint NoEPEscape(each)
11927+
Jump bb7(v67, v78)
11928+
");
11929+
}
1189011930
}

zjit/src/hir/tests.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4043,6 +4043,54 @@ pub mod hir_build_tests {
40434043
SideExit TooManyKeywordParameters
40444044
");
40454045
}
4046+
4047+
#[test]
4048+
fn test_array_each() {
4049+
assert_snapshot!(hir_string_proc("Array.instance_method(:each)"), @r"
4050+
fn each@<internal:array>:
4051+
bb0():
4052+
EntryPoint interpreter
4053+
v1:BasicObject = LoadSelf
4054+
v2:NilClass = Const Value(nil)
4055+
Jump bb2(v1, v2)
4056+
bb1(v5:BasicObject):
4057+
EntryPoint JIT(0)
4058+
v6:NilClass = Const Value(nil)
4059+
Jump bb2(v5, v6)
4060+
bb2(v8:BasicObject, v9:NilClass):
4061+
v13:NilClass = Const Value(nil)
4062+
v15:TrueClass|NilClass = Defined yield, v13
4063+
v17:CBool = Test v15
4064+
v18:NilClass = RefineType v15, Falsy
4065+
IfFalse v17, bb3(v8, v9)
4066+
v20:TrueClass = RefineType v15, Truthy
4067+
Jump bb5(v8, v9)
4068+
bb3(v23:BasicObject, v24:NilClass):
4069+
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
4070+
Jump bb4(v23, v24, v28)
4071+
bb4(v40:BasicObject, v41:NilClass, v42:BasicObject):
4072+
CheckInterrupts
4073+
Return v42
4074+
bb5(v30:BasicObject, v31:NilClass):
4075+
v35:Fixnum[0] = Const Value(0)
4076+
Jump bb7(v30, v35)
4077+
bb7(v48:BasicObject, v49:BasicObject):
4078+
v52:BasicObject = InvokeBuiltin rb_jit_ary_at_end, v48, v49
4079+
v54:CBool = Test v52
4080+
v55:Falsy = RefineType v52, Falsy
4081+
IfFalse v54, bb6(v48, v49)
4082+
v57:Truthy = RefineType v52, Truthy
4083+
v59:NilClass = Const Value(nil)
4084+
CheckInterrupts
4085+
Return v48
4086+
bb6(v67:BasicObject, v68:BasicObject):
4087+
v72:BasicObject = InvokeBuiltin rb_jit_ary_at, v67, v68
4088+
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
4089+
v78:BasicObject = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
4090+
PatchPoint NoEPEscape(each)
4091+
Jump bb7(v67, v78)
4092+
");
4093+
}
40464094
}
40474095

40484096
/// Test successor and predecessor set computations.

zjit/src/state.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Runtime state of ZJIT.
22
33
use crate::codegen::{gen_entry_trampoline, gen_exit_trampoline, gen_exit_trampoline_with_counter, gen_function_stub_hit_trampoline};
4-
use crate::cruby::{self, rb_bug_panic_hook, rb_vm_insn_count, src_loc, EcPtr, Qnil, Qtrue, rb_vm_insn_addr2opcode, rb_profile_frames, VALUE, VM_INSTRUCTION_SIZE, size_t, rb_gc_mark, with_vm_lock};
4+
use crate::cruby::{self, rb_bug_panic_hook, rb_vm_insn_count, src_loc, EcPtr, Qnil, Qtrue, rb_vm_insn_addr2opcode, rb_profile_frames, VALUE, VM_INSTRUCTION_SIZE, size_t, rb_gc_mark, with_vm_lock, rust_str_to_id, rb_funcallv, rb_const_get, rb_cRubyVM};
55
use crate::cruby_methods;
66
use crate::invariants::Invariants;
77
use crate::asm::CodeBlock;
@@ -319,7 +319,11 @@ pub extern "C" fn rb_zjit_init(zjit_enabled: bool) {
319319

320320
/// Enable ZJIT compilation.
321321
fn zjit_enable() {
322-
// TODO: call RubyVM::ZJIT::call_jit_hooks here
322+
// Call ZJIT hooks before enabling ZJIT to avoid compiling the hooks themselves
323+
unsafe {
324+
let zjit = rb_const_get(rb_cRubyVM, rust_str_to_id("ZJIT"));
325+
rb_funcallv(zjit, rust_str_to_id("call_jit_hooks"), 0, std::ptr::null());
326+
}
323327

324328
// Catch panics to avoid UB for unwinding into C frames.
325329
// See https://doc.rust-lang.org/nomicon/exception-safety.html

0 commit comments

Comments
 (0)