summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-02-14 00:22:12 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-02-14 00:22:12 +0900
commit30aa5218543cd44df7c1d90a5c10cf6f622f5a8a (patch)
treead1bf7f27553f551563fce4ae80db0c2bcd831c8
parent719f700adf7598d0ad910dcd3a94aad2ef354033 (diff)
downloadmruby-30aa5218543cd44df7c1d90a5c10cf6f622f5a8a.tar.gz
mruby-30aa5218543cd44df7c1d90a5c10cf6f622f5a8a.zip
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.
-rw-r--r--include/mruby.h1
-rw-r--r--src/hash.c21
-rw-r--r--src/kernel.c14
3 files changed, 31 insertions, 5 deletions
diff --git a/include/mruby.h b/include/mruby.h
index 99d06146f..6950cf904 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -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_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);
/*
diff --git a/src/hash.c b/src/hash.c
index 98feaceac..b7bd648c0 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -159,6 +159,9 @@ mrb_hash_new(mrb_state *mrb)
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_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;
}
- /* 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); */
return mrb_funcall(mrb, hash, "default", 1, key);
}
@@ -366,6 +371,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
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 */
/*
* call-seq:
diff --git a/src/kernel.c b/src/kernel.c
index 8b00d701b..02bb3c99b 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -28,15 +28,21 @@ typedef enum {
NOEX_RESPONDS = 0x80
} mrb_method_flag_t;
-static mrb_bool
-mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj)
+MRB_API mrb_bool
+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"));
- if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s))
+ struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid);
+ if (MRB_PROC_CFUNC_P(me) && (me->body.func == func))
return TRUE;
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 */
/*
* call-seq: