summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
authordearblue <[email protected]>2021-06-28 23:04:43 +0900
committerdearblue <[email protected]>2021-06-28 23:04:43 +0900
commit59201b59046b9e73c309508350cd3c0fafd20e4d (patch)
tree8324908ff5b72bc5da89e97a7dccf8e0a6acc220 /src/vm.c
parentd63c0df6bcd5851522c4b982dba4e0a93f44a2d7 (diff)
downloadmruby-59201b59046b9e73c309508350cd3c0fafd20e4d.tar.gz
mruby-59201b59046b9e73c309508350cd3c0fafd20e4d.zip
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, ...} ```
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c15
1 files changed, 15 insertions, 0 deletions
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);