Do not use mrb_funcall() if Hash#default is not overridden; ref #3421

This change reduces the recursion level, but does not solve the stack
overflow issue entirely.
parent 719f700a
...@@ -1147,6 +1147,7 @@ MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); ...@@ -1147,6 +1147,7 @@ MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id);
MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid);
MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c);
MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func);
/* /*
......
...@@ -159,6 +159,9 @@ mrb_hash_new(mrb_state *mrb) ...@@ -159,6 +159,9 @@ mrb_hash_new(mrb_state *mrb)
return mrb_hash_new_capa(mrb, 0); return mrb_hash_new_capa(mrb, 0);
} }
static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
MRB_API mrb_value MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{ {
...@@ -171,7 +174,9 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) ...@@ -171,7 +174,9 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
return kh_value(h, k).v; return kh_value(h, k).v;
} }
/* not found */ if (mrb_func_basic_p(mrb, hash, mrb_intern_lit(mrb, "default"), mrb_hash_default)) {
return hash_default(mrb, hash, key);
}
/* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
return mrb_funcall(mrb, hash, "default", 1, key); return mrb_funcall(mrb, hash, "default", 1, key);
} }
...@@ -366,6 +371,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self) ...@@ -366,6 +371,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
return mrb_hash_get(mrb, self, key); return mrb_hash_get(mrb, self, key);
} }
static mrb_value
hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
{
if (MRB_RHASH_DEFAULT_P(hash)) {
if (MRB_RHASH_PROCDEFAULT_P(hash)) {
return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
}
else {
return RHASH_IFNONE(hash);
}
}
return mrb_nil_value();
}
/* 15.2.13.4.5 */ /* 15.2.13.4.5 */
/* /*
* call-seq: * call-seq:
......
...@@ -28,15 +28,21 @@ typedef enum { ...@@ -28,15 +28,21 @@ typedef enum {
NOEX_RESPONDS = 0x80 NOEX_RESPONDS = 0x80
} mrb_method_flag_t; } mrb_method_flag_t;
static mrb_bool MRB_API mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func)
{ {
struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s")); struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid);
if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s)) if (MRB_PROC_CFUNC_P(me) && (me->body.func == func))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
static mrb_bool
mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
{
return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s);
}
/* 15.3.1.3.17 */ /* 15.3.1.3.17 */
/* /*
* call-seq: * call-seq:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment