diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2019-09-18 10:31:28 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2019-09-18 10:31:28 +0900 |
| commit | ca2d47c20f91dc0ceec72052c28717bb0d7a74ef (patch) | |
| tree | 807a212e030f00135141b255b10a317458d610ed | |
| parent | 47add060cc9e7b8492b5fda0dd712bcd2d7f0d32 (diff) | |
| download | mruby-ca2d47c20f91dc0ceec72052c28717bb0d7a74ef.tar.gz mruby-ca2d47c20f91dc0ceec72052c28717bb0d7a74ef.zip | |
Fix `super` from aliased methods to work correctly; fix #4718
We needed to preserve the original method name somewhere. We kept it in
the `env` structure pointed from aliased methods. #1457 and #1531 tried
to address this issue. But this patch is more memory efficient.
Limitation: this fix does not support `super` from methods defined by
`define_method`. This limitation may be addressed in the future, but
it's low priority.
| -rw-r--r-- | src/class.c | 19 | ||||
| -rw-r--r-- | src/proc.c | 3 | ||||
| -rw-r--r-- | src/vm.c | 8 |
3 files changed, 28 insertions, 2 deletions
diff --git a/src/class.c b/src/class.c index 82ad3cf0a..1b0a37d05 100644 --- a/src/class.c +++ b/src/class.c @@ -1741,6 +1741,25 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) { mrb_method_t m = mrb_method_search(mrb, c, b); + if (!MRB_METHOD_CFUNC_P(m)) { + struct RProc *p = MRB_METHOD_PROC(m); + + if (MRB_PROC_ENV_P(p)) { + MRB_PROC_ENV(p)->mid = b; + } + else { + struct RClass *tc = MRB_PROC_TARGET_CLASS(p); + struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); + + e->mid = b; + if (tc) { + e->c = tc; + mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); + } + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + } + } mrb_define_method_raw(mrb, c, a, m); } diff --git a/src/proc.c b/src/proc.c index 5283e5a3e..5f32fcfd1 100644 --- a/src/proc.c +++ b/src/proc.c @@ -77,6 +77,9 @@ closure_setup(mrb_state *mrb, struct RProc *p) e->c = tc; mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); } + if (MRB_PROC_ENV_P(up) && MRB_PROC_ENV(up)->cxt == NULL) { + e->mid = MRB_PROC_ENV(up)->mid; + } } if (e) { p->e.env = e; @@ -1558,9 +1558,13 @@ RETRY_TRY_BLOCK: struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; + struct RProc *p = ci->proc; mrb_sym mid = ci->mid; - struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); + struct RClass* target_class = MRB_PROC_TARGET_CLASS(p); + if (MRB_PROC_ENV_P(p) && p->e.env->mid && p->e.env->mid != mid) { /* alias support */ + mid = p->e.env->mid; /* restore old mid */ + } mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { @@ -2020,7 +2024,7 @@ RETRY_TRY_BLOCK: if (MRB_PROC_ENV_P(dst)) { struct REnv *e = MRB_PROC_ENV(dst); - if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt != mrb->c) { + if (!MRB_ENV_STACK_SHARED_P(e) || (e->cxt && e->cxt != mrb->c)) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } |
