diff options
| author | dearblue <[email protected]> | 2021-06-28 23:04:43 +0900 |
|---|---|---|
| committer | dearblue <[email protected]> | 2021-06-28 23:04:43 +0900 |
| commit | 59201b59046b9e73c309508350cd3c0fafd20e4d (patch) | |
| tree | 8324908ff5b72bc5da89e97a7dccf8e0a6acc220 /src/vm.c | |
| parent | d63c0df6bcd5851522c4b982dba4e0a93f44a2d7 (diff) | |
| download | mruby-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.c | 15 |
1 files changed, 15 insertions, 0 deletions
@@ -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); |
