mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
kernel.c: remove mrb_inspect_recursive_p(); #5531
And use mrb_recursive_method_p() and its helper methods. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,6 @@ void mrb_ary_decref(mrb_state*, mrb_shared_array*);
|
||||
mrb_value mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len);
|
||||
#endif
|
||||
|
||||
mrb_bool mrb_inspect_recursive_p(mrb_state *mrb, mrb_value self);
|
||||
|
||||
#ifdef MRUBY_CLASS_H
|
||||
struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym);
|
||||
struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym);
|
||||
|
||||
@@ -1380,7 +1380,7 @@ set_inspect(mrb_state *mrb, mrb_value self)
|
||||
}
|
||||
|
||||
/* Handle recursive inspection */
|
||||
if (mrb_inspect_recursive_p(mrb, self)) {
|
||||
if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
|
||||
return mrb_format(mrb, "%s[...]", classname);
|
||||
}
|
||||
|
||||
|
||||
@@ -647,7 +647,7 @@ mrb_struct_to_s(mrb_state *mrb, mrb_value self)
|
||||
mrb_str_cat_str(mrb, ret, cname);
|
||||
mrb_str_cat_lit(mrb, ret, " ");
|
||||
}
|
||||
if (mrb_inspect_recursive_p(mrb, self)) {
|
||||
if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
|
||||
mrb_str_cat_lit(mrb, ret, "...>");
|
||||
return ret;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1626,7 +1626,7 @@ mrb_ary_to_s(mrb_state *mrb, mrb_value self)
|
||||
mrb->c->ci->mid = MRB_SYM(inspect);
|
||||
mrb_value ret = mrb_str_new_lit(mrb, "[");
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
if (mrb_inspect_recursive_p(mrb, self)) {
|
||||
if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
|
||||
mrb_str_cat_lit(mrb, ret, "...]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
+1
-58
@@ -2032,7 +2032,7 @@ mrb_hash_to_s(mrb_state *mrb, mrb_value self)
|
||||
mrb->c->ci->mid = MRB_SYM(inspect);
|
||||
mrb_value ret = mrb_str_new_lit(mrb, "{");
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
if (mrb_inspect_recursive_p(mrb, self)) {
|
||||
if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
|
||||
mrb_str_cat_lit(mrb, ret, "...}");
|
||||
return ret;
|
||||
}
|
||||
@@ -2125,62 +2125,6 @@ mrb_hash_rassoc(mrb_state *mrb, mrb_value hash)
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash recursion detection for equality comparison
|
||||
*
|
||||
* This implements a memory-efficient recursion detection mechanism for Hash#== and Hash#eql?
|
||||
* to prevent SystemStackError when comparing mutually recursive hash structures.
|
||||
*
|
||||
* Background:
|
||||
* - Issue: Hash#eql? caused infinite recursion and stack overflow with recursive hashes
|
||||
* - Example: a = {}; b = {}; a[:self] = a; a[:other] = b; b[:self] = b; b[:other] = a; a.eql?(b)
|
||||
*
|
||||
* Solution:
|
||||
* - Uses call stack inspection (similar to inspect_recursive_p) to detect recursion
|
||||
* - Minimal memory overhead - examines existing call frames without additional storage
|
||||
* - Returns FALSE when recursion detected (conservative approach for mruby's constraints)
|
||||
* - Preserves all normal equality behavior for non-recursive cases
|
||||
*
|
||||
* Design considerations:
|
||||
* - Memory > Performance > Readability (mruby design priority)
|
||||
* - Compatible with mruby's embedded/memory-constrained environment
|
||||
* - Uses established pattern from kernel.c inspect_recursive_p implementation
|
||||
*/
|
||||
|
||||
static mrb_bool
|
||||
hash_eql_recursive_p(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
/* Look for recursive eql? calls on the same object in the call stack
|
||||
* Start from ci[-2] to skip current call frame (ci[-1] is __eql_recursive_p?, ci[0] is eql?)
|
||||
*/
|
||||
for (mrb_callinfo *ci=&mrb->c->ci[-2]; ci>=mrb->c->cibase; ci--) {
|
||||
if (ci->mid == MRB_SYM_Q(eql) &&
|
||||
mrb_obj_eq(mrb, obj, ci->stack[0])) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static mrb_bool
|
||||
hash_equal_recursive_p(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
/* Look for recursive == calls on the same object in the call stack */
|
||||
for (mrb_callinfo *ci=&mrb->c->ci[-2]; ci>=mrb->c->cibase; ci--) {
|
||||
if (ci->mid == MRB_OPSYM(eq) &&
|
||||
mrb_obj_eq(mrb, obj, ci->stack[0])) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_hash_eql_recursive_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return mrb_bool_value(hash_eql_recursive_p(mrb, self));
|
||||
}
|
||||
|
||||
/* 15.2.13.4.1 */
|
||||
static mrb_value
|
||||
mrb_hash_equal(mrb_state *mrb, mrb_value hash)
|
||||
@@ -2313,5 +2257,4 @@ mrb_init_hash(mrb_state *mrb)
|
||||
mrb_define_method_id(mrb, h, MRB_SYM(rassoc), mrb_hash_rassoc, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, h, MRB_SYM(__merge), mrb_hash_merge_m, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, h, MRB_SYM(__compact), mrb_hash_compact, MRB_ARGS_NONE()); /* implementation of Hash#compact! */
|
||||
mrb_define_private_method_id(mrb, h, MRB_SYM_Q(__eql_recursive_p), mrb_hash_eql_recursive_p, MRB_ARGS_NONE()); /* recursion detection for Hash#eql? */
|
||||
}
|
||||
|
||||
@@ -126,12 +126,6 @@ mrb_recursive_method_p(mrb_state *mrb, mrb_sym mid, mrb_value obj1, mrb_value ob
|
||||
#define MRB_RECURSIVE_BINARY_P(mrb, mid, obj1, obj2) \
|
||||
mrb_recursive_method_p(mrb, mid, obj1, obj2)
|
||||
|
||||
mrb_bool
|
||||
mrb_inspect_recursive_p(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
return MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), obj);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_obj_method_recursive_p(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
|
||||
+1
-1
@@ -636,7 +636,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
|
||||
mrb_str_cat_lit(mrb, str, ":");
|
||||
mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, obj));
|
||||
|
||||
if (mrb_inspect_recursive_p(mrb, mrb_obj_value(obj))) {
|
||||
if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), mrb_obj_value(obj))) {
|
||||
mrb_str_cat_lit(mrb, str, " ...>");
|
||||
return str;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user