diff options
-rw-r--r-- | jit.c | 7 | ||||
-rw-r--r-- | set.c | 132 | ||||
-rw-r--r-- | test/ruby/test_set.rb | 4 | ||||
-rw-r--r-- | yjit.c | 7 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 2 | ||||
-rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 1 | ||||
-rw-r--r-- | zjit/src/hir.rs | 101 | ||||
-rw-r--r-- | zjit/src/hir_type/mod.rs | 2 |
8 files changed, 172 insertions, 84 deletions
@@ -421,3 +421,10 @@ rb_assert_cme_handle(VALUE handle) RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle)); RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment)); } @@ -843,66 +843,72 @@ set_i_classify(VALUE set) return args[0]; } -struct set_divide_args { - VALUE self; - VALUE set_class; - VALUE final_set; - VALUE hash; - VALUE current_set; - VALUE current_item; - unsigned long ni; - unsigned long nj; -}; -static VALUE -set_divide_block0(RB_BLOCK_CALL_FUNC_ARGLIST(j, arg)) -{ - struct set_divide_args *args = (struct set_divide_args *)arg; - if (args->nj > args->ni) { - VALUE i = args->current_item; - if (RTEST(rb_yield_values(2, i, j)) && RTEST(rb_yield_values(2, j, i))) { - VALUE hash = args->hash; - if (args->current_set == Qnil) { - VALUE set = rb_hash_aref(hash, j); - if (set == Qnil) { - VALUE both[2] = {i, j}; - set = set_s_create(2, both, args->set_class); - rb_hash_aset(hash, i, set); - rb_hash_aset(hash, j, set); - set_i_add(args->final_set, set); - } - else { - set_i_add(set, i); - rb_hash_aset(hash, i, set); - } - args->current_set = set; - } - else { - set_i_add(args->current_set, j); - rb_hash_aset(hash, j, args->current_set); } } } - args->nj++; - return j; -} - -static VALUE -set_divide_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) -{ - struct set_divide_args *args = (struct set_divide_args *)arg; - VALUE hash = args->hash; - args->current_set = rb_hash_aref(hash, i); - args->current_item = i; - args->nj = 0; - rb_block_call(args->self, id_each, 0, 0, set_divide_block0, arg); - if (args->current_set == Qnil) { - VALUE set = set_s_create(1, &i, args->set_class); - rb_hash_aset(hash, i, set); - set_i_add(args->final_set, set); - } - args->ni++; - return i; } static void set_merge_enum_into(VALUE set, VALUE arg); @@ -936,19 +942,7 @@ set_i_divide(VALUE set) RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size); if (rb_block_arity() == 2) { - VALUE final_set = set_s_create(0, 0, rb_cSet); - struct set_divide_args args = { - .self = set, - .set_class = rb_obj_class(set), - .final_set = final_set, - .hash = rb_hash_new(), - .current_set = 0, - .current_item = 0, - .ni = 0, - .nj = 0 - }; - rb_block_call(set, id_each, 0, 0, set_divide_block, (VALUE)&args); - return final_set; } VALUE values = rb_hash_values(set_i_classify(set)); @@ -781,6 +781,10 @@ class TC_Set < Test::Unit::TestCase ret.each { |s| n += s.size } assert_equal(set.size, n) assert_equal(set, ret.flatten) end def test_freeze @@ -533,13 +533,6 @@ rb_str_neq_internal(VALUE str1, VALUE str2) return rb_str_eql_internal(str1, str2) == Qtrue ? Qfalse : Qtrue; } -// YJIT needs this function to never allocate and never raise -VALUE -rb_yarv_ary_entry_internal(VALUE ary, long offset) -{ - return rb_ary_entry_internal(ary, offset); -} - extern VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary); VALUE @@ -1206,7 +1206,6 @@ extern "C" { pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE; pub fn rb_yarv_str_eql_internal(str1: VALUE, str2: VALUE) -> VALUE; pub fn rb_str_neq_internal(str1: VALUE, str2: VALUE) -> VALUE; - pub fn rb_yarv_ary_entry_internal(ary: VALUE, offset: ::std::os::raw::c_long) -> VALUE; pub fn rb_ary_unshift_m(argc: ::std::os::raw::c_int, argv: *mut VALUE, ary: VALUE) -> VALUE; pub fn rb_yjit_rb_ary_subseq_length(ary: VALUE, beg: ::std::os::raw::c_long) -> VALUE; pub fn rb_yjit_fix_div_fix(recv: VALUE, obj: VALUE) -> VALUE; @@ -1328,4 +1327,5 @@ extern "C" { pub fn rb_assert_iseq_handle(handle: VALUE); pub fn rb_IMEMO_TYPE_P(imemo: VALUE, imemo_type: imemo_type) -> ::std::os::raw::c_int; pub fn rb_assert_cme_handle(handle: VALUE); } @@ -1001,4 +1001,5 @@ unsafe extern "C" { pub fn rb_assert_iseq_handle(handle: VALUE); pub fn rb_IMEMO_TYPE_P(imemo: VALUE, imemo_type: imemo_type) -> ::std::os::raw::c_int; pub fn rb_assert_cme_handle(handle: VALUE); } @@ -206,6 +206,7 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> { BOP_FREEZE => write!(f, "BOP_FREEZE")?, BOP_UMINUS => write!(f, "BOP_UMINUS")?, BOP_MAX => write!(f, "BOP_MAX")?, _ => write!(f, "{bop}")?, } write!(f, ")") @@ -1317,6 +1318,25 @@ impl Function { } } /// Rewrite SendWithoutBlock opcodes into SendWithoutBlockDirect opcodes if we know the target /// ISEQ statically. This removes run-time method lookups and opens the door for inlining. fn optimize_direct_sends(&mut self) { @@ -1351,6 +1371,8 @@ impl Function { self.try_rewrite_freeze(block, insn_id, self_val), Insn::SendWithoutBlock { self_val, call_info: CallInfo { method_name }, args, .. } if method_name == "-@" && args.len() == 0 => self.try_rewrite_uminus(block, insn_id, self_val), Insn::SendWithoutBlock { mut self_val, call_info, cd, args, state } => { let frame_state = self.frame_state(state); let (klass, guard_equal_to) = if let Some(klass) = self.type_of(self_val).runtime_exact_ruby_class() { @@ -2306,7 +2328,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { YARVINSN_putobject => { state.stack_push(fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) })); }, YARVINSN_putspecialobject => { let value_type = SpecialObjectType::from(get_arg(pc, 0).as_u32()); - state.stack_push(fun.push_insn(block, Insn::PutSpecialObject { value_type })); } YARVINSN_putstring => { let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); @@ -3900,11 +3927,11 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): - v3:BasicObject = PutSpecialObject VMCore v5:HashExact = NewHash v7:BasicObject = SendWithoutBlock v3, :core#hash_merge_kwd, v5, v1 - v8:BasicObject = PutSpecialObject VMCore - v9:StaticSymbol[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v10:Fixnum[1] = Const Value(1) v12:BasicObject = SendWithoutBlock v8, :core#hash_merge_ptr, v7, v9, v10 SideExit @@ -4352,10 +4379,10 @@ mod tests { assert_method_hir_with_opcode("test", YARVINSN_putspecialobject, expect![[r#" fn test: bb0(v0:BasicObject): - v2:BasicObject = PutSpecialObject VMCore v3:BasicObject = PutSpecialObject CBase - v4:StaticSymbol[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v5:StaticSymbol[VALUE(0x1008)] = Const Value(VALUE(0x1008)) v7:BasicObject = SendWithoutBlock v2, :core#set_method_alias, v3, v4, v5 Return v7 "#]]); @@ -6068,4 +6095,64 @@ mod opt_tests { SideExit "#]]); } } @@ -3,6 +3,7 @@ use crate::cruby::{Qfalse, Qnil, Qtrue, VALUE, RUBY_T_ARRAY, RUBY_T_STRING, RUBY use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cObject, rb_cTrueClass, rb_cFalseClass, rb_cNilClass, rb_cRange}; use crate::cruby::ClassRelationship; use crate::cruby::get_class_name; use crate::hir::PtrPrintMap; #[derive(Copy, Clone, Debug, PartialEq)] @@ -68,6 +69,7 @@ fn write_spec(f: &mut std::fmt::Formatter, printer: &TypePrinter) -> std::fmt::R let ty = printer.inner; match ty.spec { Specialization::Any | Specialization::Empty => { Ok(()) }, Specialization::Object(val) => write!(f, "[{}]", val.print(printer.ptr_map)), Specialization::Type(val) => write!(f, "[class:{}]", get_class_name(val)), Specialization::TypeExact(val) => write!(f, "[class_exact:{}]", get_class_name(val)), |