summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/string/bytesize.rdoc20
-rw-r--r--internal/error.h7
-rw-r--r--set.c132
-rw-r--r--signal.c10
-rw-r--r--test/ruby/test_set.rb4
-rw-r--r--vm_insnhelper.c12
-rw-r--r--zjit/src/codegen.rs12
-rw-r--r--zjit/src/hir.rs40
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
"#]]);
}