diff options
author | Max Bernstein <[email protected]> | 2025-04-30 17:48:12 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2025-04-30 14:48:12 -0700 |
commit | 73fdd90315a7038b060ec78ca0984951d13ccb4f (patch) | |
tree | dc9932cbda41b65bc607f98b3b8a09723ad5c7a7 /zjit/src | |
parent | c65991978baac17fbfd3bc09e58a35bb2e5f769e (diff) |
ZJIT: Compile opt_new to slow-path SendWithoutBlock (#13216)
Notes
Notes:
Merged-By: k0kubun <[email protected]>
Diffstat (limited to 'zjit/src')
-rw-r--r-- | zjit/src/hir.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index d46f5f486f..f4ecb46383 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -1600,6 +1600,10 @@ fn compute_jump_targets(iseq: *const rb_iseq_t) -> Vec<u32> { let offset = get_arg(pc, 0).as_i64(); jump_targets.insert(insn_idx_at_offset(insn_idx, offset)); } + YARVINSN_opt_new => { + let offset = get_arg(pc, 1).as_i64(); + jump_targets.insert(insn_idx_at_offset(insn_idx, offset)); + } YARVINSN_leave | YARVINSN_opt_invokebuiltin_delegate_leave => { if insn_idx < iseq_size { jump_targets.insert(insn_idx); @@ -1800,6 +1804,17 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { }); queue.push_back((state.clone(), target, target_idx)); } + YARVINSN_opt_new => { + let offset = get_arg(pc, 1).as_i64(); + // TODO(max): Check interrupts + let target_idx = insn_idx_at_offset(insn_idx, offset); + let target = insn_idx_to_block[&target_idx]; + // Skip the fast-path and go straight to the fallback code. We will let the + // optimizer take care of the converting Class#new->alloc+initialize instead. + fun.push_insn(block, Insn::Jump(BranchEdge { target, args: state.as_args() })); + queue.push_back((state.clone(), target, target_idx)); + break; // Don't enqueue the next block as a successor + } YARVINSN_jump => { let offset = get_arg(pc, 0).as_i64(); // TODO(max): Check interrupts @@ -2796,6 +2811,26 @@ mod tests { "); assert_compile_fails("test", ParseError::UnknownOpcode("sendforward".into())) } + + #[test] + fn test_opt_new() { + eval(" + class C; end + def test = C.new + "); + assert_method_hir("test", expect![[r#" + fn test: + bb0(): + v1:BasicObject = GetConstantPath 0x1000 + v2:NilClassExact = Const Value(nil) + Jump bb1(v2, v1) + bb1(v4:NilClassExact, v5:BasicObject): + v8:BasicObject = SendWithoutBlock v5, :new + Jump bb2(v8, v4) + bb2(v10:BasicObject, v11:NilClassExact): + Return v10 + "#]]); + } } #[cfg(test)] @@ -3688,4 +3723,55 @@ mod opt_tests { Return v5 "#]]); } + + #[test] + fn test_opt_new_no_initialize() { + eval(" + class C; end + def test = C.new + test + "); + assert_optimized_method_hir("test", expect![[r#" + fn test: + bb0(): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, C) + v16:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v2:NilClassExact = Const Value(nil) + Jump bb1(v2, v16) + bb1(v4:NilClassExact, v5:BasicObject[VALUE(0x1008)]): + v8:BasicObject = SendWithoutBlock v5, :new + Jump bb2(v8, v4) + bb2(v10:BasicObject, v11:NilClassExact): + Return v10 + "#]]); + } + + #[test] + fn test_opt_new_initialize() { + eval(" + class C + def initialize x + @x = x + end + end + def test = C.new 1 + test + "); + assert_optimized_method_hir("test", expect![[r#" + fn test: + bb0(): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, C) + v18:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v2:NilClassExact = Const Value(nil) + v3:Fixnum[1] = Const Value(1) + Jump bb1(v2, v18, v3) + bb1(v5:NilClassExact, v6:BasicObject[VALUE(0x1008)], v7:Fixnum[1]): + v10:BasicObject = SendWithoutBlock v6, :new, v7 + Jump bb2(v10, v5) + bb2(v12:BasicObject, v13:NilClassExact): + Return v12 + "#]]); + } } |