diff options
author | Stan Lo <[email protected]> | 2025-06-16 20:24:33 +0100 |
---|---|---|
committer | <[email protected]> | 2025-06-16 12:24:33 -0700 |
commit | cce4bfdca9e001ccac38b4f3125627b5c0d0e9f2 () | |
tree | 752075b9c05a9a198c90bbb70422ef8beb331c3c | |
parent | 260ac23a53e8db93087216d115aa4b054e9cf35b (diff) |
ZJIT: Add support for putspecialobject (#13565)
* ZJIT: Add support for putspecialobject * Address feedback * Update tests * Adjust the indentation of a Ruby test --------- Co-authored-by: Takashi Kokubun <[email protected]>
Notes: Merged-By: k0kubun <[email protected]>
-rw-r--r-- | test/ruby/test_zjit.rb | 26 | ||||
-rw-r--r-- | vm_insnhelper.c | 8 | ||||
-rw-r--r-- | zjit/src/codegen.rs | 17 | ||||
-rw-r--r-- | zjit/src/cruby.rs | 2 | ||||
-rw-r--r-- | zjit/src/hir.rs | 77 |
5 files changed, 128 insertions, 2 deletions
@@ -652,6 +652,32 @@ class TestZJIT < Test::Unit::TestCase }, call_threshold: 2 end # tool/ruby_vm/views/*.erb relies on the zjit instructions a) being contiguous and # b) being reliably ordered after all the other instructions. def test_instruction_order @@ -5555,6 +5555,14 @@ vm_get_special_object(const VALUE *const reg_ep, } } static VALUE vm_concat_array(VALUE ary1, VALUE ary2st) { @@ -7,7 +7,7 @@ use crate::state::ZJITState; use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr}; use crate::invariants::{iseq_escapes_ep, track_no_ep_escape_assumption}; use crate::backend::lir::{self, asm_comment, Assembler, Opnd, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, SP}; -use crate::hir::{iseq_to_hir, Block, BlockId, BranchEdge, CallInfo, RangeType, SELF_PARAM_IDX}; use crate::hir::{Const, FrameState, Function, Insn, InsnId}; use crate::hir_type::{types::Fixnum, Type}; use crate::options::get_option; @@ -279,6 +279,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id), Insn::SetIvar { self_val, id, val, state: _ } => return gen_setivar(asm, opnd!(self_val), *id, opnd!(val)), Insn::SideExit { state } => return gen_side_exit(jit, asm, &function.frame_state(*state)), _ => { debug!("ZJIT: gen_function: unexpected insn {:?}", insn); return None; @@ -347,6 +348,20 @@ fn gen_side_exit(jit: &mut JITState, asm: &mut Assembler, state: &FrameState) -> Some(()) } /// Compile an interpreter entry block to be inserted into an ISEQ fn gen_entry_prologue(asm: &mut Assembler, iseq: IseqPtr) { asm_comment!(asm, "ZJIT entry point: {}", iseq_get_location(iseq, 0)); @@ -133,6 +133,7 @@ unsafe extern "C" { pub fn rb_str_setbyte(str: VALUE, index: VALUE, value: VALUE) -> VALUE; pub fn rb_vm_splat_array(flag: VALUE, ary: VALUE) -> VALUE; pub fn rb_vm_concat_array(ary1: VALUE, ary2st: VALUE) -> VALUE; pub fn rb_vm_concat_to_array(ary1: VALUE, ary2st: VALUE) -> VALUE; pub fn rb_vm_defined( ec: EcPtr, @@ -213,6 +214,7 @@ pub use rb_vm_ci_flag as vm_ci_flag; pub use rb_vm_ci_kwarg as vm_ci_kwarg; pub use rb_METHOD_ENTRY_VISI as METHOD_ENTRY_VISI; pub use rb_RCLASS_ORIGIN as RCLASS_ORIGIN; /// Helper so we can get a Rust string for insn_name() pub fn insn_name(opcode: usize) -> String { @@ -138,6 +138,40 @@ impl Invariant { } } /// Print adaptor for [`Invariant`]. See [`PtrPrintMap`]. pub struct InvariantPrinter<'a> { inner: Invariant, @@ -365,6 +399,9 @@ pub enum Insn { StringCopy { val: InsnId }, StringIntern { val: InsnId }, /// Call `to_a` on `val` if the method is defined, or make a new array `[val]` otherwise. ToArray { val: InsnId, state: InsnId }, /// Call `to_a` on `val` if the method is defined, or make a new array `[val]` otherwise. If we @@ -645,6 +682,9 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::ArrayExtend { left, right, .. } => write!(f, "ArrayExtend {left}, {right}"), Insn::ArrayPush { array, val, .. } => write!(f, "ArrayPush {array}, {val}"), Insn::SideExit { .. } => write!(f, "SideExit"), insn => { write!(f, "{insn:?}") } } } @@ -958,6 +998,7 @@ impl Function { FixnumGe { left, right } => FixnumGe { left: find!(*left), right: find!(*right) }, FixnumLt { left, right } => FixnumLt { left: find!(*left), right: find!(*right) }, FixnumLe { left, right } => FixnumLe { left: find!(*left), right: find!(*right) }, SendWithoutBlock { self_val, call_info, cd, args, state } => SendWithoutBlock { self_val: find!(*self_val), call_info: call_info.clone(), @@ -1074,6 +1115,7 @@ impl Function { Insn::FixnumLe { .. } => types::BoolExact, Insn::FixnumGt { .. } => types::BoolExact, Insn::FixnumGe { .. } => types::BoolExact, Insn::SendWithoutBlock { .. } => types::BasicObject, Insn::SendWithoutBlockDirect { .. } => types::BasicObject, Insn::Send { .. } => types::BasicObject, @@ -1561,7 +1603,8 @@ impl Function { necessary[insn_id.0] = true; match self.find(insn_id) { Insn::Const { .. } | Insn::Param { .. } - | Insn::Point(..) | Insn::GetConstantPath { .. } => {} Insn::ArrayMax { elements, state } | Insn::NewArray { elements, state } => { @@ -2095,6 +2138,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { YARVINSN_nop => {}, YARVINSN_putnil => { state.stack_push(fun.push_insn(block, Insn::Const { val: Const::Value(Qnil) })); }, YARVINSN_putobject => { state.stack_push(fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) })); }, YARVINSN_putstring | YARVINSN_putchilledstring => { // TODO(max): Do something different for chilled string let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); @@ -3523,6 +3570,13 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): SideExit "#]]); } @@ -3957,6 +4011,27 @@ mod tests { } #[test] fn test_branchnil() { eval(" def test(x) = x&.itself |