diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 9e4432f4d..51b8a4da0 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -113,6 +113,8 @@ OPCODE(CLASS, BB) /* R[a] = newclass(R[a],Syms[b],R[a+1]) */ OPCODE(MODULE, BB) /* R[a] = newmodule(R[a],Syms[b]) */ OPCODE(EXEC, BB) /* R[a] = blockexec(R[a],Irep[b]) */ OPCODE(DEF, BB) /* R[a].newmethod(Syms[b],R[a+1]); R[a] = Syms[b] */ +OPCODE(TDEF, BBB) /* target_class.newmethod(Syms[b],Irep[c]); R[a] = Syms[b] */ +OPCODE(SDEF, BBB) /* R[a].singleton_class.newmethod(Syms[b],Irep[c]); R[a] = Syms[b] */ OPCODE(ALIAS, BB) /* alias_method(target_class,Syms[a],Syms[b]) */ OPCODE(UNDEF, B) /* undef_method(target_class,Syms[a]) */ OPCODE(SCLASS, B) /* R[a] = R[a].singleton_class */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index e0da700e5..080380839 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -5017,12 +5017,18 @@ codegen_def(codegen_scope *s, node *varnode, int val) /* For NODE_DEF, args should contain the full locals structure from defn_setup */ int idx = lambda_body(s, def_n->locals, def_n->args, def_n->body, 0); - genop_1(s, OP_TCLASS, cursp()); - push(); - genop_2(s, OP_METHOD, cursp(), idx); - push(); pop(); - pop(); - genop_2(s, OP_DEF, cursp(), sym); + if (idx <= 0xff) { + /* TDEF fusion: TCLASS + METHOD + DEF -> TDEF */ + genop_3(s, OP_TDEF, cursp(), sym, idx); + } + else { + genop_1(s, OP_TCLASS, cursp()); + push(); + genop_2(s, OP_METHOD, cursp(), idx); + push(); pop(); + pop(); + genop_2(s, OP_DEF, cursp(), sym); + } if (val) push(); } @@ -6400,12 +6406,18 @@ codegen_sdef(codegen_scope *s, const node *varnode, int val) codegen(s, recv, VAL); pop(); - genop_1(s, OP_SCLASS, cursp()); - push(); - genop_2(s, OP_METHOD, cursp(), idx); - push(); pop(); - pop(); - genop_2(s, OP_DEF, cursp(), sym); + if (idx <= 0xff) { + /* SDEF fusion: SCLASS + METHOD + DEF -> SDEF */ + genop_3(s, OP_SDEF, cursp(), sym, idx); + } + else { + genop_1(s, OP_SCLASS, cursp()); + push(); + genop_2(s, OP_METHOD, cursp(), idx); + push(); pop(); + pop(); + genop_2(s, OP_DEF, cursp(), sym); + } if (val) push(); } diff --git a/src/codedump.c b/src/codedump.c index 14191c0f3..308dee72f 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -427,6 +427,12 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out) CASE(OP_DEF, BB): fprintf(out, "DEF\t\tR%d\t:%s\t(R%d)\n", a, mrb_sym_dump(mrb, irep->syms[b]),a+1); break; + CASE(OP_TDEF, BBB): + fprintf(out, "TDEF\t\tR%d\t:%s\tI[%d]\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); + break; + CASE(OP_SDEF, BBB): + fprintf(out, "SDEF\t\tR%d\t:%s\tI[%d]\n", a, mrb_sym_dump(mrb, irep->syms[b]), c); + break; CASE(OP_UNDEF, B): fprintf(out, "UNDEF\t\t:%s\n", mrb_sym_dump(mrb, irep->syms[a])); break; diff --git a/src/vm.c b/src/vm.c index 667d09cf1..3f99147ba 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3396,6 +3396,42 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_TDEF, BBB) { + struct RClass *target = check_target_class(mrb); + if (!target) goto L_RAISE; + struct RProc *p = mrb_proc_new(mrb, irep->reps[c]); + mrb_method_t m; + mrb_sym mid = irep->syms[b]; + + p->flags |= MRB_PROC_SCOPE | MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + MRB_METHOD_SET_VISIBILITY(m, MRB_METHOD_VDEFAULT_FL); + mrb_define_method_raw(mrb, target, mid, m); + mrb_method_added(mrb, target, mid); + ci = mrb->c->ci; + mrb_gc_arena_restore(mrb, ai); + regs[a] = mrb_symbol_value(mid); + NEXT; + } + + CASE(OP_SDEF, BBB) { + mrb_value recv = regs[a]; + struct RClass *target = mrb_class_ptr(mrb_singleton_class(mrb, recv)); + struct RProc *p = mrb_proc_new(mrb, irep->reps[c]); + mrb_method_t m; + mrb_sym mid = irep->syms[b]; + + p->flags |= MRB_PROC_SCOPE | MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + MRB_METHOD_SET_VISIBILITY(m, MRB_METHOD_VDEFAULT_FL); + mrb_define_method_raw(mrb, target, mid, m); + mrb_method_added(mrb, target, mid); + ci = mrb->c->ci; + mrb_gc_arena_restore(mrb, ai); + regs[a] = mrb_symbol_value(mid); + NEXT; + } + CASE(OP_SCLASS, B) { regs[a] = mrb_singleton_class(mrb, regs[a]); mrb_gc_arena_restore(mrb, ai);