diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-02-14 00:22:12 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-02-14 00:22:12 +0900 |
| commit | 30aa5218543cd44df7c1d90a5c10cf6f622f5a8a (patch) | |
| tree | ad1bf7f27553f551563fce4ae80db0c2bcd831c8 /src | |
| parent | 719f700adf7598d0ad910dcd3a94aad2ef354033 (diff) | |
| download | mruby-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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/hash.c | 21 | ||||
| -rw-r--r-- | src/kernel.c | 14 |
2 files changed, 30 insertions, 5 deletions
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: |
