summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jit.c7
-rw-r--r--set.c132
-rw-r--r--test/ruby/test_set.rb4
-rw-r--r--yjit.c7
-rw-r--r--yjit/src/cruby_bindings.inc.rs2
-rw-r--r--zjit/src/cruby_bindings.inc.rs1
-rw-r--r--zjit/src/hir.rs101
-rw-r--r--zjit/src/hir_type/mod.rs2
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)),