Skip to content

Commit 0a47b9b

Browse files
committed
Enable ZJIT jit hooks for with_jit builtins
1 parent 5f6ced0 commit 0a47b9b

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

@@ -6515,9 +6515,9 @@ mod hir_opt_tests {
65156515
v11:ArrayExact = ArrayDup v10
65166516
PatchPoint NoSingletonClass(Array@0x1008)
65176517
PatchPoint MethodRedefined(Array@0x1008, map@0x1010, cme:0x1018)
6518-
v21:BasicObject = CCallWithFrame v11, :Array#map@0x1040, block=0x1048
6518+
v20:BasicObject = SendDirect v11, 0x1040, :map (0x1050)
65196519
CheckInterrupts
6520-
Return v21
6520+
Return v20
65216521
");
65226522
}
65236523

@@ -12004,4 +12004,44 @@ mod hir_opt_tests {
1200412004
Return v99
1200512005
");
1200612006
}
12007+
12008+
#[test]
12009+
fn test_array_each() {
12010+
eval("[1, 2, 3].each { |x| x }");
12011+
assert_snapshot!(hir_string_proc("Array.instance_method(:each)"), @r"
12012+
fn each@<internal:array>:
12013+
bb0():
12014+
EntryPoint interpreter
12015+
v1:BasicObject = LoadSelf
12016+
v2:NilClass = Const Value(nil)
12017+
Jump bb2(v1, v2)
12018+
bb1(v5:BasicObject):
12019+
EntryPoint JIT(0)
12020+
v6:NilClass = Const Value(nil)
12021+
Jump bb2(v5, v6)
12022+
bb2(v8:BasicObject, v9:NilClass):
12023+
v13:NilClass = Const Value(nil)
12024+
v15:TrueClass|NilClass = Defined yield, v13
12025+
v17:CBool = Test v15
12026+
IfFalse v17, bb3(v8, v9)
12027+
v35:Fixnum[0] = Const Value(0)
12028+
Jump bb7(v8, v35)
12029+
bb3(v23:BasicObject, v24:NilClass):
12030+
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
12031+
CheckInterrupts
12032+
Return v28
12033+
bb7(v48:BasicObject, v49:BasicObject):
12034+
v52:BasicObject = InvokeBuiltin rb_jit_ary_at_end, v48, v49
12035+
v54:CBool = Test v52
12036+
IfFalse v54, bb6(v48, v49)
12037+
CheckInterrupts
12038+
Return v48
12039+
bb6(v67:BasicObject, v68:BasicObject):
12040+
v72:BasicObject = InvokeBuiltin rb_jit_ary_at, v67, v68
12041+
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
12042+
v78:BasicObject = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
12043+
PatchPoint NoEPEscape(each)
12044+
Jump bb7(v67, v78)
12045+
");
12046+
}
1200712047
}

zjit/src/hir/tests.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4069,6 +4069,54 @@ pub mod hir_build_tests {
40694069
SideExit TooManyKeywordParameters
40704070
");
40714071
}
4072+
4073+
#[test]
4074+
fn test_array_each() {
4075+
assert_snapshot!(hir_string_proc("Array.instance_method(:each)"), @r"
4076+
fn each@<internal:array>:
4077+
bb0():
4078+
EntryPoint interpreter
4079+
v1:BasicObject = LoadSelf
4080+
v2:NilClass = Const Value(nil)
4081+
Jump bb2(v1, v2)
4082+
bb1(v5:BasicObject):
4083+
EntryPoint JIT(0)
4084+
v6:NilClass = Const Value(nil)
4085+
Jump bb2(v5, v6)
4086+
bb2(v8:BasicObject, v9:NilClass):
4087+
v13:NilClass = Const Value(nil)
4088+
v15:TrueClass|NilClass = Defined yield, v13
4089+
v17:CBool = Test v15
4090+
v18:NilClass = RefineType v15, Falsy
4091+
IfFalse v17, bb3(v8, v9)
4092+
v20:TrueClass = RefineType v15, Truthy
4093+
Jump bb5(v8, v9)
4094+
bb3(v23:BasicObject, v24:NilClass):
4095+
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
4096+
Jump bb4(v23, v24, v28)
4097+
bb4(v40:BasicObject, v41:NilClass, v42:BasicObject):
4098+
CheckInterrupts
4099+
Return v42
4100+
bb5(v30:BasicObject, v31:NilClass):
4101+
v35:Fixnum[0] = Const Value(0)
4102+
Jump bb7(v30, v35)
4103+
bb7(v48:BasicObject, v49:BasicObject):
4104+
v52:BasicObject = InvokeBuiltin rb_jit_ary_at_end, v48, v49
4105+
v54:CBool = Test v52
4106+
v55:Falsy = RefineType v52, Falsy
4107+
IfFalse v54, bb6(v48, v49)
4108+
v57:Truthy = RefineType v52, Truthy
4109+
v59:NilClass = Const Value(nil)
4110+
CheckInterrupts
4111+
Return v48
4112+
bb6(v67:BasicObject, v68:BasicObject):
4113+
v72:BasicObject = InvokeBuiltin rb_jit_ary_at, v67, v68
4114+
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
4115+
v78:BasicObject = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
4116+
PatchPoint NoEPEscape(each)
4117+
Jump bb7(v67, v78)
4118+
");
4119+
}
40724120
}
40734121

40744122
/// 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)