diff options
-rw-r--r-- | doc/string/bytesize.rdoc | 20 | ||||
-rw-r--r-- | internal/error.h | 7 | ||||
-rw-r--r-- | set.c | 132 | ||||
-rw-r--r-- | signal.c | 10 | ||||
-rw-r--r-- | test/ruby/test_set.rb | 4 | ||||
-rw-r--r-- | vm_insnhelper.c | 12 | ||||
-rw-r--r-- | zjit/src/codegen.rs | 12 | ||||
-rw-r--r-- | zjit/src/hir.rs | 40 |
8 files changed, 142 insertions, 95 deletions
@@ -1,11 +1,15 @@ -Returns the count of bytes (not characters) in +self+: - 'foo'.bytesize # => 3 - 'тест'.bytesize # => 8 - 'こんにちは'.bytesize # => 15 -Contrast with String#length: - 'foo'.length # => 3 - 'тест'.length # => 4 - 'こんにちは'.length # => 5 @@ -241,4 +241,11 @@ rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type) return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type); } #endif /* INTERNAL_ERROR_H */ @@ -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)); @@ -760,7 +760,6 @@ static const char *received_signal; #endif #if defined(USE_SIGALTSTACK) || defined(_WIN32) -NORETURN(void rb_ec_stack_overflow(rb_execution_context_t *ec, int crit)); # if defined __HAIKU__ # define USE_UCONTEXT_REG 1 # elif !(defined(HAVE_UCONTEXT_H) && (defined __i386__ || defined __x86_64__ || defined __amd64__)) @@ -846,18 +845,21 @@ check_stack_overflow(int sig, const uintptr_t addr, const ucontext_t *ctx) if (sp_page == fault_page || sp_page == fault_page + 1 || (sp_page <= fault_page && fault_page <= bp_page)) { rb_execution_context_t *ec = GET_EC(); - int crit = FALSE; int uplevel = roomof(pagesize, sizeof(*ec->tag)) / 2; /* XXX: heuristic */ while ((uintptr_t)ec->tag->buf / pagesize <= fault_page + 1) { /* drop the last tag if it is close to the fault, * otherwise it can cause stack overflow again at the same * place. */ - if ((crit = (!ec->tag->prev || !--uplevel)) != FALSE) break; rb_vm_tag_jmpbuf_deinit(&ec->tag->buf); ec->tag = ec->tag->prev; } reset_sigmask(sig); - rb_ec_stack_overflow(ec, crit + 1); } } # else @@ -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 @@ -79,24 +79,18 @@ vm_stackoverflow(void) ec_stack_overflow(GET_EC(), TRUE); } -NORETURN(void rb_ec_stack_overflow(rb_execution_context_t *ec, int crit)); -/* critical level - * 0: VM stack overflow or about to machine stack overflow - * 1: machine stack overflow but may be recoverable - * 2: fatal machine stack overflow - */ void -rb_ec_stack_overflow(rb_execution_context_t *ec, int crit) { if (rb_during_gc()) { rb_bug("system stack overflow during GC. Faulty native extension?"); } - if (crit > 1) { ec->raised_flag = RAISED_STACKOVERFLOW; ec->errinfo = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_stackfatal]; EC_JUMP_TAG(ec, TAG_RAISE); } - ec_stack_overflow(ec, crit == 0); } static inline void stack_check(rb_execution_context_t *ec); @@ -283,6 +283,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio 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)), Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type), _ => { debug!("ZJIT: gen_function: unexpected insn {:?}", insn); return None; @@ -814,6 +815,17 @@ fn gen_fixnum_ge(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Opti Some(asm.csel_ge(Qtrue.into(), Qfalse.into())) } /// Evaluate if a value is truthy /// Produces a CBool type (0 or 1) /// In Ruby, only nil and false are falsy @@ -498,6 +498,7 @@ pub enum Insn { // Distinct from `SendWithoutBlock` with `mid:to_s` because does not have a point for String to_s being redefined ObjToString { val: InsnId, call_info: CallInfo, cd: *const rb_call_data, state: InsnId }, /// Side-exit if val doesn't have the expected type. GuardType { val: InsnId, guard_type: Type, state: InsnId }, @@ -699,6 +700,7 @@ 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::ObjToString { val, .. } => { write!(f, "ObjToString {val}") }, Insn::SideExit { .. } => write!(f, "SideExit"), Insn::PutSpecialObject { value_type } => { write!(f, "PutSpecialObject {}", value_type) @@ -1023,6 +1025,11 @@ impl Function { cd: *cd, state: *state, }, SendWithoutBlock { self_val, call_info, cd, args, state } => SendWithoutBlock { self_val: find!(*self_val), call_info: call_info.clone(), @@ -1154,6 +1161,7 @@ impl Function { Insn::ToNewArray { .. } => types::ArrayExact, Insn::ToArray { .. } => types::ArrayExact, Insn::ObjToString { .. } => types::BasicObject, } } @@ -1398,7 +1406,7 @@ impl Function { self.make_equal_to(insn_id, replacement); } Insn::ObjToString { val, call_info, cd, state, .. } => { - if self.is_a(val, types::StringExact) { // behaves differently from `SendWithoutBlock` with `mid:to_s` because ObjToString should not have a point for String to_s being redefined self.make_equal_to(insn_id, val); } else { @@ -1406,6 +1414,13 @@ impl Function { self.make_equal_to(insn_id, replacement) } } _ => { self.push_insn_id(block, insn_id); } } } @@ -1782,6 +1797,11 @@ impl Function { worklist.push_back(val); worklist.push_back(state); } Insn::GetGlobal { state, .. } | Insn::SideExit { state } => worklist.push_back(state), } @@ -2783,6 +2803,14 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let objtostring = fun.push_insn(block, Insn::ObjToString { val: recv, call_info: CallInfo { method_name }, cd, state: exit_id }); state.stack_push(objtostring) } _ => { // Unknown opcode; side-exit into the interpreter let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); @@ -4452,7 +4480,7 @@ mod tests { } #[test] - fn test_objtostring() { eval(" def test = \"#{1}\" "); @@ -4462,6 +4490,7 @@ mod tests { v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v3:Fixnum[1] = Const Value(1) v5:BasicObject = ObjToString v3 SideExit "#]]); } @@ -6010,7 +6039,7 @@ mod opt_tests { } #[test] - fn test_objtostring_string() { eval(r##" def test = "#{('foo')}" "##); @@ -6025,7 +6054,7 @@ mod opt_tests { } #[test] - fn test_objtostring_with_non_string() { eval(r##" def test = "#{1}" "##); @@ -6034,7 +6063,8 @@ mod opt_tests { bb0(v0:BasicObject): v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v3:Fixnum[1] = Const Value(1) - v8:BasicObject = SendWithoutBlock v3, :to_s SideExit "#]]); } |