summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zjit/src/hir.rs86
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
+ "#]]);
+ }
}