From 59201b59046b9e73c309508350cd3c0fafd20e4d Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 28 Jun 2021 23:04:43 +0900 Subject: Drop unnecessary upper procs linked from class/module/def syntax It does not need to hold an anonymous proc for constant search. Also, this change can be expected to cause an anonymous proc to be GC'd. This is useful for metaprogramming that makes heavy use of the `class`/`module`/`def` syntax in the `class_eval`/`eval` method. Example: - code ```ruby p ObjectSpace.count_objects String.class_eval do def a end end p ObjectSpace.count_objects String.class_eval do eval <<~CODE def b end CODE end p ObjectSpace.count_objects ``` - result of building mruby-head (d63c0df6b) with `build_config/default.rb` ``` {:TOTAL=>1024, :FREE=>262, :T_PROC=>495, :T_ENV=>61, ...} {:TOTAL=>1024, :FREE=>259, :T_PROC=>497, :T_ENV=>62, ...} {:TOTAL=>1024, :FREE=>255, :T_PROC=>500, :T_ENV=>63, ...} ``` - result of building mruby with this patch and `build_config/default.rb` ``` {:TOTAL=>1024, :FREE=>264, :T_PROC=>494, :T_ENV=>60, ...} {:TOTAL=>1024, :FREE=>262, :T_PROC=>495, :T_ENV=>61, ...} {:TOTAL=>1024, :FREE=>261, :T_PROC=>496, :T_ENV=>61, ...} ``` --- src/vm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/vm.c') diff --git a/src/vm.c b/src/vm.c index 877057bd6..2b4a21e6c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1068,6 +1068,19 @@ get_send_args(mrb_state *mrb, mrb_int argc, mrb_value *regs) return mrb_ary_new_from_values(mrb, argc, regs); } +static void +proc_adjust_upper(struct RProc *p) +{ + /* skip upper procs while unnamed blocks and method closures */ + while (p->upper) { + if (MRB_FLAG_TEST(p->upper, MRB_PROC_SCOPE) && + !MRB_FLAG_TEST(p->upper, MRB_PROC_STRICT)) { + break; + } + p->upper = p->upper->upper; + } +} + mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod); void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid); @@ -2718,6 +2731,7 @@ RETRY_TRY_BLOCK: p->flags |= MRB_PROC_SCOPE; } if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT; + if (c == OP_L_METHOD) proc_adjust_upper(p); regs[a] = mrb_obj_value(p); mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2812,6 +2826,7 @@ RETRY_TRY_BLOCK: mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)proc); MRB_PROC_SET_TARGET_CLASS(p, mrb_class_ptr(recv)); p->flags |= MRB_PROC_SCOPE; + proc_adjust_upper(p); /* prepare call stack */ cipush(mrb, a, a, mrb_class_ptr(recv), p, 0, 0); -- cgit v1.2.3